@Test public void testGetCorrectlyCallsSimpleDB() throws Exception { // ARRANGE initialiseOptimisticPersister(); GetAttributesRequest simpleDBRequest = new GetAttributesRequest(testSimpleDBDomainName, testItemName); simpleDBRequest.setConsistentRead(true); GetAttributesResult getAttributesResult = new GetAttributesResult(); getAttributesResult.setAttributes(allAttributes); mockery.checking(new Expectations() { { oneOf(mockSimpleDBClient).getAttributes(with(equal(simpleDBRequest))); will(returnValue(getAttributesResult)); } }); // ACT optimisticPersister.get(testItemName); }
/** * {@inheritDoc} */ @Override @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") public Set<Entry<String, String>> entrySet() { final GetAttributesResult result = this.credentials.aws().getAttributes( new GetAttributesRequest() .withConsistentRead(true) .withDomainName(this.table) .withItemName(this.label) ); final Set<Entry<String, String>> entries = new HashSet<Entry<String, String>>(0); for (final Attribute attr : result.getAttributes()) { entries.add( new AbstractMap.SimpleImmutableEntry<String, String>( attr.getName(), attr.getValue() ) ); } return entries; }
@Override public ImmutablePair<Optional<Integer>, Set<Attribute>> get(String itemName) { if (!initialised) { throw new IllegalStateException("The optimistic persister has not been initialised"); } logger.log("About to get all active attributes from simpledb item: " + itemName); AmazonSimpleDB client = getSimpleDBClient(); // Do a consistent read - to ensure we get correct version number GetAttributesRequest simpleDBRequest = new GetAttributesRequest(simpleDbDomainName, itemName); logger.log("Using simpleDB domain: " + simpleDbDomainName); simpleDBRequest.setConsistentRead(true); GetAttributesResult result = client.getAttributes(simpleDBRequest); List<Attribute> attributes = result.getAttributes(); // Get the version number and other attributes. Optional<Integer> version = Optional.empty(); Set<Attribute> nonVersionAttributes = new HashSet<>(); if (attributes.size() > 0) { // If we have any attributes, we'll always have a version number Attribute versionNumberAttribute = attributes.stream() .filter(attribute -> attribute.getName().equals(versionAttributeName)).findFirst().get(); version = Optional.of(Integer.parseInt(versionNumberAttribute.getValue())); logger.log("Retrieved version number: " + versionNumberAttribute.getValue()); attributes.remove(versionNumberAttribute); // Add all active attributes (i.e. those not pending deletion) nonVersionAttributes.addAll(attributes.stream() .filter(attribute -> !attribute.getValue().startsWith("Inactive")) .collect(Collectors.toSet())); } logger.log("Got all attributes from simpledb"); return new ImmutablePair<>(version, nonVersionAttributes); }
@Test public void testGetReturnsTheCorrectVersionNumberAndAttributes() throws Exception { // Get should not return the version-number attribute (but should return the // version number as part of its result pair) and it should not return // inactive attributes. // ARRANGE initialiseOptimisticPersister(); GetAttributesRequest simpleDBRequest = new GetAttributesRequest(testSimpleDBDomainName, testItemName); simpleDBRequest.setConsistentRead(true); // First assert that our allAttribute set has both version and inactive // attributes (which should get filtered out). assertTrue("AllAttribute list should contain an inactive attribute", allAttributes.stream() .filter(attribute -> attribute.getValue().startsWith("Inactive")).count() > 0); assertTrue("AllAttribute list should contain a version number attribute", allAttributes .stream().filter(attribute -> attribute.getName().equals(versionAttributeName)).count() > 0); GetAttributesResult getAttributesResult = new GetAttributesResult(); getAttributesResult.setAttributes(allAttributes); mockery.checking(new Expectations() { { allowing(mockSimpleDBClient).getAttributes(with(equal(simpleDBRequest))); will(returnValue(getAttributesResult)); } }); // ACT ImmutablePair<Optional<Integer>, Set<Attribute>> result = optimisticPersister.get(testItemName); // ASSERT assertTrue("OptimisticPersister should return the correct attributes. Actual: " + result.right + ", Expected: " + activeNonVersionAttributes, result.right.equals(activeNonVersionAttributes)); assertTrue("OptimisticPersister should return a version number", result.left.isPresent()); assertTrue("OptimisticPersister should return the correct version number", result.left.get() .equals(testVersionNumber)); }
@Test public void testGetReturnsAnEmptyVersionNumberAndNoAttributesWhenThereAreNoAttributesInTheDatabase() throws Exception { // ARRANGE initialiseOptimisticPersister(); GetAttributesRequest simpleDBRequest = new GetAttributesRequest(testSimpleDBDomainName, testItemName); simpleDBRequest.setConsistentRead(true); // First assert that our allAttribute set has both version and inactive // attributes (which should get filtered out). assertTrue("AllAttribute list should contain an inactive attribute", allAttributes.stream() .filter(attribute -> attribute.getValue().startsWith("Inactive")).count() > 0); assertTrue("AllAttribute list should contain a version number attribute", allAttributes .stream().filter(attribute -> attribute.getName().equals(versionAttributeName)).count() > 0); // Mimic database with no attributes GetAttributesResult getAttributesResult = new GetAttributesResult(); mockery.checking(new Expectations() { { allowing(mockSimpleDBClient).getAttributes(with(equal(simpleDBRequest))); will(returnValue(getAttributesResult)); } }); // ACT ImmutablePair<Optional<Integer>, Set<Attribute>> result = optimisticPersister.get(testItemName); // ASSERT assertTrue("OptimisticPersister should return no attributes", result.right.size() == 0); assertTrue("OptimisticPersister should return an empty version number", !result.left.isPresent()); }
@Test public void testPutThrowsWhenMaximumNumberOfAttributesIsAlreadyPresent() throws Exception { // ARRANGE thrown.expect(Exception.class); thrown.expectMessage("Database put failed"); // Initialiser persister with a max number of attributes equal to the // current number (1 as there is only one active attribute) - so new put's // will be rejected. optimisticPersister.initialise(1, mockLogger); // Configure attributes for database to return - the get is used for logging // only, so does not really matter. GetAttributesRequest simpleDBRequest = new GetAttributesRequest(testSimpleDBDomainName, testItemName); simpleDBRequest.setConsistentRead(true); GetAttributesResult getAttributesResult = new GetAttributesResult(); getAttributesResult.setAttributes(allAttributes); mockery.checking(new Expectations() { { allowing(mockSimpleDBClient).getAttributes(with(equal(simpleDBRequest))); will(returnValue(getAttributesResult)); } }); // ACT ReplaceableAttribute testAttribute = new ReplaceableAttribute(); testAttribute.setName("Name"); testAttribute.setValue("Value"); // This should throw since we already have the max number of attributes. optimisticPersister.put(testItemName, Optional.of(42), testAttribute); }
private void doTestDeleteReturnsEarlyIfAttributeBeingDeletedDoesNotExist( Boolean versionNumberExists) throws Exception { // ARRANGE initialiseOptimisticPersister(); // Configure database to return no attributes. GetAttributesRequest simpleDBRequest = new GetAttributesRequest(testSimpleDBDomainName, testItemName); simpleDBRequest.setConsistentRead(true); GetAttributesResult getAttributesResult = new GetAttributesResult(); if (versionNumberExists) { // Ensure we return at least the version number attribute getAttributesResult.setAttributes(allAttributes); } mockery.checking(new Expectations() { { oneOf(mockSimpleDBClient).getAttributes(with(equal(simpleDBRequest))); will(returnValue(getAttributesResult)); } }); // Ensure we return early. mockery.checking(new Expectations() { { never(mockSimpleDBClient).deleteAttributes(with(anything())); } }); // ACT Attribute attributeToDelete = new Attribute(); attributeToDelete.setName("Name"); attributeToDelete.setValue("Value"); optimisticPersister.delete(testItemName, attributeToDelete); }
public void execute() { GetAttributesRequest request = new GetAttributesRequest() .withDomainName(determineDomainName()) .withItemName(determineItemName()) .withConsistentRead(determineConsistentRead()) .withAttributeNames(determineAttributeNames()); log.trace("Sending request [{}] for exchange [{}]...", request, exchange); GetAttributesResult result = this.sdbClient.getAttributes(request); log.trace("Received result [{}]", result); Message msg = getMessageForResponse(exchange); msg.setHeader(SdbConstants.ATTRIBUTES, result.getAttributes()); }
@Override public GetAttributesResult getAttributes(GetAttributesRequest getAttributesRequest) throws AmazonServiceException, AmazonClientException { this.getAttributesRequest = getAttributesRequest; return new GetAttributesResult() .withAttributes(new Attribute("AttributeOne", "Value One")) .withAttributes(new Attribute("AttributeTwo", "Value Two")); }
public <T> T get(String recordid, Class<T> dataClass) throws WPBIOException { try { GetAttributesRequest getAttributesRequest = new GetAttributesRequest(domainName, createInternalKey(recordid, dataClass)); GetAttributesResult attributesResult = sdbClient.getAttributes(getAttributesRequest); return copyAttributesToInstance(dataClass, attributesResult.getAttributes()); } catch (Exception e) { throw new WPBIOException("Cannot get record " + recordid, e); } }
/** * A map of attributes for a specific item in a table * * @param domainName table name * @param itemName itemName for the item * @return map of attribute name to value */ public static HashMap<String, String> getAttributesForItem(String domainName, String itemName) { GetAttributesRequest getRequest = new GetAttributesRequest(domainName, itemName).withConsistentRead(true); GetAttributesResult getResult = getInstance().getAttributes(getRequest); HashMap<String, String> attributes = new HashMap<String, String>(30); for (Object attribute : getResult.getAttributes()) { String name = ((Attribute) attribute).getName(); String value = ((Attribute) attribute).getValue(); attributes.put(name, value); } return attributes; }
/** * AwsItem can load an item. * @throws Exception If some problem inside */ @Test public void loadsItemFromSimpleDb() throws Exception { final AmazonSimpleDB aws = Mockito.mock(AmazonSimpleDB.class); Mockito.doReturn( new GetAttributesResult().withAttributes( new Attribute().withName("attr-1").withValue("value-1") ) ).when(aws).getAttributes(Mockito.any(GetAttributesRequest.class)); final Credentials credentials = Mockito.mock(Credentials.class); Mockito.doReturn(aws).when(credentials).aws(); final String name = "item-name"; final String table = "table-name"; final Item item = new AwsItem(credentials, table, name); item.get("hello"); Mockito.verify(aws).getAttributes( GetAttributesRequest.class.cast( Mockito.argThat( Matchers.allOf( Matchers.hasProperty( "domainName", Matchers.equalTo(table) ), Matchers.hasProperty( "itemName", Matchers.equalTo(name) ) ) ) ) ); }
@Test public void testPutDoesNotThrowWhenMaximumNumberOfAttributesIsAlreadyPresentIfPutIsToInactivate() throws Exception { // Our 2-stage deletion process involves an initial put to 'inactivate' the // attribute being deleted. We must allow such put's to exceed the limit - // or else we could never delete attributes when we're over the limit. // ARRANGE // Initialiser persister with a max number of attributes equal to the // current number (1 as there is only one active attribute) - so new put's // will be rejected, unless they're inactivating puts. optimisticPersister.initialise(1, mockLogger); // Configure attributes for database to return - the get is used for logging // only, so does not really matter. GetAttributesRequest simpleDBRequest = new GetAttributesRequest(testSimpleDBDomainName, testItemName); simpleDBRequest.setConsistentRead(true); GetAttributesResult getAttributesResult = new GetAttributesResult(); getAttributesResult.setAttributes(allAttributes); mockery.checking(new Expectations() { { allowing(mockSimpleDBClient).getAttributes(with(equal(simpleDBRequest))); will(returnValue(getAttributesResult)); } }); // Don't care about further calls to SimpleDB. mockery.checking(new Expectations() { { ignoring(mockSimpleDBClient); } }); // ACT // Use an 'inactivating' put i.e. value prefixed with 'Inactive' ReplaceableAttribute testAttribute = new ReplaceableAttribute(); testAttribute.setName("Name"); testAttribute.setValue("InactiveValue"); // This should not throw even though we already have the max number of // attributes. optimisticPersister.put(testItemName, Optional.of(42), testAttribute); }
private void doTestPutUsesCorrectVersionWhenCallingTheDatabase(Optional<Integer> version) throws Exception { // ARRANGE initialiseOptimisticPersister(); // Configure attributes for database to return - the get is used for logging // only, so does not really matter. GetAttributesRequest simpleDBRequest = new GetAttributesRequest(testSimpleDBDomainName, testItemName); simpleDBRequest.setConsistentRead(true); GetAttributesResult getAttributesResult = new GetAttributesResult(); mockery.checking(new Expectations() { { allowing(mockSimpleDBClient).getAttributes(with(equal(simpleDBRequest))); will(returnValue(getAttributesResult)); } }); // Configure expectations for the put: UpdateCondition updateCondition = new UpdateCondition(); updateCondition.setName(versionAttributeName); ReplaceableAttribute versionAttribute = new ReplaceableAttribute(); versionAttribute.setName(versionAttributeName); versionAttribute.setReplace(true); if (!version.isPresent()) { // A version number attribute did not exist - so it still should not updateCondition.setExists(false); // Set initial value for our version number attribute versionAttribute.setValue("0"); } else { // A version number attribute exists - so it should be unchanged updateCondition.setValue(Integer.toString(version.get())); // Bump up our version number attribute versionAttribute.setValue(Integer.toString(version.get() + 1)); } List<ReplaceableAttribute> replaceableAttributes = new ArrayList<>(); replaceableAttributes.add(versionAttribute); // Add the new attribute ReplaceableAttribute testAttribute = new ReplaceableAttribute(); testAttribute.setName("Name"); testAttribute.setValue("Value"); replaceableAttributes.add(testAttribute); PutAttributesRequest simpleDBPutRequest = new PutAttributesRequest(testSimpleDBDomainName, testItemName, replaceableAttributes, updateCondition); mockery.checking(new Expectations() { { oneOf(mockSimpleDBClient).putAttributes(with(equal(simpleDBPutRequest))); } }); // ACT optimisticPersister.put(testItemName, version, testAttribute); }
private void doTestPutHandlesExceptionsCorrectly(Boolean isConditionalCheckFailedException) throws Exception { // The persister should forward all simpleDB exceptions to us, but it should // convert ConditionalCheckFailed exceptions before forwarding, as clients // will likely want to handle that case differently. // ARRANGE thrown.expect(Exception.class); thrown.expectMessage(isConditionalCheckFailedException ? "Database put failed" : "Boom!"); initialiseOptimisticPersister(); // Configure attributes for database to return - the get is used for logging // only, so does not really matter. GetAttributesRequest simpleDBRequest = new GetAttributesRequest(testSimpleDBDomainName, testItemName); simpleDBRequest.setConsistentRead(true); GetAttributesResult getAttributesResult = new GetAttributesResult(); mockery.checking(new Expectations() { { allowing(mockSimpleDBClient).getAttributes(with(equal(simpleDBRequest))); will(returnValue(getAttributesResult)); } }); // Make the simpleDB call throw the correct exception AmazonServiceException exception = new AmazonServiceException("Boom!"); exception.setErrorCode(isConditionalCheckFailedException ? "ConditionalCheckFailed" : "SomeOtherArbitraryCode"); mockery.checking(new Expectations() { { oneOf(mockSimpleDBClient).putAttributes(with(anything())); will(throwException(exception)); } }); ReplaceableAttribute testAttribute = new ReplaceableAttribute(); testAttribute.setName("Name"); testAttribute.setValue("Value"); // ACT optimisticPersister.put(testItemName, Optional.of(42), testAttribute); }
@Test public void testPutReturnsCorrectVersion() throws Exception { // A successful put should return the version that the put-to item has after // the put - i.e. one higher than it had initially. // ARRANGE initialiseOptimisticPersister(); // Configure attributes for database to return - the get is used for logging // only, so does not really matter. GetAttributesRequest simpleDBRequest = new GetAttributesRequest(testSimpleDBDomainName, testItemName); simpleDBRequest.setConsistentRead(true); GetAttributesResult getAttributesResult = new GetAttributesResult(); mockery.checking(new Expectations() { { allowing(mockSimpleDBClient).getAttributes(with(equal(simpleDBRequest))); will(returnValue(getAttributesResult)); } }); mockery.checking(new Expectations() { { allowing(mockSimpleDBClient).putAttributes(with(anything())); } }); ReplaceableAttribute testAttribute = new ReplaceableAttribute(); testAttribute.setName("Name"); testAttribute.setValue("Value"); int initialVersion = 42; // Arbitrary // ACT int finalVersion = optimisticPersister.put(testItemName, Optional.of(initialVersion), testAttribute); // ASSERT assertTrue("The returned version should be one higher than the initial version", finalVersion == (initialVersion + 1)); }