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.iotdataplane; 17 18 import static org.hamcrest.Matchers.greaterThan; 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertThat; 21 22 import com.fasterxml.jackson.databind.JsonNode; 23 import com.fasterxml.jackson.databind.ObjectMapper; 24 import java.io.IOException; 25 import java.net.URI; 26 import java.nio.ByteBuffer; 27 import org.junit.Before; 28 import org.junit.Test; 29 import software.amazon.awssdk.core.SdkBytes; 30 import software.amazon.awssdk.regions.Region; 31 import software.amazon.awssdk.services.iot.IotClient; 32 import software.amazon.awssdk.services.iotdataplane.model.DeleteThingShadowRequest; 33 import software.amazon.awssdk.services.iotdataplane.model.DeleteThingShadowResponse; 34 import software.amazon.awssdk.services.iotdataplane.model.GetThingShadowRequest; 35 import software.amazon.awssdk.services.iotdataplane.model.GetThingShadowResponse; 36 import software.amazon.awssdk.services.iotdataplane.model.InvalidRequestException; 37 import software.amazon.awssdk.services.iotdataplane.model.PublishRequest; 38 import software.amazon.awssdk.services.iotdataplane.model.ResourceNotFoundException; 39 import software.amazon.awssdk.services.iotdataplane.model.UpdateThingShadowRequest; 40 import software.amazon.awssdk.services.iotdataplane.model.UpdateThingShadowResponse; 41 import software.amazon.awssdk.testutils.service.AwsIntegrationTestBase; 42 import software.amazon.awssdk.utils.BinaryUtils; 43 44 public class ServiceIntegrationTest extends AwsIntegrationTestBase { 45 46 private static final String STATE_FIELD_NAME = "state"; 47 private static final String THING_NAME = "foo"; 48 private static final String INVALID_THING_NAME = "INVALID_THING_NAME"; 49 50 private IotDataPlaneClient iot; 51 getPayloadAsJsonNode(ByteBuffer payload)52 private static JsonNode getPayloadAsJsonNode(ByteBuffer payload) throws IOException { 53 return new ObjectMapper().readTree(BinaryUtils.toStream(payload)); 54 } 55 assertPayloadNonEmpty(SdkBytes payload)56 private static void assertPayloadNonEmpty(SdkBytes payload) { 57 assertThat(payload.asByteBuffer().capacity(), greaterThan(0)); 58 } 59 60 /** 61 * Asserts that the returned payload has the correct state in the JSON document. It should be 62 * exactly what we sent it plus some additional metadata 63 * 64 * @param originalPayload 65 * ByteBuffer we sent to the service containing just the state 66 * @param returnedPayload 67 * ByteBuffer returned by the service containing the state (which should be the same 68 * as what we sent) plus additional metadata in the JSON document 69 */ assertPayloadIsValid(SdkBytes originalPayload, SdkBytes returnedPayload)70 private static void assertPayloadIsValid(SdkBytes originalPayload, SdkBytes returnedPayload) throws Exception { 71 JsonNode originalJson = getPayloadAsJsonNode(originalPayload.asByteBuffer()); 72 JsonNode returnedJson = getPayloadAsJsonNode(returnedPayload.asByteBuffer()); 73 assertEquals(originalJson.get(STATE_FIELD_NAME), returnedJson.get(STATE_FIELD_NAME)); 74 } 75 76 @Before setup()77 public void setup() throws Exception { 78 IotClient client = IotClient.builder().credentialsProvider(CREDENTIALS_PROVIDER_CHAIN).region(Region.US_EAST_1).build(); 79 String endpoint = client.describeEndpoint(r -> r.endpointType("iot:Data-ATS")).endpointAddress(); 80 iot = IotDataPlaneClient.builder() 81 .credentialsProvider(CREDENTIALS_PROVIDER_CHAIN) 82 .endpointOverride(URI.create("https://" + endpoint)) 83 .region(Region.US_EAST_1) 84 .build(); 85 } 86 87 @Test publish_ValidTopicAndNonEmptyPayload_DoesNotThrowException()88 public void publish_ValidTopicAndNonEmptyPayload_DoesNotThrowException() { 89 iot.publish(PublishRequest.builder().topic(THING_NAME).payload(SdkBytes.fromByteArray(new byte[] {1, 2, 3, 4})).build()); 90 } 91 92 @Test publish_WithValidTopicAndEmptyPayload_DoesNotThrowException()93 public void publish_WithValidTopicAndEmptyPayload_DoesNotThrowException() { 94 iot.publish(PublishRequest.builder().topic(THING_NAME).payload(null).build()); 95 } 96 97 @Test(expected = InvalidRequestException.class) updateThingShadow_NullPayload_ThrowsServiceException()98 public void updateThingShadow_NullPayload_ThrowsServiceException() throws Exception { 99 UpdateThingShadowRequest request = UpdateThingShadowRequest.builder().thingName(THING_NAME).payload(null).build(); 100 iot.updateThingShadow(request); 101 } 102 103 @Test(expected = InvalidRequestException.class) updateThingShadow_MalformedPayload_ThrowsServiceException()104 public void updateThingShadow_MalformedPayload_ThrowsServiceException() throws Exception { 105 SdkBytes payload = SdkBytes.fromUtf8String("{ }"); 106 UpdateThingShadowRequest request = UpdateThingShadowRequest.builder().thingName(THING_NAME).payload(payload).build(); 107 iot.updateThingShadow(request); 108 } 109 110 @Test(expected = ResourceNotFoundException.class) getThingShadow_InvalidThingName_ThrowsException()111 public void getThingShadow_InvalidThingName_ThrowsException() { 112 iot.getThingShadow(GetThingShadowRequest.builder().thingName(INVALID_THING_NAME).build()); 113 } 114 115 @Test(expected = ResourceNotFoundException.class) deleteThingShadow_InvalidThing_ThrowsException()116 public void deleteThingShadow_InvalidThing_ThrowsException() { 117 DeleteThingShadowResponse result = iot 118 .deleteThingShadow(DeleteThingShadowRequest.builder().thingName(INVALID_THING_NAME).build()); 119 assertPayloadNonEmpty(result.payload()); 120 } 121 122 @Test UpdateReadDeleteThing()123 public void UpdateReadDeleteThing() throws Exception { 124 updateThingShadow_ValidRequest_ReturnsValidResponse(THING_NAME); 125 getThingShadow_ValidThing_ReturnsThingData(THING_NAME); 126 deleteThingShadow_ValidThing_DeletesSuccessfully(THING_NAME); 127 } 128 updateThingShadow_ValidRequest_ReturnsValidResponse(String thingName)129 private void updateThingShadow_ValidRequest_ReturnsValidResponse(String thingName) throws Exception { 130 SdkBytes originalPayload = SdkBytes.fromUtf8String("{ \"state\": {\"reported\":{ \"r\": {}}}}"); 131 UpdateThingShadowRequest request = UpdateThingShadowRequest.builder().thingName(thingName).payload(originalPayload).build(); 132 UpdateThingShadowResponse result = iot.updateThingShadow(request); 133 134 // Comes back with some extra metadata so we assert it's bigger than the original 135 assertThat(result.payload().asByteBuffer().capacity(), greaterThan(originalPayload.asByteBuffer().capacity())); 136 assertPayloadIsValid(originalPayload, result.payload()); 137 } 138 getThingShadow_ValidThing_ReturnsThingData(String thingName)139 private void getThingShadow_ValidThing_ReturnsThingData(String thingName) { 140 GetThingShadowRequest request = GetThingShadowRequest.builder().thingName(thingName).build(); 141 GetThingShadowResponse result = iot.getThingShadow(request); 142 assertPayloadNonEmpty(result.payload()); 143 } 144 deleteThingShadow_ValidThing_DeletesSuccessfully(String thingName)145 private void deleteThingShadow_ValidThing_DeletesSuccessfully(String thingName) { 146 DeleteThingShadowResponse result = iot.deleteThingShadow(DeleteThingShadowRequest.builder().thingName(thingName).build()); 147 assertPayloadNonEmpty(result.payload()); 148 } 149 150 } 151