1 /* 2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"). 5 * You may not use this file except in compliance with the License. 6 * A copy of the License is located at 7 * 8 * http://aws.amazon.com/apache2.0 9 * 10 * or in the "license" file accompanying this file. This file is distributed 11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 * express or implied. See the License for the specific language governing 13 * permissions and limitations under the License. 14 */ 15 16 package utils.test.util; 17 18 import static org.junit.Assert.assertTrue; 19 import static org.junit.Assert.fail; 20 21 import java.math.BigDecimal; 22 import java.util.Collection; 23 import java.util.HashMap; 24 import java.util.HashSet; 25 import java.util.Map; 26 import java.util.Set; 27 import software.amazon.awssdk.awscore.exception.AwsServiceException; 28 import software.amazon.awssdk.core.exception.SdkClientException; 29 import software.amazon.awssdk.regions.Region; 30 import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient; 31 import software.amazon.awssdk.services.dynamodb.DynamoDbClient; 32 import software.amazon.awssdk.services.dynamodb.model.AttributeValue; 33 import software.amazon.awssdk.services.dynamodb.model.DescribeTableRequest; 34 import software.amazon.awssdk.services.dynamodb.model.TableDescription; 35 import software.amazon.awssdk.services.dynamodb.model.TableStatus; 36 import software.amazon.awssdk.testutils.service.AwsTestBase; 37 import software.amazon.awssdk.utils.Logger; 38 39 public class DynamoDBTestBase extends AwsTestBase { 40 protected static final String ENDPOINT = "http://dynamodb.us-east-1.amazonaws.com/"; 41 42 protected static final Region REGION = Region.US_EAST_1; 43 44 protected static DynamoDbClient dynamo; 45 46 protected static DynamoDbAsyncClient dynamoAsync; 47 48 private static final Logger log = Logger.loggerFor(DynamoDBTestBase.class); 49 setUpTestBase()50 public static void setUpTestBase() { 51 try { 52 setUpCredentials(); 53 } catch (Exception e) { 54 throw SdkClientException.builder().message("Unable to load credential property file.").cause(e).build(); 55 } 56 57 dynamo = DynamoDbClient.builder().region(REGION).credentialsProvider(CREDENTIALS_PROVIDER_CHAIN).build(); 58 dynamoAsync = DynamoDbAsyncClient.builder().region(REGION).credentialsProvider(CREDENTIALS_PROVIDER_CHAIN).build(); 59 } 60 getClient()61 public static DynamoDbClient getClient() { 62 if (dynamo == null) { 63 setUpTestBase(); 64 } 65 return dynamo; 66 } 67 waitForTableToBecomeDeleted(String tableName)68 protected static void waitForTableToBecomeDeleted(String tableName) { 69 waitForTableToBecomeDeleted(dynamo, tableName); 70 } 71 waitForTableToBecomeDeleted(DynamoDbClient dynamo, String tableName)72 public static void waitForTableToBecomeDeleted(DynamoDbClient dynamo, String tableName) { 73 log.info(() -> "Waiting for " + tableName + " to become Deleted..."); 74 75 long startTime = System.currentTimeMillis(); 76 long endTime = startTime + (60_000); 77 while (System.currentTimeMillis() < endTime) { 78 try { 79 Thread.sleep(5_000); 80 } catch (Exception e) { 81 // Ignored or expected. 82 } 83 try { 84 DescribeTableRequest request = DescribeTableRequest.builder().tableName(tableName).build(); 85 TableDescription table = dynamo.describeTable(request).table(); 86 87 log.info(() -> " - current state: " + table.tableStatusAsString()); 88 if (table.tableStatus() == TableStatus.DELETING) { 89 continue; 90 } 91 } catch (AwsServiceException exception) { 92 if (exception.awsErrorDetails().errorCode().equalsIgnoreCase("ResourceNotFoundException")) { 93 log.info(() -> "successfully deleted"); 94 return; 95 } 96 } 97 } 98 99 throw new RuntimeException("Table " + tableName + " never went deleted"); 100 } 101 assertSetsEqual(Collection<T> expected, Collection<T> given)102 protected static <T extends Object> void assertSetsEqual(Collection<T> expected, Collection<T> given) { 103 Set<T> givenCopy = new HashSet<T>(); 104 givenCopy.addAll(given); 105 for (T e : expected) { 106 if (!givenCopy.remove(e)) { 107 fail("Expected element not found: " + e); 108 } 109 } 110 111 assertTrue("Unexpected elements found: " + givenCopy, givenCopy.isEmpty()); 112 } 113 114 /** 115 * Only valid for whole numbers 116 */ assertNumericSetsEquals(Set<? extends Number> expected, Collection<String> given)117 protected static void assertNumericSetsEquals(Set<? extends Number> expected, Collection<String> given) { 118 Set<BigDecimal> givenCopy = new HashSet<BigDecimal>(); 119 for (String s : given) { 120 BigDecimal bd = new BigDecimal(s); 121 givenCopy.add(bd.setScale(0)); 122 } 123 124 Set<BigDecimal> expectedCopy = new HashSet<BigDecimal>(); 125 for (Number n : expected) { 126 BigDecimal bd = new BigDecimal(n.toString()); 127 expectedCopy.add(bd.setScale(0)); 128 } 129 130 assertSetsEqual(expectedCopy, givenCopy); 131 } 132 toSet(T... array)133 protected static <T extends Object> Set<T> toSet(T... array) { 134 Set<T> set = new HashSet<T>(); 135 for (T t : array) { 136 set.add(t); 137 } 138 return set; 139 } 140 toSet(Collection<T> collection)141 protected static <T extends Object> Set<T> toSet(Collection<T> collection) { 142 Set<T> set = new HashSet<T>(); 143 for (T t : collection) { 144 set.add(t); 145 } 146 return set; 147 } 148 generateByteArray(int length)149 protected static byte[] generateByteArray(int length) { 150 byte[] bytes = new byte[length]; 151 for (int i = 0; i < length; i++) { 152 bytes[i] = (byte) (i % Byte.MAX_VALUE); 153 } 154 return bytes; 155 } 156 157 /** 158 * Gets a map of key values for the single hash key attribute value given. 159 */ mapKey(String attributeName, AttributeValue value)160 protected Map<String, AttributeValue> mapKey(String attributeName, AttributeValue value) { 161 HashMap<String, AttributeValue> map = new HashMap<String, AttributeValue>(); 162 map.put(attributeName, value); 163 return map; 164 } 165 166 } 167