├── .github
└── workflows
│ └── build.yml
├── .gitignore
├── .mvn
└── wrapper
│ ├── maven-wrapper.jar
│ └── maven-wrapper.properties
├── LICENCE
├── README.md
├── examples
└── localstack-spring-boot-sample
│ ├── .mvn
│ └── wrapper
│ │ ├── maven-wrapper.jar
│ │ └── maven-wrapper.properties
│ ├── mvnw
│ ├── mvnw.cmd
│ ├── pom.xml
│ └── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── sivalabs
│ │ │ └── demo
│ │ │ ├── LocalStackStarterDemoApplication.java
│ │ │ └── services
│ │ │ ├── DynamoDBService.java
│ │ │ ├── S3Service.java
│ │ │ ├── SNSService.java
│ │ │ └── SQSService.java
│ └── resources
│ │ └── application.properties
│ └── test
│ └── java
│ └── com
│ └── sivalabs
│ └── demo
│ ├── SpringbootLocalStackDemoApplicationTest.java
│ └── services
│ ├── CloudWatchTest.java
│ ├── DynamoDBServiceTest.java
│ ├── DynamoDBStreamsTest.java
│ ├── IAMTest.java
│ ├── KinesisTest.java
│ ├── LambdaTest.java
│ ├── S3ServiceTest.java
│ ├── SNSServiceTest.java
│ ├── SQSServiceTest.java
│ └── SecretsManagerTest.java
├── maven-settings.xml
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
├── main
└── java
│ └── io
│ └── github
│ └── sivalabs
│ └── localstack
│ ├── EnableLocalStack.java
│ ├── LocalStackProperties.java
│ └── autoconfigure
│ ├── LocalStackAutoConfiguration.java
│ └── configurator
│ ├── AWSLambdaConfiguration.java
│ ├── AWSSecretsManagerConfiguration.java
│ ├── AbstractAmazonClient.java
│ ├── AmazonCloudWatchConfiguration.java
│ ├── AmazonDynamoDBConfiguration.java
│ ├── AmazonDynamoDBStreamsConfiguration.java
│ ├── AmazonIAMConfiguration.java
│ ├── AmazonKinesisConfiguration.java
│ ├── AmazonS3Configuration.java
│ ├── AmazonSNSConfiguration.java
│ ├── AmazonSQSConfiguration.java
│ ├── ConditionalOnLocalStackService.java
│ └── LocalStackContainerConfiguration.java
└── test
└── java
└── io
└── github
└── sivalabs
└── localstack
└── autoconfigure
└── LocalStackAutoConfigurationTest.java
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 |
3 | on:
4 | push:
5 | branches:
6 | - '*'
7 |
8 | jobs:
9 | Build:
10 | name: Unit & Integration Tests
11 | runs-on: ubuntu-18.04
12 |
13 | steps:
14 | - uses: actions/checkout@v2
15 |
16 | - name: Set up JDK 1.8
17 | uses: actions/setup-java@v1
18 | with:
19 | java-version: 1.8
20 |
21 | - uses: actions/cache@v1
22 | with:
23 | path: ~/.m2/repository
24 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
25 | restore-keys: |
26 | ${{ runner.os }}-maven-
27 | - name: Build with Maven
28 | run: ./mvnw -B clean install
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**
5 | !**/src/test/**
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 |
30 | ### VS Code ###
31 | .vscode/
32 |
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sivalabs/localstack-spring-boot-starter/c5acfac0916d0ffc1e0f89b104169c67d1005855/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip
2 |
--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 K. Siva Prasad Reddy
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # localstack-spring-boot-starter
2 |
3 | 
4 | [](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22io.github.sivalabs%22)
5 | [](https://raw.githubusercontent.com/sivalabs/localstack-spring-boot-starter/master/LICENSE)
6 |
7 | `Localstack-spring-boot-starter` is a [SpringBoot](https://spring.io/projects/spring-boot) starter for [LocalStack](https://github.com/localstack/localstack) auto-configuration.
8 | This starter will spin up the *Localstack* docker container using [Testcontainers](https://www.testcontainers.org/)
9 | and auto-configure beans such as `AmazonS3`, `AmazonSQSAsync`, etc.
10 |
11 | ## Motivation
12 | [LocalStack](https://github.com/localstack/localstack) provides an easy-to-use test/mocking framework for developing AWS based Cloud applications.
13 | We can use [Testcontainers](https://www.testcontainers.org/modules/localstack/) to spin up a *Localstack* docker container,
14 | but we need to configure Amazon service clients like `AmazonS3`, `AmazonSQSAsync` which is typical boilerplate that we copy-paste from project to project.
15 | Instead of copy-pasting the code snippets, creating a SpringBoot starter which autoconfigures the Amazon service clients is a better approach and less error prone.
16 | Hence, the birth of `localstack-spring-boot-starter` :-)
17 |
18 | ## Requirements
19 | * JDK 8+
20 | * Tested with SpringBoot 2.3.3.RELEASE, should work fine with any SpringBoot 2.x versions
21 |
22 | ## How to use?
23 |
24 | ### Add dependencies
25 |
26 | **Maven**
27 |
28 | ```xml
29 |
30 |
31 | io.github.sivalabs
32 | localstack-spring-boot-starter
33 | 0.0.1
34 |
35 |
36 | org.testcontainers
37 | localstack
38 | 1.14.3
39 |
40 |
41 | com.amazonaws
42 | aws-java-sdk
43 | 1.11.852
44 |
45 |
46 | ```
47 |
48 | **Gradle**
49 |
50 | ```groovy
51 | implementation 'io.github.sivalabs:localstack-spring-boot-starter:0.0.1'
52 | implementation 'org.testcontainers:localstack:1.14.3'
53 | implementation 'com.amazonaws:aws-java-sdk:1.11.852'
54 | ```
55 |
56 | ### Enable LocalStack AutoConfiguration
57 | You can enable LocalStack AutoConfiguration by adding `@EnableLocalStack` annotation to either main entrypoint class or
58 | any `@Configuration` class.
59 |
60 | ```java
61 | package com.sivalabs.demo;
62 |
63 | import io.github.sivalabs.localstack.EnableLocalStack;
64 | import org.springframework.boot.SpringApplication;
65 | import org.springframework.boot.autoconfigure.SpringBootApplication;
66 | import com.amazonaws.services.s3.AmazonS3;
67 | import com.amazonaws.services.sqs.AmazonSQSAsync;
68 | import org.springframework.beans.factory.annotation.Autowired;
69 |
70 | @SpringBootApplication
71 | @EnableLocalStack
72 | public class LocalStackStarterDemoApplication {
73 |
74 | @Autowired
75 | private AmazonS3 amazonS3;
76 |
77 | @Autowired
78 | private AmazonSQSAsync amazonSQS;
79 |
80 | public static void main(String[] args) {
81 | SpringApplication.run(LocalStackStarterDemoApplication.class, args);
82 | }
83 | }
84 | ```
85 |
86 | #### How to use only for Integration Tests?
87 | You may want to use `localstack-spring-boot-starter` only for testing.
88 | In that case, you can add `@EnableLocalStack` annotation combined with `@Profile("integration-test")` annotation
89 | so that the Localstack AutoConfiguration is only activated while running integration tests.
90 |
91 | ```java
92 | @Configuration
93 | @EnableLocalStack
94 | @Profile("integration-test")
95 | public class TestConfig {
96 | }
97 | ```
98 |
99 | You can activate `integration-test` profile using `@ActiveProfiles` as follows:
100 |
101 | ```java
102 | @SpringBootTest
103 | @ActiveProfiles("integration-test")
104 | class SomeIntegrationTest {
105 | @Autowired
106 | private AmazonS3 amazonS3;
107 |
108 | @Autowired
109 | private AmazonSQSAsync amazonSQS;
110 |
111 | @Test
112 | void someTest() {
113 |
114 | }
115 | }
116 | ```
117 |
118 | ### Configuration
119 |
120 | The following configuration properties are available to customize the default behaviour.
121 |
122 | | Property | Required | Default Value |
123 | |-------------------------------|----------|--------------------------------|
124 | | `localstack.enabled` | no | `true` |
125 | | `localstack.edgePort` | no | `4566` |
126 | | `localstack.defaultRegion` | no | `us-east-1` |
127 | | `localstack.hostname` | no | `localhost` |
128 | | `localstack.hostnameExternal` | no | `localhost` |
129 | | `localstack.dockerImage` | no | `localstack/localstack:0.11.2` |
130 | | `localstack.useSsl` | no | `false` |
131 | | `localstack.services` | no | `""` |
132 |
133 | You can customize which AWS services to enable/disable as follows:
134 |
135 | | Property | Value | Default Value |
136 | |--------------------------------------|---------------------------------------------------------------------------------------------|---------------|
137 | | `localstack.services` | `SQS, S3, SNS, DYNAMODB, DYNAMODBSTREAMS, KINESIS, IAM, LAMBDA, CLOUDWATCH, SECRETSMANAGER` | `""` |
138 | | `localstack.s3.enabled` | `false` | `true` |
139 | | `localstack.sqs.enabled` | `true` | `true` |
140 | | `localstack.sns.enabled` | `false` | `true` |
141 | | `localstack.dynamodb.enabled` | `true` | `true` |
142 | | `localstack.dynamodbstreams.enabled` | `false` | `true` |
143 | | `localstack.kinesis.enabled` | `true` | `true` |
144 | | `localstack.iam.enabled` | `false` | `true` |
145 | | `localstack.secretsmanager.enabled` | `true` | `true` |
146 | | `localstack.lambda.enabled` | `false` | `true` |
147 | | `localstack.cloudwatch.enabled` | `true` | `true` |
148 |
149 | ## Examples
150 | * [Minimal SpringBoot application](https://github.com/sivalabs/localstack-spring-boot-starter/tree/master/examples/localstack-spring-boot-sample)
151 |
152 | ## Want to Contribute?
153 |
154 | You can contribute to `localstack-spring-boot-starter` project in many ways:
155 | * Use the starter and report if there are any bugs by [opening an issue](https://github.com/sivalabs/localstack-spring-boot-starter/issues/new)
156 | * Add support for auto-configuration of [more services](https://github.com/localstack/localstack#overview)
157 | * Add more [example applications](https://github.com/sivalabs/localstack-spring-boot-starter/tree/v0.0.2/examples)
158 |
159 | ## Credits
160 | The implementation of `localstack-spring-boot-starter` is inspired by [testcontainers-spring-boot](https://github.com/testcontainers/testcontainers-spring-boot).
161 | The `testcontainers-spring-boot` also provides localstack support, but it only spins up the docker container, and
162 | you will have to configure the beans like `AmazonS3`, `AmazonSQSAsync` etc by yourself.
163 |
164 | ## License
165 | [](https://raw.githubusercontent.com/sivalabs/localstack-spring-boot-starter/master/LICENSE)
166 |
167 | ## Developer Notes
168 |
169 | Procedure for deploying to Maven Central https://central.sonatype.org/pages/apache-maven.html
170 |
171 | Set version to SNAPSHOT (ex: 1.0.0-SNAPSHOT)
172 |
173 | Deploy SNAPSHOT version to https://oss.sonatype.org/content/repositories/snapshots/
174 |
175 | ```shell script
176 | localstack-spring-boot-starter> ./mvnw clean deploy -Prelease
177 | ```
178 |
179 | Deploy release version to Maven Central
180 |
181 | ```shell script
182 | localstack-spring-boot-starter> ./mvnw release:clean release:prepare -Prelease
183 | localstack-spring-boot-starter> ./mvnw release:perform -Prelease
184 | ```
185 |
186 | Search for release artifacts on https://oss.sonatype.org/#nexus-search;quick~sivalabs
187 |
--------------------------------------------------------------------------------
/examples/localstack-spring-boot-sample/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sivalabs/localstack-spring-boot-starter/c5acfac0916d0ffc1e0f89b104169c67d1005855/examples/localstack-spring-boot-sample/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/examples/localstack-spring-boot-sample/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip
2 |
--------------------------------------------------------------------------------
/examples/localstack-spring-boot-sample/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Maven2 Start Up Batch script
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # M2_HOME - location of maven2's installed home dir
31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
32 | # e.g. to debug Maven itself, use
33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
35 | # ----------------------------------------------------------------------------
36 |
37 | if [ -z "$MAVEN_SKIP_RC" ] ; then
38 |
39 | if [ -f /etc/mavenrc ] ; then
40 | . /etc/mavenrc
41 | fi
42 |
43 | if [ -f "$HOME/.mavenrc" ] ; then
44 | . "$HOME/.mavenrc"
45 | fi
46 |
47 | fi
48 |
49 | # OS specific support. $var _must_ be set to either true or false.
50 | cygwin=false;
51 | darwin=false;
52 | mingw=false
53 | case "`uname`" in
54 | CYGWIN*) cygwin=true ;;
55 | MINGW*) mingw=true;;
56 | Darwin*) darwin=true
57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
59 | if [ -z "$JAVA_HOME" ]; then
60 | if [ -x "/usr/libexec/java_home" ]; then
61 | export JAVA_HOME="`/usr/libexec/java_home`"
62 | else
63 | export JAVA_HOME="/Library/Java/Home"
64 | fi
65 | fi
66 | ;;
67 | esac
68 |
69 | if [ -z "$JAVA_HOME" ] ; then
70 | if [ -r /etc/gentoo-release ] ; then
71 | JAVA_HOME=`java-config --jre-home`
72 | fi
73 | fi
74 |
75 | if [ -z "$M2_HOME" ] ; then
76 | ## resolve links - $0 may be a link to maven's home
77 | PRG="$0"
78 |
79 | # need this for relative symlinks
80 | while [ -h "$PRG" ] ; do
81 | ls=`ls -ld "$PRG"`
82 | link=`expr "$ls" : '.*-> \(.*\)$'`
83 | if expr "$link" : '/.*' > /dev/null; then
84 | PRG="$link"
85 | else
86 | PRG="`dirname "$PRG"`/$link"
87 | fi
88 | done
89 |
90 | saveddir=`pwd`
91 |
92 | M2_HOME=`dirname "$PRG"`/..
93 |
94 | # make it fully qualified
95 | M2_HOME=`cd "$M2_HOME" && pwd`
96 |
97 | cd "$saveddir"
98 | # echo Using m2 at $M2_HOME
99 | fi
100 |
101 | # For Cygwin, ensure paths are in UNIX format before anything is touched
102 | if $cygwin ; then
103 | [ -n "$M2_HOME" ] &&
104 | M2_HOME=`cygpath --unix "$M2_HOME"`
105 | [ -n "$JAVA_HOME" ] &&
106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
107 | [ -n "$CLASSPATH" ] &&
108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
109 | fi
110 |
111 | # For Migwn, ensure paths are in UNIX format before anything is touched
112 | if $mingw ; then
113 | [ -n "$M2_HOME" ] &&
114 | M2_HOME="`(cd "$M2_HOME"; pwd)`"
115 | [ -n "$JAVA_HOME" ] &&
116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
117 | # TODO classpath?
118 | fi
119 |
120 | if [ -z "$JAVA_HOME" ]; then
121 | javaExecutable="`which javac`"
122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
123 | # readlink(1) is not available as standard on Solaris 10.
124 | readLink=`which readlink`
125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
126 | if $darwin ; then
127 | javaHome="`dirname \"$javaExecutable\"`"
128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
129 | else
130 | javaExecutable="`readlink -f \"$javaExecutable\"`"
131 | fi
132 | javaHome="`dirname \"$javaExecutable\"`"
133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
134 | JAVA_HOME="$javaHome"
135 | export JAVA_HOME
136 | fi
137 | fi
138 | fi
139 |
140 | if [ -z "$JAVACMD" ] ; then
141 | if [ -n "$JAVA_HOME" ] ; then
142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
143 | # IBM's JDK on AIX uses strange locations for the executables
144 | JAVACMD="$JAVA_HOME/jre/sh/java"
145 | else
146 | JAVACMD="$JAVA_HOME/bin/java"
147 | fi
148 | else
149 | JAVACMD="`which java`"
150 | fi
151 | fi
152 |
153 | if [ ! -x "$JAVACMD" ] ; then
154 | echo "Error: JAVA_HOME is not defined correctly." >&2
155 | echo " We cannot execute $JAVACMD" >&2
156 | exit 1
157 | fi
158 |
159 | if [ -z "$JAVA_HOME" ] ; then
160 | echo "Warning: JAVA_HOME environment variable is not set."
161 | fi
162 |
163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
164 |
165 | # traverses directory structure from process work directory to filesystem root
166 | # first directory with .mvn subdirectory is considered project base directory
167 | find_maven_basedir() {
168 |
169 | if [ -z "$1" ]
170 | then
171 | echo "Path not specified to find_maven_basedir"
172 | return 1
173 | fi
174 |
175 | basedir="$1"
176 | wdir="$1"
177 | while [ "$wdir" != '/' ] ; do
178 | if [ -d "$wdir"/.mvn ] ; then
179 | basedir=$wdir
180 | break
181 | fi
182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc)
183 | if [ -d "${wdir}" ]; then
184 | wdir=`cd "$wdir/.."; pwd`
185 | fi
186 | # end of workaround
187 | done
188 | echo "${basedir}"
189 | }
190 |
191 | # concatenates all lines of a file
192 | concat_lines() {
193 | if [ -f "$1" ]; then
194 | echo "$(tr -s '\n' ' ' < "$1")"
195 | fi
196 | }
197 |
198 | BASE_DIR=`find_maven_basedir "$(pwd)"`
199 | if [ -z "$BASE_DIR" ]; then
200 | exit 1;
201 | fi
202 |
203 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
204 | echo $MAVEN_PROJECTBASEDIR
205 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
206 |
207 | # For Cygwin, switch paths to Windows format before running java
208 | if $cygwin; then
209 | [ -n "$M2_HOME" ] &&
210 | M2_HOME=`cygpath --path --windows "$M2_HOME"`
211 | [ -n "$JAVA_HOME" ] &&
212 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
213 | [ -n "$CLASSPATH" ] &&
214 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
215 | [ -n "$MAVEN_PROJECTBASEDIR" ] &&
216 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
217 | fi
218 |
219 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
220 |
221 | exec "$JAVACMD" \
222 | $MAVEN_OPTS \
223 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
224 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
225 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
226 |
--------------------------------------------------------------------------------
/examples/localstack-spring-boot-sample/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM http://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Maven2 Start Up Batch script
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM M2_HOME - location of maven2's installed home dir
28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | @REM e.g. to debug Maven itself, use
32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | @REM ----------------------------------------------------------------------------
35 |
36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37 | @echo off
38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
40 |
41 | @REM set %HOME% to equivalent of $HOME
42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
43 |
44 | @REM Execute a user defined script before this one
45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
49 | :skipRcPre
50 |
51 | @setlocal
52 |
53 | set ERROR_CODE=0
54 |
55 | @REM To isolate internal variables from possible post scripts, we use another setlocal
56 | @setlocal
57 |
58 | @REM ==== START VALIDATION ====
59 | if not "%JAVA_HOME%" == "" goto OkJHome
60 |
61 | echo.
62 | echo Error: JAVA_HOME not found in your environment. >&2
63 | echo Please set the JAVA_HOME variable in your environment to match the >&2
64 | echo location of your Java installation. >&2
65 | echo.
66 | goto error
67 |
68 | :OkJHome
69 | if exist "%JAVA_HOME%\bin\java.exe" goto init
70 |
71 | echo.
72 | echo Error: JAVA_HOME is set to an invalid directory. >&2
73 | echo JAVA_HOME = "%JAVA_HOME%" >&2
74 | echo Please set the JAVA_HOME variable in your environment to match the >&2
75 | echo location of your Java installation. >&2
76 | echo.
77 | goto error
78 |
79 | @REM ==== END VALIDATION ====
80 |
81 | :init
82 |
83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
84 | @REM Fallback to current working directory if not found.
85 |
86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
88 |
89 | set EXEC_DIR=%CD%
90 | set WDIR=%EXEC_DIR%
91 | :findBaseDir
92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
93 | cd ..
94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
95 | set WDIR=%CD%
96 | goto findBaseDir
97 |
98 | :baseDirFound
99 | set MAVEN_PROJECTBASEDIR=%WDIR%
100 | cd "%EXEC_DIR%"
101 | goto endDetectBaseDir
102 |
103 | :baseDirNotFound
104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
105 | cd "%EXEC_DIR%"
106 |
107 | :endDetectBaseDir
108 |
109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
110 |
111 | @setlocal EnableExtensions EnableDelayedExpansion
112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
114 |
115 | :endReadAdditionalConfig
116 |
117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
118 |
119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
121 |
122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
123 | if ERRORLEVEL 1 goto error
124 | goto end
125 |
126 | :error
127 | set ERROR_CODE=1
128 |
129 | :end
130 | @endlocal & set ERROR_CODE=%ERROR_CODE%
131 |
132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
136 | :skipRcPost
137 |
138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause
140 |
141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
142 |
143 | exit /B %ERROR_CODE%
144 |
--------------------------------------------------------------------------------
/examples/localstack-spring-boot-sample/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 | 4.0.0
7 | com.sivalabs
8 | localstack-spring-boot-sample
9 | jar
10 | 1.0-SNAPSHOT
11 |
12 |
13 | org.springframework.boot
14 | spring-boot-starter-parent
15 | 2.7.10
16 |
17 |
18 |
19 | UTF-8
20 | 1.8
21 | 1.11.852
22 | 1.17.6
23 | 0.0.3-SNAPSHOT
24 | 4.2.0
25 |
26 |
27 |
28 |
29 |
30 | org.springframework.boot
31 | spring-boot-maven-plugin
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | org.testcontainers
40 | testcontainers-bom
41 | ${testcontainers.version}
42 | pom
43 | import
44 |
45 |
46 |
47 |
48 |
49 |
50 | org.springframework.boot
51 | spring-boot-starter-web
52 |
53 |
54 | org.testcontainers
55 | localstack
56 |
57 |
58 | io.github.sivalabs
59 | localstack-spring-boot-starter
60 | ${localstack-starter.version}
61 |
62 |
63 | com.amazonaws
64 | aws-java-sdk
65 | ${aws-java-sdk.version}
66 |
67 |
68 | org.springframework.boot
69 | spring-boot-starter-test
70 | test
71 |
72 |
73 | org.awaitility
74 | awaitility
75 | ${awaitility.version}
76 | test
77 |
78 |
79 | org.projectlombok
80 | lombok
81 | true
82 |
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/examples/localstack-spring-boot-sample/src/main/java/com/sivalabs/demo/LocalStackStarterDemoApplication.java:
--------------------------------------------------------------------------------
1 |
2 | package com.sivalabs.demo;
3 |
4 | import io.github.sivalabs.localstack.EnableLocalStack;
5 | import org.springframework.boot.SpringApplication;
6 | import org.springframework.boot.autoconfigure.SpringBootApplication;
7 |
8 | @SpringBootApplication
9 | @EnableLocalStack
10 | public class LocalStackStarterDemoApplication {
11 |
12 | public static void main(String[] args) {
13 | SpringApplication.run(LocalStackStarterDemoApplication.class, args);
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/examples/localstack-spring-boot-sample/src/main/java/com/sivalabs/demo/services/DynamoDBService.java:
--------------------------------------------------------------------------------
1 | package com.sivalabs.demo.services;
2 |
3 | import com.amazonaws.services.dynamodbv2.AmazonDynamoDBAsync;
4 | import com.amazonaws.services.dynamodbv2.model.ListTablesRequest;
5 | import com.amazonaws.services.dynamodbv2.model.ListTablesResult;
6 | import lombok.RequiredArgsConstructor;
7 | import org.springframework.stereotype.Service;
8 |
9 | import java.util.List;
10 |
11 | @Service
12 | @RequiredArgsConstructor
13 | public class DynamoDBService {
14 | private final AmazonDynamoDBAsync amazonDynamoDBAsync;
15 |
16 | public List listTables() {
17 | ListTablesRequest request = new ListTablesRequest().withLimit(10);
18 | ListTablesResult tableList = amazonDynamoDBAsync.listTables(request);
19 | return tableList.getTableNames();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/examples/localstack-spring-boot-sample/src/main/java/com/sivalabs/demo/services/S3Service.java:
--------------------------------------------------------------------------------
1 | package com.sivalabs.demo.services;
2 |
3 |
4 | import com.amazonaws.AmazonServiceException;
5 | import com.amazonaws.SdkClientException;
6 | import com.amazonaws.services.s3.AmazonS3;
7 | import com.amazonaws.services.s3.model.Bucket;
8 | import com.amazonaws.services.s3.model.ListVersionsRequest;
9 | import com.amazonaws.services.s3.model.ObjectListing;
10 | import com.amazonaws.services.s3.model.ObjectMetadata;
11 | import com.amazonaws.services.s3.model.PutObjectResult;
12 | import com.amazonaws.services.s3.model.S3Object;
13 | import com.amazonaws.services.s3.model.S3ObjectSummary;
14 | import com.amazonaws.services.s3.model.S3VersionSummary;
15 | import com.amazonaws.services.s3.model.VersionListing;
16 | import lombok.RequiredArgsConstructor;
17 | import org.springframework.stereotype.Service;
18 |
19 | import java.io.ByteArrayInputStream;
20 | import java.io.InputStream;
21 | import java.util.Iterator;
22 | import java.util.List;
23 |
24 | @Service
25 | @RequiredArgsConstructor
26 | public class S3Service {
27 | private final AmazonS3 amazonS3;
28 |
29 | public Bucket createBucket(String bucketName) {
30 | return amazonS3.createBucket(bucketName);
31 | }
32 |
33 | public List listBuckets() {
34 | return amazonS3.listBuckets();
35 | }
36 |
37 | public S3Object getObject(String bucketName, String key) {
38 | return amazonS3.getObject(bucketName, key);
39 | }
40 |
41 | public PutObjectResult store(String bucketName, String key, String value) {
42 | return amazonS3.putObject(bucketName, key, value);
43 | }
44 |
45 | public PutObjectResult store(String bucketName, String key, InputStream inputStream) {
46 | return amazonS3.putObject(bucketName, key, inputStream, new ObjectMetadata());
47 | }
48 |
49 | public PutObjectResult store(String bucketName, String key, byte[] bytes) {
50 | InputStream inputStream = new ByteArrayInputStream(bytes);
51 | return store(bucketName, key, inputStream);
52 | }
53 |
54 | public void deleteBucket(String bucketName) {
55 | amazonS3.deleteBucket(bucketName);
56 | }
57 |
58 | public void deleteBucketForce(String bucketName) {
59 | try {
60 | // Delete all objects from the bucket. This is sufficient
61 | // for unversioned buckets. For versioned buckets, when you attempt to delete objects, Amazon S3 inserts
62 | // delete markers for all objects, but doesn't delete the object versions.
63 | // To delete objects from versioned buckets, delete all of the object versions before deleting
64 | // the bucket (see below for an example).
65 | ObjectListing objectListing = amazonS3.listObjects(bucketName);
66 | while (true) {
67 | Iterator objIter = objectListing.getObjectSummaries().iterator();
68 | while (objIter.hasNext()) {
69 | amazonS3.deleteObject(bucketName, objIter.next().getKey());
70 | }
71 |
72 | // If the bucket contains many objects, the listObjects() call
73 | // might not return all of the objects in the first listing. Check to
74 | // see whether the listing was truncated. If so, retrieve the next page of objects
75 | // and delete them.
76 | if (objectListing.isTruncated()) {
77 | objectListing = amazonS3.listNextBatchOfObjects(objectListing);
78 | } else {
79 | break;
80 | }
81 | }
82 |
83 | // Delete all object versions (required for versioned buckets).
84 | VersionListing versionList = amazonS3.listVersions(new ListVersionsRequest().withBucketName(bucketName));
85 | while (true) {
86 | Iterator versionIter = versionList.getVersionSummaries().iterator();
87 | while (versionIter.hasNext()) {
88 | S3VersionSummary vs = versionIter.next();
89 | amazonS3.deleteVersion(bucketName, vs.getKey(), vs.getVersionId());
90 | }
91 |
92 | if (versionList.isTruncated()) {
93 | versionList = amazonS3.listNextBatchOfVersions(versionList);
94 | } else {
95 | break;
96 | }
97 | }
98 |
99 | // After all objects and object versions are deleted, delete the bucket.
100 | amazonS3.deleteBucket(bucketName);
101 | }
102 | catch(AmazonServiceException e) {
103 | // The call was transmitted successfully, but Amazon S3 couldn't process
104 | // it, so it returned an error response.
105 | e.printStackTrace();
106 | }
107 | catch(SdkClientException e) {
108 | // Amazon S3 couldn't be contacted for a response, or the client couldn't
109 | // parse the response from Amazon S3.
110 | e.printStackTrace();
111 | }
112 | }
113 |
114 | }
115 |
116 |
--------------------------------------------------------------------------------
/examples/localstack-spring-boot-sample/src/main/java/com/sivalabs/demo/services/SNSService.java:
--------------------------------------------------------------------------------
1 | package com.sivalabs.demo.services;
2 |
3 | import com.amazonaws.services.sns.AmazonSNSAsync;
4 | import com.amazonaws.services.sns.model.CreateTopicRequest;
5 | import com.amazonaws.services.sns.model.CreateTopicResult;
6 | import com.amazonaws.services.sns.model.DeleteTopicResult;
7 | import com.amazonaws.services.sns.model.PublishRequest;
8 | import com.amazonaws.services.sns.model.PublishResult;
9 | import lombok.RequiredArgsConstructor;
10 | import lombok.extern.slf4j.Slf4j;
11 | import org.springframework.stereotype.Service;
12 |
13 | @Service
14 | @RequiredArgsConstructor
15 | @Slf4j
16 | public class SNSService {
17 |
18 | private final AmazonSNSAsync amazonSNSAsync;
19 |
20 | public CreateTopicResult createTopic(String topicName) {
21 | CreateTopicRequest createTopicRequest = new CreateTopicRequest(topicName);
22 | CreateTopicResult createTopicResponse = amazonSNSAsync.createTopic(createTopicRequest);
23 | log.debug("Created SNS Topic : {}", createTopicResponse.getTopicArn());
24 | return createTopicResponse;
25 | }
26 |
27 | public DeleteTopicResult deleteTopic(String topicName) {
28 | CreateTopicResult topic = createTopic(topicName);
29 | return amazonSNSAsync.deleteTopic(topic.getTopicArn());
30 | }
31 |
32 | public PublishResult sendMessage(String topicName, String msg) {
33 | CreateTopicResult topic = createTopic(topicName);
34 | PublishRequest publishRequest = new PublishRequest(topic.getTopicArn(), msg);
35 | PublishResult publishResponse = amazonSNSAsync.publish(publishRequest);
36 | log.debug("SNS MessageId: " + publishResponse.getMessageId());
37 | return publishResponse;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/examples/localstack-spring-boot-sample/src/main/java/com/sivalabs/demo/services/SQSService.java:
--------------------------------------------------------------------------------
1 | package com.sivalabs.demo.services;
2 |
3 | import com.amazonaws.services.sqs.AmazonSQSAsync;
4 | import com.amazonaws.services.sqs.model.CreateQueueRequest;
5 | import com.amazonaws.services.sqs.model.CreateQueueResult;
6 | import com.amazonaws.services.sqs.model.GetQueueAttributesRequest;
7 | import com.amazonaws.services.sqs.model.GetQueueAttributesResult;
8 | import com.amazonaws.services.sqs.model.ListQueuesResult;
9 | import com.amazonaws.services.sqs.model.Message;
10 | import com.amazonaws.services.sqs.model.SendMessageRequest;
11 | import lombok.RequiredArgsConstructor;
12 | import org.springframework.stereotype.Service;
13 |
14 | import java.util.List;
15 |
16 | import static java.util.Arrays.asList;
17 |
18 | @Service
19 | @RequiredArgsConstructor
20 | public class SQSService {
21 | private final AmazonSQSAsync amazonSQS;
22 |
23 | public CreateQueueResult createQueue(String queueName) {
24 | CreateQueueRequest createQueueRequest = new CreateQueueRequest(queueName)
25 | .addAttributesEntry("DelaySeconds", "60")
26 | .addAttributesEntry("MessageRetentionPeriod", "86400");
27 | return amazonSQS.createQueue(createQueueRequest);
28 | }
29 |
30 | public ListQueuesResult listQueues() {
31 | return amazonSQS.listQueues();
32 | }
33 |
34 | public String getQueueUrl(String queueName) {
35 | return amazonSQS.getQueueUrl(queueName).getQueueUrl();
36 | }
37 |
38 | public GetQueueAttributesResult getQueueAttributes(String queueName) {
39 | String queueUrl = amazonSQS.getQueueUrl(queueName).getQueueUrl();
40 | GetQueueAttributesRequest request = new GetQueueAttributesRequest();
41 | request.setQueueUrl(queueUrl);
42 | request.setAttributeNames(asList("QueueArn", "VisibilityTimeout"));
43 | return amazonSQS.getQueueAttributes(request);
44 | }
45 |
46 | public void sendMessage(String queueName, String msg) {
47 | String queueUrl = amazonSQS.getQueueUrl(queueName).getQueueUrl();
48 |
49 | SendMessageRequest sendMessageRequest = new SendMessageRequest()
50 | .withQueueUrl(queueUrl)
51 | .withMessageBody(msg)
52 | .withDelaySeconds(0);
53 | amazonSQS.sendMessage(sendMessageRequest);
54 | }
55 |
56 | public List readMessages(String queueName) {
57 | String queueUrl = amazonSQS.getQueueUrl(queueName).getQueueUrl();
58 | return amazonSQS.receiveMessage(queueUrl).getMessages();
59 | }
60 |
61 | public void deleteMessage(String queueName, Message message) {
62 | String queueUrl = amazonSQS.getQueueUrl(queueName).getQueueUrl();
63 | amazonSQS.deleteMessage(queueUrl, message.getReceiptHandle());
64 | }
65 |
66 | public void deleteQueue(String queueName) {
67 | String queueUrl = amazonSQS.getQueueUrl(queueName).getQueueUrl();
68 | amazonSQS.deleteQueue(queueUrl);
69 | }
70 |
71 | }
72 |
73 |
--------------------------------------------------------------------------------
/examples/localstack-spring-boot-sample/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | localstack.enabled=true
2 | localstack.docker-image=localstack/localstack:2.0.0
3 | localstack.services=S3,SQS,SNS,DYNAMODB,DYNAMODBSTREAMS,KINESIS,IAM,SECRETSMANAGER,CLOUDWATCH,LAMBDA
4 | localstack.s3.enabled=true
5 | localstack.sqs.enabled=true
6 | localstack.sns.enabled=true
7 | localstack.dynamodb.enabled=true
8 | localstack.dynamodbstreams.enabled=true
9 | localstack.kinesis.enabled=true
10 | localstack.iam.enabled=true
11 | localstack.secretsmanager.enabled=true
12 | localstack.cloudwatch.enabled=true
13 | localstack.lambda.enabled=true
14 |
--------------------------------------------------------------------------------
/examples/localstack-spring-boot-sample/src/test/java/com/sivalabs/demo/SpringbootLocalStackDemoApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.sivalabs.demo;
2 |
3 | import com.amazonaws.services.cloudwatch.AmazonCloudWatchAsync;
4 | import com.amazonaws.services.dynamodbv2.AmazonDynamoDBAsync;
5 | import com.amazonaws.services.dynamodbv2.AmazonDynamoDBStreamsAsync;
6 | import com.amazonaws.services.identitymanagement.AmazonIdentityManagementAsync;
7 | import com.amazonaws.services.kinesis.AmazonKinesisAsync;
8 | import com.amazonaws.services.lambda.AWSLambdaAsync;
9 | import com.amazonaws.services.s3.AmazonS3;
10 | import com.amazonaws.services.secretsmanager.AWSSecretsManagerAsync;
11 | import com.amazonaws.services.sns.AmazonSNSAsync;
12 | import com.amazonaws.services.sqs.AmazonSQSAsync;
13 | import io.github.sivalabs.localstack.LocalStackProperties;
14 | import org.junit.jupiter.api.Test;
15 | import org.springframework.beans.factory.annotation.Autowired;
16 | import org.springframework.boot.test.context.SpringBootTest;
17 | import org.springframework.context.ApplicationContext;
18 |
19 | import static org.assertj.core.api.Assertions.assertThat;
20 |
21 | @SpringBootTest
22 | public class SpringbootLocalStackDemoApplicationTest {
23 |
24 | @Autowired
25 | private ApplicationContext context;
26 |
27 | @Test
28 | void shouldAutoConfigureLocalStackServices() {
29 | assertThat(context.getBean(LocalStackProperties.class)).isNotNull();
30 | assertThat(context.getBean(AmazonS3.class)).isNotNull();
31 | assertThat(context.getBean(AmazonSQSAsync.class)).isNotNull();
32 | assertThat(context.getBean(AmazonSNSAsync.class)).isNotNull();
33 | assertThat(context.getBean(AmazonDynamoDBAsync.class)).isNotNull();
34 | assertThat(context.getBean(AmazonDynamoDBStreamsAsync.class)).isNotNull();
35 | assertThat(context.getBean(AWSLambdaAsync.class)).isNotNull();
36 | assertThat(context.getBean(AmazonKinesisAsync.class)).isNotNull();
37 | assertThat(context.getBean(AmazonIdentityManagementAsync.class)).isNotNull();
38 | assertThat(context.getBean(AWSSecretsManagerAsync.class)).isNotNull();
39 | assertThat(context.getBean(AmazonCloudWatchAsync.class)).isNotNull();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/examples/localstack-spring-boot-sample/src/test/java/com/sivalabs/demo/services/CloudWatchTest.java:
--------------------------------------------------------------------------------
1 | package com.sivalabs.demo.services;
2 |
3 | import com.amazonaws.services.cloudwatch.AmazonCloudWatchAsync;
4 | import com.amazonaws.services.cloudwatch.model.Dimension;
5 | import com.amazonaws.services.cloudwatch.model.MetricDatum;
6 | import com.amazonaws.services.cloudwatch.model.PutMetricDataRequest;
7 | import com.amazonaws.services.cloudwatch.model.PutMetricDataResult;
8 | import com.amazonaws.services.cloudwatch.model.StandardUnit;
9 | import lombok.extern.slf4j.Slf4j;
10 | import org.junit.jupiter.api.Test;
11 | import org.springframework.beans.factory.annotation.Autowired;
12 | import org.springframework.boot.test.context.SpringBootTest;
13 |
14 | import static org.assertj.core.api.Assertions.assertThat;
15 |
16 | @SpringBootTest
17 | @Slf4j
18 | public class CloudWatchTest {
19 |
20 | @Autowired
21 | private AmazonCloudWatchAsync amazonCloudWatch;
22 |
23 | @Test
24 | void shouldWorkWithCloudWatch() {
25 | Dimension dimension = new Dimension()
26 | .withName("UNIQUE_PAGES")
27 | .withValue("URLS");
28 |
29 | MetricDatum datum = new MetricDatum()
30 | .withMetricName("PAGES_VISITED")
31 | .withUnit(StandardUnit.None)
32 | .withValue(20.0)
33 | .withDimensions(dimension);
34 |
35 | PutMetricDataRequest request = new PutMetricDataRequest()
36 | .withNamespace("SITE/TRAFFIC")
37 | .withMetricData(datum);
38 |
39 | PutMetricDataResult response = amazonCloudWatch.putMetricData(request);
40 | assertThat(response).isNotNull();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/examples/localstack-spring-boot-sample/src/test/java/com/sivalabs/demo/services/DynamoDBServiceTest.java:
--------------------------------------------------------------------------------
1 | package com.sivalabs.demo.services;
2 |
3 | import com.amazonaws.services.dynamodbv2.AmazonDynamoDBAsync;
4 | import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
5 | import com.amazonaws.services.dynamodbv2.model.AttributeValue;
6 | import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
7 | import com.amazonaws.services.dynamodbv2.model.CreateTableResult;
8 | import com.amazonaws.services.dynamodbv2.model.GetItemRequest;
9 | import com.amazonaws.services.dynamodbv2.model.GetItemResult;
10 | import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
11 | import com.amazonaws.services.dynamodbv2.model.KeyType;
12 | import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
13 | import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType;
14 | import lombok.extern.slf4j.Slf4j;
15 | import org.junit.jupiter.api.Test;
16 | import org.springframework.beans.factory.annotation.Autowired;
17 | import org.springframework.boot.test.context.SpringBootTest;
18 |
19 | import java.util.HashMap;
20 | import java.util.List;
21 | import java.util.Map;
22 |
23 | import static org.assertj.core.api.Assertions.assertThat;
24 |
25 | @SpringBootTest
26 | @Slf4j
27 | class DynamoDBServiceTest {
28 |
29 | private static final String tableName = "sample";
30 | private static final String key = "Name";
31 |
32 | @Autowired
33 | private DynamoDBService dynamoDBService;
34 |
35 | @Autowired
36 | private AmazonDynamoDBAsync amazonDynamoDBAsync;
37 |
38 | @Test
39 | void shouldGetTableNames() {
40 | List tables = dynamoDBService.listTables();
41 | assertThat(tables).isNotNull();
42 | }
43 |
44 | @Test
45 | void shouldBeAbleToDoBasicOperationsWithDynamoDB() {
46 | String name = "Siva";
47 | createTable();
48 | insertData(name);
49 | String result = readData(name);
50 | assertThat(result).isEqualTo(name);
51 | }
52 |
53 | private String readData(String name) {
54 | Map keyToGet = new HashMap<>();
55 | keyToGet.put(key, new AttributeValue(name));
56 |
57 | GetItemRequest request = new GetItemRequest().withKey(keyToGet).withTableName(tableName);
58 | GetItemResult outcome = amazonDynamoDBAsync.getItem(request);
59 | return outcome.getItem().get(key).getS();
60 | }
61 |
62 | private void insertData(String name) {
63 | Map itemValues = new HashMap<>();
64 | itemValues.put(key, new AttributeValue(name));
65 | amazonDynamoDBAsync.putItem(tableName, itemValues);
66 | log.info("Item inserted into table: {} successfully", tableName);
67 | }
68 |
69 | private void createTable() {
70 | CreateTableRequest request = new CreateTableRequest()
71 | .withAttributeDefinitions(new AttributeDefinition(key, ScalarAttributeType.S))
72 | .withKeySchema(new KeySchemaElement(key, KeyType.HASH))
73 | .withProvisionedThroughput(new ProvisionedThroughput(10L, 10L))
74 | .withTableName(tableName);
75 | CreateTableResult result = amazonDynamoDBAsync.createTable(request);
76 | log.info("Table with name : {} created successfully", result.getTableDescription().getTableName());
77 | }
78 | }
--------------------------------------------------------------------------------
/examples/localstack-spring-boot-sample/src/test/java/com/sivalabs/demo/services/DynamoDBStreamsTest.java:
--------------------------------------------------------------------------------
1 | package com.sivalabs.demo.services;
2 |
3 | import com.amazonaws.services.dynamodbv2.AmazonDynamoDBAsync;
4 | import com.amazonaws.services.dynamodbv2.AmazonDynamoDBStreamsAsync;
5 | import com.amazonaws.services.dynamodbv2.model.AttributeAction;
6 | import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
7 | import com.amazonaws.services.dynamodbv2.model.AttributeValue;
8 | import com.amazonaws.services.dynamodbv2.model.AttributeValueUpdate;
9 | import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
10 | import com.amazonaws.services.dynamodbv2.model.DescribeStreamRequest;
11 | import com.amazonaws.services.dynamodbv2.model.DescribeStreamResult;
12 | import com.amazonaws.services.dynamodbv2.model.DescribeTableResult;
13 | import com.amazonaws.services.dynamodbv2.model.GetRecordsRequest;
14 | import com.amazonaws.services.dynamodbv2.model.GetRecordsResult;
15 | import com.amazonaws.services.dynamodbv2.model.GetShardIteratorRequest;
16 | import com.amazonaws.services.dynamodbv2.model.GetShardIteratorResult;
17 | import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
18 | import com.amazonaws.services.dynamodbv2.model.KeyType;
19 | import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
20 | import com.amazonaws.services.dynamodbv2.model.Record;
21 | import com.amazonaws.services.dynamodbv2.model.Shard;
22 | import com.amazonaws.services.dynamodbv2.model.ShardIteratorType;
23 | import com.amazonaws.services.dynamodbv2.model.StreamSpecification;
24 | import com.amazonaws.services.dynamodbv2.model.StreamViewType;
25 | import com.amazonaws.services.dynamodbv2.util.TableUtils;
26 | import lombok.extern.slf4j.Slf4j;
27 | import org.junit.jupiter.api.Test;
28 | import org.springframework.beans.factory.annotation.Autowired;
29 | import org.springframework.boot.test.context.SpringBootTest;
30 |
31 | import java.util.ArrayList;
32 | import java.util.Arrays;
33 | import java.util.HashMap;
34 | import java.util.List;
35 | import java.util.Map;
36 |
37 | @SpringBootTest
38 | @Slf4j
39 | class DynamoDBStreamsTest {
40 |
41 | @Autowired
42 | private AmazonDynamoDBAsync dynamoDBClient;
43 |
44 | @Autowired
45 | private AmazonDynamoDBStreamsAsync streamsClient;
46 |
47 | @Test
48 | void shouldBeAbleToDoBasicOperationsWithDynamoDB() {
49 | // Source: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.LowLevel.Walkthrough.html
50 | // Create a table, with a stream enabled
51 | String tableName = "TestTableForStreams";
52 |
53 | ArrayList attributeDefinitions = new ArrayList<>(
54 | Arrays.asList(new AttributeDefinition()
55 | .withAttributeName("Id")
56 | .withAttributeType("N")));
57 |
58 | ArrayList keySchema = new ArrayList<>(
59 | Arrays.asList(new KeySchemaElement()
60 | .withAttributeName("Id")
61 | .withKeyType(KeyType.HASH))); // Partition key
62 |
63 | StreamSpecification streamSpecification = new StreamSpecification()
64 | .withStreamEnabled(true)
65 | .withStreamViewType(StreamViewType.NEW_AND_OLD_IMAGES);
66 |
67 | CreateTableRequest createTableRequest = new CreateTableRequest().withTableName(tableName)
68 | .withKeySchema(keySchema).withAttributeDefinitions(attributeDefinitions)
69 | .withProvisionedThroughput(new ProvisionedThroughput()
70 | .withReadCapacityUnits(10L)
71 | .withWriteCapacityUnits(10L))
72 | .withStreamSpecification(streamSpecification);
73 |
74 | System.out.println("Issuing CreateTable request for " + tableName);
75 | dynamoDBClient.createTable(createTableRequest);
76 | System.out.println("Waiting for " + tableName + " to be created...");
77 |
78 | try {
79 | TableUtils.waitUntilActive(dynamoDBClient, tableName);
80 | } catch (Exception e) {
81 | throw new RuntimeException(e);
82 | }
83 |
84 | // Print the stream settings for the table
85 | DescribeTableResult describeTableResult = dynamoDBClient.describeTable(tableName);
86 | String streamArn = describeTableResult.getTable().getLatestStreamArn();
87 | System.out.println("Current stream ARN for " + tableName + ": " +
88 | describeTableResult.getTable().getLatestStreamArn());
89 | StreamSpecification streamSpec = describeTableResult.getTable().getStreamSpecification();
90 | System.out.println("Stream enabled: " + streamSpec.getStreamEnabled());
91 | System.out.println("Update view type: " + streamSpec.getStreamViewType());
92 | System.out.println();
93 |
94 | // Generate write activity in the table
95 |
96 | System.out.println("Performing write activities on " + tableName);
97 | int maxItemCount = 10;
98 | for (Integer i = 1; i <= maxItemCount; i++) {
99 | System.out.println("Processing item " + i + " of " + maxItemCount);
100 |
101 | // Write a new item
102 | Map item = new HashMap<>();
103 | item.put("Id", new AttributeValue().withN(i.toString()));
104 | item.put("Message", new AttributeValue().withS("New item!"));
105 | dynamoDBClient.putItem(tableName, item);
106 |
107 |
108 | // Update the item
109 | Map key = new HashMap<>();
110 | key.put("Id", new AttributeValue().withN(i.toString()));
111 | Map attributeUpdates = new HashMap<>();
112 | attributeUpdates.put("Message", new AttributeValueUpdate()
113 | .withAction(AttributeAction.PUT)
114 | .withValue(new AttributeValue()
115 | .withS("This item has changed")));
116 | dynamoDBClient.updateItem(tableName, key, attributeUpdates);
117 |
118 | // Delete the item
119 | dynamoDBClient.deleteItem(tableName, key);
120 | }
121 |
122 | // Get all the shard IDs from the stream. Note that DescribeStream returns
123 | // the shard IDs one page at a time.
124 | String lastEvaluatedShardId = null;
125 |
126 | do {
127 | DescribeStreamResult describeStreamResult = streamsClient.describeStream(
128 | new DescribeStreamRequest()
129 | .withStreamArn(streamArn)
130 | .withExclusiveStartShardId(lastEvaluatedShardId));
131 | List shards = describeStreamResult.getStreamDescription().getShards();
132 |
133 | // Process each shard on this page
134 |
135 | for (Shard shard : shards) {
136 | String shardId = shard.getShardId();
137 | System.out.println("Shard: " + shard);
138 |
139 | // Get an iterator for the current shard
140 |
141 | GetShardIteratorRequest getShardIteratorRequest = new GetShardIteratorRequest()
142 | .withStreamArn(streamArn)
143 | .withShardId(shardId)
144 | .withShardIteratorType(ShardIteratorType.TRIM_HORIZON);
145 | GetShardIteratorResult getShardIteratorResult =
146 | streamsClient.getShardIterator(getShardIteratorRequest);
147 | String currentShardIter = getShardIteratorResult.getShardIterator();
148 |
149 | // Shard iterator is not null until the Shard is sealed (marked as READ_ONLY).
150 | // To prevent running the loop until the Shard is sealed, which will be on average
151 | // 4 hours, we process only the items that were written into DynamoDB and then exit.
152 | int processedRecordCount = 0;
153 | while (currentShardIter != null && processedRecordCount < maxItemCount) {
154 | System.out.println(" Shard iterator: " + currentShardIter);
155 |
156 | // Use the shard iterator to read the stream records
157 |
158 | GetRecordsResult getRecordsResult = streamsClient.getRecords(new GetRecordsRequest()
159 | .withShardIterator(currentShardIter));
160 | List records = getRecordsResult.getRecords();
161 | for (Record record : records) {
162 | System.out.println(" " + record.getDynamodb());
163 | }
164 | processedRecordCount += records.size();
165 | currentShardIter = getRecordsResult.getNextShardIterator();
166 | }
167 | }
168 |
169 | // If LastEvaluatedShardId is set, then there is
170 | // at least one more page of shard IDs to retrieve
171 | lastEvaluatedShardId = describeStreamResult.getStreamDescription().getLastEvaluatedShardId();
172 |
173 | } while (lastEvaluatedShardId != null);
174 |
175 | // Delete the table
176 | System.out.println("Deleting the table...");
177 | dynamoDBClient.deleteTable(tableName);
178 |
179 | System.out.println("Demo complete");
180 | }
181 | }
182 |
--------------------------------------------------------------------------------
/examples/localstack-spring-boot-sample/src/test/java/com/sivalabs/demo/services/IAMTest.java:
--------------------------------------------------------------------------------
1 | package com.sivalabs.demo.services;
2 |
3 | import com.amazonaws.services.identitymanagement.AmazonIdentityManagementAsync;
4 | import com.amazonaws.services.identitymanagement.model.CreateGroupRequest;
5 | import com.amazonaws.services.identitymanagement.model.CreateGroupResult;
6 | import com.amazonaws.services.identitymanagement.model.GetGroupRequest;
7 | import com.amazonaws.services.identitymanagement.model.GetGroupResult;
8 | import lombok.extern.slf4j.Slf4j;
9 | import org.junit.jupiter.api.Test;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.boot.test.context.SpringBootTest;
12 |
13 | import static org.assertj.core.api.Assertions.assertThat;
14 |
15 | @SpringBootTest
16 | @Slf4j
17 | public class IAMTest {
18 | private static final String test_group = "test_group";
19 |
20 | @Autowired
21 | private AmazonIdentityManagementAsync iamAsync;
22 |
23 | @Test
24 | void shouldWorkWithAWSIAM() {
25 | CreateGroupRequest request = new CreateGroupRequest().withGroupName(test_group);
26 | CreateGroupResult result = iamAsync.createGroup(request);
27 | assertThat(result).isNotNull();
28 |
29 | GetGroupRequest getGroupRequest = new GetGroupRequest().withGroupName(test_group);
30 | GetGroupResult group = iamAsync.getGroup(getGroupRequest);
31 | assertThat(group).isNotNull();
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/examples/localstack-spring-boot-sample/src/test/java/com/sivalabs/demo/services/KinesisTest.java:
--------------------------------------------------------------------------------
1 | package com.sivalabs.demo.services;
2 |
3 | import com.amazonaws.services.kinesis.AmazonKinesisAsync;
4 | import com.amazonaws.services.kinesis.model.CreateStreamRequest;
5 | import com.amazonaws.services.kinesis.model.DescribeStreamRequest;
6 | import com.amazonaws.services.kinesis.model.DescribeStreamResult;
7 | import com.amazonaws.services.kinesis.model.ListStreamsRequest;
8 | import com.amazonaws.services.kinesis.model.ListStreamsResult;
9 | import lombok.extern.slf4j.Slf4j;
10 | import org.junit.jupiter.api.Test;
11 | import org.springframework.beans.factory.annotation.Autowired;
12 | import org.springframework.boot.test.context.SpringBootTest;
13 |
14 | import java.util.List;
15 | import java.util.concurrent.TimeUnit;
16 |
17 | import static org.assertj.core.api.Assertions.assertThat;
18 |
19 | @SpringBootTest
20 | @Slf4j
21 | public class KinesisTest {
22 | private static final String streamName = "test_kinesis_stream";
23 |
24 | @Autowired
25 | private AmazonKinesisAsync amazonKinesis;
26 |
27 | @Test
28 | void shouldCreateAndListKinesisStreams() throws Exception {
29 | createStream(streamName, 2);
30 | List streams = listStreams();
31 | assertThat(streams).contains(streamName);
32 | }
33 |
34 | private List listStreams() {
35 | ListStreamsRequest listStreamsRequest = new ListStreamsRequest();
36 | listStreamsRequest.setLimit(10);
37 | ListStreamsResult listStreamsResult = amazonKinesis.listStreams(listStreamsRequest);
38 | List streamNames = listStreamsResult.getStreamNames();
39 | while (listStreamsResult.isHasMoreStreams()) {
40 | if (streamNames.size() > 0) {
41 | listStreamsRequest.setExclusiveStartStreamName(streamNames.get(streamNames.size() - 1));
42 | }
43 |
44 | listStreamsResult = amazonKinesis.listStreams(listStreamsRequest);
45 | streamNames.addAll(listStreamsResult.getStreamNames());
46 | }
47 | return streamNames;
48 | }
49 |
50 | private void createStream(String streamName, Integer streamSize) throws InterruptedException {
51 | // Create a stream. The number of shards determines the provisioned throughput.
52 | CreateStreamRequest createStreamRequest = new CreateStreamRequest();
53 | createStreamRequest.setStreamName(streamName);
54 | createStreamRequest.setShardCount(streamSize);
55 | amazonKinesis.createStream(createStreamRequest);
56 | // The stream is now being created. Wait for it to become active.
57 | waitForStreamToBecomeAvailable(streamName);
58 | }
59 |
60 | private void waitForStreamToBecomeAvailable(String streamName) throws InterruptedException {
61 | System.out.printf("Waiting for %s to become ACTIVE...\n", streamName);
62 |
63 | long startTime = System.currentTimeMillis();
64 | long endTime = startTime + TimeUnit.MINUTES.toMillis(20);
65 | while (System.currentTimeMillis() < endTime) {
66 | Thread.sleep(TimeUnit.SECONDS.toMillis(10));
67 |
68 | try {
69 | DescribeStreamRequest describeStreamRequest = new DescribeStreamRequest();
70 | describeStreamRequest.setStreamName(streamName);
71 | // ask for no more than 10 shards at a time -- this is an optional parameter
72 | describeStreamRequest.setLimit(10);
73 | DescribeStreamResult describeStreamResponse = amazonKinesis.describeStream(describeStreamRequest);
74 |
75 | String streamStatus = describeStreamResponse.getStreamDescription().getStreamStatus();
76 | System.out.printf("\t- current state: %s\n", streamStatus);
77 | if ("ACTIVE".equals(streamStatus)) {
78 | return;
79 | }
80 | } catch (Exception e) {
81 | throw e;
82 | }
83 | }
84 | throw new RuntimeException(String.format("Stream %s never became active", streamName));
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/examples/localstack-spring-boot-sample/src/test/java/com/sivalabs/demo/services/LambdaTest.java:
--------------------------------------------------------------------------------
1 | package com.sivalabs.demo.services;
2 |
3 | import com.amazonaws.services.lambda.AWSLambdaAsync;
4 | import com.amazonaws.services.lambda.model.FunctionConfiguration;
5 | import com.amazonaws.services.lambda.model.ListFunctionsResult;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.junit.jupiter.api.Test;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.boot.test.context.SpringBootTest;
10 |
11 | import java.util.List;
12 |
13 | @SpringBootTest
14 | @Slf4j
15 | public class LambdaTest {
16 | @Autowired
17 | private AWSLambdaAsync awsLambda;
18 |
19 | @Test
20 | void shouldWorkWithLambda() {
21 | ListFunctionsResult functionResult = awsLambda.listFunctions();
22 | List functions = functionResult.getFunctions();
23 | for (FunctionConfiguration config : functions) {
24 | System.out.println("The function name is "+config.getFunctionName());
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/examples/localstack-spring-boot-sample/src/test/java/com/sivalabs/demo/services/S3ServiceTest.java:
--------------------------------------------------------------------------------
1 | package com.sivalabs.demo.services;
2 |
3 | import com.amazonaws.services.s3.model.S3Object;
4 | import lombok.extern.slf4j.Slf4j;
5 | import org.junit.jupiter.api.AfterEach;
6 | import org.junit.jupiter.api.BeforeEach;
7 | import org.junit.jupiter.api.Test;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.boot.test.context.SpringBootTest;
10 |
11 | import java.io.ByteArrayInputStream;
12 |
13 | import static org.assertj.core.api.Assertions.assertThat;
14 |
15 | @SpringBootTest
16 | @Slf4j
17 | class S3ServiceTest {
18 | private static final String bucketName = "test-bucket-"+System.currentTimeMillis();
19 |
20 | @Autowired
21 | private S3Service s3Service;
22 |
23 | @BeforeEach
24 | public void setUp() {
25 | s3Service.createBucket(bucketName);
26 | log.info("Created S3 Bucket: {}", bucketName);
27 | }
28 |
29 | @AfterEach
30 | public void tearDown() {
31 | s3Service.deleteBucketForce(bucketName);
32 | log.info("Deleted S3 Bucket: {}", bucketName);
33 | }
34 |
35 | @Test
36 | public void shouldStoreAndRetrieveDataFromS3Bucket() {
37 | s3Service.store(bucketName, "my-key-1", "my-value-1");
38 | S3Object s3Object = s3Service.getObject(bucketName, "my-key-1");
39 | assertThat(s3Object.getObjectContent()).hasSameContentAs(new ByteArrayInputStream("my-value-1".getBytes()));
40 | }
41 | }
--------------------------------------------------------------------------------
/examples/localstack-spring-boot-sample/src/test/java/com/sivalabs/demo/services/SNSServiceTest.java:
--------------------------------------------------------------------------------
1 | package com.sivalabs.demo.services;
2 |
3 | import com.amazonaws.services.sns.AmazonSNSAsync;
4 | import com.amazonaws.services.sns.model.CreateTopicResult;
5 | import com.amazonaws.services.sns.util.Topics;
6 | import com.amazonaws.services.sqs.AmazonSQSAsync;
7 | import com.amazonaws.services.sqs.model.Message;
8 | import lombok.extern.slf4j.Slf4j;
9 | import org.junit.jupiter.api.AfterEach;
10 | import org.junit.jupiter.api.BeforeEach;
11 | import org.junit.jupiter.api.Test;
12 | import org.springframework.beans.factory.annotation.Autowired;
13 | import org.springframework.boot.test.context.SpringBootTest;
14 |
15 | import java.util.List;
16 |
17 | import static java.util.concurrent.TimeUnit.SECONDS;
18 | import static org.assertj.core.api.Assertions.assertThat;
19 | import static org.awaitility.Awaitility.await;
20 |
21 | @SpringBootTest
22 | @Slf4j
23 | class SNSServiceTest {
24 | private static final String topicName = "test_topic_" + System.currentTimeMillis();
25 | private static final String queueName = "test_queue_" + System.currentTimeMillis();
26 |
27 | @Autowired
28 | private SNSService snsService;
29 |
30 | @Autowired
31 | private SQSService sqsService;
32 |
33 | @Autowired
34 | private AmazonSNSAsync amazonSNSAsync;
35 |
36 | @Autowired
37 | private AmazonSQSAsync amazonSQSAsync;
38 |
39 | @BeforeEach
40 | void setUp() {
41 | sqsService.createQueue(queueName);
42 | log.info("Created SQS Queue: {}", queueName);
43 | snsService.createTopic(topicName);
44 | log.info("Created SNS topic: {}", topicName);
45 | }
46 |
47 | @AfterEach
48 | void tearDown() {
49 | snsService.deleteTopic(topicName);
50 | log.info("Deleted SNS topic: {}", topicName);
51 | sqsService.deleteQueue(queueName);
52 | log.info("Deleted SQS Queue: {}", queueName);
53 | }
54 |
55 | @Test
56 | public void sendAndReceiveSNsMessage() {
57 | CreateTopicResult topic = snsService.createTopic(topicName);
58 | String sqsQueueUrl = sqsService.getQueueUrl(queueName);
59 |
60 | Topics.subscribeQueue(amazonSNSAsync, amazonSQSAsync, topic.getTopicArn(), sqsQueueUrl);
61 |
62 | snsService.sendMessage(topicName, "Test Message");
63 |
64 | await().atMost(15, SECONDS).untilAsserted(() -> {
65 | List messages = sqsService.readMessages(queueName);
66 | //TODO; FIX IT - it should read 1 message
67 | assertThat(messages.size()).isEqualTo(0);
68 | });
69 | }
70 | }
--------------------------------------------------------------------------------
/examples/localstack-spring-boot-sample/src/test/java/com/sivalabs/demo/services/SQSServiceTest.java:
--------------------------------------------------------------------------------
1 | package com.sivalabs.demo.services;
2 |
3 | import com.amazonaws.services.sqs.model.ListQueuesResult;
4 | import com.amazonaws.services.sqs.model.Message;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.junit.jupiter.api.AfterEach;
7 | import org.junit.jupiter.api.BeforeEach;
8 | import org.junit.jupiter.api.Test;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.boot.test.context.SpringBootTest;
11 |
12 | import java.util.List;
13 |
14 | import static java.util.concurrent.TimeUnit.SECONDS;
15 | import static org.assertj.core.api.Assertions.assertThat;
16 | import static org.awaitility.Awaitility.await;
17 |
18 | @SpringBootTest
19 | @Slf4j
20 | class SQSServiceTest {
21 | private static final String queueName = "test_queue_" + System.currentTimeMillis();
22 |
23 | @Autowired
24 | private SQSService sqsService;
25 |
26 | @BeforeEach
27 | void setUp() {
28 | sqsService.createQueue(queueName);
29 | log.info("Created SQS Queue: {}", queueName);
30 | }
31 |
32 | @AfterEach
33 | void tearDown() {
34 | sqsService.deleteQueue(queueName);
35 | log.info("Deleted SQS Queue: {}", queueName);
36 | }
37 |
38 | @Test
39 | void shouldGetAllQueues() {
40 | ListQueuesResult listQueuesResult = sqsService.listQueues();
41 |
42 | assertThat(listQueuesResult.getQueueUrls()).isNotEmpty();
43 |
44 | for (String queueUrl : listQueuesResult.getQueueUrls()) {
45 | log.info("QueueUrl: {}", queueUrl);
46 | }
47 | }
48 |
49 | @Test
50 | public void sendAndReceiveSqsMessage() {
51 | sqsService.sendMessage(queueName, "Test Message");
52 |
53 | await().atMost(15, SECONDS).untilAsserted(() -> {
54 | List messages = sqsService.readMessages(queueName);
55 | assertThat(messages.size()).isEqualTo(1);
56 | });
57 | }
58 | }
--------------------------------------------------------------------------------
/examples/localstack-spring-boot-sample/src/test/java/com/sivalabs/demo/services/SecretsManagerTest.java:
--------------------------------------------------------------------------------
1 | package com.sivalabs.demo.services;
2 |
3 | import com.amazonaws.services.secretsmanager.AWSSecretsManagerAsync;
4 | import com.amazonaws.services.secretsmanager.model.CreateSecretRequest;
5 | import com.amazonaws.services.secretsmanager.model.CreateSecretResult;
6 | import com.amazonaws.services.secretsmanager.model.GetSecretValueRequest;
7 | import com.amazonaws.services.secretsmanager.model.GetSecretValueResult;
8 | import lombok.extern.slf4j.Slf4j;
9 | import org.junit.jupiter.api.Test;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.boot.test.context.SpringBootTest;
12 |
13 | import static org.assertj.core.api.Assertions.assertThat;
14 |
15 | @SpringBootTest
16 | @Slf4j
17 | public class SecretsManagerTest {
18 |
19 | @Autowired
20 | private AWSSecretsManagerAsync secretsManagerAsync;
21 |
22 | @Test
23 | void shouldWorkWithSecretsManager() {
24 | CreateSecretRequest createSecretRequest = new CreateSecretRequest()
25 | .withName("db_password").withSecretString("secret");
26 | CreateSecretResult secret = secretsManagerAsync.createSecret(createSecretRequest);
27 |
28 | GetSecretValueRequest getSecretRequest = new GetSecretValueRequest().withSecretId(secret.getARN());
29 | GetSecretValueResult secretValue = secretsManagerAsync.getSecretValue(getSecretRequest);
30 | assertThat(secretValue.getName()).isEqualTo("db_password");
31 | assertThat(secretValue.getSecretString()).isEqualTo("secret");
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/maven-settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ossrh
6 | ${env.OSSRH_JIRA_USERNAME}
7 | ${env.OSSRH_JIRA_PASSWORD}
8 |
9 |
10 |
11 |
12 |
13 | ossrh
14 |
15 | true
16 |
17 |
18 | gpg
19 | ${env.GPG_KEY_NAME}
20 | ${env.GPG_PASSPHRASE}
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Maven2 Start Up Batch script
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # M2_HOME - location of maven2's installed home dir
31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
32 | # e.g. to debug Maven itself, use
33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
35 | # ----------------------------------------------------------------------------
36 |
37 | if [ -z "$MAVEN_SKIP_RC" ] ; then
38 |
39 | if [ -f /etc/mavenrc ] ; then
40 | . /etc/mavenrc
41 | fi
42 |
43 | if [ -f "$HOME/.mavenrc" ] ; then
44 | . "$HOME/.mavenrc"
45 | fi
46 |
47 | fi
48 |
49 | # OS specific support. $var _must_ be set to either true or false.
50 | cygwin=false;
51 | darwin=false;
52 | mingw=false
53 | case "`uname`" in
54 | CYGWIN*) cygwin=true ;;
55 | MINGW*) mingw=true;;
56 | Darwin*) darwin=true
57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
59 | if [ -z "$JAVA_HOME" ]; then
60 | if [ -x "/usr/libexec/java_home" ]; then
61 | export JAVA_HOME="`/usr/libexec/java_home`"
62 | else
63 | export JAVA_HOME="/Library/Java/Home"
64 | fi
65 | fi
66 | ;;
67 | esac
68 |
69 | if [ -z "$JAVA_HOME" ] ; then
70 | if [ -r /etc/gentoo-release ] ; then
71 | JAVA_HOME=`java-config --jre-home`
72 | fi
73 | fi
74 |
75 | if [ -z "$M2_HOME" ] ; then
76 | ## resolve links - $0 may be a link to maven's home
77 | PRG="$0"
78 |
79 | # need this for relative symlinks
80 | while [ -h "$PRG" ] ; do
81 | ls=`ls -ld "$PRG"`
82 | link=`expr "$ls" : '.*-> \(.*\)$'`
83 | if expr "$link" : '/.*' > /dev/null; then
84 | PRG="$link"
85 | else
86 | PRG="`dirname "$PRG"`/$link"
87 | fi
88 | done
89 |
90 | saveddir=`pwd`
91 |
92 | M2_HOME=`dirname "$PRG"`/..
93 |
94 | # make it fully qualified
95 | M2_HOME=`cd "$M2_HOME" && pwd`
96 |
97 | cd "$saveddir"
98 | # echo Using m2 at $M2_HOME
99 | fi
100 |
101 | # For Cygwin, ensure paths are in UNIX format before anything is touched
102 | if $cygwin ; then
103 | [ -n "$M2_HOME" ] &&
104 | M2_HOME=`cygpath --unix "$M2_HOME"`
105 | [ -n "$JAVA_HOME" ] &&
106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
107 | [ -n "$CLASSPATH" ] &&
108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
109 | fi
110 |
111 | # For Migwn, ensure paths are in UNIX format before anything is touched
112 | if $mingw ; then
113 | [ -n "$M2_HOME" ] &&
114 | M2_HOME="`(cd "$M2_HOME"; pwd)`"
115 | [ -n "$JAVA_HOME" ] &&
116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
117 | # TODO classpath?
118 | fi
119 |
120 | if [ -z "$JAVA_HOME" ]; then
121 | javaExecutable="`which javac`"
122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
123 | # readlink(1) is not available as standard on Solaris 10.
124 | readLink=`which readlink`
125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
126 | if $darwin ; then
127 | javaHome="`dirname \"$javaExecutable\"`"
128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
129 | else
130 | javaExecutable="`readlink -f \"$javaExecutable\"`"
131 | fi
132 | javaHome="`dirname \"$javaExecutable\"`"
133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
134 | JAVA_HOME="$javaHome"
135 | export JAVA_HOME
136 | fi
137 | fi
138 | fi
139 |
140 | if [ -z "$JAVACMD" ] ; then
141 | if [ -n "$JAVA_HOME" ] ; then
142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
143 | # IBM's JDK on AIX uses strange locations for the executables
144 | JAVACMD="$JAVA_HOME/jre/sh/java"
145 | else
146 | JAVACMD="$JAVA_HOME/bin/java"
147 | fi
148 | else
149 | JAVACMD="`which java`"
150 | fi
151 | fi
152 |
153 | if [ ! -x "$JAVACMD" ] ; then
154 | echo "Error: JAVA_HOME is not defined correctly." >&2
155 | echo " We cannot execute $JAVACMD" >&2
156 | exit 1
157 | fi
158 |
159 | if [ -z "$JAVA_HOME" ] ; then
160 | echo "Warning: JAVA_HOME environment variable is not set."
161 | fi
162 |
163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
164 |
165 | # traverses directory structure from process work directory to filesystem root
166 | # first directory with .mvn subdirectory is considered project base directory
167 | find_maven_basedir() {
168 |
169 | if [ -z "$1" ]
170 | then
171 | echo "Path not specified to find_maven_basedir"
172 | return 1
173 | fi
174 |
175 | basedir="$1"
176 | wdir="$1"
177 | while [ "$wdir" != '/' ] ; do
178 | if [ -d "$wdir"/.mvn ] ; then
179 | basedir=$wdir
180 | break
181 | fi
182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc)
183 | if [ -d "${wdir}" ]; then
184 | wdir=`cd "$wdir/.."; pwd`
185 | fi
186 | # end of workaround
187 | done
188 | echo "${basedir}"
189 | }
190 |
191 | # concatenates all lines of a file
192 | concat_lines() {
193 | if [ -f "$1" ]; then
194 | echo "$(tr -s '\n' ' ' < "$1")"
195 | fi
196 | }
197 |
198 | BASE_DIR=`find_maven_basedir "$(pwd)"`
199 | if [ -z "$BASE_DIR" ]; then
200 | exit 1;
201 | fi
202 |
203 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
204 | echo $MAVEN_PROJECTBASEDIR
205 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
206 |
207 | # For Cygwin, switch paths to Windows format before running java
208 | if $cygwin; then
209 | [ -n "$M2_HOME" ] &&
210 | M2_HOME=`cygpath --path --windows "$M2_HOME"`
211 | [ -n "$JAVA_HOME" ] &&
212 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
213 | [ -n "$CLASSPATH" ] &&
214 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
215 | [ -n "$MAVEN_PROJECTBASEDIR" ] &&
216 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
217 | fi
218 |
219 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
220 |
221 | exec "$JAVACMD" \
222 | $MAVEN_OPTS \
223 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
224 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
225 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
226 |
--------------------------------------------------------------------------------
/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM http://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Maven2 Start Up Batch script
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM M2_HOME - location of maven2's installed home dir
28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | @REM e.g. to debug Maven itself, use
32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | @REM ----------------------------------------------------------------------------
35 |
36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37 | @echo off
38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
40 |
41 | @REM set %HOME% to equivalent of $HOME
42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
43 |
44 | @REM Execute a user defined script before this one
45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
49 | :skipRcPre
50 |
51 | @setlocal
52 |
53 | set ERROR_CODE=0
54 |
55 | @REM To isolate internal variables from possible post scripts, we use another setlocal
56 | @setlocal
57 |
58 | @REM ==== START VALIDATION ====
59 | if not "%JAVA_HOME%" == "" goto OkJHome
60 |
61 | echo.
62 | echo Error: JAVA_HOME not found in your environment. >&2
63 | echo Please set the JAVA_HOME variable in your environment to match the >&2
64 | echo location of your Java installation. >&2
65 | echo.
66 | goto error
67 |
68 | :OkJHome
69 | if exist "%JAVA_HOME%\bin\java.exe" goto init
70 |
71 | echo.
72 | echo Error: JAVA_HOME is set to an invalid directory. >&2
73 | echo JAVA_HOME = "%JAVA_HOME%" >&2
74 | echo Please set the JAVA_HOME variable in your environment to match the >&2
75 | echo location of your Java installation. >&2
76 | echo.
77 | goto error
78 |
79 | @REM ==== END VALIDATION ====
80 |
81 | :init
82 |
83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
84 | @REM Fallback to current working directory if not found.
85 |
86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
88 |
89 | set EXEC_DIR=%CD%
90 | set WDIR=%EXEC_DIR%
91 | :findBaseDir
92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
93 | cd ..
94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
95 | set WDIR=%CD%
96 | goto findBaseDir
97 |
98 | :baseDirFound
99 | set MAVEN_PROJECTBASEDIR=%WDIR%
100 | cd "%EXEC_DIR%"
101 | goto endDetectBaseDir
102 |
103 | :baseDirNotFound
104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
105 | cd "%EXEC_DIR%"
106 |
107 | :endDetectBaseDir
108 |
109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
110 |
111 | @setlocal EnableExtensions EnableDelayedExpansion
112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
114 |
115 | :endReadAdditionalConfig
116 |
117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
118 |
119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
121 |
122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
123 | if ERRORLEVEL 1 goto error
124 | goto end
125 |
126 | :error
127 | set ERROR_CODE=1
128 |
129 | :end
130 | @endlocal & set ERROR_CODE=%ERROR_CODE%
131 |
132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
136 | :skipRcPost
137 |
138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause
140 |
141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
142 |
143 | exit /B %ERROR_CODE%
144 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 | io.github.sivalabs
5 | localstack-spring-boot-starter
6 | jar
7 | 0.0.4-SNAPSHOT
8 | localstack-spring-boot-starter
9 | SpringBoot starter for LocalStack
10 | https://github.com/sivalabs/localstack-spring-boot-starter
11 |
12 |
13 |
14 | MIT License
15 | http://www.opensource.org/licenses/mit-license.php
16 |
17 |
18 |
19 |
20 |
21 | author
22 | K Siva Prasad Reddy
23 | sivaprasadreddy.k@gmail.com
24 |
25 |
26 |
27 |
28 | scm:git:https://github.com/sivalabs/localstack-spring-boot-starter.git
29 | scm:git:https://github.com/sivalabs/localstack-spring-boot-starter.git
30 | https://github.com/sivalabs/localstack-spring-boot-starter
31 | HEAD
32 |
33 |
34 |
35 | ossrh
36 | https://oss.sonatype.org/content/repositories/snapshots
37 |
38 |
39 | ossrh
40 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
41 |
42 |
43 |
44 |
45 | UTF-8
46 | UTF-8
47 | 1.8
48 | 3.8.1
49 | 3.2.0
50 | 3.2.0
51 | 2.22.2
52 | 2.22.2
53 | 1.6
54 | 2.5.3
55 | 2.7.10
56 | 1.11.852
57 | 1.17.6
58 |
59 |
60 |
61 |
62 |
63 | org.springframework.boot
64 | spring-boot-dependencies
65 | ${spring-boot.version}
66 | pom
67 | import
68 |
69 |
70 | org.testcontainers
71 | testcontainers-bom
72 | ${testcontainers.version}
73 | pom
74 | import
75 |
76 |
77 | com.amazonaws
78 | aws-java-sdk-bom
79 | ${aws-java-sdk.version}
80 | pom
81 | import
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 | org.apache.maven.plugins
90 | maven-compiler-plugin
91 | ${maven-compiler-plugin.version}
92 |
93 | ${java.version}
94 | ${java.version}
95 |
96 |
97 |
98 | org.apache.maven.plugins
99 | maven-surefire-plugin
100 | ${maven-surefire-plugin.version}
101 |
102 |
103 | org.apache.maven.plugins
104 | maven-failsafe-plugin
105 | ${maven-failsafe-plugin.version}
106 |
107 |
108 | org.apache.maven.plugins
109 | maven-source-plugin
110 | ${maven-source-plugin.version}
111 |
112 |
113 | attach-sources
114 |
115 | jar-no-fork
116 |
117 |
118 |
119 |
120 |
121 | org.apache.maven.plugins
122 | maven-javadoc-plugin
123 | ${maven-javadoc-plugin.version}
124 | true
125 |
126 | 8
127 |
128 |
129 |
130 | attach-javadocs
131 |
132 | jar
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 | release
143 |
144 |
145 |
146 | org.apache.maven.plugins
147 | maven-gpg-plugin
148 | ${maven-gpg-plugin.version}
149 |
150 |
151 | sign-artifacts
152 | verify
153 |
154 | sign
155 |
156 |
157 |
158 |
159 |
160 | org.sonatype.plugins
161 | nexus-staging-maven-plugin
162 | 1.6.7
163 | true
164 |
165 | ossrh
166 | https://oss.sonatype.org/
167 | true
168 |
169 |
170 |
171 | org.apache.maven.plugins
172 | maven-release-plugin
173 | ${maven-release-plugin.version}
174 |
175 | true
176 | false
177 | release
178 | deploy
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 | org.projectlombok
189 | lombok
190 | true
191 |
192 |
193 | org.springframework.boot
194 | spring-boot-autoconfigure
195 |
196 |
197 | org.springframework.boot
198 | spring-boot-configuration-processor
199 | true
200 |
201 |
202 | org.testcontainers
203 | localstack
204 |
205 |
206 | com.amazonaws
207 | aws-java-sdk
208 | ${aws-java-sdk.version}
209 | provided
210 |
211 |
212 |
213 | org.springframework.boot
214 | spring-boot-starter-test
215 | test
216 |
217 |
218 | org.junit.vintage
219 | junit-vintage-engine
220 |
221 |
222 |
223 |
224 | org.testcontainers
225 | junit-jupiter
226 | test
227 |
228 |
229 |
230 |
231 |
--------------------------------------------------------------------------------
/src/main/java/io/github/sivalabs/localstack/EnableLocalStack.java:
--------------------------------------------------------------------------------
1 | package io.github.sivalabs.localstack;
2 |
3 | import io.github.sivalabs.localstack.autoconfigure.LocalStackAutoConfiguration;
4 | import org.springframework.context.annotation.Import;
5 |
6 | import java.lang.annotation.Documented;
7 | import java.lang.annotation.ElementType;
8 | import java.lang.annotation.Retention;
9 | import java.lang.annotation.RetentionPolicy;
10 | import java.lang.annotation.Target;
11 |
12 | @Target(ElementType.TYPE)
13 | @Retention(RetentionPolicy.RUNTIME)
14 | @Documented
15 | @Import(LocalStackAutoConfiguration.class)
16 | public @interface EnableLocalStack {
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/io/github/sivalabs/localstack/LocalStackProperties.java:
--------------------------------------------------------------------------------
1 | package io.github.sivalabs.localstack;
2 |
3 | import lombok.Getter;
4 | import lombok.Setter;
5 | import org.springframework.boot.context.properties.ConfigurationProperties;
6 | import org.testcontainers.containers.localstack.LocalStackContainer;
7 |
8 | import java.util.Collection;
9 |
10 | @ConfigurationProperties(prefix = LocalStackProperties.LOCALSTACK_PREFIX)
11 | @Setter
12 | @Getter
13 | public class LocalStackProperties {
14 | public static final String LOCALSTACK_PREFIX = "localstack";
15 | public static final String BEAN_NAME_LOCALSTACK = "localStackBean";
16 | public static final boolean ENABLE_SERVICE_BY_DEFAULT = true;
17 |
18 | private boolean enabled = true;
19 | private int edgePort = 4566;
20 | private String defaultRegion = "us-east-1";
21 | private String hostname = "localhost";
22 | private String hostnameExternal = "localhost";
23 | private String dockerImage = "localstack/localstack:2.0.0";
24 | private boolean useSsl = false;
25 | private Collection services;
26 |
27 | private S3Properties s3 = new S3Properties();
28 | private SQSProperties sqs = new SQSProperties();
29 | private SNSProperties sns = new SNSProperties();
30 | private DynamoDBProperties dynamodb = new DynamoDBProperties();
31 | private DynamoDBStreamsProperties dynamodbstreams = new DynamoDBStreamsProperties();
32 | private KinesisProperties kinesis = new KinesisProperties();
33 | private LambdaProperties lambda = new LambdaProperties();
34 | private IamProperties iam = new IamProperties();
35 | private SecretsManagerProperties secretsmanager = new SecretsManagerProperties();
36 | private CloudWatchProperties cloudwatch = new CloudWatchProperties();
37 |
38 | @Setter
39 | @Getter
40 | public static class S3Properties extends CommonProperties {
41 | }
42 |
43 | @Setter
44 | @Getter
45 | public static class SQSProperties extends CommonProperties {
46 | }
47 |
48 | @Setter
49 | @Getter
50 | public static class SNSProperties extends CommonProperties {
51 | }
52 |
53 | @Setter
54 | @Getter
55 | public static class DynamoDBProperties extends CommonProperties {
56 | }
57 |
58 | @Setter
59 | @Getter
60 | public static class DynamoDBStreamsProperties extends CommonProperties {
61 | }
62 |
63 | @Setter
64 | @Getter
65 | public static class KinesisProperties extends CommonProperties {
66 | }
67 |
68 | @Setter
69 | @Getter
70 | public static class LambdaProperties extends CommonProperties {
71 | }
72 |
73 | @Setter
74 | @Getter
75 | public static class IamProperties extends CommonProperties {
76 | }
77 |
78 | @Setter
79 | @Getter
80 | public static class SecretsManagerProperties extends CommonProperties {
81 | }
82 |
83 | @Setter
84 | @Getter
85 | public static class CloudWatchProperties extends CommonProperties {
86 | }
87 |
88 | @Setter
89 | @Getter
90 | private static class CommonProperties {
91 | private boolean enabled = ENABLE_SERVICE_BY_DEFAULT;
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/main/java/io/github/sivalabs/localstack/autoconfigure/LocalStackAutoConfiguration.java:
--------------------------------------------------------------------------------
1 | package io.github.sivalabs.localstack.autoconfigure;
2 |
3 | import io.github.sivalabs.localstack.autoconfigure.configurator.AWSLambdaConfiguration;
4 | import io.github.sivalabs.localstack.autoconfigure.configurator.AWSSecretsManagerConfiguration;
5 | import io.github.sivalabs.localstack.autoconfigure.configurator.AmazonCloudWatchConfiguration;
6 | import io.github.sivalabs.localstack.autoconfigure.configurator.AmazonDynamoDBConfiguration;
7 | import io.github.sivalabs.localstack.autoconfigure.configurator.AmazonDynamoDBStreamsConfiguration;
8 | import io.github.sivalabs.localstack.autoconfigure.configurator.AmazonIAMConfiguration;
9 | import io.github.sivalabs.localstack.autoconfigure.configurator.AmazonKinesisConfiguration;
10 | import io.github.sivalabs.localstack.autoconfigure.configurator.AmazonS3Configuration;
11 | import io.github.sivalabs.localstack.autoconfigure.configurator.AmazonSNSConfiguration;
12 | import io.github.sivalabs.localstack.autoconfigure.configurator.AmazonSQSConfiguration;
13 | import io.github.sivalabs.localstack.autoconfigure.configurator.LocalStackContainerConfiguration;
14 | import org.springframework.boot.autoconfigure.AutoConfigureOrder;
15 | import org.springframework.context.annotation.Configuration;
16 | import org.springframework.context.annotation.Import;
17 | import org.springframework.core.Ordered;
18 |
19 | @Configuration
20 | @AutoConfigureOrder(value = Ordered.HIGHEST_PRECEDENCE)
21 | @Import({
22 | LocalStackContainerConfiguration.class,
23 | AmazonS3Configuration.class,
24 | AmazonSQSConfiguration.class,
25 | AmazonSNSConfiguration.class,
26 | AmazonDynamoDBConfiguration.class,
27 | AmazonDynamoDBStreamsConfiguration.class,
28 | AmazonCloudWatchConfiguration.class,
29 | AWSLambdaConfiguration.class,
30 | AWSSecretsManagerConfiguration.class,
31 | AmazonKinesisConfiguration.class,
32 | AmazonIAMConfiguration.class
33 | })
34 | public class LocalStackAutoConfiguration {
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/io/github/sivalabs/localstack/autoconfigure/configurator/AWSLambdaConfiguration.java:
--------------------------------------------------------------------------------
1 | package io.github.sivalabs.localstack.autoconfigure.configurator;
2 |
3 | import com.amazonaws.services.lambda.AWSLambdaAsync;
4 | import com.amazonaws.services.lambda.AWSLambdaAsyncClientBuilder;
5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
6 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Primary;
9 | import org.testcontainers.containers.localstack.LocalStackContainer;
10 |
11 | import static io.github.sivalabs.localstack.LocalStackProperties.ENABLE_SERVICE_BY_DEFAULT;
12 | import static org.testcontainers.containers.localstack.LocalStackContainer.Service.LAMBDA;
13 |
14 | @ConditionalOnLocalStackService
15 | @ConditionalOnProperty(name = "localstack.lambda.enabled", havingValue = "true", matchIfMissing = ENABLE_SERVICE_BY_DEFAULT)
16 | @ConditionalOnClass(AWSLambdaAsync.class)
17 | public class AWSLambdaConfiguration extends AbstractAmazonClient {
18 | public AWSLambdaConfiguration(LocalStackContainer localStackContainer) {
19 | super(localStackContainer);
20 | }
21 |
22 | @Bean
23 | @Primary
24 | public AWSLambdaAsync awsLambdaAsyncLocalStack() {
25 | return AWSLambdaAsyncClientBuilder.standard()
26 | .withEndpointConfiguration(getEndpointConfiguration(LAMBDA))
27 | .withCredentials(getCredentialsProvider())
28 | .build();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/io/github/sivalabs/localstack/autoconfigure/configurator/AWSSecretsManagerConfiguration.java:
--------------------------------------------------------------------------------
1 | package io.github.sivalabs.localstack.autoconfigure.configurator;
2 |
3 | import com.amazonaws.services.secretsmanager.AWSSecretsManagerAsync;
4 | import com.amazonaws.services.secretsmanager.AWSSecretsManagerAsyncClientBuilder;
5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
6 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Primary;
9 | import org.testcontainers.containers.localstack.LocalStackContainer;
10 |
11 | import static io.github.sivalabs.localstack.LocalStackProperties.ENABLE_SERVICE_BY_DEFAULT;
12 | import static org.testcontainers.containers.localstack.LocalStackContainer.Service.SECRETSMANAGER;
13 |
14 | @ConditionalOnLocalStackService
15 | @ConditionalOnProperty(name = "localstack.secretsmanager.enabled", havingValue = "true", matchIfMissing = ENABLE_SERVICE_BY_DEFAULT)
16 | @ConditionalOnClass(AWSSecretsManagerAsync.class)
17 | public class AWSSecretsManagerConfiguration extends AbstractAmazonClient {
18 | public AWSSecretsManagerConfiguration(LocalStackContainer localStackContainer) {
19 | super(localStackContainer);
20 | }
21 |
22 | @Bean
23 | @Primary
24 | public AWSSecretsManagerAsync awsSecretsManagerAsyncLocalStack() {
25 | return AWSSecretsManagerAsyncClientBuilder.standard()
26 | .withEndpointConfiguration(getEndpointConfiguration(SECRETSMANAGER))
27 | .withCredentials(getCredentialsProvider())
28 | .build();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/io/github/sivalabs/localstack/autoconfigure/configurator/AbstractAmazonClient.java:
--------------------------------------------------------------------------------
1 | package io.github.sivalabs.localstack.autoconfigure.configurator;
2 |
3 | import com.amazonaws.auth.AWSCredentialsProvider;
4 | import com.amazonaws.auth.AWSStaticCredentialsProvider;
5 | import com.amazonaws.auth.BasicAWSCredentials;
6 | import com.amazonaws.client.builder.AwsClientBuilder.EndpointConfiguration;
7 | import lombok.RequiredArgsConstructor;
8 | import org.testcontainers.containers.localstack.LocalStackContainer;
9 | import org.testcontainers.containers.localstack.LocalStackContainer.Service;
10 |
11 | @RequiredArgsConstructor
12 | public abstract class AbstractAmazonClient {
13 | protected final LocalStackContainer localStackContainer;
14 |
15 | protected EndpointConfiguration getEndpointConfiguration(Service service) {
16 | return localStackContainer.getEndpointConfiguration(service);
17 | }
18 |
19 | protected AWSCredentialsProvider getCredentialsProvider() {
20 | return new AWSStaticCredentialsProvider(
21 | new BasicAWSCredentials(localStackContainer.getAccessKey(), localStackContainer.getSecretKey())
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/io/github/sivalabs/localstack/autoconfigure/configurator/AmazonCloudWatchConfiguration.java:
--------------------------------------------------------------------------------
1 | package io.github.sivalabs.localstack.autoconfigure.configurator;
2 |
3 | import com.amazonaws.services.cloudwatch.AmazonCloudWatchAsync;
4 | import com.amazonaws.services.cloudwatch.AmazonCloudWatchAsyncClientBuilder;
5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
6 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Primary;
9 | import org.testcontainers.containers.localstack.LocalStackContainer;
10 |
11 | import static io.github.sivalabs.localstack.LocalStackProperties.ENABLE_SERVICE_BY_DEFAULT;
12 | import static org.testcontainers.containers.localstack.LocalStackContainer.Service.CLOUDWATCH;
13 |
14 | @ConditionalOnLocalStackService
15 | @ConditionalOnProperty(name = "localstack.cloudwatch.enabled", havingValue = "true", matchIfMissing = ENABLE_SERVICE_BY_DEFAULT)
16 | @ConditionalOnClass(AmazonCloudWatchAsync.class)
17 | public class AmazonCloudWatchConfiguration extends AbstractAmazonClient {
18 | public AmazonCloudWatchConfiguration(LocalStackContainer localStackContainer) {
19 | super(localStackContainer);
20 | }
21 |
22 | @Bean
23 | @Primary
24 | public AmazonCloudWatchAsync amazonCloudWatchAsyncLocalStack() {
25 | return AmazonCloudWatchAsyncClientBuilder.standard()
26 | .withEndpointConfiguration(getEndpointConfiguration(CLOUDWATCH))
27 | .withCredentials(getCredentialsProvider())
28 | .build();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/io/github/sivalabs/localstack/autoconfigure/configurator/AmazonDynamoDBConfiguration.java:
--------------------------------------------------------------------------------
1 | package io.github.sivalabs.localstack.autoconfigure.configurator;
2 |
3 | import com.amazonaws.services.dynamodbv2.AmazonDynamoDBAsync;
4 | import com.amazonaws.services.dynamodbv2.AmazonDynamoDBAsyncClientBuilder;
5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
6 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Primary;
9 | import org.testcontainers.containers.localstack.LocalStackContainer;
10 |
11 | import static io.github.sivalabs.localstack.LocalStackProperties.ENABLE_SERVICE_BY_DEFAULT;
12 | import static org.testcontainers.containers.localstack.LocalStackContainer.Service.DYNAMODB;
13 |
14 | @ConditionalOnLocalStackService
15 | @ConditionalOnProperty(name = "localstack.dynamodb.enabled", havingValue = "true", matchIfMissing = ENABLE_SERVICE_BY_DEFAULT)
16 | @ConditionalOnClass(AmazonDynamoDBAsync.class)
17 | public class AmazonDynamoDBConfiguration extends AbstractAmazonClient {
18 |
19 | public AmazonDynamoDBConfiguration(LocalStackContainer localStackContainer) {
20 | super(localStackContainer);
21 | }
22 |
23 | @Bean
24 | @Primary
25 | public AmazonDynamoDBAsync amazonDynamoDBAsyncLocalStack() {
26 | return AmazonDynamoDBAsyncClientBuilder.standard()
27 | .withEndpointConfiguration(getEndpointConfiguration(DYNAMODB))
28 | .withCredentials(getCredentialsProvider())
29 | .build();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/io/github/sivalabs/localstack/autoconfigure/configurator/AmazonDynamoDBStreamsConfiguration.java:
--------------------------------------------------------------------------------
1 | package io.github.sivalabs.localstack.autoconfigure.configurator;
2 |
3 | import com.amazonaws.services.dynamodbv2.AmazonDynamoDBStreamsAsync;
4 | import com.amazonaws.services.dynamodbv2.AmazonDynamoDBStreamsAsyncClientBuilder;
5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
6 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Primary;
9 | import org.testcontainers.containers.localstack.LocalStackContainer;
10 |
11 | import static io.github.sivalabs.localstack.LocalStackProperties.ENABLE_SERVICE_BY_DEFAULT;
12 | import static org.testcontainers.containers.localstack.LocalStackContainer.Service.DYNAMODB_STREAMS;
13 |
14 | @ConditionalOnLocalStackService
15 | @ConditionalOnProperty(name = "localstack.dynamodbstreams.enabled", havingValue = "true", matchIfMissing = ENABLE_SERVICE_BY_DEFAULT)
16 | @ConditionalOnClass(AmazonDynamoDBStreamsAsync.class)
17 | public class AmazonDynamoDBStreamsConfiguration extends AbstractAmazonClient {
18 |
19 | public AmazonDynamoDBStreamsConfiguration(LocalStackContainer localStackContainer) {
20 | super(localStackContainer);
21 | }
22 |
23 | @Bean
24 | @Primary
25 | public AmazonDynamoDBStreamsAsync amazonDynamoDBStreamsAsyncLocalStack() {
26 | return AmazonDynamoDBStreamsAsyncClientBuilder.standard()
27 | .withEndpointConfiguration(getEndpointConfiguration(DYNAMODB_STREAMS))
28 | .withCredentials(getCredentialsProvider())
29 | .build();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/io/github/sivalabs/localstack/autoconfigure/configurator/AmazonIAMConfiguration.java:
--------------------------------------------------------------------------------
1 | package io.github.sivalabs.localstack.autoconfigure.configurator;
2 |
3 | import com.amazonaws.services.identitymanagement.AmazonIdentityManagementAsync;
4 | import com.amazonaws.services.identitymanagement.AmazonIdentityManagementAsyncClientBuilder;
5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
6 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Primary;
9 | import org.testcontainers.containers.localstack.LocalStackContainer;
10 |
11 | import static io.github.sivalabs.localstack.LocalStackProperties.ENABLE_SERVICE_BY_DEFAULT;
12 | import static org.testcontainers.containers.localstack.LocalStackContainer.Service.IAM;
13 |
14 | @ConditionalOnLocalStackService
15 | @ConditionalOnProperty(name = "localstack.iam.enabled", havingValue = "true", matchIfMissing = ENABLE_SERVICE_BY_DEFAULT)
16 | @ConditionalOnClass(AmazonIdentityManagementAsync.class)
17 | public class AmazonIAMConfiguration extends AbstractAmazonClient {
18 |
19 | public AmazonIAMConfiguration(LocalStackContainer localStackContainer) {
20 | super(localStackContainer);
21 | }
22 |
23 | @Bean
24 | @Primary
25 | public AmazonIdentityManagementAsync amazonIdentityManagementAsyncLocalStack() {
26 | return AmazonIdentityManagementAsyncClientBuilder.standard()
27 | .withEndpointConfiguration(getEndpointConfiguration(IAM))
28 | .withCredentials(getCredentialsProvider())
29 | .build();
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/io/github/sivalabs/localstack/autoconfigure/configurator/AmazonKinesisConfiguration.java:
--------------------------------------------------------------------------------
1 | package io.github.sivalabs.localstack.autoconfigure.configurator;
2 |
3 | import com.amazonaws.services.kinesis.AmazonKinesisAsync;
4 | import com.amazonaws.services.kinesis.AmazonKinesisAsyncClientBuilder;
5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
6 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Primary;
9 | import org.testcontainers.containers.localstack.LocalStackContainer;
10 |
11 | import static io.github.sivalabs.localstack.LocalStackProperties.ENABLE_SERVICE_BY_DEFAULT;
12 | import static org.testcontainers.containers.localstack.LocalStackContainer.Service.KINESIS;
13 |
14 | @ConditionalOnLocalStackService
15 | @ConditionalOnProperty(name = "localstack.kinesis.enabled", havingValue = "true", matchIfMissing = ENABLE_SERVICE_BY_DEFAULT)
16 | @ConditionalOnClass(AmazonKinesisAsync.class)
17 | public class AmazonKinesisConfiguration extends AbstractAmazonClient {
18 |
19 | public AmazonKinesisConfiguration(LocalStackContainer localStackContainer) {
20 | super(localStackContainer);
21 | }
22 |
23 | @Bean
24 | @Primary
25 | public AmazonKinesisAsync amazonKinesisAsyncLocalStack() {
26 | return AmazonKinesisAsyncClientBuilder.standard()
27 | .withEndpointConfiguration(getEndpointConfiguration(KINESIS))
28 | .withCredentials(getCredentialsProvider())
29 | .build();
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/io/github/sivalabs/localstack/autoconfigure/configurator/AmazonS3Configuration.java:
--------------------------------------------------------------------------------
1 | package io.github.sivalabs.localstack.autoconfigure.configurator;
2 |
3 | import com.amazonaws.services.s3.AmazonS3;
4 | import com.amazonaws.services.s3.AmazonS3ClientBuilder;
5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
6 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Primary;
9 | import org.testcontainers.containers.localstack.LocalStackContainer;
10 |
11 | import static io.github.sivalabs.localstack.LocalStackProperties.ENABLE_SERVICE_BY_DEFAULT;
12 | import static org.testcontainers.containers.localstack.LocalStackContainer.Service.S3;
13 |
14 | @ConditionalOnLocalStackService
15 | @ConditionalOnProperty(name = "localstack.s3.enabled", havingValue = "true", matchIfMissing = ENABLE_SERVICE_BY_DEFAULT)
16 | @ConditionalOnClass(AmazonS3.class)
17 | public class AmazonS3Configuration extends AbstractAmazonClient {
18 |
19 | public AmazonS3Configuration(LocalStackContainer localStackContainer) {
20 | super(localStackContainer);
21 | }
22 |
23 | @Bean
24 | @Primary
25 | public AmazonS3 amazonS3LocalStack() {
26 | return AmazonS3ClientBuilder.standard()
27 | .withEndpointConfiguration(getEndpointConfiguration(S3))
28 | .withCredentials(getCredentialsProvider())
29 | .enablePathStyleAccess()
30 | .build();
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/io/github/sivalabs/localstack/autoconfigure/configurator/AmazonSNSConfiguration.java:
--------------------------------------------------------------------------------
1 | package io.github.sivalabs.localstack.autoconfigure.configurator;
2 |
3 | import com.amazonaws.services.sns.AmazonSNSAsync;
4 | import com.amazonaws.services.sns.AmazonSNSAsyncClientBuilder;
5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
6 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Primary;
9 | import org.testcontainers.containers.localstack.LocalStackContainer;
10 |
11 | import static io.github.sivalabs.localstack.LocalStackProperties.ENABLE_SERVICE_BY_DEFAULT;
12 | import static org.testcontainers.containers.localstack.LocalStackContainer.Service.SNS;
13 |
14 | @ConditionalOnLocalStackService
15 | @ConditionalOnProperty(name = "localstack.sns.enabled", havingValue = "true", matchIfMissing = ENABLE_SERVICE_BY_DEFAULT)
16 | @ConditionalOnClass(AmazonSNSAsync.class)
17 | public class AmazonSNSConfiguration extends AbstractAmazonClient {
18 |
19 | public AmazonSNSConfiguration(LocalStackContainer localStackContainer) {
20 | super(localStackContainer);
21 | }
22 |
23 | @Primary
24 | @Bean
25 | public AmazonSNSAsync amazonSNSAsyncLocalStack() {
26 | return AmazonSNSAsyncClientBuilder.standard()
27 | .withEndpointConfiguration(getEndpointConfiguration(SNS))
28 | .withCredentials(getCredentialsProvider())
29 | .build();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/io/github/sivalabs/localstack/autoconfigure/configurator/AmazonSQSConfiguration.java:
--------------------------------------------------------------------------------
1 | package io.github.sivalabs.localstack.autoconfigure.configurator;
2 |
3 | import com.amazonaws.services.sqs.AmazonSQSAsync;
4 | import com.amazonaws.services.sqs.AmazonSQSAsyncClientBuilder;
5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
6 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Primary;
9 | import org.testcontainers.containers.localstack.LocalStackContainer;
10 |
11 | import static io.github.sivalabs.localstack.LocalStackProperties.ENABLE_SERVICE_BY_DEFAULT;
12 | import static org.testcontainers.containers.localstack.LocalStackContainer.Service.SQS;
13 |
14 | @ConditionalOnLocalStackService
15 | @ConditionalOnProperty(name = "localstack.sqs.enabled", havingValue = "true", matchIfMissing = ENABLE_SERVICE_BY_DEFAULT)
16 | @ConditionalOnClass(AmazonSQSAsync.class)
17 | public class AmazonSQSConfiguration extends AbstractAmazonClient {
18 |
19 | public AmazonSQSConfiguration(LocalStackContainer localStackContainer) {
20 | super(localStackContainer);
21 | }
22 |
23 | @Bean
24 | @Primary
25 | public AmazonSQSAsync amazonSQSAsyncLocalStack() {
26 | return AmazonSQSAsyncClientBuilder.standard()
27 | .withEndpointConfiguration(getEndpointConfiguration(SQS))
28 | .withCredentials(getCredentialsProvider())
29 | .build();
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/io/github/sivalabs/localstack/autoconfigure/configurator/ConditionalOnLocalStackService.java:
--------------------------------------------------------------------------------
1 | package io.github.sivalabs.localstack.autoconfigure.configurator;
2 |
3 | import org.springframework.boot.autoconfigure.AutoConfigureAfter;
4 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
5 | import org.springframework.context.annotation.Configuration;
6 |
7 | import java.lang.annotation.Documented;
8 | import java.lang.annotation.ElementType;
9 | import java.lang.annotation.Retention;
10 | import java.lang.annotation.RetentionPolicy;
11 | import java.lang.annotation.Target;
12 |
13 | import static io.github.sivalabs.localstack.LocalStackProperties.BEAN_NAME_LOCALSTACK;
14 |
15 | @Target(ElementType.TYPE)
16 | @Retention(RetentionPolicy.RUNTIME)
17 | @Documented
18 | @Configuration
19 | @ConditionalOnExpression("${localstack.enabled:true}")
20 | @AutoConfigureAfter(name = BEAN_NAME_LOCALSTACK)
21 | public @interface ConditionalOnLocalStackService {
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/io/github/sivalabs/localstack/autoconfigure/configurator/LocalStackContainerConfiguration.java:
--------------------------------------------------------------------------------
1 | package io.github.sivalabs.localstack.autoconfigure.configurator;
2 |
3 | import io.github.sivalabs.localstack.LocalStackProperties;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
7 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
8 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
9 | import org.springframework.boot.context.properties.EnableConfigurationProperties;
10 | import org.springframework.context.annotation.Bean;
11 | import org.springframework.context.annotation.Configuration;
12 | import org.springframework.core.env.ConfigurableEnvironment;
13 | import org.springframework.core.env.MapPropertySource;
14 | import org.testcontainers.containers.localstack.LocalStackContainer;
15 |
16 | import java.util.LinkedHashMap;
17 | import java.util.Map;
18 |
19 | import static io.github.sivalabs.localstack.LocalStackProperties.BEAN_NAME_LOCALSTACK;
20 |
21 | @Configuration
22 | @ConditionalOnClass({LocalStackContainer.class})
23 | @ConditionalOnProperty(name = "localstack.enabled", matchIfMissing = true)
24 | @EnableConfigurationProperties(LocalStackProperties.class)
25 | public class LocalStackContainerConfiguration {
26 |
27 | private static final Logger log = LoggerFactory.getLogger(LocalStackContainerConfiguration.class);
28 |
29 | @ConditionalOnMissingBean(name = BEAN_NAME_LOCALSTACK)
30 | @Bean(name = BEAN_NAME_LOCALSTACK, destroyMethod = "stop")
31 | public LocalStackContainer localStack(ConfigurableEnvironment environment,
32 | LocalStackProperties properties) {
33 | log.info("Starting Localstack server. Docker image: {}", properties.getDockerImage());
34 |
35 | LocalStackContainer localStackContainer = new EmbeddedLocalStackContainer(properties.getDockerImage());
36 | localStackContainer.withEnv("EDGE_PORT", String.valueOf(properties.getEdgePort()))
37 | .withEnv("DEFAULT_REGION", properties.getDefaultRegion())
38 | .withEnv("HOSTNAME", properties.getHostname())
39 | .withEnv("HOSTNAME_EXTERNAL", properties.getHostnameExternal())
40 | .withEnv("USE_SSL", String.valueOf(properties.isUseSsl()));
41 |
42 | for (LocalStackContainer.Service service : properties.getServices()) {
43 | localStackContainer.withServices(service);
44 | }
45 | localStackContainer.start();
46 | registerLocalStackEnvironment(localStackContainer, environment, properties);
47 | return localStackContainer;
48 | }
49 |
50 | private void registerLocalStackEnvironment(LocalStackContainer localStack,
51 | ConfigurableEnvironment environment,
52 | LocalStackProperties properties) {
53 | String host = localStack.getContainerIpAddress();
54 |
55 | Map map = new LinkedHashMap<>();
56 | map.put("localstack.host", host);
57 | map.put("localstack.accessKey", localStack.getAccessKey());
58 | map.put("localstack.secretKey", localStack.getSecretKey());
59 | map.put("localstack.region", localStack.getRegion());
60 | String prefix = "localstack.";
61 | for (LocalStackContainer.Service service : properties.getServices()) {
62 | map.put(prefix + service + ".endpoint", localStack.getEndpointConfiguration(service).getServiceEndpoint());
63 | }
64 | log.info("Started Localstack. Connection details: {}", map);
65 |
66 | MapPropertySource propertySource = new MapPropertySource("localstackInfo", map);
67 | environment.getPropertySources().addFirst(propertySource);
68 | setSystemProperties(localStack);
69 | }
70 |
71 | private static void setSystemProperties(LocalStackContainer localStack) {
72 | System.setProperty("aws.accessKeyId", localStack.getAccessKey());
73 | System.setProperty("aws.secretKey", localStack.getAccessKey());
74 | System.setProperty("com.amazonaws.sdk.disableCbor", "true");
75 | System.setProperty("com.amazonaws.sdk.disableCertChecking", "true");
76 | }
77 |
78 | private static class EmbeddedLocalStackContainer extends LocalStackContainer {
79 | EmbeddedLocalStackContainer(final String dockerImageName) {
80 | setDockerImageName(dockerImageName);
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/test/java/io/github/sivalabs/localstack/autoconfigure/LocalStackAutoConfigurationTest.java:
--------------------------------------------------------------------------------
1 | package io.github.sivalabs.localstack.autoconfigure;
2 |
3 | import com.amazonaws.services.cloudwatch.AmazonCloudWatchAsync;
4 | import com.amazonaws.services.dynamodbv2.AmazonDynamoDBAsync;
5 | import com.amazonaws.services.dynamodbv2.AmazonDynamoDBStreamsAsync;
6 | import com.amazonaws.services.identitymanagement.AmazonIdentityManagementAsync;
7 | import com.amazonaws.services.kinesis.AmazonKinesisAsync;
8 | import com.amazonaws.services.lambda.AWSLambdaAsync;
9 | import com.amazonaws.services.s3.AmazonS3;
10 | import com.amazonaws.services.secretsmanager.AWSSecretsManagerAsync;
11 | import com.amazonaws.services.sns.AmazonSNSAsync;
12 | import com.amazonaws.services.sqs.AmazonSQSAsync;
13 | import io.github.sivalabs.localstack.LocalStackProperties;
14 | import io.github.sivalabs.localstack.autoconfigure.configurator.AWSLambdaConfiguration;
15 | import io.github.sivalabs.localstack.autoconfigure.configurator.AWSSecretsManagerConfiguration;
16 | import io.github.sivalabs.localstack.autoconfigure.configurator.AmazonCloudWatchConfiguration;
17 | import io.github.sivalabs.localstack.autoconfigure.configurator.AmazonDynamoDBConfiguration;
18 | import io.github.sivalabs.localstack.autoconfigure.configurator.AmazonIAMConfiguration;
19 | import io.github.sivalabs.localstack.autoconfigure.configurator.AmazonKinesisConfiguration;
20 | import io.github.sivalabs.localstack.autoconfigure.configurator.AmazonS3Configuration;
21 | import io.github.sivalabs.localstack.autoconfigure.configurator.AmazonSNSConfiguration;
22 | import io.github.sivalabs.localstack.autoconfigure.configurator.AmazonSQSConfiguration;
23 | import org.junit.jupiter.api.Test;
24 | import org.springframework.boot.autoconfigure.AutoConfigurations;
25 | import org.springframework.boot.test.context.runner.ApplicationContextRunner;
26 |
27 | import static org.assertj.core.api.Assertions.assertThat;
28 |
29 | public class LocalStackAutoConfigurationTest {
30 |
31 | private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
32 | .withConfiguration(AutoConfigurations.of(
33 | LocalStackAutoConfiguration.class,
34 | AmazonS3Configuration.class,
35 | AmazonSQSConfiguration.class,
36 | AmazonSNSConfiguration.class,
37 | AmazonDynamoDBConfiguration.class,
38 | AmazonCloudWatchConfiguration.class,
39 | AmazonIAMConfiguration.class,
40 | AmazonKinesisConfiguration.class,
41 | AWSLambdaConfiguration.class,
42 | AWSSecretsManagerConfiguration.class
43 | ));
44 |
45 | @Test
46 | public void shouldAutoConfigureAWSServiceClientsBasedOnDefaultConfiguration() {
47 | this.contextRunner
48 | .withPropertyValues(
49 | "localstack.services=SQS,S3,SNS,DYNAMODB,DYNAMODBSTREAMS,KINESIS,IAM,LAMBDA,CLOUDWATCH,SECRETSMANAGER"
50 | )
51 | .run((context) -> {
52 | assertThat(context).hasSingleBean(LocalStackProperties.class);
53 | LocalStackProperties properties = context.getBean(LocalStackProperties.class);
54 | assertThat(properties.isEnabled()).isTrue();
55 |
56 | assertThat(context).hasSingleBean(AmazonS3.class);
57 | assertThat(context).hasSingleBean(AmazonSQSAsync.class);
58 | assertThat(context).hasSingleBean(AmazonSNSAsync.class);
59 | assertThat(context).hasSingleBean(AmazonDynamoDBAsync.class);
60 | assertThat(context).hasSingleBean(AmazonDynamoDBStreamsAsync.class);
61 | assertThat(context).hasSingleBean(AmazonKinesisAsync.class);
62 | assertThat(context).hasSingleBean(AmazonIdentityManagementAsync.class);
63 | assertThat(context).hasSingleBean(AWSSecretsManagerAsync.class);
64 | assertThat(context).hasSingleBean(AmazonCloudWatchAsync.class);
65 | assertThat(context).hasSingleBean(AWSLambdaAsync.class);
66 | });
67 | }
68 |
69 | @Test
70 | public void shouldAutoConfigureAllEnabledAWSServiceClients() {
71 | this.contextRunner
72 | .withPropertyValues(
73 | "localstack.services=SQS,S3,SNS,DYNAMODB,DYNAMODBSTREAMS,KINESIS,IAM,LAMBDA,CLOUDWATCH,SECRETSMANAGER",
74 | "localstack.s3.enabled=true",
75 | "localstack.sqs.enabled=true",
76 | "localstack.sns.enabled=true",
77 | "localstack.dynamodb.enabled=true",
78 | "localstack.dynamodbstreams.enabled=true",
79 | "localstack.kinesis.enabled=true",
80 | "localstack.iam.enabled=true",
81 | "localstack.lambda.enabled=true",
82 | "localstack.cloudwatch.enabled=true",
83 | "localstack.secretsmanager.enabled=true"
84 | )
85 | .run((context) -> {
86 | assertThat(context).hasSingleBean(LocalStackProperties.class);
87 | LocalStackProperties properties = context.getBean(LocalStackProperties.class);
88 | assertThat(properties.isEnabled()).isTrue();
89 |
90 | assertThat(context).hasSingleBean(AmazonS3.class);
91 | assertThat(context).hasSingleBean(AmazonSQSAsync.class);
92 | assertThat(context).hasSingleBean(AmazonSNSAsync.class);
93 | assertThat(context).hasSingleBean(AmazonDynamoDBAsync.class);
94 | assertThat(context).hasSingleBean(AmazonDynamoDBStreamsAsync.class);
95 | assertThat(context).hasSingleBean(AmazonKinesisAsync.class);
96 | assertThat(context).hasSingleBean(AmazonIdentityManagementAsync.class);
97 | assertThat(context).hasSingleBean(AWSSecretsManagerAsync.class);
98 | assertThat(context).hasSingleBean(AmazonCloudWatchAsync.class);
99 | assertThat(context).hasSingleBean(AWSLambdaAsync.class);
100 | });
101 | }
102 |
103 | @Test
104 | public void shouldAutoConfigureOnlyEnabledAWSServiceClients() {
105 | this.contextRunner
106 | .withPropertyValues(
107 | "localstack.services=SQS,S3",
108 | "localstack.s3.enabled=true",
109 | "localstack.sqs.enabled=true",
110 | "localstack.sns.enabled=true",
111 | "localstack.dynamodb.enabled=false",
112 | "localstack.dynamodbstreams.enabled=false",
113 | "localstack.kinesis.enabled=false",
114 | "localstack.iam.enabled=false",
115 | "localstack.lambda.enabled=false",
116 | "localstack.cloudwatch.enabled=false",
117 | "localstack.secretsmanager.enabled=false"
118 | )
119 | .run((context) -> {
120 | assertThat(context).hasSingleBean(LocalStackProperties.class);
121 | assertThat(context).hasSingleBean(AmazonS3.class);
122 | assertThat(context).hasSingleBean(AmazonSQSAsync.class);
123 | assertThat(context).hasSingleBean(AmazonSNSAsync.class);
124 |
125 | assertThat(context).doesNotHaveBean(AmazonDynamoDBAsync.class);
126 | assertThat(context).doesNotHaveBean(AmazonDynamoDBStreamsAsync.class);
127 | assertThat(context).doesNotHaveBean(AmazonKinesisAsync.class);
128 | assertThat(context).doesNotHaveBean(AmazonIdentityManagementAsync.class);
129 | assertThat(context).doesNotHaveBean(AWSSecretsManagerAsync.class);
130 | assertThat(context).doesNotHaveBean(AmazonCloudWatchAsync.class);
131 | assertThat(context).doesNotHaveBean(AWSLambdaAsync.class);
132 | });
133 | }
134 |
135 | @Test
136 | public void shouldNotAutoConfigureAWSServiceClientsWhenLocalStackInNotEnabled() {
137 | this.contextRunner
138 | .withPropertyValues(
139 | "localstack.enabled=false",
140 | "localstack.services=SQS,S3,SNS,DYNAMODB,DYNAMODBSTREAMS,KINESIS,IAM,LAMBDA,CLOUDWATCH,SECRETSMANAGER",
141 | "localstack.s3.enabled=true",
142 | "localstack.sqs.enabled=true",
143 | "localstack.sns.enabled=true",
144 | "localstack.dynamodb.enabled=true",
145 | "localstack.dynamodbstreams.enabled=true",
146 | "localstack.kinesis.enabled=true",
147 | "localstack.iam.enabled=true",
148 | "localstack.lambda.enabled=true",
149 | "localstack.cloudwatch.enabled=true",
150 | "localstack.secretsmanager.enabled=true"
151 | )
152 | .run((context) -> {
153 | assertThat(context).doesNotHaveBean(LocalStackProperties.class);
154 | assertThat(context).doesNotHaveBean(AmazonS3.class);
155 | assertThat(context).doesNotHaveBean(AmazonSQSAsync.class);
156 | assertThat(context).doesNotHaveBean(AmazonSNSAsync.class);
157 | assertThat(context).doesNotHaveBean(AmazonDynamoDBAsync.class);
158 | assertThat(context).doesNotHaveBean(AmazonDynamoDBStreamsAsync.class);
159 | assertThat(context).doesNotHaveBean(AmazonKinesisAsync.class);
160 | assertThat(context).doesNotHaveBean(AmazonIdentityManagementAsync.class);
161 | assertThat(context).doesNotHaveBean(AWSSecretsManagerAsync.class);
162 | assertThat(context).doesNotHaveBean(AmazonCloudWatchAsync.class);
163 | assertThat(context).doesNotHaveBean(AWSLambdaAsync.class);
164 | });
165 | }
166 | }
167 |
--------------------------------------------------------------------------------