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 software.amazon.awssdk.services.apigateway; 17 18 import com.google.common.util.concurrent.RateLimiter; 19 import java.time.Duration; 20 import java.time.Instant; 21 import java.util.List; 22 import java.util.concurrent.atomic.AtomicInteger; 23 import junit.framework.Assert; 24 import org.junit.AfterClass; 25 import org.junit.BeforeClass; 26 import org.junit.Test; 27 import software.amazon.awssdk.services.apigateway.model.CreateApiKeyRequest; 28 import software.amazon.awssdk.services.apigateway.model.CreateApiKeyResponse; 29 import software.amazon.awssdk.services.apigateway.model.CreateResourceRequest; 30 import software.amazon.awssdk.services.apigateway.model.CreateResourceResponse; 31 import software.amazon.awssdk.services.apigateway.model.CreateRestApiRequest; 32 import software.amazon.awssdk.services.apigateway.model.CreateRestApiResponse; 33 import software.amazon.awssdk.services.apigateway.model.DeleteRestApiRequest; 34 import software.amazon.awssdk.services.apigateway.model.GetApiKeyRequest; 35 import software.amazon.awssdk.services.apigateway.model.GetApiKeyResponse; 36 import software.amazon.awssdk.services.apigateway.model.GetResourceRequest; 37 import software.amazon.awssdk.services.apigateway.model.GetResourceResponse; 38 import software.amazon.awssdk.services.apigateway.model.GetResourcesRequest; 39 import software.amazon.awssdk.services.apigateway.model.GetResourcesResponse; 40 import software.amazon.awssdk.services.apigateway.model.GetRestApiRequest; 41 import software.amazon.awssdk.services.apigateway.model.GetRestApiResponse; 42 import software.amazon.awssdk.services.apigateway.model.IntegrationType; 43 import software.amazon.awssdk.services.apigateway.model.NotFoundException; 44 import software.amazon.awssdk.services.apigateway.model.Op; 45 import software.amazon.awssdk.services.apigateway.model.PatchOperation; 46 import software.amazon.awssdk.services.apigateway.model.PutIntegrationRequest; 47 import software.amazon.awssdk.services.apigateway.model.PutIntegrationResponse; 48 import software.amazon.awssdk.services.apigateway.model.PutMethodRequest; 49 import software.amazon.awssdk.services.apigateway.model.PutMethodResponse; 50 import software.amazon.awssdk.services.apigateway.model.Resource; 51 import software.amazon.awssdk.services.apigateway.model.RestApi; 52 import software.amazon.awssdk.services.apigateway.model.TooManyRequestsException; 53 import software.amazon.awssdk.services.apigateway.model.UpdateApiKeyRequest; 54 import software.amazon.awssdk.services.apigateway.model.UpdateResourceRequest; 55 import software.amazon.awssdk.services.apigateway.model.UpdateRestApiRequest; 56 import software.amazon.awssdk.utils.Lazy; 57 import software.amazon.awssdk.utils.Logger; 58 59 public class ServiceIntegrationTest extends IntegrationTestBase { 60 private static final Logger log = Logger.loggerFor(ServiceIntegrationTest.class); 61 62 private static final String NAME_PREFIX = "java-sdk-integration-"; 63 private static final String NAME = NAME_PREFIX + System.currentTimeMillis(); 64 65 private static final String DESCRIPTION = "fooDesc"; 66 67 // Limit deletes to once every 31 seconds 68 // https://docs.aws.amazon.com/apigateway/latest/developerguide/limits.html#api-gateway-control-service-limits-table 69 private static final Lazy<RateLimiter> DELETE_RATE_LIMITER = new Lazy<>(() -> RateLimiter.create(1.0 / 31)); 70 71 private static String restApiId = null; 72 73 @BeforeClass createRestApi()74 public static void createRestApi() { 75 deleteStaleRestApis(); 76 CreateRestApiResponse createRestApiResult = apiGateway.createRestApi( 77 CreateRestApiRequest.builder().name(NAME) 78 .description(DESCRIPTION).build()); 79 80 Assert.assertNotNull(createRestApiResult); 81 Assert.assertNotNull(createRestApiResult.description()); 82 Assert.assertNotNull(createRestApiResult.id()); 83 Assert.assertNotNull(createRestApiResult.name()); 84 Assert.assertNotNull(createRestApiResult.createdDate()); 85 Assert.assertEquals(createRestApiResult.name(), NAME); 86 Assert.assertEquals(createRestApiResult.description(), DESCRIPTION); 87 88 restApiId = createRestApiResult.id(); 89 } 90 91 @AfterClass deleteRestApiKey()92 public static void deleteRestApiKey() { 93 if (restApiId != null) { 94 DELETE_RATE_LIMITER.getValue().acquire(); 95 try { 96 apiGateway.deleteRestApi(DeleteRestApiRequest.builder().restApiId(restApiId).build()); 97 } catch (TooManyRequestsException e) { 98 log.warn(() -> String.format("Failed to delete REST API %s (%s). This API should be deleted automatically in a " 99 + "future 'deleteStaleRestApis' execution.", 100 NAME, restApiId), e); 101 } 102 } 103 } 104 deleteStaleRestApis()105 private static void deleteStaleRestApis() { 106 Instant startTime = Instant.now(); 107 Duration maxRunTime = Duration.ofMinutes(5); 108 Duration maxApiAge = Duration.ofDays(7); 109 AtomicInteger success = new AtomicInteger(); 110 AtomicInteger failure = new AtomicInteger(); 111 112 log.info(() -> String.format("Searching for stale REST APIs older than %s days...", maxApiAge.toDays())); 113 for (RestApi api : apiGateway.getRestApisPaginator().items()) { 114 if (Instant.now().isAfter(startTime.plus(maxRunTime))) { 115 log.info(() -> String.format("More than %s has elapsed trying to delete stale REST APIs, giving up for this run. " 116 + "Successfully deleted: %s. Failed to delete: %s.", 117 maxRunTime, success.get(), failure.get())); 118 return; 119 } 120 Duration apiAge = Duration.between(api.createdDate(), Instant.now()); 121 if (api.name().startsWith(NAME_PREFIX) && apiAge.compareTo(maxApiAge) > 0) { 122 DELETE_RATE_LIMITER.getValue().acquire(); 123 try { 124 apiGateway.deleteRestApi(r -> r.restApiId(api.id())); 125 log.info(() -> String.format("Successfully deleted REST API %s (%s) which was %s days old.", 126 api.name(), api.id(), apiAge.toDays())); 127 success.incrementAndGet(); 128 } catch (Exception e) { 129 log.error(() -> String.format("Failed to delete REST API %s (%s) which is %s days old.", 130 api.name(), api.id(), apiAge.toDays()), e); 131 failure.incrementAndGet(); 132 } 133 } 134 } 135 log.info(() -> String.format("Finished searching for stale REST APIs. Successfully deleted: %s. Failed to delete: %s.", 136 success.get(), failure.get())); 137 } 138 139 @Test testUpdateRetrieveRestApi()140 public void testUpdateRetrieveRestApi() { 141 PatchOperation patch = PatchOperation.builder().op(Op.REPLACE) 142 .path("/description").value("updatedDesc").build(); 143 apiGateway.updateRestApi(UpdateRestApiRequest.builder().restApiId(restApiId) 144 .patchOperations(patch).build()); 145 146 GetRestApiResponse getRestApiResult = apiGateway 147 .getRestApi(GetRestApiRequest.builder().restApiId(restApiId).build()); 148 149 Assert.assertNotNull(getRestApiResult); 150 Assert.assertNotNull(getRestApiResult.description()); 151 Assert.assertNotNull(getRestApiResult.id()); 152 Assert.assertNotNull(getRestApiResult.name()); 153 Assert.assertNotNull(getRestApiResult.createdDate()); 154 Assert.assertEquals(getRestApiResult.name(), NAME); 155 Assert.assertEquals(getRestApiResult.description(), "updatedDesc"); 156 } 157 158 @Test testCreateUpdateRetrieveApiKey()159 public void testCreateUpdateRetrieveApiKey() { 160 CreateApiKeyResponse createApiKeyResult = apiGateway 161 .createApiKey(CreateApiKeyRequest.builder().name(NAME) 162 .description(DESCRIPTION).build()); 163 164 Assert.assertNotNull(createApiKeyResult); 165 Assert.assertNotNull(createApiKeyResult.description()); 166 Assert.assertNotNull(createApiKeyResult.id()); 167 Assert.assertNotNull(createApiKeyResult.name()); 168 Assert.assertNotNull(createApiKeyResult.createdDate()); 169 Assert.assertNotNull(createApiKeyResult.enabled()); 170 Assert.assertNotNull(createApiKeyResult.lastUpdatedDate()); 171 Assert.assertNotNull(createApiKeyResult.stageKeys()); 172 173 String apiKeyId = createApiKeyResult.id(); 174 Assert.assertEquals(createApiKeyResult.name(), NAME); 175 Assert.assertEquals(createApiKeyResult.description(), DESCRIPTION); 176 177 PatchOperation patch = PatchOperation.builder().op(Op.REPLACE) 178 .path("/description").value("updatedDesc").build(); 179 apiGateway.updateApiKey(UpdateApiKeyRequest.builder().apiKey(apiKeyId) 180 .patchOperations(patch).build()); 181 182 GetApiKeyResponse getApiKeyResult = apiGateway 183 .getApiKey(GetApiKeyRequest.builder().apiKey(apiKeyId).build()); 184 185 Assert.assertNotNull(getApiKeyResult); 186 Assert.assertNotNull(getApiKeyResult.description()); 187 Assert.assertNotNull(getApiKeyResult.id()); 188 Assert.assertNotNull(getApiKeyResult.name()); 189 Assert.assertNotNull(getApiKeyResult.createdDate()); 190 Assert.assertNotNull(getApiKeyResult.enabled()); 191 Assert.assertNotNull(getApiKeyResult.lastUpdatedDate()); 192 Assert.assertNotNull(getApiKeyResult.stageKeys()); 193 Assert.assertEquals(getApiKeyResult.id(), apiKeyId); 194 Assert.assertEquals(getApiKeyResult.name(), NAME); 195 Assert.assertEquals(getApiKeyResult.description(), "updatedDesc"); 196 } 197 198 @Test testResourceOperations()199 public void testResourceOperations() { 200 GetResourcesResponse resourcesResult = apiGateway 201 .getResources(GetResourcesRequest.builder() 202 .restApiId(restApiId).build()); 203 List<Resource> resources = resourcesResult.items(); 204 Assert.assertEquals(resources.size(), 1); 205 Resource rootResource = resources.get(0); 206 Assert.assertNotNull(rootResource); 207 Assert.assertEquals(rootResource.path(), "/"); 208 String rootResourceId = rootResource.id(); 209 210 CreateResourceResponse createResourceResult = apiGateway 211 .createResource(CreateResourceRequest.builder() 212 .restApiId(restApiId) 213 .pathPart("fooPath") 214 .parentId(rootResourceId).build()); 215 Assert.assertNotNull(createResourceResult); 216 Assert.assertNotNull(createResourceResult.id()); 217 Assert.assertNotNull(createResourceResult.parentId()); 218 Assert.assertNotNull(createResourceResult.path()); 219 Assert.assertNotNull(createResourceResult.pathPart()); 220 Assert.assertEquals(createResourceResult.pathPart(), "fooPath"); 221 Assert.assertEquals(createResourceResult.parentId(), rootResourceId); 222 223 PatchOperation patch = PatchOperation.builder().op(Op.REPLACE) 224 .path("/pathPart").value("updatedPath").build(); 225 apiGateway.updateResource(UpdateResourceRequest.builder() 226 .restApiId(restApiId) 227 .resourceId(createResourceResult.id()) 228 .patchOperations(patch).build()); 229 230 GetResourceResponse getResourceResult = apiGateway 231 .getResource(GetResourceRequest.builder() 232 .restApiId(restApiId) 233 .resourceId(createResourceResult.id()).build()); 234 Assert.assertNotNull(getResourceResult); 235 Assert.assertNotNull(getResourceResult.id()); 236 Assert.assertNotNull(getResourceResult.parentId()); 237 Assert.assertNotNull(getResourceResult.path()); 238 Assert.assertNotNull(getResourceResult.pathPart()); 239 Assert.assertEquals(getResourceResult.pathPart(), "updatedPath"); 240 Assert.assertEquals(getResourceResult.parentId(), rootResourceId); 241 242 PutMethodResponse putMethodResult = apiGateway 243 .putMethod(PutMethodRequest.builder().restApiId(restApiId) 244 .resourceId(createResourceResult.id()) 245 .authorizationType("AWS_IAM").httpMethod("PUT").build()); 246 Assert.assertNotNull(putMethodResult); 247 Assert.assertNotNull(putMethodResult.authorizationType()); 248 Assert.assertNotNull(putMethodResult.apiKeyRequired()); 249 Assert.assertNotNull(putMethodResult.httpMethod()); 250 Assert.assertEquals(putMethodResult.authorizationType(), "AWS_IAM"); 251 Assert.assertEquals(putMethodResult.httpMethod(), "PUT"); 252 253 PutIntegrationResponse putIntegrationResult = apiGateway 254 .putIntegration(PutIntegrationRequest.builder() 255 .restApiId(restApiId) 256 .resourceId(createResourceResult.id()) 257 .httpMethod("PUT").type(IntegrationType.MOCK) 258 .uri("http://foo.bar") 259 .integrationHttpMethod("GET").build()); 260 Assert.assertNotNull(putIntegrationResult); 261 Assert.assertNotNull(putIntegrationResult.cacheNamespace()); 262 Assert.assertNotNull(putIntegrationResult.type()); 263 Assert.assertEquals(putIntegrationResult.type(), 264 IntegrationType.MOCK); 265 } 266 267 @Test(expected = NotFoundException.class) resourceWithDotSignedCorrectly()268 public void resourceWithDotSignedCorrectly() { 269 apiGateway.createResource(r -> r.restApiId(restApiId).pathPart("fooPath").parentId(".")); 270 } 271 272 @Test(expected = NotFoundException.class) resourceWithDoubleDotSignedCorrectly()273 public void resourceWithDoubleDotSignedCorrectly() { 274 apiGateway.createResource(r -> r.restApiId(restApiId).pathPart("fooPath").parentId("..")); 275 } 276 277 @Test(expected = NotFoundException.class) resourceWithEncodedCharactersSignedCorrectly()278 public void resourceWithEncodedCharactersSignedCorrectly() { 279 apiGateway.createResource(r -> r.restApiId(restApiId).pathPart("fooPath").parentId("foo/../bar")); 280 } 281 } 282