diff --git a/README.md b/README.md index ef87294..72d94d3 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,7 @@ make build ## Change Log +* v0.2.2: Addition of CloudWatch Logs endpoint configuration * v0.2.1: Move Java sources into separate project; mark non-Docker Java `LocalstackExtension` as deprecated; update paths for Python code lookup in Docker container ## License diff --git a/pom.xml b/pom.xml index e67c962..4b82de2 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ cloud.localstack localstack-utils jar - 0.2.1 + 0.2.2 localstack-utils Java utilities for the LocalStack platform. diff --git a/src/main/java/cloud/localstack/Localstack.java b/src/main/java/cloud/localstack/Localstack.java index c9d7723..2e694a7 100644 --- a/src/main/java/cloud/localstack/Localstack.java +++ b/src/main/java/cloud/localstack/Localstack.java @@ -169,6 +169,10 @@ public String getEndpointCloudWatch() { return endpointForService(ServiceName.CLOUDWATCH); } + public String getEndpointCloudWatchLogs() { + return endpointForService(ServiceName.CLOUDWATCH_LOGS); + } + public String getEndpointSES() { return endpointForService(ServiceName.SES); } diff --git a/src/main/java/cloud/localstack/ServiceName.java b/src/main/java/cloud/localstack/ServiceName.java index 934701f..a10154c 100644 --- a/src/main/java/cloud/localstack/ServiceName.java +++ b/src/main/java/cloud/localstack/ServiceName.java @@ -17,6 +17,7 @@ public class ServiceName { public static final String ROUTE53 = "route53"; public static final String CLOUDFORMATION = "cloudformation"; public static final String CLOUDWATCH = "cloudwatch"; + public static final String CLOUDWATCH_LOGS = "logs"; public static final String SSM = "ssm"; public static final String SECRETSMANAGER = "secretsmanager"; public static final String STEPFUNCTIONS = "stepfunctions"; diff --git a/src/main/java/cloud/localstack/awssdkv1/TestUtils.java b/src/main/java/cloud/localstack/awssdkv1/TestUtils.java index 2ccf388..e7936e1 100644 --- a/src/main/java/cloud/localstack/awssdkv1/TestUtils.java +++ b/src/main/java/cloud/localstack/awssdkv1/TestUtils.java @@ -22,6 +22,8 @@ import com.amazonaws.services.lambda.AWSLambdaAsync; import com.amazonaws.services.lambda.AWSLambdaAsyncClientBuilder; import com.amazonaws.services.lambda.AWSLambdaClientBuilder; +import com.amazonaws.services.logs.AWSLogs; +import com.amazonaws.services.logs.AWSLogsClientBuilder; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; import com.amazonaws.services.sns.AmazonSNS; @@ -156,6 +158,12 @@ public static AmazonCloudWatch getClientCloudWatch() { withEndpointConfiguration(getEndpointConfigurationCloudWatch()). withCredentials(getCredentialsProvider()).build(); } + + public static AWSLogs getClientCloudWatchLogs() { + return AWSLogsClientBuilder.standard(). + withEndpointConfiguration(getEndpointConfigurationCloudWatchLogs()). + withCredentials(getCredentialsProvider()).build(); + } public static AmazonIdentityManagement getClientIAM() { return AmazonIdentityManagementClientBuilder.standard(). @@ -198,6 +206,10 @@ protected static AwsClientBuilder.EndpointConfiguration getEndpointConfiguration protected static AwsClientBuilder.EndpointConfiguration getEndpointConfigurationCloudWatch() { return getEndpointConfiguration(Localstack.INSTANCE.getEndpointCloudWatch()); } + + private static AwsClientBuilder.EndpointConfiguration getEndpointConfigurationCloudWatchLogs() { + return getEndpointConfiguration(Localstack.INSTANCE.getEndpointCloudWatchLogs()); + } protected static AwsClientBuilder.EndpointConfiguration getEndpointConfigurationSecretsManager() { return getEndpointConfiguration(Localstack.INSTANCE.getEndpointSecretsmanager()); diff --git a/src/test/java/cloud/localstack/CloudWatchLogsTest.java b/src/test/java/cloud/localstack/CloudWatchLogsTest.java new file mode 100644 index 0000000..29396b6 --- /dev/null +++ b/src/test/java/cloud/localstack/CloudWatchLogsTest.java @@ -0,0 +1,118 @@ +package cloud.localstack; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.runner.RunWith; + +import com.amazonaws.services.logs.AWSLogs; +import com.amazonaws.services.logs.model.CreateLogGroupRequest; +import com.amazonaws.services.logs.model.CreateLogStreamRequest; +import com.amazonaws.services.logs.model.DescribeLogGroupsResult; +import com.amazonaws.services.logs.model.GetLogEventsRequest; +import com.amazonaws.services.logs.model.GetLogEventsResult; +import com.amazonaws.services.logs.model.InputLogEvent; +import com.amazonaws.services.logs.model.LogGroup; +import com.amazonaws.services.logs.model.OutputLogEvent; +import com.amazonaws.services.logs.model.PutLogEventsRequest; + +import cloud.localstack.awssdkv1.TestUtils; +import cloud.localstack.docker.LocalstackDockerExtension; +import cloud.localstack.docker.annotation.LocalstackDockerProperties; + +/** + * Test service usage of CloudWatchLogs with example connection, creation of log group stream + * and manual publication of sample events and their basic retrieval + * + * Issue: https://github.com/localstack/localstack-java-utils/issues/11 + * + * @author Andrew Duffy + * + */ +@RunWith(LocalstackTestRunner.class) +@ExtendWith(LocalstackDockerExtension.class) +@LocalstackDockerProperties(services = {"logs"}, ignoreDockerRunErrors=true) +class CloudWatchLogsTest { + + @org.junit.Test + @org.junit.jupiter.api.Test + void testLogGroupSetupAndPublish() { + AWSLogs cloudWatchLogs = TestUtils.getClientCloudWatchLogs(); + DescribeLogGroupsResult groups = cloudWatchLogs.describeLogGroups(); + Assertions.assertTrue(groups.getLogGroups().isEmpty()); + + String logGroupName = createLogGroup(); + + DescribeLogGroupsResult groupsAfterCreation = cloudWatchLogs.describeLogGroups(); + Assertions.assertFalse(groupsAfterCreation.getLogGroups().isEmpty()); + Assertions.assertEquals(1, groupsAfterCreation.getLogGroups().size()); + + LogGroup newGroup = groupsAfterCreation.getLogGroups().get(0); + Assertions.assertEquals(logGroupName, newGroup.getLogGroupName()); + Assertions.assertNotNull(newGroup.getArn()); + Assertions.assertEquals(0, newGroup.getStoredBytes()); + + String logStream = createLogStream(logGroupName); + + List events = publishLogEvents(logGroupName, logStream); + + GetLogEventsResult publishedEvents = fetchEvents(logGroupName, logStream); + Assertions.assertEquals(events.size(), publishedEvents.getEvents().size()); + + List messagesSent = events.stream().map(InputLogEvent::getMessage).collect(Collectors.toList()); + for (OutputLogEvent publishedOutputEvent: publishedEvents.getEvents()) { + Assertions.assertTrue(messagesSent.contains(publishedOutputEvent.getMessage())); + } + } + + public String createLogGroup() { + CreateLogGroupRequest createLogGroupRequest = new CreateLogGroupRequest(); + createLogGroupRequest.setLogGroupName("testLogGroupName-" + UUID.randomUUID().toString()); + + TestUtils.getClientCloudWatchLogs().createLogGroup(createLogGroupRequest); + return createLogGroupRequest.getLogGroupName(); + } + + public String createLogStream(String newGroup) { + CreateLogStreamRequest newStreamRequest = new CreateLogStreamRequest(); + newStreamRequest.setLogGroupName(newGroup); + newStreamRequest.setLogStreamName("stream-" + UUID.randomUUID().toString()); + + TestUtils.getClientCloudWatchLogs().createLogStream(newStreamRequest); + return newStreamRequest.getLogStreamName(); + } + + public List publishLogEvents(String groupName, String logStream) { + InputLogEvent event1 = new InputLogEvent(); + event1.setMessage("Event1-" + UUID.randomUUID().toString()); + event1.setTimestamp(System.currentTimeMillis()); + + InputLogEvent event2 = new InputLogEvent(); + event2.setMessage("Event2-" + UUID.randomUUID().toString()); + event2.setTimestamp(System.currentTimeMillis()); + List events = new ArrayList<>(); + events.add(event1); + events.add(event2); + + PutLogEventsRequest putLogEventsRequest = new PutLogEventsRequest(); + putLogEventsRequest.setLogGroupName(groupName); + putLogEventsRequest.setLogStreamName(logStream); + putLogEventsRequest.setLogEvents(events); + + TestUtils.getClientCloudWatchLogs().putLogEvents(putLogEventsRequest); + return events; + } + + public GetLogEventsResult fetchEvents(String groupName, String logStream) { + GetLogEventsRequest getLogEventsRequest = new GetLogEventsRequest(); + getLogEventsRequest.setLogStreamName(logStream); + getLogEventsRequest.setLogGroupName(groupName); + + return TestUtils.getClientCloudWatchLogs().getLogEvents(getLogEventsRequest); + } + +}