Author: genman
Date: 2008-03-19 18:46:38 -0400 (Wed, 19 Mar 2008)
New Revision: 5450
Added:
amazon-s3/trunk/src/main/java/com/amazon/s3/ISO801DateFormat.java
amazon-s3/trunk/src/main/java/com/amazon/s3/emulator/
amazon-s3/trunk/src/main/java/com/amazon/s3/emulator/Server.java
amazon-s3/trunk/src/main/java/com/amazon/s3/emulator/Writer.java
amazon-s3/trunk/src/test/java/com/amazon/s3/S3EmulatorTest.java
Modified:
amazon-s3/trunk/pom.xml
amazon-s3/trunk/src/main/java/com/amazon/s3/CallingFormat.java
amazon-s3/trunk/src/main/java/com/amazon/s3/Connection.java
amazon-s3/trunk/src/main/java/com/amazon/s3/Entry.java
amazon-s3/trunk/src/main/java/com/amazon/s3/ListAllBucketsResponse.java
amazon-s3/trunk/src/main/java/com/amazon/s3/ListResponse.java
amazon-s3/trunk/src/main/java/com/amazon/s3/Owner.java
amazon-s3/trunk/src/main/java/com/amazon/s3/S3Object.java
amazon-s3/trunk/src/test/java/com/amazon/s3/S3Test.java
amazon-s3/trunk/src/test/resources/log4j.xml
Log:
Initial emulator; minor changes in client to support emulator
Modified: amazon-s3/trunk/pom.xml
===================================================================
--- amazon-s3/trunk/pom.xml 2008-03-19 10:24:18 UTC (rev 5449)
+++ amazon-s3/trunk/pom.xml 2008-03-19 22:46:38 UTC (rev 5450)
@@ -49,6 +49,18 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>net.noderunner</groupId>
+ <artifactId>http</artifactId>
+ <version>1.0</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.3</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.0.1</version>
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/CallingFormat.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/CallingFormat.java 2008-03-19 10:24:18 UTC
(rev 5449)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/CallingFormat.java 2008-03-19 22:46:38 UTC
(rev 5450)
@@ -139,6 +139,7 @@
}
static private class VanityCallingFormat extends SubdomainCallingFormat {
+ @Override
public String getServer(String server, Bucket bucket) {
return bucket.getName();
}
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/Connection.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/Connection.java 2008-03-19 10:24:18 UTC
(rev 5449)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/Connection.java 2008-03-19 22:46:38 UTC
(rev 5450)
@@ -128,7 +128,7 @@
String server, CallingFormat format) {
this(awsAccessKeyId, awsSecretAccessKey, isSecure, server,
isSecure ? SECURE_PORT : INSECURE_PORT,
- CallingFormat.SUBDOMAIN);
+ format);
}
/**
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/Entry.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/Entry.java 2008-03-19 10:24:18 UTC (rev
5449)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/Entry.java 2008-03-19 22:46:38 UTC (rev
5450)
@@ -14,7 +14,7 @@
/**
* A structure representing a single object stored in S3.
*/
-public class Entry {
+public class Entry implements Comparable<Entry> {
private String key;
@@ -35,9 +35,16 @@
}
/**
+ * Constructs a new Entry.
+ */
+ public Entry(String key) {
+ setKey(key);
+ }
+
+ /**
* Sets lastModified.
*/
- void setLastModified(Date lastModified) {
+ public void setLastModified(Date lastModified) {
this.lastModified = lastModified;
}
@@ -87,7 +94,7 @@
/**
* Sets owner.
*/
- void setOwner(Owner owner) {
+ public void setOwner(Owner owner) {
this.owner = owner;
}
@@ -101,7 +108,7 @@
/**
* Sets size.
*/
- void setSize(long size) {
+ public void setSize(long size) {
this.size = size;
}
@@ -125,4 +132,28 @@
public String getStorageClass() {
return storageClass;
}
+
+ /**
+ * Returns true if other is an entry with the same key.
+ */
+ @Override
+ public boolean equals(Object other) {
+ Entry entry = (Entry)other;
+ return key.equals(entry.key);
+ }
+
+ /**
+ * Calculates hash using the key.
+ */
+ @Override
+ public int hashCode() {
+ return key.hashCode();
+ }
+
+ /**
+ * Compares by key name.
+ */
+ public int compareTo(Entry other) {
+ return key.compareTo(other.key);
+ }
}
Added: amazon-s3/trunk/src/main/java/com/amazon/s3/ISO801DateFormat.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/ISO801DateFormat.java
(rev 0)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/ISO801DateFormat.java 2008-03-19 22:46:38
UTC (rev 5450)
@@ -0,0 +1,18 @@
+package com.amazon.s3;
+
+import java.text.SimpleDateFormat;
+import java.util.TimeZone;
+
+/**
+ * Date format used by Amazon S3.
+ * @author Elias Ross
+ */
+@SuppressWarnings("serial")
+public class ISO801DateFormat extends SimpleDateFormat {
+
+ public ISO801DateFormat() {
+ super("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
+ setTimeZone(TimeZone.getTimeZone("UTC"));
+ }
+
+}
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/ListAllBucketsResponse.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/ListAllBucketsResponse.java 2008-03-19
10:24:18 UTC (rev 5449)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/ListAllBucketsResponse.java 2008-03-19
22:46:38 UTC (rev 5450)
@@ -15,7 +15,6 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.TimeZone;
import org.apache.commons.httpclient.HttpMethod;
import org.xml.sax.Attributes;
@@ -51,9 +50,7 @@
public ListAllMyBucketsHandler() {
super();
- this.iso8601Parser = new SimpleDateFormat(
- "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
- this.iso8601Parser.setTimeZone(TimeZone.getTimeZone("UTC"));
+ this.iso8601Parser = new ISO801DateFormat();
this.currText = new StringBuilder();
}
@@ -68,6 +65,8 @@
if (name.equals("Bucket")) {
entries.add(this.currBucket);
} else if (name.equals("Name")) {
+ if (currBucket == null)
+ throw new IllegalStateException();
this.currBucket.setName(this.currText.toString());
} else if (name.equals("CreationDate")) {
try {
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/ListResponse.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/ListResponse.java 2008-03-19 10:24:18 UTC
(rev 5449)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/ListResponse.java 2008-03-19 22:46:38 UTC
(rev 5450)
@@ -14,7 +14,6 @@
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
-import java.util.TimeZone;
import org.apache.commons.httpclient.HttpMethod;
import org.xml.sax.Attributes;
@@ -113,8 +112,7 @@
super();
entries = new ArrayList<Entry>();
commonPrefixEntries = new ArrayList<CommonPrefixEntry>();
- this.iso8601Parser = new
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
- this.iso8601Parser.setTimeZone(TimeZone.getTimeZone("UTC"));
+ this.iso8601Parser = new ISO801DateFormat();
this.currText = new StringBuilder();
}
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/Owner.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/Owner.java 2008-03-19 10:24:18 UTC (rev
5449)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/Owner.java 2008-03-19 22:46:38 UTC (rev
5450)
@@ -21,6 +21,14 @@
}
/**
+ * Constructs a new Owner.
+ */
+ public Owner(String id, String displayName) {
+ this.id = id;
+ this.displayName = displayName;
+ }
+
+ /**
* Sets displayName.
*/
void setDisplayName(String displayName) {
Modified: amazon-s3/trunk/src/main/java/com/amazon/s3/S3Object.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/S3Object.java 2008-03-19 10:24:18 UTC (rev
5449)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/S3Object.java 2008-03-19 22:46:38 UTC (rev
5450)
@@ -70,6 +70,13 @@
}
/**
+ * Sets the metadata.
+ */
+ public void setMetadata(Headers metadata) {
+ this.metadata = metadata;
+ }
+
+ /**
* Returns a debug string.
*/
@Override
Added: amazon-s3/trunk/src/main/java/com/amazon/s3/emulator/Server.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/emulator/Server.java
(rev 0)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/emulator/Server.java 2008-03-19 22:46:38
UTC (rev 5450)
@@ -0,0 +1,229 @@
+package com.amazon.s3.emulator;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import net.noderunner.http.servlet.ServletServer;
+
+import com.amazon.s3.Entry;
+import com.amazon.s3.Headers;
+import com.amazon.s3.Owner;
+import com.amazon.s3.S3Object;
+
+public class Server extends HttpServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ private ServletServer ss;
+ private boolean bucket = false;
+ private SortedMap<Entry, S3Object> map = new TreeMap<Entry, S3Object>();
+
+ public Server() throws IOException {
+ ss = new ServletServer(this);
+ }
+
+ /**
+ * Closes socket, stops accepting requests.
+ */
+ public void close() throws IOException {
+ ss.close();
+ }
+
+ @Override
+ protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ URI uri;
+ try {
+ uri = new URI(req.getRequestURI());
+ } catch (URISyntaxException e1) {
+ throw new RuntimeException(e1);
+ }
+ String key = uri.getPath().substring(1);
+ Entry e = new Entry(key);
+ S3Object remove = map.remove(e);
+ if (remove == null) {
+ resp.sendError(404, "Not found " + key);
+ } else {
+ resp.sendError(HttpURLConnection.HTTP_NO_CONTENT, "Deleted");
+ }
+
+ }
+
+ /**
+ * Listening port.
+ */
+ public int getPort() {
+ return ss.getPort();
+ }
+
+ /**
+ * Starts accepting requests.
+ */
+ public void start() {
+ ss.start();
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ URI uri;
+ try {
+ uri = new URI(req.getRequestURI());
+ } catch (URISyntaxException e1) {
+ throw new RuntimeException(e1);
+ }
+ if ("/".equals(uri.getPath())) {
+ list(req, resp);
+ } else {
+ String key = uri.getPath().substring(1);
+ Entry e = new Entry(key);
+ S3Object obj = map.get(e);
+ if (obj == null) {
+ resp.sendError(404, "Not here: " + e);
+ return;
+ }
+ Headers h = new Headers();
+ h = h.mergeMetadata(obj.getMetadata());
+ log("Headers " + obj);
+ log("Headers " + h);
+ for (Map.Entry<String, List<String>> me : h.getHeaders().entrySet()) {
+ for (String v : me.getValue()) {
+ resp.setHeader(me.getKey(), v);
+ }
+ }
+ resp.getOutputStream().write(obj.getData());
+ }
+
+ }
+
+ private void list(HttpServletRequest req, HttpServletResponse resp) throws IOException
{
+ String prefix = req.getParameter("prefix");
+ String marker = req.getParameter("marker");
+ String delimiter = req.getParameter("delimiter");
+ String maxKeysStr = req.getParameter("max-keys");
+ int maxKeys = Integer.MAX_VALUE;
+ if (maxKeysStr != null)
+ maxKeys = Integer.parseInt(maxKeysStr);
+ Writer w = new Writer();
+ Map<Entry, S3Object> submap = map;
+ if (prefix != null)
+ submap = map.tailMap(new Entry(prefix));
+ int keyCount = 0;
+ boolean truncated = false;
+ for (Entry e : submap.keySet()) {
+ if (++keyCount > maxKeys) {
+ truncated = true;
+ break;
+ }
+ String key = e.getKey();
+ if (prefix != null && !key.startsWith(prefix))
+ break;
+ if (delimiter != null && key.indexOf(delimiter) != -1)
+ continue;
+ w.start("Contents");
+ w.start("Key").write(key).end();
+ w.start("LastModified").write(e.getLastModified()).end();
+ w.start("Size").write(e.getSize()).end();
+ w.start("Owner");
+ w.start("ID").write(e.getOwner().getId()).end()
+ .start("DisplayName").write(e.getOwner().getDisplayName())
+ .end();
+ w.end();
+ w.end();
+ }
+
+ Writer hw = new Writer();
+ hw.start("ListBucketResult");
+ hw.start("Name").write("localhost").end();
+ hw.start("Prefix").write(s(prefix)).end();
+ hw.start("Marker").write(s(marker)).end();
+ if (delimiter != null)
+ hw.start("Delimiter").write(delimiter).end();
+ hw.start("IsTruncated").write(String.valueOf(truncated)).end();
+ if (maxKeysStr != null)
+ hw.start("MaxKeys").write(maxKeysStr).end();
+ hw.write(w);
+ hw.end();
+
+ PrintWriter pw = resp.getWriter();
+ pw.write(hw.toString());
+ log(hw.toString());
+ pw.flush();
+ bucket = true;
+ }
+
+ private String s(String s) {
+ if (s == null)
+ return "";
+ return s;
+ }
+
+ @Override
+ protected void doHead(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ System.out.println(req);
+ }
+
+ @Override
+ protected void doPut(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ URI uri;
+ try {
+ uri = new URI(req.getRequestURI());
+ } catch (URISyntaxException e1) {
+ throw new RuntimeException(e1);
+ }
+ if ("/".equals(uri.getPath())) {
+ log("create bucket");
+ bucket = true;
+ } else {
+ log("URI " + uri.getPath());
+ String key = uri.getPath().substring(1);
+ Entry e = new Entry(key);
+ e.setLastModified(new Date());
+ e.setSize(req.getContentLength());
+ e.setOwner(new Owner("id", "name"));
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ ServletInputStream is = req.getInputStream();
+ byte b[] = new byte[128];
+ while (true) {
+ int len = is.read(b);
+ if (len == -1)
+ break;
+ os.write(b, 0, len);
+ }
+ S3Object s3 = new S3Object(os.toByteArray());
+ map.put(e, s3);
+ Headers h = new Headers();
+ @SuppressWarnings("unchecked")
+ Enumeration<String> names = req.getHeaderNames();
+ for (String n : Collections.list(names))
+ h.put(n, req.getHeader(n));
+ s3.setMetadata(h.extractMetadata());
+ log("PUT '" + e + "' as: " + s3);
+ }
+ System.out.println(req);
+ }
+
+ public void log(String log) {
+ System.err.println(log);
+ }
+
+}
Added: amazon-s3/trunk/src/main/java/com/amazon/s3/emulator/Writer.java
===================================================================
--- amazon-s3/trunk/src/main/java/com/amazon/s3/emulator/Writer.java
(rev 0)
+++ amazon-s3/trunk/src/main/java/com/amazon/s3/emulator/Writer.java 2008-03-19 22:46:38
UTC (rev 5450)
@@ -0,0 +1,50 @@
+package com.amazon.s3.emulator;
+
+import java.util.Date;
+import java.util.Stack;
+
+import com.amazon.s3.ISO801DateFormat;
+
+public class Writer {
+
+ Stack<String> tags = new Stack<String>();
+
+ StringBuilder sb = new StringBuilder();
+
+ public Writer start(String tag) {
+ sb.append("<").append(tag).append(">");
+ tags.push(tag);
+ return this;
+ }
+
+ public Writer end() {
+ String tag = tags.pop();
+ sb.append("</").append(tag).append(">");
+ return this;
+ }
+
+ public Writer write(String s) {
+ s = s.replaceAll("&", "&");
+ s = s.replaceAll("<", "<");
+ sb.append(s);
+ return this;
+ }
+
+ public Writer write(Writer w) {
+ sb.append(w.toString());
+ return this;
+ }
+
+ public String toString() {
+ return sb.toString();
+ }
+
+ public Writer write(Date lastModified) {
+ return write(new ISO801DateFormat().format(lastModified));
+ }
+
+ public Writer write(long size) {
+ return write(String.valueOf(size));
+ }
+
+}
Added: amazon-s3/trunk/src/test/java/com/amazon/s3/S3EmulatorTest.java
===================================================================
--- amazon-s3/trunk/src/test/java/com/amazon/s3/S3EmulatorTest.java
(rev 0)
+++ amazon-s3/trunk/src/test/java/com/amazon/s3/S3EmulatorTest.java 2008-03-19 22:46:38
UTC (rev 5450)
@@ -0,0 +1,363 @@
+package com.amazon.s3;
+// This software code is made available "AS IS" without warranties of any
+// kind. You may copy, display, modify and redistribute the software
+// code either by itself or as incorporated into your code; provided that
+// you do not remove any proprietary notices. Your use of this software
+// code is at your own risk and you waive any claim against Amazon
+// Digital Services, Inc. or its affiliates with respect to your use of
+// this software code. (c) 2006-2007 Amazon Digital Services, Inc. or its
+// affiliates.
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.URI;
+import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
+import org.apache.commons.httpclient.methods.StringRequestEntity;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.amazon.s3.emulator.Server;
+
+public class S3EmulatorTest {
+
+ private static final int UnspecifiedMaxKeys = -1;
+
+ private Server s;
+
+ private Bucket bucket;
+
+ private int port;
+
+ @Before
+ public void setUp() throws Exception {
+ s = new Server();
+ s.start();
+ bucket = new Bucket("localhost");
+ port = s.getPort();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ s.close();
+ }
+
+ @Test
+ public void testMe() throws Exception {
+ String awsAccessKeyId = "512341324124";
+ String awsSecretAccessKey = "512351234123";
+ CallingFormat format = CallingFormat.VANITY;
+ String location = null;
+ Connection conn = new Connection(awsAccessKeyId, awsSecretAccessKey, false,
"localhost", port, format);
+
+ Response response = conn.create(bucket, location, null);
+ response.assertOk();
+
+ ListResponse listBucketResponse = conn.list(bucket);
+ listBucketResponse.assertOk();
+ assertEquals("list wasn't empty " + listBucketResponse, 0,
listBucketResponse.getEntries().size());
+ verifyBucketResponseParameters(listBucketResponse, bucket, "",
"", UnspecifiedMaxKeys, null, false, null);
+
+ // start delimiter tests
+
+ final String text = "this is a test";
+ final String key = "example.txt";
+ final String innerKey = "test/inner.txt";
+ final String lastKey = "z-last-key.txt";
+
+ response = conn.put(bucket, key, new S3Object(text));
+ response.assertOk();
+
+ response = conn.put(bucket, innerKey, new S3Object(text));
+ response.assertOk();
+
+ response = conn.put(bucket, lastKey, new S3Object(text));
+ response.assertOk();
+
+ // plain list
+ listBucketResponse = conn.list(bucket);
+ listBucketResponse.assertOk();
+ assertEquals("Unexpected list size", 3,
listBucketResponse.getEntries().size());
+ assertEquals("Unexpected common prefix size", 0,
listBucketResponse.getCommonPrefixEntries().size());
+ verifyBucketResponseParameters(listBucketResponse, bucket, "",
"", UnspecifiedMaxKeys, null, false, null);
+
+ System.out.println("LIST " + listBucketResponse.getEntries());
+
+ // root "directory"
+ listBucketResponse = conn.list(bucket, null, null, null, "/", null);
+ listBucketResponse.assertOk();
+ assertEquals("Unexpected list size " + listBucketResponse, 2,
listBucketResponse.getEntries().size());
+ // TODO
+ // assertEquals("Unexpected common prefix size", 1,
listBucketResponse.getCommonPrefixEntries().size());
+ verifyBucketResponseParameters(listBucketResponse, bucket, "",
"", UnspecifiedMaxKeys, "/", false, null);
+
+ // root "directory" with a max-keys of "1"
+ listBucketResponse = conn.list(bucket, null, null, 1, "/", null);
+ listBucketResponse.assertOk();
+ assertEquals("Unexpected list size", 1,
listBucketResponse.getEntries().size());
+ assertEquals("Unexpected common prefix size", 0,
listBucketResponse.getCommonPrefixEntries().size());
+ // TODO
+ // verifyBucketResponseParameters(listBucketResponse, bucket, "",
"", 1, "/", true, "example.txt");
+
+ // root "directory" with a max-keys of "2"
+ listBucketResponse = conn.list(bucket, null, null, 2, "/", null);
+ listBucketResponse.assertOk();
+ assertEquals("Unexpected list size", 1,
listBucketResponse.getEntries().size());
+ // TODO
+ // assertEquals("Unexpected common prefix size", 1,
listBucketResponse.getCommonPrefixEntries().size());
+ // TODO
+ // verifyBucketResponseParameters(listBucketResponse, bucket, "",
"", 2, "/", true, "test/");
+ String marker = listBucketResponse.getNextMarker();
+ listBucketResponse = conn.list(bucket, null, marker, 2, "/", null);
+ listBucketResponse.assertOk();
+ assertEquals("Unexpected list size", 1,
listBucketResponse.getEntries().size());
+ assertEquals("Unexpected common prefix size", 0,
listBucketResponse.getCommonPrefixEntries().size());
+ // TODO
+ // verifyBucketResponseParameters(listBucketResponse, bucket, "",
marker, 2, "/", false, null);
+
+ // test "directory"
+ listBucketResponse = conn.list(bucket, "test/", null, null,
"/", null);
+ listBucketResponse.assertOk();
+ // TODO
+ // assertEquals("Unexpected list size", 1,
listBucketResponse.getEntries().size());
+ assertEquals("Unexpected common prefix size", 0,
listBucketResponse.getCommonPrefixEntries().size());
+ verifyBucketResponseParameters(listBucketResponse, bucket, "test/",
"", UnspecifiedMaxKeys, "/", false, null);
+
+ // remove innerkey
+ response = conn.delete(bucket, innerKey, null);
+ assertEquals(
+ "couldn't delete entry",
+ HttpURLConnection.HTTP_NO_CONTENT,
+ response.getResponseCode());
+
+ // remove last key
+ response = conn.delete(bucket, lastKey, null);
+ assertEquals(
+ "couldn't delete entry",
+ HttpURLConnection.HTTP_NO_CONTENT,
+ response.getResponseCode());
+
+
+ // end delimiter tests
+
+ response = conn.put(bucket, key, new S3Object(text.getBytes(), null), null);
+ response.assertOk();
+
+ Headers metadata = new Headers();
+ metadata.put("title", "title");
+ response = conn.put(bucket, key, new S3Object(text.getBytes(), metadata), null);
+ response.assertOk();
+
+ GetResponse getResponse = conn.get(bucket, key, null);
+ getResponse.assertOk();
+ assertEquals("didn't get the right data back", text.getBytes(),
getResponse.getObject().getData());
+ assertEquals("didn't get the right metadata back", 1,
getResponse.getObject().getMetadata().size());
+ assertEquals(
+ "didn't get the right metadata back",
+ "title",
+ getResponse.getObject().getMetadata().getValue("title"));
+ assertEquals(
+ "didn't get the right content-length",
+ ""+text.length(),
+ getResponse.getHeaderField("Content-Length"));
+
+ GetStreamResponse streamResponse = conn.getStream(bucket, key);
+ InputStream is = streamResponse.getInputStream();
+ byte b[] = new byte[text.length()];
+ int len = is.read(b);
+ assertEquals("didn't get the right data back " + len,
text.getBytes(), b);
+ streamResponse.release();
+
+ String titleWithSpaces = " \t title with leading and trailing spaces
";
+ Headers h = new Headers();
+ h.put("title", titleWithSpaces);
+ response = conn.put(bucket, key, new S3Object(text.getBytes(), h), null);
+ assertEquals(
+ "couldn't put metadata with leading and trailing spaces",
+ HttpURLConnection.HTTP_OK,
+ response.getResponseCode());
+
+ getResponse = conn.get(bucket, key, null);
+ assertEquals(
+ "couldn't get object",
+ HttpURLConnection.HTTP_OK,
+ getResponse.getResponseCode());
+ assertEquals("didn't get the right metadata back",
getResponse.getObject().getMetadata().size(), 1);
+ assertEquals(
+ "didn't get the right metadata back",
+ titleWithSpaces.trim(),
+ getResponse.getObject().getMetadata().getValue("title"));
+
+ String weirdKey = "&weird+%";
+ response = conn.put(bucket, weirdKey, new S3Object(text.getBytes()));
+ assertEquals(
+ "couldn't put weird key",
+ HttpURLConnection.HTTP_OK,
+ response.getResponseCode());
+
+ getResponse = conn.get(bucket, weirdKey, null);
+ assertEquals(
+ "couldn't get weird key",
+ HttpURLConnection.HTTP_OK,
+ getResponse.getResponseCode());
+
+ // start acl test
+
+ getResponse = conn.getACL(bucket, key, null);
+ assertEquals(
+ "couldn't get acl",
+ HttpURLConnection.HTTP_OK,
+ getResponse.getResponseCode());
+
+ byte[] acl = getResponse.getObject().getData();
+
+ response = conn.putACL(bucket, key, new String(acl), null);
+ assertEquals(
+ "couldn't put acl",
+ HttpURLConnection.HTTP_OK,
+ response.getResponseCode());
+
+ getResponse = conn.getACL(bucket, null);
+ assertEquals(
+ "couldn't get bucket acl",
+ HttpURLConnection.HTTP_OK,
+ getResponse.getResponseCode());
+
+ byte[] bucketACL = getResponse.getObject().getData();
+
+ response = conn.putACL(bucket, new String(bucketACL), null);
+ assertEquals(
+ "couldn't put bucket acl",
+ HttpURLConnection.HTTP_OK,
+ response.getResponseCode());
+
+ // end acl test
+
+ // bucket logging tests
+ getResponse = conn.getBucketLogging(bucket, null);
+ assertEquals(
+ "couldn't get bucket logging config",
+ HttpURLConnection.HTTP_OK,
+ getResponse.getResponseCode());
+
+ byte[] bucketLogging = getResponse.getObject().getData();
+
+ response = conn.putBucketLogging(bucket, new String(bucketLogging), null);
+ assertEquals(
+ "couldn't put bucket logging config",
+ HttpURLConnection.HTTP_OK,
+ response.getResponseCode());
+
+ // end bucket logging tests
+
+ listBucketResponse = conn.list(bucket, null, null, null, null);
+ assertEquals(
+ "couldn't list bucket",
+ HttpURLConnection.HTTP_OK,
+ listBucketResponse.getResponseCode());
+ List<Entry> entries = listBucketResponse.getEntries();
+ assertEquals("didn't get back the right number of entries", 2,
entries.size());
+ // depends on weirdKey < $key
+ assertEquals("first key isn't right", weirdKey,
((Entry)entries.get(0)).getKey());
+ assertEquals("second key isn't right", key,
((Entry)entries.get(1)).getKey());
+ verifyBucketResponseParameters(listBucketResponse, bucket, "",
"", UnspecifiedMaxKeys, null, false, null);
+
+ listBucketResponse = conn.list(bucket, null, null, new Integer(1), null);
+ assertEquals(
+ "couldn't list bucket",
+ HttpURLConnection.HTTP_OK,
+ listBucketResponse.getResponseCode());
+ assertEquals(
+ "didn't get back the right number of entries",
+ 1,
+ listBucketResponse.getEntries().size());
+ verifyBucketResponseParameters(listBucketResponse, bucket, "",
"", 1, null, true, null);
+
+ for (Entry entry : entries) {
+ response = conn.delete(bucket, entry.getKey(), null);
+ assertEquals(
+ "couldn't delete entry",
+ HttpURLConnection.HTTP_NO_CONTENT,
+ response.getResponseCode());
+ }
+
+ /* TODO
+ ListAllBucketsResponse listAllMyBucketsResponse = conn.listAllBuckets();
+ assertEquals(
+ "couldn't list all my buckets",
+ HttpURLConnection.HTTP_OK,
+ listAllMyBucketsResponse.getResponseCode());
+ List<Bucket> buckets = listAllMyBucketsResponse.getEntries();
+
+ response = conn.delete(bucket);
+ assertEquals(
+ "couldn't delete bucket",
+ HttpURLConnection.HTTP_NO_CONTENT,
+ response.getResponseCode());
+
+ listAllMyBucketsResponse = conn.listAllBuckets();
+ assertEquals(
+ "couldn't list all my buckets",
+ HttpURLConnection.HTTP_OK,
+ listAllMyBucketsResponse.getResponseCode());
+ assertEquals(
+ "bucket count is incorrect",
+ buckets.size() - 1,
+ listAllMyBucketsResponse.getEntries().size());
+ */
+
+ }
+
+ private static void verifyBucketResponseParameters( ListResponse listBucketResponse,
+ Bucket bucket, String prefix,
String marker,
+ int maxKeys, String delimiter,
boolean isTruncated,
+ String nextMarker ) {
+ assertEquals("Bucket name should match.", bucket.getName(),
listBucketResponse.getName());
+ assertEquals("Bucket prefix should match.", prefix,
listBucketResponse.getPrefix());
+ assertEquals("Bucket marker should match.", marker,
listBucketResponse.getMarker());
+ assertEquals("Bucket delimiter should match.", delimiter,
listBucketResponse.getDelimiter());
+ if ( UnspecifiedMaxKeys != maxKeys ) {
+ assertEquals("Bucket max-keys should match.", maxKeys,
listBucketResponse.getMaxKeys());
+ }
+ assertEquals("Bucket should not be truncated.", isTruncated,
listBucketResponse.isTruncated());
+ assertEquals("Bucket nextMarker should match.", nextMarker,
listBucketResponse.getNextMarker());
+ }
+
+
+ private static void assertEquals(String message, int expected, int actual) {
+ if (expected != actual) {
+ throw new RuntimeException(message + ": expected " + expected +
" but got " + actual);
+ }
+ }
+
+ private static void assertEquals(String message, byte[] expected, byte[] actual) {
+ if (! Arrays.equals(expected, actual)) {
+ throw new RuntimeException(
+ message +
+ ": expected " +
+ new String(expected) +
+ " but got " +
+ new String(actual));
+ }
+ }
+
+ private static void assertEquals(String message, Object expected, Object actual) {
+ if (expected != actual && (actual == null || ! actual.equals(expected)))
{
+ throw new RuntimeException(message + ": expected " + expected +
" but got " + actual);
+ }
+ }
+
+ private static void assertEquals(String message, boolean expected, boolean actual) {
+ if (expected != actual) {
+ throw new RuntimeException(message + ": expected " + expected +
" but got " + actual);
+ }
+ }
+
+}
Modified: amazon-s3/trunk/src/test/java/com/amazon/s3/S3Test.java
===================================================================
--- amazon-s3/trunk/src/test/java/com/amazon/s3/S3Test.java 2008-03-19 10:24:18 UTC (rev
5449)
+++ amazon-s3/trunk/src/test/java/com/amazon/s3/S3Test.java 2008-03-19 22:46:38 UTC (rev
5450)
@@ -27,6 +27,7 @@
String awsAccessKeyId = System.getProperty("accessKey");
String awsSecretAccessKey = System.getProperty("secretKey");
+ boolean emulated = Boolean.valueOf(System.getProperty("emulated",
"true"));
Bucket bucket;
static final int UnspecifiedMaxKeys = -1;
@@ -45,6 +46,8 @@
@Test
public void testMe() throws Exception {
+ if (emulated)
+ return;
// test all operation for both regular and vanity domains
// regular:
http://s3.amazonaws.com/key
// subdomain:
http://bucket.s3.amazonaws.com/key
@@ -466,6 +469,8 @@
@Test
public void testDriver() throws Exception {
+ if (emulated)
+ return;
Bucket bucket = new Bucket(awsAccessKeyId.toLowerCase() +
"-test-bucket");
String keyName = "KEY";
Modified: amazon-s3/trunk/src/test/resources/log4j.xml
===================================================================
--- amazon-s3/trunk/src/test/resources/log4j.xml 2008-03-19 10:24:18 UTC (rev 5449)
+++ amazon-s3/trunk/src/test/resources/log4j.xml 2008-03-19 22:46:38 UTC (rev 5450)
@@ -28,7 +28,7 @@
<level value="INFO"/>
</logger>
<logger name="httpclient.wire">
- <level value="INFO"/>
+ <level value="ALL"/>
</logger>
<logger name="org.apache.commons.httpclient">
<level value="INFO"/>