├── .sdkmanrc
├── cloudwatch
├── src
│ ├── test
│ │ ├── resources
│ │ │ ├── application.properties
│ │ │ └── logback-test.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── cloudwatch
│ │ │ └── CloudwatchApplicationTests.java
│ └── main
│ │ ├── resources
│ │ └── application.properties
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── cloudwatch
│ │ ├── CloudwatchApplication.java
│ │ └── GreetingController.java
└── pom.xml
├── s3
├── src
│ ├── main
│ │ ├── resources
│ │ │ └── application.properties
│ │ └── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── s3
│ │ │ └── S3Application.java
│ └── test
│ │ ├── resources
│ │ └── logback-test.xml
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── s3
│ │ └── S3ApplicationTests.java
└── pom.xml
├── ses
├── src
│ ├── main
│ │ ├── resources
│ │ │ └── application.properties
│ │ └── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── ses
│ │ │ └── SesApplication.java
│ └── test
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── ses
│ │ └── SesApplicationTests.java
└── pom.xml
├── sqs
├── src
│ ├── main
│ │ ├── resources
│ │ │ └── application.properties
│ │ └── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── sqs
│ │ │ └── SqsApplication.java
│ └── test
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── sqs
│ │ └── SqsApplicationTests.java
└── pom.xml
├── cognito
├── src
│ ├── main
│ │ ├── resources
│ │ │ └── application.properties
│ │ └── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── cognito
│ │ │ ├── CognitoApplication.java
│ │ │ ├── ExampleSecurity.java
│ │ │ └── ExampleController.java
│ └── test
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── cognito
│ │ └── CognitoApplicationTests.java
└── pom.xml
├── parameterstore
├── src
│ ├── main
│ │ ├── resources
│ │ │ └── application.properties
│ │ └── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── parameterstore
│ │ │ ├── ParameterstoreApplication.java
│ │ │ └── GreetingController.java
│ └── test
│ │ ├── resources
│ │ └── logback-test.xml
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── parameterstore
│ │ └── ParameterstoreApplicationTests.java
└── pom.xml
├── secretsmanager
├── src
│ ├── main
│ │ ├── resources
│ │ │ └── application.properties
│ │ └── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── secretsmanager
│ │ │ ├── SecretsmanagerApplication.java
│ │ │ └── GreetingController.java
│ └── test
│ │ ├── resources
│ │ └── logback-test.xml
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── secretsmanager
│ │ └── SecretsmanagerApplicationTests.java
└── pom.xml
├── snowflake
├── src
│ ├── main
│ │ ├── resources
│ │ │ └── db
│ │ │ │ └── migration
│ │ │ │ └── V1__setup.sql
│ │ └── java
│ │ │ └── org
│ │ │ └── example
│ │ │ └── snowflake
│ │ │ └── SpringBootSnowflakeApplication.java
│ └── test
│ │ ├── resources
│ │ └── logback-test.xml
│ │ └── java
│ │ └── org
│ │ └── example
│ │ └── snowflake
│ │ └── SnowflakeTest.java
└── pom.xml
├── lambda
├── src
│ ├── main
│ │ ├── resources
│ │ │ └── db
│ │ │ │ └── migration
│ │ │ │ └── V1__create_populate_table.sql
│ │ └── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── springcloudfunctionaws
│ │ │ └── SpringCloudFunctionAwsApplication.java
│ └── test
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── springcloudfunctionaws
│ │ └── SpringCloudFunctionAwsApplicationTests.java
└── pom.xml
├── .gitignore
├── mq-broker
├── src
│ └── test
│ │ ├── resources
│ │ └── logback-test.xml
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── mqbroker
│ │ └── MqBrokerTests.java
└── pom.xml
├── api-gateway
├── src
│ └── test
│ │ ├── resources
│ │ └── logback-test.xml
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── apigateway
│ │ └── ApiGatewayTests.java
└── pom.xml
├── step-functions
├── src
│ └── test
│ │ ├── resources
│ │ └── logback-test.xml
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── stepfunctions
│ │ └── StepFunctionsTests.java
└── pom.xml
├── .mvn
└── wrapper
│ └── maven-wrapper.properties
├── LICENSE
├── pom.xml
├── .github
└── workflows
│ └── ci.yml
├── mvnw.cmd
└── mvnw
/.sdkmanrc:
--------------------------------------------------------------------------------
1 | java=25-tem
2 |
--------------------------------------------------------------------------------
/cloudwatch/src/test/resources/application.properties:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/s3/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/ses/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/sqs/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/cloudwatch/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/cognito/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/parameterstore/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/secretsmanager/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/snowflake/src/main/resources/db/migration/V1__setup.sql:
--------------------------------------------------------------------------------
1 | create table profile (name VARCHAR(25) NOT NULL PRIMARY KEY);
2 |
3 | insert into profile (name) values ('test');
--------------------------------------------------------------------------------
/lambda/src/main/resources/db/migration/V1__create_populate_table.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE IF NOT EXISTS profile(id serial primary key, name varchar(255) not null);
2 |
3 | INSERT INTO profile (name) VALUES ('profile-1');
4 | INSERT INTO profile (name) VALUES ('profile-2');
5 | INSERT INTO profile (name) VALUES ('profile-3');
6 | INSERT INTO profile (name) VALUES ('profile-4');
--------------------------------------------------------------------------------
/s3/src/main/java/com/example/s3/S3Application.java:
--------------------------------------------------------------------------------
1 | package com.example.s3;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class S3Application {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(S3Application.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/ses/src/main/java/com/example/ses/SesApplication.java:
--------------------------------------------------------------------------------
1 | package com.example.ses;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class SesApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(SesApplication.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/sqs/src/main/java/com/example/sqs/SqsApplication.java:
--------------------------------------------------------------------------------
1 | package com.example.sqs;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class SqsApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(SqsApplication.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/cognito/src/main/java/com/example/cognito/CognitoApplication.java:
--------------------------------------------------------------------------------
1 | package com.example.cognito;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class CognitoApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(CognitoApplication.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/cloudwatch/src/main/java/com/example/cloudwatch/CloudwatchApplication.java:
--------------------------------------------------------------------------------
1 | package com.example.cloudwatch;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class CloudwatchApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(CloudwatchApplication.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/parameterstore/src/main/java/com/example/parameterstore/ParameterstoreApplication.java:
--------------------------------------------------------------------------------
1 | package com.example.parameterstore;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class ParameterstoreApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(ParameterstoreApplication.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/secretsmanager/src/main/java/com/example/secretsmanager/SecretsmanagerApplication.java:
--------------------------------------------------------------------------------
1 | package com.example.secretsmanager;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class SecretsmanagerApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(SecretsmanagerApplication.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/snowflake/src/main/java/org/example/snowflake/SpringBootSnowflakeApplication.java:
--------------------------------------------------------------------------------
1 | package org.example.snowflake;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class SpringBootSnowflakeApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(SpringBootSnowflakeApplication.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/parameterstore/src/main/java/com/example/parameterstore/GreetingController.java:
--------------------------------------------------------------------------------
1 | package com.example.parameterstore;
2 |
3 | import org.springframework.beans.factory.annotation.Value;
4 | import org.springframework.web.bind.annotation.GetMapping;
5 | import org.springframework.web.bind.annotation.RestController;
6 |
7 | @RestController
8 | public class GreetingController {
9 |
10 | @Value("${text}")
11 | private String text;
12 |
13 | @GetMapping("/greetings")
14 | public String greeting() {
15 | return this.text;
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/secretsmanager/src/main/java/com/example/secretsmanager/GreetingController.java:
--------------------------------------------------------------------------------
1 | package com.example.secretsmanager;
2 |
3 | import org.springframework.beans.factory.annotation.Value;
4 | import org.springframework.web.bind.annotation.GetMapping;
5 | import org.springframework.web.bind.annotation.RestController;
6 |
7 | @RestController
8 | public class GreetingController {
9 |
10 | @Value("${text}")
11 | private String secret;
12 |
13 | @GetMapping("/greetings")
14 | public String greeting() {
15 | return this.secret;
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 | !**/src/main/**/target/
4 | !**/src/test/**/target/
5 |
6 | ### IntelliJ IDEA ###
7 | .idea/
8 | *.iws
9 | *.iml
10 | *.ipr
11 |
12 | ### Eclipse ###
13 | .apt_generated
14 | .classpath
15 | .factorypath
16 | .project
17 | .settings
18 | .springBeans
19 | .sts4-cache
20 |
21 | ### NetBeans ###
22 | /nbproject/private/
23 | /nbbuild/
24 | /dist/
25 | /nbdist/
26 | /.nb-gradle/
27 | build/
28 | !**/src/main/**/build/
29 | !**/src/test/**/build/
30 |
31 | ### VS Code ###
32 | .vscode/
33 |
34 | ### Mac OS ###
35 | .DS_Store
--------------------------------------------------------------------------------
/s3/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 | %d{HH:mm:ss.SSS} %-5level %logger - %msg%n
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/cloudwatch/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 | %d{HH:mm:ss.SSS} %-5level %logger - %msg%n
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/mq-broker/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 | %d{HH:mm:ss.SSS} %-5level %logger - %msg%n
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/snowflake/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 | %d{HH:mm:ss.SSS} %-5level %logger - %msg%n
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/api-gateway/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 | %d{HH:mm:ss.SSS} %-5level %logger - %msg%n
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/parameterstore/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 | %d{HH:mm:ss.SSS} %-5level %logger - %msg%n
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/secretsmanager/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 | %d{HH:mm:ss.SSS} %-5level %logger - %msg%n
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/step-functions/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/cloudwatch/src/main/java/com/example/cloudwatch/GreetingController.java:
--------------------------------------------------------------------------------
1 | package com.example.cloudwatch;
2 |
3 | import io.micrometer.core.annotation.Timed;
4 | import org.springframework.web.bind.annotation.GetMapping;
5 | import org.springframework.web.bind.annotation.PathVariable;
6 | import org.springframework.web.bind.annotation.RequestMapping;
7 | import org.springframework.web.bind.annotation.RestController;
8 |
9 | @Timed
10 | @RestController
11 | @RequestMapping("/greetings")
12 | public class GreetingController {
13 |
14 | @GetMapping
15 | public String greetings() {
16 | return "Hello World";
17 | }
18 |
19 | @GetMapping("/{name}")
20 | public String greetings(@PathVariable String name) {
21 | return "Hello " + name;
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/lambda/src/main/java/com/example/springcloudfunctionaws/SpringCloudFunctionAwsApplication.java:
--------------------------------------------------------------------------------
1 | package com.example.springcloudfunctionaws;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.jdbc.core.JdbcTemplate;
7 |
8 | import java.util.function.Function;
9 |
10 | @SpringBootApplication
11 | public class SpringCloudFunctionAwsApplication {
12 |
13 | public static void main(String[] args) {
14 | SpringApplication.run(SpringCloudFunctionAwsApplication.class, args);
15 | }
16 |
17 | @Bean
18 | public Function fetchByName(JdbcTemplate jdbcTemplate) {
19 | return profile -> jdbcTemplate.queryForObject("SELECT COUNT(*) FROM profile WHERE name LIKE ?", Integer.class,
20 | profile.name() + "%");
21 | }
22 |
23 | record Profile(String name) {
24 |
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | # Licensed to the Apache Software Foundation (ASF) under one
2 | # or more contributor license agreements. See the NOTICE file
3 | # distributed with this work for additional information
4 | # regarding copyright ownership. The ASF licenses this file
5 | # to you under the Apache License, Version 2.0 (the
6 | # "License"); you may not use this file except in compliance
7 | # with the License. You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 | wrapperVersion=3.3.2
18 | distributionType=only-script
19 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.10/apache-maven-3.9.10-bin.zip
20 |
--------------------------------------------------------------------------------
/cognito/src/main/java/com/example/cognito/ExampleSecurity.java:
--------------------------------------------------------------------------------
1 | package com.example.cognito;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.http.HttpMethod;
6 | import org.springframework.security.config.Customizer;
7 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
8 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
9 | import org.springframework.security.web.SecurityFilterChain;
10 |
11 | @Configuration
12 | @EnableWebSecurity
13 | public class ExampleSecurity {
14 |
15 | @Bean
16 | protected SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
17 | return http
18 | .authorizeHttpRequests(c -> c.requestMatchers(HttpMethod.GET, "/topsecret")
19 | .authenticated()
20 | .requestMatchers(HttpMethod.GET, "/")
21 | .permitAll())
22 | .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
23 | .build();
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/cognito/src/main/java/com/example/cognito/ExampleController.java:
--------------------------------------------------------------------------------
1 | package com.example.cognito;
2 |
3 | import org.springframework.security.core.Authentication;
4 | import org.springframework.security.core.context.SecurityContextHolder;
5 | import org.springframework.security.oauth2.jwt.Jwt;
6 | import org.springframework.web.bind.annotation.GetMapping;
7 | import org.springframework.web.bind.annotation.RestController;
8 |
9 | @RestController
10 | public class ExampleController {
11 |
12 | @GetMapping("/")
13 | public String unsecured() {
14 | return "No secrets here!\n";
15 | }
16 |
17 | @GetMapping("/topsecret")
18 | String secured() {
19 | Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
20 | if (authentication != null && authentication.getPrincipal() instanceof Jwt) {
21 | Jwt jwt = (Jwt) authentication.getPrincipal();
22 | return String.format("You are [%s] with e-mail address [%s].%n", jwt.getSubject(),
23 | jwt.getClaimAsString("email"));
24 | }
25 | else {
26 | return "Something went wrong; authentication is not provided by Cognito.\n";
27 | }
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Eddú Meléndez Gonzales
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.
22 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.example
7 | testcontainers-localstack
8 | 0.0.1-SNAPSHOT
9 | testcontainers-localstack
10 | Demo project for Testcontainers LocalStack Samples
11 | pom
12 |
13 |
14 | api-gateway
15 | cloudwatch
16 | cognito
17 | lambda
18 | mq-broker
19 | parameterstore
20 | s3
21 | secretsmanager
22 | ses
23 | snowflake
24 | sqs
25 | step-functions
26 |
27 |
28 |
29 |
30 |
31 | io.spring.javaformat
32 | spring-javaformat-maven-plugin
33 | 0.0.47
34 |
35 |
36 | validate
37 | true
38 |
39 | validate
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: Java CI with Maven
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | workflow_dispatch:
8 |
9 | concurrency:
10 | group: "${{ github.workflow }}-${{ github.head_ref || github.sha }}"
11 | cancel-in-progress: true
12 |
13 | permissions:
14 | contents: read
15 |
16 | jobs:
17 | find_jobs:
18 | runs-on: ubuntu-24.04
19 | outputs:
20 | matrix: ${{ steps.set-matrix.outputs.matrix }}
21 | steps:
22 | - uses: actions/checkout@v6
23 | - uses: actions/setup-java@v5
24 | with:
25 | java-version: '25'
26 | distribution: temurin
27 | cache: maven
28 | - id: set-matrix
29 | run: |
30 | TASKS=$(./mvnw help:evaluate -Dexpression=project.modules -q -DforceStdout | sed -n 's|.*\(.*\).*|"\1"|p' | paste -sd "," - | sed 's/^/[/' | sed 's/$/]/')
31 | echo $TASKS
32 | echo "matrix={\"modules\":$TASKS}" >> $GITHUB_OUTPUT
33 |
34 | build:
35 | name: "${{ matrix.modules }}"
36 | needs: [find_jobs]
37 | runs-on: ubuntu-24.04
38 | strategy:
39 | fail-fast: false
40 | matrix: ${{ fromJson(needs.find_jobs.outputs.matrix) }}
41 | steps:
42 | - name: Free Disk Space
43 | uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1
44 | with:
45 | large-packages: false
46 | - uses: actions/checkout@v4
47 | - uses: actions/setup-java@v4
48 | with:
49 | java-version: '25'
50 | distribution: temurin
51 | cache: maven
52 | cache-dependency-path: ${{ matrix.modules }}/pom.xml
53 | - name: Build with Maven (${{ matrix.modules }})
54 | run: ./mvnw -V -B verify -pl ${{ matrix.modules }}
55 | env:
56 | LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }}
57 |
--------------------------------------------------------------------------------
/snowflake/src/test/java/org/example/snowflake/SnowflakeTest.java:
--------------------------------------------------------------------------------
1 | package org.example.snowflake;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.boot.test.context.SpringBootTest;
7 | import org.springframework.jdbc.core.simple.JdbcClient;
8 | import org.springframework.test.context.DynamicPropertyRegistry;
9 | import org.springframework.test.context.DynamicPropertySource;
10 | import org.testcontainers.containers.GenericContainer;
11 | import org.testcontainers.containers.wait.strategy.Wait;
12 | import org.testcontainers.junit.jupiter.Container;
13 | import org.testcontainers.junit.jupiter.Testcontainers;
14 |
15 | import static org.assertj.core.api.Assertions.assertThat;
16 |
17 | @SpringBootTest(properties = { "spring.datasource.username=test", "spring.datasource.password=test",
18 | "spring.datasource.driver-class-name=net.snowflake.client.jdbc.SnowflakeDriver", })
19 | @Testcontainers
20 | @EnabledIfEnvironmentVariable(named = "LOCALSTACK_AUTH_TOKEN", matches = ".+")
21 | public class SnowflakeTest {
22 |
23 | @Container
24 | private static final GenericContainer> container = new GenericContainer<>("localstack/snowflake:1.5.0")
25 | .withExposedPorts(4566)
26 | .withEnv("LOCALSTACK_AUTH_TOKEN", System.getenv("LOCALSTACK_AUTH_TOKEN"))
27 | .waitingFor(Wait.forLogMessage(".*Ready.*", 1));
28 |
29 | @DynamicPropertySource
30 | static void setProperties(DynamicPropertyRegistry registry) {
31 | registry.add("spring.datasource.url", () -> "jdbc:snowflake://snowflake.localhost.localstack.cloud:"
32 | + container.getMappedPort(4566) + "/?db=test&schema=test&JDBC_QUERY_RESULT_FORMAT=JSON");
33 | }
34 |
35 | @Autowired
36 | private JdbcClient jdbcClient;
37 |
38 | @Test
39 | void test() {
40 | String name = this.jdbcClient.sql("select name from profile").query(String.class).single();
41 | assertThat(name).isEqualTo("test");
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/secretsmanager/src/test/java/com/example/secretsmanager/SecretsmanagerApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.example.secretsmanager;
2 |
3 | import io.restassured.RestAssured;
4 | import org.junit.jupiter.api.BeforeAll;
5 | import org.junit.jupiter.api.Test;
6 | import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer;
7 | import org.springframework.boot.test.context.SpringBootTest;
8 | import org.springframework.boot.test.web.server.LocalServerPort;
9 | import org.springframework.test.context.ContextConfiguration;
10 | import org.springframework.test.context.DynamicPropertyRegistry;
11 | import org.springframework.test.context.DynamicPropertySource;
12 | import org.testcontainers.containers.localstack.LocalStackContainer;
13 | import org.testcontainers.junit.jupiter.Container;
14 | import org.testcontainers.junit.jupiter.Testcontainers;
15 | import org.testcontainers.utility.DockerImageName;
16 |
17 | import java.io.IOException;
18 |
19 | import static org.hamcrest.Matchers.equalTo;
20 |
21 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
22 | properties = { "spring.cloud.aws.credentials.access-key=noop", "spring.cloud.aws.credentials.secret-key=noop",
23 | "spring.cloud.aws.region.static=us-east-1" })
24 | @ContextConfiguration(initializers = ConfigDataApplicationContextInitializer.class)
25 | @Testcontainers
26 | class SecretsmanagerApplicationTests {
27 |
28 | @Container
29 | private static LocalStackContainer localstack = new LocalStackContainer(
30 | DockerImageName.parse("localstack/localstack:4.12.0"));
31 |
32 | @LocalServerPort
33 | private int localPort;
34 |
35 | private static final String text = "This is not a secret anymore. Love testing AWS with Testcontainers and LocalStack.";
36 |
37 | @DynamicPropertySource
38 | static void properties(DynamicPropertyRegistry registry) {
39 | registry.add("spring.cloud.aws.secretsmanager.endpoint", () -> localstack.getEndpoint().toString());
40 | registry.add("spring.cloud.aws.secretsmanager.region", localstack::getRegion);
41 | registry.add("spring.config.import", () -> "aws-secretsmanager:/spring/secret/text");
42 | }
43 |
44 | @BeforeAll
45 | static void beforeAll() throws IOException, InterruptedException {
46 | localstack.execInContainer("awslocal", "secretsmanager", "create-secret", "--name", "/spring/secret/text",
47 | "--secret-string", text, "--region", localstack.getRegion());
48 | }
49 |
50 | @Test
51 | void contextLoads() {
52 | RestAssured.given().port(this.localPort).get("/greetings").then().assertThat().body(equalTo(text));
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/step-functions/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 3.5.9
9 |
10 |
11 | com.example
12 | step-functions
13 | 0.0.1-SNAPSHOT
14 | step-functions
15 | Demo project for Step Functions with LocalStack
16 |
17 | 25
18 | 1.21.4
19 | 2.29.34
20 |
21 |
22 |
23 | software.amazon.awssdk
24 | sfn
25 | ${aws-java-sdk-v2.version}
26 | test
27 |
28 |
29 | software.amazon.awssdk
30 | iam
31 | ${aws-java-sdk-v2.version}
32 | test
33 |
34 |
35 | software.amazon.awssdk
36 | cloudformation
37 | ${aws-java-sdk-v2.version}
38 | test
39 |
40 |
41 |
42 | org.springframework.boot
43 | spring-boot-starter-test
44 | test
45 |
46 |
47 | org.testcontainers
48 | junit-jupiter
49 | test
50 |
51 |
52 | org.testcontainers
53 | localstack
54 | test
55 |
56 |
57 | org.awaitility
58 | awaitility
59 | test
60 |
61 |
62 |
63 |
64 |
65 |
66 | org.testcontainers
67 | testcontainers-bom
68 | ${testcontainers.version}
69 | pom
70 | import
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/parameterstore/src/test/java/com/example/parameterstore/ParameterstoreApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.example.parameterstore;
2 |
3 | import io.restassured.RestAssured;
4 | import org.junit.jupiter.api.BeforeAll;
5 | import org.junit.jupiter.api.Test;
6 | import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer;
7 | import org.springframework.boot.test.context.SpringBootTest;
8 | import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
9 | import org.springframework.boot.test.web.server.LocalServerPort;
10 | import org.springframework.test.context.ContextConfiguration;
11 | import org.springframework.test.context.DynamicPropertyRegistry;
12 | import org.springframework.test.context.DynamicPropertySource;
13 | import org.testcontainers.containers.localstack.LocalStackContainer;
14 | import org.testcontainers.junit.jupiter.Container;
15 | import org.testcontainers.junit.jupiter.Testcontainers;
16 | import org.testcontainers.utility.DockerImageName;
17 |
18 | import java.io.IOException;
19 |
20 | import static org.hamcrest.Matchers.equalTo;
21 |
22 | @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,
23 | properties = { "spring.cloud.aws.credentials.access-key=noop", "spring.cloud.aws.credentials.secret-key=noop",
24 | "spring.cloud.aws.region.static=us-east-1" })
25 | @ContextConfiguration(initializers = ConfigDataApplicationContextInitializer.class)
26 | @Testcontainers
27 | class ParameterstoreApplicationTests {
28 |
29 | @LocalServerPort
30 | private int localPort;
31 |
32 | @Container
33 | private static LocalStackContainer localstack = new LocalStackContainer(
34 | DockerImageName.parse("localstack/localstack:4.12.0"));
35 |
36 | @DynamicPropertySource
37 | static void properties(DynamicPropertyRegistry registry) {
38 | registry.add("spring.cloud.aws.parameterstore.endpoint", () -> localstack.getEndpoint().toString());
39 | registry.add("spring.cloud.aws.parameterstore.region", localstack::getRegion);
40 | registry.add("spring.cloud.aws.endpoint", () -> localstack.getEndpoint().toString());
41 | registry.add("spring.cloud.aws.region.static", localstack::getRegion);
42 | registry.add("spring.config.import", () -> "aws-parameterstore:/spring/config/");
43 | }
44 |
45 | @BeforeAll
46 | static void beforeAll() throws IOException, InterruptedException {
47 | localstack.execInContainer("awslocal", "ssm", "put-parameter", "--name", "/spring/config/text", "--value",
48 | "Hello World", "--type", "String", "--region", localstack.getRegion());
49 | }
50 |
51 | @Test
52 | void contextLoads() {
53 | RestAssured.given().port(this.localPort).get("/greetings").then().assertThat().body(equalTo("Hello World"));
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/sqs/src/test/java/com/example/sqs/SqsApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.example.sqs;
2 |
3 | import io.awspring.cloud.sqs.annotation.SqsListener;
4 | import io.awspring.cloud.sqs.operations.SqsTemplate;
5 | import org.awaitility.Awaitility;
6 | import org.junit.jupiter.api.Test;
7 | import org.junit.jupiter.api.extension.AfterAllCallback;
8 | import org.junit.jupiter.api.extension.ExtendWith;
9 | import org.junit.jupiter.api.extension.ExtensionContext;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.boot.test.context.SpringBootTest;
12 | import org.springframework.boot.test.context.TestConfiguration;
13 | import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
14 | import org.springframework.context.ConfigurableApplicationContext;
15 | import org.springframework.context.annotation.Bean;
16 | import org.springframework.test.context.junit.jupiter.SpringExtension;
17 | import org.testcontainers.containers.localstack.LocalStackContainer;
18 | import org.testcontainers.junit.jupiter.Container;
19 | import org.testcontainers.junit.jupiter.Testcontainers;
20 | import org.testcontainers.utility.DockerImageName;
21 |
22 | import java.time.Duration;
23 | import java.util.ArrayList;
24 | import java.util.List;
25 |
26 | import static org.assertj.core.api.Assertions.assertThat;
27 |
28 | @SpringBootTest
29 | @Testcontainers
30 | @ExtendWith(SqsApplicationTests.SqsAfterAllCallBack.class)
31 | class SqsApplicationTests {
32 |
33 | @Container
34 | @ServiceConnection
35 | static LocalStackContainer localStackContainer = new LocalStackContainer(
36 | DockerImageName.parse("localstack/localstack:4.12.0"));
37 |
38 | @Autowired
39 | private SqsTemplate sqsTemplate;
40 |
41 | @Autowired
42 | private TestListener testListener;
43 |
44 | @Test
45 | void consumeMessage() {
46 | this.sqsTemplate.send("test", "Hello World!");
47 |
48 | Awaitility.waitAtMost(Duration.ofSeconds(30)).untilAsserted(() -> {
49 | assertThat(this.testListener.messages).hasSize(1);
50 | });
51 | }
52 |
53 | @TestConfiguration(proxyBeanMethods = false)
54 | static class TestConfig {
55 |
56 | @Bean
57 | TestListener testListener() {
58 | return new TestListener();
59 | }
60 |
61 | }
62 |
63 | static class TestListener {
64 |
65 | private final List messages = new ArrayList<>();
66 |
67 | @SqsListener("test")
68 | void listen(String message) {
69 | this.messages.add(message);
70 | }
71 |
72 | }
73 |
74 | static class SqsAfterAllCallBack implements AfterAllCallback {
75 |
76 | @Override
77 | public void afterAll(ExtensionContext context) throws Exception {
78 | ConfigurableApplicationContext applicationContext = (ConfigurableApplicationContext) SpringExtension
79 | .getApplicationContext(context);
80 | applicationContext.stop();
81 | }
82 |
83 | }
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/api-gateway/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 3.5.9
9 |
10 |
11 | com.example
12 | api-gateway
13 | 0.0.1-SNAPSHOT
14 | api-gateway
15 | Demo project for Spring Boot
16 |
17 | 25
18 | 2.26.20
19 | 1.21.4
20 |
21 |
22 |
23 | org.springframework.boot
24 | spring-boot-starter-web
25 |
26 |
27 |
28 | org.springframework.boot
29 | spring-boot-starter-test
30 | test
31 |
32 |
33 | org.testcontainers
34 | junit-jupiter
35 | test
36 |
37 |
38 | org.testcontainers
39 | localstack
40 | test
41 |
42 |
43 | io.rest-assured
44 | rest-assured
45 | test
46 |
47 |
48 | software.amazon.awssdk
49 | apigateway
50 | test
51 |
52 |
53 |
54 |
55 |
56 |
57 | software.amazon.awssdk
58 | bom
59 | ${awssdk-v2.version}
60 | pom
61 | import
62 |
63 |
64 |
65 |
66 |
67 |
68 | spring-milestones
69 | Spring Milestones
70 | https://repo.spring.io/milestone
71 |
72 | false
73 |
74 |
75 |
76 |
77 |
78 | spring-milestones
79 | Spring Milestones
80 | https://repo.spring.io/milestone
81 |
82 | false
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/snowflake/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 3.5.9
9 |
10 |
11 | com.example
12 | snowflake
13 | 0.0.1-SNAPSHOT
14 | snowflake
15 | Demo project for Spring Boot
16 |
17 | 25
18 | 1.21.4
19 |
20 |
21 |
22 | org.springframework.boot
23 | spring-boot-starter-jdbc
24 |
25 |
26 | org.flywaydb
27 | flyway-core
28 |
29 |
30 | org.flywaydb
31 | flyway-database-snowflake
32 |
33 |
34 |
35 | net.snowflake
36 | snowflake-jdbc
37 | 3.26.1
38 | runtime
39 |
40 |
41 |
42 | org.springframework.boot
43 | spring-boot-starter-test
44 | test
45 |
46 |
47 | org.testcontainers
48 | junit-jupiter
49 | test
50 |
51 |
52 | org.assertj
53 | assertj-core
54 | test
55 |
56 |
57 |
58 |
59 |
60 |
61 | org.springframework.boot
62 | spring-boot-maven-plugin
63 |
64 |
65 | org.apache.maven.plugins
66 | maven-surefire-plugin
67 |
68 | --add-opens=java.base/java.nio=ALL-UNNAMED
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | spring-milestones
77 | Spring Milestones
78 | https://repo.spring.io/milestone
79 |
80 | false
81 |
82 |
83 |
84 |
85 |
86 | spring-milestones
87 | Spring Milestones
88 | https://repo.spring.io/milestone
89 |
90 | false
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/ses/src/test/java/com/example/ses/SesApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.example.ses;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import org.junit.jupiter.api.BeforeAll;
5 | import org.junit.jupiter.api.Test;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.boot.test.context.SpringBootTest;
8 | import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
9 | import org.springframework.core.ParameterizedTypeReference;
10 | import org.springframework.mail.MailSender;
11 | import org.springframework.mail.SimpleMailMessage;
12 | import org.springframework.web.client.RestClient;
13 | import org.testcontainers.containers.localstack.LocalStackContainer;
14 | import org.testcontainers.junit.jupiter.Container;
15 | import org.testcontainers.junit.jupiter.Testcontainers;
16 | import org.testcontainers.utility.DockerImageName;
17 |
18 | import java.io.IOException;
19 | import java.util.List;
20 |
21 | import static org.assertj.core.api.Assertions.assertThat;
22 |
23 | @SpringBootTest
24 | @Testcontainers
25 | class SesApplicationTests {
26 |
27 | @Container
28 | @ServiceConnection
29 | static LocalStackContainer localStackContainer = new LocalStackContainer(
30 | DockerImageName.parse("localstack/localstack:4.12.0"));
31 |
32 | @Autowired
33 | private MailSender mailSender;
34 |
35 | @BeforeAll
36 | static void beforeAll() throws IOException, InterruptedException {
37 | localStackContainer.execInContainer("awslocal", "ses", "verify-email-identity", "--email", "hello@example.com");
38 | }
39 |
40 | @Test
41 | void consumeMessage() {
42 | SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
43 | simpleMailMessage.setFrom("hello@example.com");
44 | simpleMailMessage.setTo("bar@baz.com");
45 | simpleMailMessage.setSubject("test subject");
46 | simpleMailMessage.setText("test content");
47 | this.mailSender.send(simpleMailMessage);
48 | var restClient = RestClient.builder().baseUrl(localStackContainer.getEndpoint().toString()).build();
49 | var response = restClient.get()
50 | .uri("/_aws/ses", uriBuilder -> uriBuilder.queryParam("email", "hello@example.com").build())
51 | .retrieve()
52 | .body(new ParameterizedTypeReference() {
53 | });
54 | assertThat(response.messages()).hasSize(1);
55 | Message message = response.messages().getFirst();
56 | assertThat(message.source()).isEqualTo("hello@example.com");
57 | assertThat(message.subject()).isEqualTo("test subject");
58 | assertThat(message.body().textPart()).isEqualTo("test content");
59 | }
60 |
61 | record Messages(List messages) {
62 |
63 | }
64 |
65 | record Message(@JsonProperty("Id") String id, @JsonProperty("Region") String region,
66 | @JsonProperty("Destination") Destination destination, @JsonProperty("Source") String source,
67 | @JsonProperty("Subject") String subject, @JsonProperty("Body") Body body) {
68 |
69 | }
70 |
71 | record Destination(@JsonProperty("ToAddresses") List toAddresses) {
72 |
73 | }
74 |
75 | record Body(@JsonProperty("text_part") String textPart, @JsonProperty("html_part") String htmlPart) {
76 |
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/ses/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 3.5.9
9 |
10 |
11 | com.example
12 | ses
13 | 0.0.1-SNAPSHOT
14 | ses
15 | Demo project for Spring Boot
16 |
17 | 25
18 | 1.21.4
19 |
20 |
21 |
22 | org.springframework.boot
23 | spring-boot-starter-web
24 |
25 |
26 | io.awspring.cloud
27 | spring-cloud-aws-starter-ses
28 |
29 |
30 |
31 | org.springframework.boot
32 | spring-boot-starter-test
33 | test
34 |
35 |
36 | org.testcontainers
37 | junit-jupiter
38 | test
39 |
40 |
41 | org.testcontainers
42 | localstack
43 | test
44 |
45 |
46 | org.awaitility
47 | awaitility
48 | test
49 |
50 |
51 | io.awspring.cloud
52 | spring-cloud-aws-testcontainers
53 | test
54 |
55 |
56 |
57 |
58 |
59 |
60 | org.springframework.boot
61 | spring-boot-maven-plugin
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | io.awspring.cloud
70 | spring-cloud-aws-dependencies
71 | 3.4.0
72 | pom
73 | import
74 |
75 |
76 |
77 |
78 |
79 |
80 | spring-milestones
81 | Spring Milestones
82 | https://repo.spring.io/milestone
83 |
84 | false
85 |
86 |
87 |
88 |
89 |
90 | spring-milestones
91 | Spring Milestones
92 | https://repo.spring.io/milestone
93 |
94 | false
95 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/sqs/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 3.5.9
9 |
10 |
11 | com.example
12 | sqs
13 | 0.0.1-SNAPSHOT
14 | sqs
15 | Demo project for Spring Boot
16 |
17 | 25
18 | 1.21.4
19 |
20 |
21 |
22 | org.springframework.boot
23 | spring-boot-starter-web
24 |
25 |
26 | io.awspring.cloud
27 | spring-cloud-aws-starter-sqs
28 |
29 |
30 |
31 | org.springframework.boot
32 | spring-boot-starter-test
33 | test
34 |
35 |
36 | org.testcontainers
37 | junit-jupiter
38 | test
39 |
40 |
41 | org.testcontainers
42 | localstack
43 | test
44 |
45 |
46 | org.awaitility
47 | awaitility
48 | test
49 |
50 |
51 | io.awspring.cloud
52 | spring-cloud-aws-testcontainers
53 | test
54 |
55 |
56 |
57 |
58 |
59 |
60 | org.springframework.boot
61 | spring-boot-maven-plugin
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | io.awspring.cloud
70 | spring-cloud-aws-dependencies
71 | 3.4.0
72 | pom
73 | import
74 |
75 |
76 |
77 |
78 |
79 |
80 | spring-milestones
81 | Spring Milestones
82 | https://repo.spring.io/milestone
83 |
84 | false
85 |
86 |
87 |
88 |
89 |
90 | spring-milestones
91 | Spring Milestones
92 | https://repo.spring.io/milestone
93 |
94 | false
95 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/parameterstore/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 3.5.9
9 |
10 |
11 | com.example
12 | parameterstore
13 | 0.0.1-SNAPSHOT
14 | parameterstore
15 | Demo project for Spring Boot
16 |
17 | 25
18 | 1.21.4
19 |
20 |
21 |
22 | org.springframework.boot
23 | spring-boot-starter-web
24 |
25 |
26 | io.awspring.cloud
27 | spring-cloud-aws-starter-parameter-store
28 |
29 |
30 |
31 | org.springframework.boot
32 | spring-boot-starter-test
33 | test
34 |
35 |
36 | org.testcontainers
37 | junit-jupiter
38 | test
39 |
40 |
41 | org.testcontainers
42 | localstack
43 | test
44 |
45 |
46 | io.rest-assured
47 | rest-assured
48 | test
49 |
50 |
51 | org.awaitility
52 | awaitility
53 | test
54 |
55 |
56 |
57 |
58 |
59 |
60 | org.springframework.boot
61 | spring-boot-maven-plugin
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | io.awspring.cloud
70 | spring-cloud-aws-dependencies
71 | 3.4.0
72 | pom
73 | import
74 |
75 |
76 |
77 |
78 |
79 |
80 | spring-milestones
81 | Spring Milestones
82 | https://repo.spring.io/milestone
83 |
84 | false
85 |
86 |
87 |
88 |
89 |
90 | spring-milestones
91 | Spring Milestones
92 | https://repo.spring.io/milestone
93 |
94 | false
95 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/secretsmanager/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 3.5.9
9 |
10 |
11 | com.example
12 | secretsmanager
13 | 0.0.1-SNAPSHOT
14 | secretsmanager
15 | Demo project for Spring Boot
16 |
17 | 25
18 | 1.21.4
19 |
20 |
21 |
22 | org.springframework.boot
23 | spring-boot-starter-web
24 |
25 |
26 | io.awspring.cloud
27 | spring-cloud-aws-starter-secrets-manager
28 |
29 |
30 |
31 | org.springframework.boot
32 | spring-boot-starter-test
33 | test
34 |
35 |
36 | org.testcontainers
37 | junit-jupiter
38 | test
39 |
40 |
41 | org.testcontainers
42 | localstack
43 | test
44 |
45 |
46 | io.rest-assured
47 | rest-assured
48 | test
49 |
50 |
51 | org.awaitility
52 | awaitility
53 | test
54 |
55 |
56 |
57 |
58 |
59 |
60 | org.springframework.boot
61 | spring-boot-maven-plugin
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | io.awspring.cloud
70 | spring-cloud-aws-dependencies
71 | 3.4.0
72 | pom
73 | import
74 |
75 |
76 |
77 |
78 |
79 |
80 | spring-milestones
81 | Spring Milestones
82 | https://repo.spring.io/milestone
83 |
84 | false
85 |
86 |
87 |
88 |
89 |
90 | spring-milestones
91 | Spring Milestones
92 | https://repo.spring.io/milestone
93 |
94 | false
95 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/cloudwatch/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 3.5.9
9 |
10 |
11 | com.example
12 | cloudwatch
13 | 0.0.1-SNAPSHOT
14 | cloudwatch
15 | Demo project for Spring Boot
16 |
17 | 25
18 | 1.21.4
19 |
20 |
21 |
22 | org.springframework.boot
23 | spring-boot-starter-web
24 |
25 |
26 | io.awspring.cloud
27 | spring-cloud-aws-starter-metrics
28 |
29 |
30 |
31 | org.springframework.boot
32 | spring-boot-starter-test
33 | test
34 |
35 |
36 | org.testcontainers
37 | junit-jupiter
38 | test
39 |
40 |
41 | org.testcontainers
42 | localstack
43 | test
44 |
45 |
46 | io.rest-assured
47 | rest-assured
48 | test
49 |
50 |
51 | org.awaitility
52 | awaitility
53 | test
54 |
55 |
56 | io.awspring.cloud
57 | spring-cloud-aws-testcontainers
58 | test
59 |
60 |
61 |
62 |
63 |
64 |
65 | org.springframework.boot
66 | spring-boot-maven-plugin
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | io.awspring.cloud
75 | spring-cloud-aws-dependencies
76 | 3.4.0
77 | pom
78 | import
79 |
80 |
81 |
82 |
83 |
84 |
85 | spring-milestones
86 | Spring Milestones
87 | https://repo.spring.io/milestone
88 |
89 | false
90 |
91 |
92 |
93 |
94 |
95 | spring-milestones
96 | Spring Milestones
97 | https://repo.spring.io/milestone
98 |
99 | false
100 |
101 |
102 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/cognito/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 3.5.9
9 |
10 |
11 | com.example
12 | cognito
13 | 0.0.1-SNAPSHOT
14 | cognito
15 | Demo project for Spring Boot
16 |
17 | 25
18 | 2.26.20
19 | 1.21.4
20 |
21 |
22 |
23 | org.springframework.boot
24 | spring-boot-starter-oauth2-client
25 |
26 |
27 | org.springframework.boot
28 | spring-boot-starter-security
29 |
30 |
31 | org.springframework.boot
32 | spring-boot-starter-oauth2-resource-server
33 |
34 |
35 | org.springframework.boot
36 | spring-boot-starter-web
37 |
38 |
39 |
40 | org.springframework.boot
41 | spring-boot-starter-test
42 | test
43 |
44 |
45 | org.testcontainers
46 | junit-jupiter
47 | test
48 |
49 |
50 | org.testcontainers
51 | localstack
52 | test
53 |
54 |
55 | software.amazon.awssdk
56 | cognitoidentityprovider
57 | test
58 |
59 |
60 |
61 |
62 |
63 |
64 | software.amazon.awssdk
65 | bom
66 | ${awssdk-v2.version}
67 | pom
68 | import
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | org.springframework.boot
77 | spring-boot-maven-plugin
78 |
79 |
80 |
81 |
82 |
83 |
84 | spring-milestones
85 | Spring Milestones
86 | https://repo.spring.io/milestone
87 |
88 | false
89 |
90 |
91 |
92 |
93 |
94 | spring-milestones
95 | Spring Milestones
96 | https://repo.spring.io/milestone
97 |
98 | false
99 |
100 |
101 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/mq-broker/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 3.5.9
9 |
10 |
11 | com.example
12 | mq-broker
13 | 0.0.1-SNAPSHOT
14 | mq-broker
15 | Demo project for Spring Boot
16 |
17 | 25
18 | 2.26.20
19 | 1.21.4
20 |
21 |
22 |
23 | org.springframework.boot
24 | spring-boot-starter-test
25 | test
26 |
27 |
28 | org.testcontainers
29 | junit-jupiter
30 | test
31 |
32 |
33 | org.testcontainers
34 | localstack
35 | test
36 |
37 |
38 | software.amazon.awssdk
39 | mq
40 | test
41 |
42 |
43 | org.junit.jupiter
44 | junit-jupiter
45 | test
46 |
47 |
48 | org.assertj
49 | assertj-core
50 | test
51 |
52 |
53 | org.awaitility
54 | awaitility
55 | test
56 |
57 |
58 | io.rest-assured
59 | rest-assured
60 | test
61 |
62 |
63 | org.apache.activemq
64 | activemq-client
65 | test
66 |
67 |
68 | jakarta.jms
69 | jakarta.jms-api
70 | test
71 |
72 |
73 |
74 |
75 |
76 |
77 | software.amazon.awssdk
78 | bom
79 | ${awssdk-v2.version}
80 | pom
81 | import
82 |
83 |
84 |
85 |
86 |
87 |
88 | spring-milestones
89 | Spring Milestones
90 | https://repo.spring.io/milestone
91 |
92 | false
93 |
94 |
95 |
96 |
97 |
98 | spring-milestones
99 | Spring Milestones
100 | https://repo.spring.io/milestone
101 |
102 | false
103 |
104 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/s3/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 3.5.9
9 |
10 |
11 | com.example
12 | s3
13 | 0.0.1-SNAPSHOT
14 | s3
15 | Demo project for Spring Boot
16 |
17 | 25
18 | 1.21.4
19 |
20 |
21 |
22 | org.springframework.boot
23 | spring-boot-starter-web
24 |
25 |
26 | io.awspring.cloud
27 | spring-cloud-aws-starter-s3
28 |
29 |
30 | io.awspring.cloud
31 | spring-cloud-aws-starter-sqs
32 |
33 |
34 |
35 | org.springframework.boot
36 | spring-boot-starter-test
37 | test
38 |
39 |
40 | org.testcontainers
41 | junit-jupiter
42 | test
43 |
44 |
45 | org.testcontainers
46 | localstack
47 | test
48 |
49 |
50 | io.rest-assured
51 | rest-assured
52 | test
53 |
54 |
55 | org.awaitility
56 | awaitility
57 | test
58 |
59 |
60 | io.awspring.cloud
61 | spring-cloud-aws-testcontainers
62 | test
63 |
64 |
65 | software.amazon.awssdk
66 | s3-event-notifications
67 | test
68 |
69 |
70 |
71 |
72 |
73 |
74 | org.springframework.boot
75 | spring-boot-maven-plugin
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | io.awspring.cloud
84 | spring-cloud-aws-dependencies
85 | 3.4.0
86 | pom
87 | import
88 |
89 |
90 |
91 |
92 |
93 |
94 | spring-milestones
95 | Spring Milestones
96 | https://repo.spring.io/milestone
97 |
98 | false
99 |
100 |
101 |
102 |
103 |
104 | spring-milestones
105 | Spring Milestones
106 | https://repo.spring.io/milestone
107 |
108 | false
109 |
110 |
111 |
112 |
113 |
114 |
--------------------------------------------------------------------------------
/cloudwatch/src/test/java/com/example/cloudwatch/CloudwatchApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.example.cloudwatch;
2 |
3 | import io.restassured.RestAssured;
4 | import org.junit.jupiter.api.Test;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.boot.test.autoconfigure.actuate.observability.AutoConfigureObservability;
7 | import org.springframework.boot.test.context.SpringBootTest;
8 | import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
9 | import org.springframework.boot.test.web.server.LocalServerPort;
10 | import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
11 | import org.testcontainers.containers.localstack.LocalStackContainer;
12 | import org.testcontainers.junit.jupiter.Container;
13 | import org.testcontainers.junit.jupiter.Testcontainers;
14 | import org.testcontainers.utility.DockerImageName;
15 | import software.amazon.awssdk.services.cloudwatch.CloudWatchAsyncClient;
16 | import software.amazon.awssdk.services.cloudwatch.model.*;
17 |
18 | import java.time.Duration;
19 | import java.time.Instant;
20 |
21 | import static org.assertj.core.api.Assertions.assertThat;
22 | import static org.awaitility.Awaitility.await;
23 | import static org.hamcrest.Matchers.equalTo;
24 |
25 | @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,
26 | properties = { "management.cloudwatch.metrics.export.namespace=tc-localstack",
27 | "management.cloudwatch.metrics.export.step=5s", "management.metrics.enable.all=false",
28 | "management.metrics.enable.http=true" })
29 | @AutoConfigureObservability(tracing = false)
30 | @Testcontainers
31 | class CloudwatchApplicationTests {
32 |
33 | @Container
34 | @ServiceConnection
35 | private static LocalStackContainer localstack = new LocalStackContainer(
36 | DockerImageName.parse("localstack/localstack:4.12.0"));
37 |
38 | @Autowired
39 | private CloudWatchAsyncClient cloudWatchAsyncClient;
40 |
41 | @LocalServerPort
42 | private int localPort;
43 |
44 | @Test
45 | void contextLoads() {
46 | Instant startTime = Instant.now();
47 | Instant endTime = startTime.plus(Duration.ofSeconds(30));
48 |
49 | for (int i = 0; i < 5; i++) {
50 | RestAssured.given().port(this.localPort).get("/greetings").then().assertThat().body(equalTo("Hello World"));
51 | }
52 |
53 | Dimension error = Dimension.builder().name("error").value("none").build();
54 | Dimension exception = Dimension.builder().name("exception").value("none").build();
55 | Dimension method = Dimension.builder().name("method").value("GET").build();
56 | Dimension outcome = Dimension.builder().name("outcome").value("SUCCESS").build();
57 | Dimension uri = Dimension.builder().name("uri").value("/greetings").build();
58 | Dimension status = Dimension.builder().name("status").value("200").build();
59 | Metric metric = Metric.builder()
60 | .namespace("tc-localstack")
61 | .metricName("http.server.requests.count")
62 | .dimensions(error, exception, method, outcome, uri, status)
63 | .build();
64 | MetricStat metricStat = MetricStat.builder()
65 | .stat("Maximum")
66 | .metric(metric)
67 | .unit(StandardUnit.COUNT)
68 | .period(5)
69 | .build();
70 | MetricDataQuery metricDataQuery = MetricDataQuery.builder()
71 | .metricStat(metricStat)
72 | .id("test1")
73 | .returnData(true)
74 | .build();
75 | await().atMost(Duration.ofSeconds(20))
76 | .pollInterval(Duration.ofSeconds(5))
77 | .ignoreExceptions()
78 | .untilAsserted(() -> {
79 | GetMetricDataResponse response = this.cloudWatchAsyncClient
80 | .getMetricData(GetMetricDataRequest.builder()
81 | .startTime(startTime)
82 | .endTime(endTime)
83 | .metricDataQueries(metricDataQuery)
84 | .build())
85 | .get();
86 | assertThat(response.metricDataResults()).hasSize(1);
87 | assertThat(response.metricDataResults().get(0).label()).isEqualTo("http.server.requests.count");
88 | assertThat(response.metricDataResults().get(0).values()).contains(5d);
89 | });
90 | }
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/mq-broker/src/test/java/com/example/mqbroker/MqBrokerTests.java:
--------------------------------------------------------------------------------
1 | package com.example.mqbroker;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
5 | import org.testcontainers.containers.localstack.LocalStackContainer;
6 | import org.testcontainers.junit.jupiter.Container;
7 | import org.testcontainers.junit.jupiter.Testcontainers;
8 | import org.testcontainers.utility.DockerImageName;
9 | import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
10 | import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
11 | import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration;
12 | import software.amazon.awssdk.regions.Region;
13 | import software.amazon.awssdk.services.mq.MqClient;
14 | import software.amazon.awssdk.services.mq.model.BrokerState;
15 | import software.amazon.awssdk.services.mq.model.CreateBrokerRequest;
16 | import software.amazon.awssdk.services.mq.model.CreateBrokerResponse;
17 | import software.amazon.awssdk.services.mq.model.DescribeBrokerRequest;
18 | import software.amazon.awssdk.services.mq.model.EngineType;
19 | import software.amazon.awssdk.services.mq.model.User;
20 |
21 | import jakarta.jms.Connection;
22 | import jakarta.jms.ConnectionFactory;
23 | import jakarta.jms.Message;
24 | import jakarta.jms.MessageConsumer;
25 | import jakarta.jms.Queue;
26 | import jakarta.jms.Session;
27 | import jakarta.jms.TextMessage;
28 | import java.time.Duration;
29 |
30 | import org.apache.activemq.ActiveMQConnectionFactory;
31 |
32 | import static io.restassured.RestAssured.given;
33 | import static org.assertj.core.api.Assertions.assertThat;
34 | import static org.awaitility.Awaitility.await;
35 |
36 | @Testcontainers
37 | @EnabledIfEnvironmentVariable(named = "LOCALSTACK_AUTH_TOKEN", matches = ".+")
38 | public class MqBrokerTests {
39 |
40 | @Container
41 | private static final LocalStackContainer localstack = new LocalStackContainer(
42 | DockerImageName.parse("localstack/localstack-pro:4.12.0"))
43 | .withExposedPorts(4566, 4510, 4511)
44 | .withEnv("LOCALSTACK_AUTH_TOKEN", System.getenv("LOCALSTACK_AUTH_TOKEN"));
45 |
46 | @Test
47 | void test() throws Exception {
48 | AwsBasicCredentials awsCreds = AwsBasicCredentials.create(localstack.getAccessKey(), localstack.getSecretKey());
49 |
50 | try (MqClient mqClient = MqClient.builder()
51 | .region(Region.of(localstack.getRegion()))
52 | .endpointOverride(localstack.getEndpoint())
53 | .credentialsProvider(StaticCredentialsProvider.create(awsCreds))
54 | .build()) {
55 |
56 | User adminUser = User.builder().username("admin").password("admin123456789").build();
57 |
58 | CreateBrokerRequest createBrokerRequest = CreateBrokerRequest.builder()
59 | .brokerName("test-broker")
60 | .engineType(EngineType.ACTIVEMQ)
61 | .engineVersion("5.18")
62 | .hostInstanceType("mq.t3.micro")
63 | .publiclyAccessible(true)
64 | .users(adminUser)
65 | .overrideConfiguration(
66 | AwsRequestOverrideConfiguration.builder().apiCallAttemptTimeout(Duration.ofMinutes(3)).build())
67 | .build();
68 |
69 | CreateBrokerResponse createBrokerResponse = mqClient.createBroker(createBrokerRequest);
70 | String brokerId = createBrokerResponse.brokerId();
71 |
72 | DescribeBrokerRequest describeBrokerRequest = DescribeBrokerRequest.builder().brokerId(brokerId).build();
73 |
74 | await().atMost(Duration.ofMinutes(2)).pollInterval(Duration.ofSeconds(5)).untilAsserted(() -> {
75 | BrokerState brokerState = mqClient.describeBroker(describeBrokerRequest).brokerState();
76 | System.out.println("Broker state: " + brokerState);
77 | assertThat(brokerState).isEqualTo(BrokerState.RUNNING);
78 | });
79 |
80 | String messageContent = "Hello, ActiveMQ!";
81 | given().baseUri("http://%s:%d".formatted(localstack.getHost(), localstack.getMappedPort(4510)))
82 | .auth()
83 | .preemptive()
84 | .basic("admin", "admin")
85 | .queryParam("destination", "queue://test.topic")
86 | .body(messageContent)
87 | .post("/api/message")
88 | .then()
89 | .statusCode(200);
90 |
91 | String brokerEndpoint = "tcp://%s:%d".formatted(localstack.getHost(), localstack.getMappedPort(4511));
92 |
93 | ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("admin", "admin123456789",
94 | brokerEndpoint);
95 |
96 | try (Connection connection = connectionFactory.createConnection()) {
97 | connection.start();
98 | Session session = connection.createSession();
99 | Queue queue = session.createQueue("test.topic");
100 | MessageConsumer consumer = session.createConsumer(queue);
101 |
102 | Message message = consumer.receive(5000);
103 | String receivedContent = ((TextMessage) message).getText();
104 | assertThat(receivedContent).isEqualToIgnoringNewLines(messageContent);
105 |
106 | consumer.close();
107 | session.close();
108 | }
109 | }
110 | }
111 |
112 | }
113 |
--------------------------------------------------------------------------------
/api-gateway/src/test/java/com/example/apigateway/ApiGatewayTests.java:
--------------------------------------------------------------------------------
1 | package com.example.apigateway;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.testcontainers.containers.localstack.LocalStackContainer;
5 | import org.testcontainers.junit.jupiter.Container;
6 | import org.testcontainers.junit.jupiter.Testcontainers;
7 | import org.testcontainers.utility.DockerImageName;
8 | import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
9 | import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
10 | import software.amazon.awssdk.regions.Region;
11 | import software.amazon.awssdk.services.apigateway.ApiGatewayClient;
12 | import software.amazon.awssdk.services.apigateway.model.CreateDeploymentRequest;
13 | import software.amazon.awssdk.services.apigateway.model.CreateResourceRequest;
14 | import software.amazon.awssdk.services.apigateway.model.CreateResourceResponse;
15 | import software.amazon.awssdk.services.apigateway.model.CreateRestApiRequest;
16 | import software.amazon.awssdk.services.apigateway.model.CreateRestApiResponse;
17 | import software.amazon.awssdk.services.apigateway.model.GetResourcesRequest;
18 | import software.amazon.awssdk.services.apigateway.model.GetResourcesResponse;
19 | import software.amazon.awssdk.services.apigateway.model.IntegrationType;
20 | import software.amazon.awssdk.services.apigateway.model.PutIntegrationRequest;
21 | import software.amazon.awssdk.services.apigateway.model.PutIntegrationResponseRequest;
22 | import software.amazon.awssdk.services.apigateway.model.PutMethodRequest;
23 |
24 | import java.util.Collections;
25 |
26 | import static io.restassured.RestAssured.given;
27 | import static org.assertj.core.api.Assertions.assertThat;
28 |
29 | @Testcontainers
30 | class ApiGatewayTests {
31 |
32 | @Container
33 | private static final LocalStackContainer localstack = new LocalStackContainer(
34 | DockerImageName.parse("localstack/localstack:4.12.0"));
35 |
36 | @Test
37 | void test() {
38 | AwsBasicCredentials awsCreds = AwsBasicCredentials.create(localstack.getAccessKey(), localstack.getSecretKey());
39 | try (ApiGatewayClient apiGateway = ApiGatewayClient.builder()
40 | .region(Region.of(localstack.getRegion()))
41 | .endpointOverride(localstack.getEndpoint())
42 | .credentialsProvider(StaticCredentialsProvider.create(awsCreds))
43 | .build()) {
44 |
45 | CreateRestApiRequest createApiRequest = CreateRestApiRequest.builder().name("MyAPI").build();
46 | CreateRestApiResponse createApiResponse = apiGateway.createRestApi(createApiRequest);
47 | String restApiId = createApiResponse.id();
48 |
49 | GetResourcesRequest getResourcesRequest = GetResourcesRequest.builder().restApiId(restApiId).build();
50 | GetResourcesResponse getResourcesResponse = apiGateway.getResources(getResourcesRequest);
51 | String rootResourceId = getResourcesResponse.items().get(0).id();
52 |
53 | CreateResourceRequest createResourceRequest = CreateResourceRequest.builder()
54 | .restApiId(restApiId)
55 | .parentId(rootResourceId)
56 | .pathPart("example")
57 | .build();
58 | CreateResourceResponse createResourceResponse = apiGateway.createResource(createResourceRequest);
59 | String resourceId = createResourceResponse.id();
60 |
61 | PutMethodRequest putMethodRequest = PutMethodRequest.builder()
62 | .restApiId(restApiId)
63 | .resourceId(resourceId)
64 | .httpMethod("GET")
65 | .authorizationType("NONE")
66 | .build();
67 | apiGateway.putMethod(putMethodRequest);
68 |
69 | String requestTemplate = "{ \"statusCode\": 200 }";
70 | PutIntegrationRequest putIntegrationRequest = PutIntegrationRequest.builder()
71 | .restApiId(restApiId)
72 | .resourceId(resourceId)
73 | .httpMethod("GET")
74 | .type(IntegrationType.MOCK)
75 | .requestTemplates(Collections.singletonMap("application/json", requestTemplate))
76 | .build();
77 | apiGateway.putIntegration(putIntegrationRequest);
78 |
79 | String responseTemplate = "{\"message\": \"Hello, $input.params('name')\"}";
80 | PutIntegrationResponseRequest putIntegrationResponseRequest = PutIntegrationResponseRequest.builder()
81 | .restApiId(restApiId)
82 | .resourceId(resourceId)
83 | .httpMethod("GET")
84 | .statusCode("200")
85 | .responseTemplates(Collections.singletonMap("application/json", responseTemplate))
86 | .build();
87 | apiGateway.putIntegrationResponse(putIntegrationResponseRequest);
88 |
89 | CreateDeploymentRequest request = CreateDeploymentRequest.builder()
90 | .restApiId(restApiId)
91 | .stageName("test")
92 | .build();
93 | apiGateway.createDeployment(request);
94 |
95 | String body = given()
96 | .baseUri("http://%s.execute-api.localhost.localstack.cloud:%d".formatted(restApiId,
97 | localstack.getMappedPort(4566)))
98 | .queryParam("name", "World")
99 | .get("/test/example")
100 | .body()
101 | .asString();
102 | assertThat(body).contains("Hello, World");
103 | }
104 | }
105 |
106 | }
107 |
--------------------------------------------------------------------------------
/s3/src/test/java/com/example/s3/S3ApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.example.s3;
2 |
3 | import io.awspring.cloud.s3.S3Template;
4 | import io.awspring.cloud.sqs.annotation.SqsListener;
5 | import org.junit.jupiter.api.BeforeAll;
6 | import org.junit.jupiter.api.Test;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.boot.test.context.SpringBootTest;
9 | import org.springframework.boot.test.context.TestConfiguration;
10 | import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
11 | import org.springframework.context.annotation.Bean;
12 | import org.testcontainers.containers.localstack.LocalStackContainer;
13 | import org.testcontainers.junit.jupiter.Container;
14 | import org.testcontainers.junit.jupiter.Testcontainers;
15 | import org.testcontainers.utility.DockerImageName;
16 | import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
17 | import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
18 | import software.amazon.awssdk.eventnotifications.s3.model.S3EventNotification;
19 | import software.amazon.awssdk.regions.Region;
20 | import software.amazon.awssdk.services.s3.S3Client;
21 | import software.amazon.awssdk.services.s3.model.ListObjectsV2Request;
22 | import software.amazon.awssdk.services.s3.model.ListObjectsV2Response;
23 | import software.amazon.awssdk.services.sqs.SqsClient;
24 |
25 | import java.io.IOException;
26 | import java.util.ArrayList;
27 | import java.util.List;
28 |
29 | import static org.assertj.core.api.Assertions.assertThat;
30 |
31 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
32 | @Testcontainers
33 | class S3ApplicationTests {
34 |
35 | @Container
36 | @ServiceConnection
37 | private static LocalStackContainer localstack = new LocalStackContainer(
38 | DockerImageName.parse("localstack/localstack:4.12.0"));
39 |
40 | @Autowired
41 | private S3Template s3Template;
42 |
43 | @Autowired
44 | private S3Client s3Client;
45 |
46 | @Autowired
47 | private TestListener testListener;
48 |
49 | private static final String POLICY = """
50 | {
51 | "QueueConfigurations": [
52 | {
53 | "QueueArn": "%s",
54 | "Events": ["s3:ObjectCreated:*"]
55 | }
56 | ]
57 | }
58 | """;
59 |
60 | @BeforeAll
61 | static void beforeAll() throws IOException, InterruptedException {
62 | localstack.execInContainer("awslocal", "s3api", "create-bucket", "--bucket", "conferences", "--region",
63 | localstack.getRegion());
64 | try (var sqsClient = SqsClient.builder()
65 | .region(Region.of(localstack.getRegion()))
66 | .credentialsProvider(StaticCredentialsProvider
67 | .create(AwsBasicCredentials.create(localstack.getAccessKey(), localstack.getSecretKey())))
68 | .endpointOverride(localstack.getEndpoint())
69 | .build()) {
70 | var queue = sqsClient.createQueue(builder -> builder.queueName("s3-event-notification-queue"));
71 | var queueAttributes = sqsClient.getQueueAttributes(
72 | builder -> builder.queueUrl(queue.queueUrl()).attributeNamesWithStrings("QueueArn"));
73 | var queueArn = queueAttributes.attributesAsStrings().get("QueueArn");
74 | localstack.execInContainer("awslocal", "s3api", "put-bucket-notification-configuration", "--bucket",
75 | "conferences", "--notification-configuration", String.format(POLICY, queueArn));
76 | }
77 | }
78 |
79 | @Test
80 | void contextLoads() {
81 | assertThat(this.s3Client.listBuckets().buckets()).hasSize(1);
82 |
83 | this.s3Template.store("conferences", "javaone.txt", "Las Vegas");
84 | ListObjectsV2Response listConferencesObjectsV2Response = this.s3Client
85 | .listObjectsV2(ListObjectsV2Request.builder().bucket("conferences").build());
86 | assertThat(listConferencesObjectsV2Response.contents()).hasSize(1);
87 |
88 | this.s3Template.createBucket("talks");
89 | assertThat(this.s3Client.listBuckets().buckets()).hasSize(2);
90 |
91 | this.s3Template.store("talks", "Adopting Testcontainers for local development.txt", "Oleg Šelajev");
92 | ListObjectsV2Response listTalksObjectsV2Response = this.s3Client
93 | .listObjectsV2(ListObjectsV2Request.builder().bucket("talks").build());
94 | assertThat(listTalksObjectsV2Response.contents()).hasSize(1);
95 | assertThat(testListener.messages).hasSize(2);
96 | var s3EventNotification = S3EventNotification.fromJson(testListener.messages.get(1));
97 | assertThat(s3EventNotification.getRecords().getFirst().getEventSource()).isEqualTo("aws:s3");
98 | assertThat(s3EventNotification.getRecords().getFirst().getEventName()).isEqualTo("ObjectCreated:Put");
99 | }
100 |
101 | @TestConfiguration(proxyBeanMethods = false)
102 | static class TestConfig {
103 |
104 | @Bean
105 | TestListener testListener() {
106 | return new TestListener();
107 | }
108 |
109 | }
110 |
111 | static class TestListener {
112 |
113 | private final List messages = new ArrayList<>();
114 |
115 | @SqsListener("s3-event-notification-queue")
116 | void listen(String message) {
117 | this.messages.add(message);
118 | }
119 |
120 | }
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/step-functions/src/test/java/com/example/stepfunctions/StepFunctionsTests.java:
--------------------------------------------------------------------------------
1 | package com.example.stepfunctions;
2 |
3 | import static org.assertj.core.api.Assertions.assertThat;
4 | import static org.awaitility.Awaitility.await;
5 |
6 | import java.time.Duration;
7 | import java.util.HashMap;
8 | import java.util.Map;
9 |
10 | import org.junit.jupiter.api.Test;
11 | import org.testcontainers.containers.localstack.LocalStackContainer;
12 | import org.testcontainers.junit.jupiter.Container;
13 | import org.testcontainers.junit.jupiter.Testcontainers;
14 | import org.testcontainers.utility.DockerImageName;
15 |
16 | import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
17 | import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
18 | import software.amazon.awssdk.regions.Region;
19 | import software.amazon.awssdk.services.iam.IamClient;
20 | import software.amazon.awssdk.services.iam.model.CreateRoleRequest;
21 | import software.amazon.awssdk.services.iam.model.CreateRoleResponse;
22 | import software.amazon.awssdk.services.sfn.SfnClient;
23 | import software.amazon.awssdk.services.sfn.model.CreateStateMachineRequest;
24 | import software.amazon.awssdk.services.sfn.model.CreateStateMachineResponse;
25 | import software.amazon.awssdk.services.sfn.model.DescribeExecutionRequest;
26 | import software.amazon.awssdk.services.sfn.model.DescribeExecutionResponse;
27 | import software.amazon.awssdk.services.sfn.model.ExecutionStatus;
28 | import software.amazon.awssdk.services.sfn.model.StartExecutionRequest;
29 | import software.amazon.awssdk.services.sfn.model.StartExecutionResponse;
30 | import software.amazon.awssdk.services.sfn.model.StateMachineType;
31 |
32 | @Testcontainers
33 | class StepFunctionsTests {
34 |
35 | @Container
36 | static LocalStackContainer localstack = new LocalStackContainer(
37 | DockerImageName.parse("localstack/localstack:4.7.0"));
38 |
39 | @Test
40 | void createAndExecuteStateMachine() throws Exception {
41 | try (SfnClient sfnClient = SfnClient.builder()
42 | .endpointOverride(localstack.getEndpoint())
43 | .credentialsProvider(StaticCredentialsProvider
44 | .create(AwsBasicCredentials.create(localstack.getAccessKey(), localstack.getSecretKey())))
45 | .region(Region.of(localstack.getRegion()))
46 | .build()) {
47 |
48 | String roleArn = createIamRole();
49 |
50 | String stateMachineDefinition = """
51 | {
52 | "Comment": "A Hello World example",
53 | "StartAt": "HelloWorld",
54 | "States": {
55 | "HelloWorld": {
56 | "Type": "Pass",
57 | "Result": "Hello World!",
58 | "End": true
59 | }
60 | }
61 | }
62 | """;
63 |
64 | CreateStateMachineRequest createRequest = CreateStateMachineRequest.builder()
65 | .name("HelloWorldStateMachine")
66 | .definition(stateMachineDefinition)
67 | .roleArn(roleArn)
68 | .type(StateMachineType.STANDARD)
69 | .build();
70 |
71 | CreateStateMachineResponse createResponse = sfnClient.createStateMachine(createRequest);
72 | assertThat(createResponse.stateMachineArn()).isNotNull();
73 |
74 | Map input = new HashMap<>();
75 | input.put("name", "World");
76 |
77 | StartExecutionRequest startRequest = StartExecutionRequest.builder()
78 | .stateMachineArn(createResponse.stateMachineArn())
79 | .name("test-execution")
80 | .input("{\"name\": \"World\"}")
81 | .build();
82 |
83 | StartExecutionResponse startResponse = sfnClient.startExecution(startRequest);
84 | assertThat(startResponse.executionArn()).isNotNull();
85 |
86 | await().atMost(Duration.ofSeconds(30)).pollInterval(Duration.ofSeconds(1)).until(() -> {
87 | DescribeExecutionResponse execution = sfnClient.describeExecution(
88 | DescribeExecutionRequest.builder().executionArn(startResponse.executionArn()).build());
89 | return execution.status() == ExecutionStatus.SUCCEEDED;
90 | });
91 |
92 | DescribeExecutionResponse finalExecution = sfnClient.describeExecution(
93 | DescribeExecutionRequest.builder().executionArn(startResponse.executionArn()).build());
94 |
95 | assertThat(finalExecution.status()).isEqualTo(ExecutionStatus.SUCCEEDED);
96 | assertThat(finalExecution.output()).isEqualTo("\"Hello World!\"");
97 | }
98 | }
99 |
100 | private String createIamRole() {
101 | try (IamClient iamClient = IamClient.builder()
102 | .endpointOverride(localstack.getEndpoint())
103 | .credentialsProvider(StaticCredentialsProvider
104 | .create(AwsBasicCredentials.create(localstack.getAccessKey(), localstack.getSecretKey())))
105 | .region(Region.of(localstack.getRegion()))
106 | .build()) {
107 |
108 | String trustPolicy = """
109 | {
110 | "Version": "2012-10-17",
111 | "Statement": [
112 | {
113 | "Effect": "Allow",
114 | "Principal": {
115 | "Service": "states.amazonaws.com"
116 | },
117 | "Action": "sts:AssumeRole"
118 | }
119 | ]
120 | }
121 | """;
122 |
123 | CreateRoleRequest roleRequest = CreateRoleRequest.builder()
124 | .roleName("StepFunctionsRole")
125 | .assumeRolePolicyDocument(trustPolicy)
126 | .build();
127 |
128 | CreateRoleResponse roleResponse = iamClient.createRole(roleRequest);
129 | return roleResponse.role().arn();
130 | }
131 | }
132 |
133 | }
--------------------------------------------------------------------------------
/lambda/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 3.5.9
9 |
10 |
11 | com.example
12 | lambda
13 | 0.0.1-SNAPSHOT
14 | lambda
15 | Demo project for Spring Boot
16 |
17 | 25
18 | 2025.0.0-RC1
19 | 1.0.29.RELEASE
20 | 2.39.3
21 | 1.21.4
22 |
23 |
24 |
25 | org.springframework.boot
26 | spring-boot-starter
27 |
28 |
29 | org.springframework.cloud
30 | spring-cloud-function-adapter-aws
31 |
32 |
33 | org.springframework.boot
34 | spring-boot-starter-data-jdbc
35 |
36 |
37 | org.flywaydb
38 | flyway-core
39 |
40 |
41 | org.flywaydb
42 | flyway-database-postgresql
43 |
44 |
45 |
46 | org.postgresql
47 | postgresql
48 | runtime
49 |
50 |
51 | org.springframework.boot
52 | spring-boot-starter-test
53 | test
54 |
55 |
56 | org.testcontainers
57 | junit-jupiter
58 | test
59 |
60 |
61 | org.testcontainers
62 | localstack
63 | test
64 |
65 |
66 | org.testcontainers
67 | postgresql
68 | test
69 |
70 |
71 | software.amazon.awssdk
72 | lambda
73 |
74 |
75 | org.apache.maven.shared
76 | maven-invoker
77 | 3.2.0
78 | test
79 |
80 |
81 | io.rest-assured
82 | rest-assured
83 | test
84 |
85 |
86 |
87 |
88 |
89 | org.springframework.cloud
90 | spring-cloud-dependencies
91 | ${spring-cloud.version}
92 | pom
93 | import
94 |
95 |
96 | software.amazon.awssdk
97 | bom
98 | ${aws.java.sdk.version}
99 | pom
100 | import
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 | org.apache.maven.plugins
109 | maven-deploy-plugin
110 |
111 | true
112 |
113 |
114 |
115 | org.springframework.boot
116 | spring-boot-maven-plugin
117 |
118 |
119 | org.springframework.boot.experimental
120 | spring-boot-thin-layout
121 | 1.0.29.RELEASE
122 |
123 |
124 |
125 |
126 | org.apache.maven.plugins
127 | maven-shade-plugin
128 | 3.2.4
129 |
130 | false
131 | true
132 | aws
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 | spring-milestones
141 | Spring Milestones
142 | https://repo.spring.io/milestone
143 |
144 | false
145 |
146 |
147 |
148 |
149 |
150 | spring-milestones
151 | Spring Milestones
152 | https://repo.spring.io/milestone
153 |
154 | false
155 |
156 |
157 |
158 |
159 |
160 |
--------------------------------------------------------------------------------
/lambda/src/test/java/com/example/springcloudfunctionaws/SpringCloudFunctionAwsApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.example.springcloudfunctionaws;
2 |
3 | import io.restassured.RestAssured;
4 | import org.apache.commons.io.FileUtils;
5 | import org.apache.maven.shared.invoker.DefaultInvocationRequest;
6 | import org.apache.maven.shared.invoker.DefaultInvoker;
7 | import org.apache.maven.shared.invoker.MavenInvocationException;
8 | import org.junit.jupiter.api.Test;
9 | import org.springframework.util.StringUtils;
10 | import org.testcontainers.containers.Network;
11 | import org.testcontainers.containers.PostgreSQLContainer;
12 | import org.testcontainers.containers.localstack.LocalStackContainer;
13 | import org.testcontainers.junit.jupiter.Container;
14 | import org.testcontainers.junit.jupiter.Testcontainers;
15 | import org.testcontainers.utility.DockerImageName;
16 | import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
17 | import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
18 | import software.amazon.awssdk.core.SdkBytes;
19 | import software.amazon.awssdk.regions.Region;
20 | import software.amazon.awssdk.services.lambda.LambdaClient;
21 | import software.amazon.awssdk.services.lambda.model.CreateFunctionRequest;
22 | import software.amazon.awssdk.services.lambda.model.CreateFunctionUrlConfigRequest;
23 | import software.amazon.awssdk.services.lambda.model.Environment;
24 | import software.amazon.awssdk.services.lambda.model.FunctionCode;
25 | import software.amazon.awssdk.services.lambda.model.FunctionUrlAuthType;
26 | import software.amazon.awssdk.services.lambda.model.GetFunctionConfigurationRequest;
27 | import software.amazon.awssdk.services.lambda.model.PackageType;
28 | import software.amazon.awssdk.services.lambda.model.Runtime;
29 |
30 | import java.io.File;
31 | import java.io.IOException;
32 | import java.nio.file.Paths;
33 | import java.util.List;
34 | import java.util.Map;
35 | import java.util.Properties;
36 |
37 | import static org.assertj.core.api.Assertions.assertThat;
38 |
39 | @Testcontainers
40 | class SpringCloudFunctionAwsApplicationTests {
41 |
42 | static String jar = buildJar();
43 |
44 | static Network network = Network.newNetwork();
45 |
46 | @Container
47 | static PostgreSQLContainer> postgres = new PostgreSQLContainer<>("postgres:15-alpine").withNetwork(network)
48 | .withNetworkAliases("postgres");
49 |
50 | @Container
51 | static LocalStackContainer localstack = new LocalStackContainer(
52 | DockerImageName.parse("localstack/localstack:4.12.0"))
53 | .withNetwork(network)
54 | .withEnv("LOCALSTACK_HOST", "localhost.localstack.cloud")
55 | .withEnv("LAMBDA_DOCKER_NETWORK", ((Network.NetworkImpl) network).getName())
56 | .withNetworkAliases("localstack");
57 |
58 | static String buildJar() {
59 | try {
60 | var properties = new Properties();
61 | properties.setProperty("skipTests", "true");
62 |
63 | var defaultInvocationRequest = new DefaultInvocationRequest();
64 | if (StringUtils.hasText(System.getenv("MAVEN_HOME"))) {
65 | defaultInvocationRequest.setMavenHome(new File(System.getenv("MAVEN_HOME")));
66 | }
67 | defaultInvocationRequest.setJavaHome(new File(System.getenv("JAVA_HOME")));
68 | defaultInvocationRequest.setPomFile(Paths.get("pom.xml").toFile());
69 | defaultInvocationRequest.setGoals(List.of("package"));
70 | defaultInvocationRequest.setProperties(properties);
71 | var appInvoker = new DefaultInvoker();
72 | appInvoker.execute(defaultInvocationRequest);
73 | }
74 | catch (MavenInvocationException e) {
75 | throw new RuntimeException("Could not build jar", e);
76 | }
77 | return "target/lambda-0.0.1-SNAPSHOT-aws.jar";
78 | }
79 |
80 | @Test
81 | void contextLoads() throws IOException {
82 | // Setup for lambda
83 | var fnName = "uppercase-fn";
84 | var envVars = Map.ofEntries(Map.entry("SPRING_DATASOURCE_URL", "jdbc:postgresql://postgres:5432/test"),
85 | Map.entry("SPRING_DATASOURCE_USERNAME", "test"), Map.entry("SPRING_DATASOURCE_PASSWORD", "test"));
86 | var createFunctionRequest = CreateFunctionRequest.builder()
87 | .functionName(fnName)
88 | .runtime(Runtime.JAVA25)
89 | .role("arn:aws:iam::123456789012:role/irrelevant")
90 | .packageType(PackageType.ZIP)
91 | .code(FunctionCode.builder()
92 | .zipFile(SdkBytes.fromByteArray(FileUtils.readFileToByteArray(new File(jar))))
93 | .build())
94 | .timeout(10)
95 | .handler("org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest")
96 | .environment(Environment.builder().variables(envVars).build())
97 | .build();
98 |
99 | // Lambda client pointing to LocalStack
100 | try (var lambdaClient = LambdaClient.builder()
101 | .region(Region.of(localstack.getRegion()))
102 | .credentialsProvider(StaticCredentialsProvider
103 | .create(AwsBasicCredentials.create(localstack.getAccessKey(), localstack.getSecretKey())))
104 | .endpointOverride(localstack.getEndpoint())
105 | .build()) {
106 |
107 | // Create a function and wait for it to be active
108 | var createFunctionResponse = lambdaClient.createFunction(createFunctionRequest);
109 | var waiterResponse = lambdaClient.waiter()
110 | .waitUntilFunctionActive(GetFunctionConfigurationRequest.builder().functionName(fnName).build());
111 |
112 | // Create a URL for the function and replace it 4566 by the random port
113 | var createFunctionUrlConfigRequest = CreateFunctionUrlConfigRequest.builder()
114 | .functionName(fnName)
115 | .authType(FunctionUrlAuthType.NONE)
116 | .build();
117 | var createFunctionUrlConfigResponse = lambdaClient.createFunctionUrlConfig(createFunctionUrlConfigRequest);
118 | var functionUrl = createFunctionUrlConfigResponse.functionUrl()
119 | .replace("" + 4566, "" + localstack.getMappedPort(4566));
120 |
121 | // Test the function
122 | var body = RestAssured.given().body("""
123 | {"name": "profile"}
124 | """).get(functionUrl).prettyPeek().andReturn().body();
125 | assertThat(body.asString()).isEqualTo("4");
126 | }
127 | }
128 |
129 | }
130 |
--------------------------------------------------------------------------------
/cognito/src/test/java/com/example/cognito/CognitoApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.example.cognito;
2 |
3 | import org.junit.jupiter.api.BeforeAll;
4 | import org.junit.jupiter.api.Test;
5 | import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
6 | import org.springframework.boot.test.context.SpringBootTest;
7 | import org.springframework.boot.test.web.server.LocalServerPort;
8 | import org.springframework.http.HttpStatus;
9 | import org.springframework.test.context.DynamicPropertyRegistry;
10 | import org.springframework.test.context.DynamicPropertySource;
11 | import org.springframework.web.client.HttpClientErrorException;
12 | import org.springframework.web.client.RestClient;
13 | import org.testcontainers.containers.localstack.LocalStackContainer;
14 | import org.testcontainers.junit.jupiter.Container;
15 | import org.testcontainers.junit.jupiter.Testcontainers;
16 | import org.testcontainers.utility.DockerImageName;
17 | import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
18 | import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
19 | import software.amazon.awssdk.regions.Region;
20 | import software.amazon.awssdk.services.cognitoidentityprovider.CognitoIdentityProviderClient;
21 | import software.amazon.awssdk.services.cognitoidentityprovider.model.AdminCreateUserRequest;
22 | import software.amazon.awssdk.services.cognitoidentityprovider.model.AdminResetUserPasswordRequest;
23 | import software.amazon.awssdk.services.cognitoidentityprovider.model.AdminSetUserPasswordRequest;
24 | import software.amazon.awssdk.services.cognitoidentityprovider.model.AttributeType;
25 | import software.amazon.awssdk.services.cognitoidentityprovider.model.AuthFlowType;
26 | import software.amazon.awssdk.services.cognitoidentityprovider.model.CreateUserPoolClientRequest;
27 | import software.amazon.awssdk.services.cognitoidentityprovider.model.CreateUserPoolRequest;
28 | import software.amazon.awssdk.services.cognitoidentityprovider.model.InitiateAuthRequest;
29 |
30 | import java.util.Map;
31 |
32 | import static org.assertj.core.api.Assertions.assertThat;
33 | import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
34 |
35 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
36 | @Testcontainers
37 | @EnabledIfEnvironmentVariable(named = "LOCALSTACK_AUTH_TOKEN", matches = ".+")
38 | class CognitoApplicationTests {
39 |
40 | @Container
41 | private static final LocalStackContainer localstack = new LocalStackContainer(
42 | DockerImageName.parse("localstack/localstack-pro:4.12.0"))
43 | .withEnv("SERVICES", "cognito-idp")
44 | .withEnv("LOCALSTACK_AUTH_TOKEN", System.getenv("LOCALSTACK_AUTH_TOKEN"));
45 |
46 | private static String userPoolId;
47 |
48 | private static String appClientId;
49 |
50 | private static String accessToken;
51 |
52 | @LocalServerPort
53 | private int port;
54 |
55 | @BeforeAll
56 | static void beforeAll() {
57 | var credentialsProvider = StaticCredentialsProvider
58 | .create(AwsBasicCredentials.create(localstack.getAccessKey(), localstack.getSecretKey()));
59 | try (var cognitoClient = CognitoIdentityProviderClient.builder()
60 | .credentialsProvider(credentialsProvider)
61 | .region(Region.of(localstack.getRegion()))
62 | .endpointOverride(localstack.getEndpoint())
63 | .build()) {
64 |
65 | var userPoolResponse = cognitoClient
66 | .createUserPool(CreateUserPoolRequest.builder().poolName("awspring-test").build());
67 | userPoolId = userPoolResponse.userPool().id();
68 |
69 | var userPoolClientResponse = cognitoClient.createUserPoolClient(CreateUserPoolClientRequest.builder()
70 | .clientName("awspring-test-client")
71 | .userPoolId(userPoolId)
72 | .build());
73 | appClientId = userPoolClientResponse.userPoolClient().clientId();
74 |
75 | cognitoClient.adminCreateUser(AdminCreateUserRequest.builder()
76 | .userPoolId(userPoolId)
77 | .username("testuser@test.com")
78 | .temporaryPassword("testP@ssw0rd")
79 | .userAttributes(AttributeType.builder().name("email").value("testuser@test.com").build(),
80 | AttributeType.builder().name("email_verified").value("true").build())
81 | .build());
82 |
83 | cognitoClient.adminResetUserPassword(AdminResetUserPasswordRequest.builder()
84 | .username("testuser@test.com")
85 | .userPoolId(userPoolId)
86 | .build());
87 |
88 | cognitoClient.adminSetUserPassword(AdminSetUserPasswordRequest.builder()
89 | .username("testuser@test.com")
90 | .password("testP4ssw*rd")
91 | .userPoolId(userPoolId)
92 | .permanent(Boolean.TRUE)
93 | .build());
94 |
95 | var initiateAuthResponse = cognitoClient.initiateAuth(InitiateAuthRequest.builder()
96 | .authFlow(AuthFlowType.USER_PASSWORD_AUTH)
97 | .clientId(appClientId)
98 | .authParameters(Map.of("USERNAME", "testuser@test.com", "PASSWORD", "testP4ssw*rd"))
99 | .build());
100 | accessToken = initiateAuthResponse.authenticationResult().accessToken();
101 | }
102 | }
103 |
104 | @DynamicPropertySource
105 | static void dynamicProperties(DynamicPropertyRegistry registry) {
106 | // registry.add("spring.security.oauth2.resourceserver.jwt.issuer-uri", () ->
107 | // localstack.getEndpoint() + "/" + userPoolId);
108 | registry.add("spring.security.oauth2.resourceserver.jwt.jwk-set-uri",
109 | () -> localstack.getEndpoint() + "/" + userPoolId + "/.well-known/jwks.json");
110 | }
111 |
112 | @Test
113 | void contextLoads() {
114 | var appBaseUrl = "http://localhost:" + this.port;
115 |
116 | var restClient = RestClient.builder().baseUrl(appBaseUrl).build();
117 |
118 | var unsecuredResponse = restClient.get().uri(appBaseUrl).retrieve().toBodilessEntity();
119 | assertThat(unsecuredResponse.getStatusCode()).isEqualTo(HttpStatus.OK);
120 |
121 | assertThatExceptionOfType(HttpClientErrorException.Unauthorized.class)
122 | .isThrownBy(() -> restClient.get().uri("/topsecret").retrieve().toBodilessEntity());
123 |
124 | var securedResponse = restClient.get()
125 | .uri("/topsecret")
126 | .headers(h -> h.setBearerAuth(accessToken))
127 | .retrieve()
128 | .toBodilessEntity();
129 | assertThat(securedResponse.getStatusCode()).isEqualTo(HttpStatus.OK);
130 | }
131 |
132 | }
133 |
--------------------------------------------------------------------------------
/mvnw.cmd:
--------------------------------------------------------------------------------
1 | <# : batch portion
2 | @REM ----------------------------------------------------------------------------
3 | @REM Licensed to the Apache Software Foundation (ASF) under one
4 | @REM or more contributor license agreements. See the NOTICE file
5 | @REM distributed with this work for additional information
6 | @REM regarding copyright ownership. The ASF licenses this file
7 | @REM to you under the Apache License, Version 2.0 (the
8 | @REM "License"); you may not use this file except in compliance
9 | @REM with the License. You may obtain a copy of the License at
10 | @REM
11 | @REM http://www.apache.org/licenses/LICENSE-2.0
12 | @REM
13 | @REM Unless required by applicable law or agreed to in writing,
14 | @REM software distributed under the License is distributed on an
15 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | @REM KIND, either express or implied. See the License for the
17 | @REM specific language governing permissions and limitations
18 | @REM under the License.
19 | @REM ----------------------------------------------------------------------------
20 |
21 | @REM ----------------------------------------------------------------------------
22 | @REM Apache Maven Wrapper startup batch script, version 3.3.2
23 | @REM
24 | @REM Optional ENV vars
25 | @REM MVNW_REPOURL - repo url base for downloading maven distribution
26 | @REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
27 | @REM MVNW_VERBOSE - true: enable verbose log; others: silence the output
28 | @REM ----------------------------------------------------------------------------
29 |
30 | @IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0)
31 | @SET __MVNW_CMD__=
32 | @SET __MVNW_ERROR__=
33 | @SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
34 | @SET PSModulePath=
35 | @FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
36 | IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
37 | )
38 | @SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
39 | @SET __MVNW_PSMODULEP_SAVE=
40 | @SET __MVNW_ARG0_NAME__=
41 | @SET MVNW_USERNAME=
42 | @SET MVNW_PASSWORD=
43 | @IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*)
44 | @echo Cannot start maven from wrapper >&2 && exit /b 1
45 | @GOTO :EOF
46 | : end batch / begin powershell #>
47 |
48 | $ErrorActionPreference = "Stop"
49 | if ($env:MVNW_VERBOSE -eq "true") {
50 | $VerbosePreference = "Continue"
51 | }
52 |
53 | # calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
54 | $distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
55 | if (!$distributionUrl) {
56 | Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
57 | }
58 |
59 | switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {
60 | "maven-mvnd-*" {
61 | $USE_MVND = $true
62 | $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
63 | $MVN_CMD = "mvnd.cmd"
64 | break
65 | }
66 | default {
67 | $USE_MVND = $false
68 | $MVN_CMD = $script -replace '^mvnw','mvn'
69 | break
70 | }
71 | }
72 |
73 | # apply MVNW_REPOURL and calculate MAVEN_HOME
74 | # maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/
75 | if ($env:MVNW_REPOURL) {
76 | $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" }
77 | $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')"
78 | }
79 | $distributionUrlName = $distributionUrl -replace '^.*/',''
80 | $distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
81 | $MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain"
82 | if ($env:MAVEN_USER_HOME) {
83 | $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain"
84 | }
85 | $MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
86 | $MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"
87 |
88 | if (Test-Path -Path "$MAVEN_HOME" -PathType Container) {
89 | Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME"
90 | Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
91 | exit $?
92 | }
93 |
94 | if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {
95 | Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl"
96 | }
97 |
98 | # prepare tmp dir
99 | $TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile
100 | $TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir"
101 | $TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null
102 | trap {
103 | if ($TMP_DOWNLOAD_DIR.Exists) {
104 | try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
105 | catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
106 | }
107 | }
108 |
109 | New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null
110 |
111 | # Download and Install Apache Maven
112 | Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
113 | Write-Verbose "Downloading from: $distributionUrl"
114 | Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
115 |
116 | $webclient = New-Object System.Net.WebClient
117 | if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
118 | $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
119 | }
120 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
121 | $webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
122 |
123 | # If specified, validate the SHA-256 sum of the Maven distribution zip file
124 | $distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
125 | if ($distributionSha256Sum) {
126 | if ($USE_MVND) {
127 | Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
128 | }
129 | Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
130 | if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
131 | Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property."
132 | }
133 | }
134 |
135 | # unzip and move
136 | Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
137 | Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null
138 | try {
139 | Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
140 | } catch {
141 | if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
142 | Write-Error "fail to move MAVEN_HOME"
143 | }
144 | } finally {
145 | try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
146 | catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
147 | }
148 |
149 | Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
150 |
--------------------------------------------------------------------------------
/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 | # Apache Maven Wrapper startup batch script, version 3.3.2
23 | #
24 | # Optional ENV vars
25 | # -----------------
26 | # JAVA_HOME - location of a JDK home dir, required when download maven via java source
27 | # MVNW_REPOURL - repo url base for downloading maven distribution
28 | # MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
29 | # MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output
30 | # ----------------------------------------------------------------------------
31 |
32 | set -euf
33 | [ "${MVNW_VERBOSE-}" != debug ] || set -x
34 |
35 | # OS specific support.
36 | native_path() { printf %s\\n "$1"; }
37 | case "$(uname)" in
38 | CYGWIN* | MINGW*)
39 | [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")"
40 | native_path() { cygpath --path --windows "$1"; }
41 | ;;
42 | esac
43 |
44 | # set JAVACMD and JAVACCMD
45 | set_java_home() {
46 | # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched
47 | if [ -n "${JAVA_HOME-}" ]; then
48 | if [ -x "$JAVA_HOME/jre/sh/java" ]; then
49 | # IBM's JDK on AIX uses strange locations for the executables
50 | JAVACMD="$JAVA_HOME/jre/sh/java"
51 | JAVACCMD="$JAVA_HOME/jre/sh/javac"
52 | else
53 | JAVACMD="$JAVA_HOME/bin/java"
54 | JAVACCMD="$JAVA_HOME/bin/javac"
55 |
56 | if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then
57 | echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2
58 | echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2
59 | return 1
60 | fi
61 | fi
62 | else
63 | JAVACMD="$(
64 | 'set' +e
65 | 'unset' -f command 2>/dev/null
66 | 'command' -v java
67 | )" || :
68 | JAVACCMD="$(
69 | 'set' +e
70 | 'unset' -f command 2>/dev/null
71 | 'command' -v javac
72 | )" || :
73 |
74 | if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then
75 | echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2
76 | return 1
77 | fi
78 | fi
79 | }
80 |
81 | # hash string like Java String::hashCode
82 | hash_string() {
83 | str="${1:-}" h=0
84 | while [ -n "$str" ]; do
85 | char="${str%"${str#?}"}"
86 | h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296))
87 | str="${str#?}"
88 | done
89 | printf %x\\n $h
90 | }
91 |
92 | verbose() { :; }
93 | [ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; }
94 |
95 | die() {
96 | printf %s\\n "$1" >&2
97 | exit 1
98 | }
99 |
100 | trim() {
101 | # MWRAPPER-139:
102 | # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.
103 | # Needed for removing poorly interpreted newline sequences when running in more
104 | # exotic environments such as mingw bash on Windows.
105 | printf "%s" "${1}" | tr -d '[:space:]'
106 | }
107 |
108 | # parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties
109 | while IFS="=" read -r key value; do
110 | case "${key-}" in
111 | distributionUrl) distributionUrl=$(trim "${value-}") ;;
112 | distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;;
113 | esac
114 | done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties"
115 | [ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties"
116 |
117 | case "${distributionUrl##*/}" in
118 | maven-mvnd-*bin.*)
119 | MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/
120 | case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in
121 | *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;
122 | :Darwin*x86_64) distributionPlatform=darwin-amd64 ;;
123 | :Darwin*arm64) distributionPlatform=darwin-aarch64 ;;
124 | :Linux*x86_64*) distributionPlatform=linux-amd64 ;;
125 | *)
126 | echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2
127 | distributionPlatform=linux-amd64
128 | ;;
129 | esac
130 | distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip"
131 | ;;
132 | maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;
133 | *) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
134 | esac
135 |
136 | # apply MVNW_REPOURL and calculate MAVEN_HOME
137 | # maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/
138 | [ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}"
139 | distributionUrlName="${distributionUrl##*/}"
140 | distributionUrlNameMain="${distributionUrlName%.*}"
141 | distributionUrlNameMain="${distributionUrlNameMain%-bin}"
142 | MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}"
143 | MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")"
144 |
145 | exec_maven() {
146 | unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :
147 | exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD"
148 | }
149 |
150 | if [ -d "$MAVEN_HOME" ]; then
151 | verbose "found existing MAVEN_HOME at $MAVEN_HOME"
152 | exec_maven "$@"
153 | fi
154 |
155 | case "${distributionUrl-}" in
156 | *?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;
157 | *) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;;
158 | esac
159 |
160 | # prepare tmp dir
161 | if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then
162 | clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; }
163 | trap clean HUP INT TERM EXIT
164 | else
165 | die "cannot create temp dir"
166 | fi
167 |
168 | mkdir -p -- "${MAVEN_HOME%/*}"
169 |
170 | # Download and Install Apache Maven
171 | verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
172 | verbose "Downloading from: $distributionUrl"
173 | verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
174 |
175 | # select .zip or .tar.gz
176 | if ! command -v unzip >/dev/null; then
177 | distributionUrl="${distributionUrl%.zip}.tar.gz"
178 | distributionUrlName="${distributionUrl##*/}"
179 | fi
180 |
181 | # verbose opt
182 | __MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''
183 | [ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v
184 |
185 | # normalize http auth
186 | case "${MVNW_PASSWORD:+has-password}" in
187 | '') MVNW_USERNAME='' MVNW_PASSWORD='' ;;
188 | has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;
189 | esac
190 |
191 | if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then
192 | verbose "Found wget ... using wget"
193 | wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl"
194 | elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then
195 | verbose "Found curl ... using curl"
196 | curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl"
197 | elif set_java_home; then
198 | verbose "Falling back to use Java to download"
199 | javaSource="$TMP_DOWNLOAD_DIR/Downloader.java"
200 | targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName"
201 | cat >"$javaSource" <<-END
202 | public class Downloader extends java.net.Authenticator
203 | {
204 | protected java.net.PasswordAuthentication getPasswordAuthentication()
205 | {
206 | return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() );
207 | }
208 | public static void main( String[] args ) throws Exception
209 | {
210 | setDefault( new Downloader() );
211 | java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
212 | }
213 | }
214 | END
215 | # For Cygwin/MinGW, switch paths to Windows format before running javac and java
216 | verbose " - Compiling Downloader.java ..."
217 | "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java"
218 | verbose " - Running Downloader.java ..."
219 | "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")"
220 | fi
221 |
222 | # If specified, validate the SHA-256 sum of the Maven distribution zip file
223 | if [ -n "${distributionSha256Sum-}" ]; then
224 | distributionSha256Result=false
225 | if [ "$MVN_CMD" = mvnd.sh ]; then
226 | echo "Checksum validation is not supported for maven-mvnd." >&2
227 | echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
228 | exit 1
229 | elif command -v sha256sum >/dev/null; then
230 | if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then
231 | distributionSha256Result=true
232 | fi
233 | elif command -v shasum >/dev/null; then
234 | if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then
235 | distributionSha256Result=true
236 | fi
237 | else
238 | echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
239 | echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
240 | exit 1
241 | fi
242 | if [ $distributionSha256Result = false ]; then
243 | echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2
244 | echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2
245 | exit 1
246 | fi
247 | fi
248 |
249 | # unzip and move
250 | if command -v unzip >/dev/null; then
251 | unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip"
252 | else
253 | tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar"
254 | fi
255 | printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url"
256 | mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME"
257 |
258 | clean || :
259 | exec_maven "$@"
260 |
--------------------------------------------------------------------------------