/** * Copyright 2010 TransPac Software, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.bixolabs.aws; import static org.junit.Assert.*; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import org.junit.After; import org.junit.Before; import org.junit.Test; public class SimpleDBIntegrationTest { private SimpleDB _sdb; @Before public void setUp() throws IOException { _sdb = new SimpleDB(TestUtils.getAccessKeyID(), TestUtils.getSecretAccessKey(), new BackoffHttpHandler()); } @After public void tearDown() { if (_sdb != null) { try { _sdb.deleteDomain(TestUtils.TEST_DOMAIN_NAME); } catch (Exception e) { // ignore } } } @Test public void testConnection() throws Exception { assertEquals(TestUtils.TEST_DOMAIN_NAME, _sdb.createDomain(TestUtils.TEST_DOMAIN_NAME)); boolean foundDomain = false; List<String> domains = _sdb.listDomains(); for (String domain : domains) { if (domain.equals(TestUtils.TEST_DOMAIN_NAME)) { foundDomain = true; break; } } assertTrue(foundDomain); assertEquals(TestUtils.TEST_DOMAIN_NAME, _sdb.deleteDomain(TestUtils.TEST_DOMAIN_NAME)); domains = _sdb.listDomains(); for (String domain : domains) { if (domain.equals(TestUtils.TEST_DOMAIN_NAME)) { fail("found domain that was deleted"); } } } @Test public void testDomainMetadata() throws Exception { _sdb.createDomain(TestUtils.TEST_DOMAIN_NAME); Map<String, String> attributes = new HashMap<String, String>(); attributes.put("attr1", "item1-attr1-value1"); attributes.put("attr2", "item1-attr2-value1"); _sdb.putAttributes(TestUtils.TEST_DOMAIN_NAME, "item1", attributes); // Force everything to be updated. _sdb.getAttributes(TestUtils.TEST_DOMAIN_NAME, "item1", true); Thread.sleep(2000); Map<String, String> metadata = _sdb.domainMetaData(TestUtils.TEST_DOMAIN_NAME); for (String key : metadata.keySet()) { System.out.println(key + ": " + metadata.get(key)); } } @Test public void testErrorHandling() throws Exception { try { _sdb.getAttributes(TestUtils.TEST_DOMAIN_NAME, "item1"); fail("Exception not thrown"); } catch (AWSException e) { assertEquals(AWSException.NO_SUCH_DOMAIN, e.getAWSErrorCode()); } } @Test public void testAttributeReadWrite() throws Exception { _sdb.createDomain(TestUtils.TEST_DOMAIN_NAME); // validate XML unescaping by forcing key/value names to be escaped Map<String, String> attributes = new HashMap<String, String>(); attributes.put("attr1", "item1-attr1-<&;>-value1"); attributes.put("attr2", "item1-attr2-<&;>-value2"); _sdb.putAttributes(TestUtils.TEST_DOMAIN_NAME, "item1", attributes); Map<String, String[]> result = _sdb.getAttributes(TestUtils.TEST_DOMAIN_NAME, "item1", true); assertEquals(2, result.size()); assertEquals("item1-attr1-<&;>-value1", result.get("attr1")[0]); assertEquals("item1-attr2-<&;>-value2", result.get("attr2")[0]); } @Test public void testLimit() throws Exception { final String domainName = TestUtils.TEST_DOMAIN_NAME; _sdb.createDomain(domainName); Map<String, String> attributes = new HashMap<String, String>(); attributes.put("status", "LOADED"); final int numBaseItems = 10; for (int i = 0; i < numBaseItems; i++) { _sdb.putAttributes(domainName, "item-" + i, attributes); } while (true) { List<Map<String, String[]>> result = _sdb.select("select count(*) from `" + domainName + "`"); assertEquals(1, result.size()); String count = result.get(0).get("Count")[0]; if (count.equals("" + numBaseItems)) { break; } } List<Map<String, String[]>> result = _sdb.select("select count(*) from `" + domainName + "` limit 1"); assertEquals(1, result.size()); String count = result.get(0).get("Count")[0]; assertEquals("1", count); } @Test public void testSelection() throws Exception { final String domainName = TestUtils.TEST_DOMAIN_NAME; _sdb.createDomain(domainName); Map<String, String> attributes = new HashMap<String, String>(); attributes.put("status", "LOADED"); final int numBaseItems = 10; for (int i = 0; i < numBaseItems; i++) { _sdb.putAttributes(domainName, "item-" + i, attributes); } attributes.put("status", "ERROR"); _sdb.putAttributes(domainName, "item-special", attributes); List<Map<String, String[]>> result = _sdb.select("select count(*) from `" + domainName + "` where status = 'ERROR'", true); assertEquals(null, _sdb.getLastToken()); assertEquals(1, result.size()); String count = result.get(0).get("Count")[0]; assertEquals("1", count); } @Test public void testConditionalPut() throws Exception { final String domainName = TestUtils.TEST_DOMAIN_NAME; _sdb.createDomain(domainName); Map<String, String> attributes = new HashMap<String, String>(); attributes.put("attr1", "item1-attr1-value1"); _sdb.putAttributes(TestUtils.TEST_DOMAIN_NAME, "item1", attributes); String[] result = _sdb.getAttribute(TestUtils.TEST_DOMAIN_NAME, "item1", "attr1", true); assertEquals(1, result.length); assertEquals("item1-attr1-value1", result[0]); attributes.put("attr1", "item1-attr1-value2"); Set<String> replaceAttrs = new HashSet<String>(); replaceAttrs.add("attr1"); _sdb.putAttributes(TestUtils.TEST_DOMAIN_NAME, "item1", attributes, replaceAttrs, "attr1", "item1-attr1-value1", true); result = _sdb.getAttribute(TestUtils.TEST_DOMAIN_NAME, "item1", "attr1", true); assertEquals(1, result.length); assertEquals("item1-attr1-value2", result[0]); // Now try to change to value3, but this time say that the attribute can't exist. attributes.put("attr1", "item1-attr1-value3"); try { _sdb.putAttributes(TestUtils.TEST_DOMAIN_NAME, "item1", attributes, replaceAttrs, "attr1", null, false); fail("Should have failed"); } catch (AWSException e) { assertEquals("ConditionalCheckFailed", e.getAWSErrorCode()); } // Should still have the old value. result = _sdb.getAttribute(TestUtils.TEST_DOMAIN_NAME, "item1", "attr1", true); assertEquals(1, result.length); assertEquals("item1-attr1-value2", result[0]); } @Test public void testBackoff() throws Exception { final int numThreads = 300; final int numRequestsPerThread = 10; final int numAttributes = 1; final String domainName = TestUtils.TEST_DOMAIN_NAME; _sdb.createDomain(domainName); ThreadGroup tg = new ThreadGroup("testBackoff"); final Map<String, String> attributes = new HashMap<String, String>(); for (int i = 1; i <= numAttributes; i++) { attributes.put("attr-" + i, "attr-" + i + "-value"); } final List<Exception> sdbExceptions = Collections.synchronizedList(new ArrayList<Exception>()); final AtomicBoolean hold = new AtomicBoolean(true); final AtomicInteger reqCount = new AtomicInteger(); IHttpHandler httpHandler = new BackoffHttpHandler(numThreads); for (int i = 0; i < numThreads; i++) { final SimpleDB sdb = new SimpleDB(TestUtils.getAccessKeyID(), TestUtils.getSecretAccessKey(), httpHandler); final int threadIndex = i; Runnable target = new Runnable() { @Override public void run() { // Wait till we get the go-ahead to hit the server while (hold.get()) { try { Thread.sleep(10); } catch (InterruptedException e) { return; } } try { for (int ri = 0; ri < numRequestsPerThread; ri++) { int itemId = (threadIndex * numRequestsPerThread) + numRequestsPerThread; sdb.putAttributes(TestUtils.TEST_DOMAIN_NAME, "item-" + itemId, attributes); reqCount.incrementAndGet(); if (sdbExceptions.size() > 0) { // Skip processing more requests once we get an error. break; } } } catch (Exception e) { e.printStackTrace(); sdbExceptions.add(e); } } }; Thread t = new Thread(tg, target); t.start(); } System.out.println("Starting requests"); long startTime = System.currentTimeMillis(); hold.set(false); while (!Thread.interrupted() && (tg.activeCount() > 0)) { try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } long deltaTime = System.currentTimeMillis() - startTime; int numPutAttributeRequests = reqCount.get(); System.out.println(String.format("%d PutAttribute requests took %d millisecond", numPutAttributeRequests, deltaTime)); assertEquals("Exceptions occurred", 0, sdbExceptions.size()); } }