Spring Boot DynamoDB Integration Test using Testcontainers

Spring Boot DynamoDB Integration Tests using TestContainers

1. Overview

Spring Boot Webflux DynamoDB Integration tests – In this tutorial we will see how to setup integration test for a Spring Boot Webflux project with DynamoDB using Testcontainers. This post will use the example from previous Spring Boot Webflux DynamoDB tutorial. Let us add integration tests using Testcontainers and integrate DynamoDB tests with our Spring Boot project.

2. What is Testcontainers?

Testcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.

The key here is Docker containers. It allows us to use any Docker image and run it as container within our integration tests. There are number of standard Testcontainers available to test integration with technologies such as Elastic search, Kafka, RabbitMQ etc. We can also use any Docker container using Testcontainers GenericContainer api.

One key thing to remember while using Testcontainers is that local Docker installation is required to run these test cases. If you are running your integration tests in continues integration (CI) pipelines, remember to use machine instance instead of docker. As Testcontainers need Docker to run, we cannot run it inside a Docker container in CI. Usually all the standard CI platforms such as Circle CI do provides machine instance where you can run your integration tests.

3. Spring Boot DynamoDB Integration Tests using Testcontainers

3.1 Gradle test dependencies

Add following dependencies for Testcontainers and Junit support for Testcontainers.

build.gradle

testCompile "org.testcontainers:testcontainers:1.14.1"
testCompile "org.testcontainers:junit-jupiter:1.14.1"

Or if you are using Maven, add following test dependencies.

pom.xml

<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>testcontainers</artifactId>
    <version>1.14.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>1.14.1</version>
    <scope>test</scope>
</dependency>

3.2 Define DynamoDB Docker @Container

Once the dependencies are defined, we can start using the Testcontainers in JUnit. First thing is to define a GenericContainer object with official docker image of DynamoDB amazon/dynamodb-local. The withExposedPorts() method defines the port where DynamoDB will be listening to inside the Docker container. The GenericContainer object is annotated with @Container annotation. This annotation works in conjunction with @Testcontainers annotation to mark containers that should be managed by the Testcontainers extension.

private static final int DYNAMODB_PORT = 8000;

@Container
public static GenericContainer dynamodb =
        new GenericContainer<>("amazon/dynamodb-local")
            .withExposedPorts(DYNAMODB_PORT);

Testcontainers will start the Docker container with DynamoDB on the given DYNAMO_PORT 8000, however that will be the internal port which we need to map to actual random port which the AWS DynamoDB client from Spring Boot app can connect to.

Since our Spring Boot app connects to DynamoDB on the host and port defined under application.dynamodb.endpoint config in application.yaml file, for the test case we need to override this config at runtime to point to actual host and port where Docker is running.

To achieve this we are using ApplicationContextInitializer to override the application.dynamodb.endpoint property. We are using GenericContainer‘s getContainerIpAddress and getMappedPort method to get the ip address and actual port number of DynamoDB running inside Docker.

public static class DynamoDBInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialise(ConfigurableApplicationContext ctx) {

        TestPropertyValues.of(
                String.format("application.dynamodb.endpoint: http://%s:%s",
                    dynamodb.getContainerIpAddress(), dynamodb.getMappedPort(DYNAMODB_PORT)))
                .applyTo(ctx);
    }
}

3.3 End to end integration test

In following RoutesTests, we have one testcase that creates a blank table customers and then uses Spring’s WebTestClient to call POST /customers API. The testcase checks the response from API. Since this is an integration test, the whole service is booted and the customer record is created in DynamoDB database using Testcontainers.

RoutesTests.java

package net.viralpatel.springbootwebfluxdynamodb;

import net.viralpatel.springbootwebfluxdynamodb.customer.Customer;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import reactor.core.publisher.Mono;
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
import software.amazon.awssdk.services.dynamodb.model.*;

import java.util.concurrent.CompletableFuture;

import static org.hamcrest.Matchers.*;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Testcontainers
@ContextConfiguration(initializers = RoutesTests.DynamoDBInitializer.class)
public class RoutesTests {

    private static final int DYNAMODB_PORT = 8000;

    @Autowired
    DynamoDbAsyncClient dynamoDbAsyncClient;

    @Container
    public static GenericContainer dynamodb =
            new GenericContainer<>("amazon/dynamodb-local:latest")
                .withExposedPorts(DYNAMODB_PORT);

    public static class DynamoDBInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
        @Override
        public void initialize(ConfigurableApplicationContext ctx) {

            TestPropertyValues.of(
                    String.format("application.dynamodb.endpoint: http://%s:%s",
                        dynamodb.getContainerIpAddress(), dynamodb.getMappedPort(DYNAMODB_PORT)))
                    .applyTo(ctx);
        }
    }

    @Autowired
    public WebTestClient webTestClient;

    @Test
    public void shouldCreateCustomerWhenCustomerAPIInvoked() {

        // Create customers table in DynamoDB
        CompletableFuture<CreateTableResponse> createTable = dynamoDbAsyncClient.createTable(CreateTableRequest.builder()
                .tableName("customers")
                .attributeDefinitions(AttributeDefinition.builder().attributeName("customerId").attributeType("S").build())
                .keySchema(KeySchemaElement.builder().attributeName("customerId").keyType(KeyType.HASH).build())
                .provisionedThroughput(ProvisionedThroughput.builder().readCapacityUnits(5l).writeCapacityUnits(5l).build())
                .build());

        Mono.fromFuture(createTable).block();

        Customer customer = new Customer();
        customer.setName("John");
        customer.setCity("Sydney");
        customer.setEmail("john@example.com");

        webTestClient
                .post()
                .uri("/customers")
                .bodyValue(customer)
                .exchange()
                .expectStatus().is2xxSuccessful()
                .expectHeader().value("Location", is(not(blankOrNullString())));
    }
}

Let us go through the above code step by step and see what is going on.

@SpringBootTest – Specify that the test case is an integration test. Spring should load the full application context and make all beans available to the test case.

@Testcontainers – It is a JUnit Jupiter extension to activate automatic startup and stop of containers used in a test case. The test containers extension finds all fields that are annotated with Container and calls their container lifecycle methods. Containers declared as static fields will be shared between test methods. They will be started only once before any test method is executed and stopped after the last test method has executed. Containers declared as instance fields will be started and stopped for every test method.

@ContextConfiguration – It overrides the Spring properties. We use it to override the host and port of DynamoDB where our DynamoDB client connects. The DynamoDBInitializer static class defined within the test case override this property. We can move this logic into an abstract class and reuse it across multiple tests.

4. Gotchas / Errors in Integration Test

If you haven’t setup your local AWS CLI, you might get following error when running the test case. This is because when the DynamoDB client initialize, it tries to find credentials to connect to dynamodb. In our DynamoDBConfig client we are using DefaultCredentialsProvider which tries to find the credentials at number of places.

Unable to load credentials from service endpoint

software.amazon.awssdk.core.exception.SdkClientException: Unable to load credentials from any of the providers in the chain AwsCredentialsProviderChain(credentialsProviders=[SystemPropertyCredentialsProvider(), EnvironmentVariableCredentialsProvider(), ProfileCredentialsProvider(), WebIdentityTokenCredentialsProvider(), ContainerCredentialsProvider(), InstanceProfileCredentialsProvider()]) : [SystemPropertyCredentialsProvider(): Unable to load credentials from system settings. Access key must be specified either via environment variable (AWS_ACCESS_KEY_ID) or system property (aws.accessKeyId)., EnvironmentVariableCredentialsProvider(): Unable to load credentials from system settings. Access key must be specified either via environment variable (AWS_ACCESS_KEY_ID) or system property (aws.accessKeyId)., ProfileCredentialsProvider(): Profile file contained no credentials for profile 'default': ProfileFile(profiles=[]), WebIdentityTokenCredentialsProvider(): Either the environment variable AWS_WEB_IDENTITY_TOKEN_FILE or the javaproperty aws.webIdentityTokenFile must be set., ContainerCredentialsProvider(): Cannot fetch credentials from container - neither AWS_CONTAINER_CREDENTIALS_FULL_URI or AWS_CONTAINER_CREDENTIALS_RELATIVE_URI environment variables are set., InstanceProfileCredentialsProvider(): Unable to load credentials from service endpoint.]
    at software.amazon.awssdk.core.exception.SdkClientException$BuilderImpl.build(SdkClientException.java:97) ~[sdk-core-2.10.40.jar:na]
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
    |_ checkpoint ⇢ HTTP POST "/customers" [ExceptionHandlingWebHandler]
Stack trace:
        at software.amazon.awssdk.core.exception.SdkClientException$BuilderImpl.build(SdkClientException.java:97) ~[sdk-core-2.10.40.jar:na]

To resolve this error, either setup your AWS CLI so that client can find the credential or define environment variables:

export AWS_SECRET_ACCESS_KEY=test
export AWS_ACCESS_KEY_ID=test

The env variables value can be any non empty string.

Read more on working with AWS Credentials

5. Source Code – Spring Boot DynamoDB Integration Tests

Source code for the Testcontainers integration test for DynamoDB and Spring Boot is in Github.

Github – spring-boot-webflux-dynamodb

References

  1. Testcontainers
  2. Spring Boot Webflux
  3. AWS DynamoDB Async Client


via ViralPatel.net https://ift.tt/2Lzekhl

[Fix] “Choose Where to Get Apps” Option Grayed Out in Windows 10 Settings

https://ift.tt/eA8V8J Recently an AskVG reader contacted me regarding this problem in Windows 10. The option "Choose where to get apps" in Windows...

Read the full article at AskVG.com

via AskVG https://ift.tt/365BdlQ

How To Turn Off Notifications in Google Chrome (Desktop and Android)

You can allow many websites to send you notifications of updates right in your Chrome browsers. Although it’s a useful feature to stay updated, but many websites can spam notifications that might annoy you. This is especially annoying when those notifications come from a website you didn’t even intend to allow, which isn’t uncommon as many websites use cheap tactics to trick you to allow notifications.

If you are dealing with annoying notifications from a particular website or even if you just want to disable notifications altogether, then today I will show you how to disable notifications in Google Chrome.

Turn off notifications in Chrome for desktop

Open up the Chrome browser and follow the below-mentioned instructions:

Click on the three vertical dots menu at the top-right corner and select “Settings” from it.

Chrome settings

Now click on “Privacy and security” in the left panel and then click on the “Site Settings” option.

Chrome site settings

Here, scroll down and click on “Notifications”.

Chrome notifications

In the “Allow” section, you will see all the websites that are allowed to send you notifications. You can click the three vertical dots menu next to any website and select “Remove” or “Block” from it to turn off its notifications. If you choose “Remove” then the website will be able to again request to allow notifications when you will visit again, and “Block” will stop that website from asking to show notifications in the future.

Turn off notifications in Chrome for desktop

You can follow the above process to remove all unwanted websites from the “Allow” list. If you don’t want websites to ask for notifications in the future, then you can turn off the toggle button next to “Notifications” at the top.

Disable future notifications

Turn off notifications in Chrome for Android

The process is quite similar on Chrome for Android as well, just follow the below instructions:

Tap on the three vertical dots menu at the top-right corner and select “Settings” from it.

Here click on the “Notifications” option.

Now scroll down to the “Sites” section and you will see all the websites that are allowed to send notifications here. Simply tap on the toggle button next to each website to disable notifications for it.

Turn off notifications in Chrome for Android

If you want to prevent websites from asking for notifications in the future, then tap on “Additional settings in the app” option and turn off the toggle next to “Notifications”.

Disable future notifications on Android

Ending words

These instructions should be enough to turn off notifications in Google Chrome on both your PC and smartphone. Although I will recommend you to not disable notification requests for the future as there are many websites on which it’s important to enable notifications, such as your email provider. If you have any further questions, let us know in the comments below.

The post How To Turn Off Notifications in Google Chrome (Desktop and Android) appeared first on Gtricks.



via Gtricks https://ift.tt/3fY1fMu

[Fix] No Such Interface Supported Error Message in Windows

https://ift.tt/eA8V8J Recently a reader contacted me regarding this weird issue, so I decided to publish a dedicated article containing its solution so...

Read the full article at AskVG.com

via AskVG https://ift.tt/3bxE7AV

3 Best Bulk Image Downloader Chrome Extensions To Download Images in Bulk

Downloading images online is as simple as right-clicking and selecting “Save image”. However, if you need to download images in bulk, then downloading each one separately can be very tedious. And most popular browsers don’t offer a built-in bulk image downloader either. No worries though, if you are using Chrome then you can install a bulk image downloader Chrome extension to easily download all the images on a webpage in one go.

Although there are many extensions to download images in a batch, but I have selected 3 of the best with unique features to this list so you could make the right choice. Let’s get straight to them.

1. Fatkun Batch Download Image

Fatkun offers reliable customization options to download the right images easily in bulk. You can bulk download images on the current tab or even all the opened tabs. Just select the tab you want to search for images and it will open a new tab loading all the images on the page. Here you have multiple options to filter and download images. You can sort and find images by size, keywords, and pages. Just select the images you need and click the “Download” button to download them all.

Fatkun Batch Download Image

Fatkun also has a bunch of customization options to tweak in the “Settings” section. Like you can auto-convert WEBP images to JPG and manage output settings. Interestingly, this extension also lets you bulk download images from websites that prevent downloads of images. Although you will have to download images from those websites using the extension settings instead.

One thing I didn’t like is that the extension downloads images as previewed on the page. It doesn’t download images from the source, so a small image will be downloaded as a small image even if the original image is large.

2. Imageye – Image downloader

This is a simpler bulk image downloader and I personally find it easier to use due to its intuitive interface. Imageye works right from the extension button and as soon as you click it, it will load the images on the current page in its own interface. The cool part is that it loads the images with all the available sizes on the webpage. This means you can download images in the preview size or even the original size. Of course, this also means that you will have to search through a lot more images (usually twice as much) to download them.

Imageye Image downloader

You can click on each image to select them (can select all as well) and then click on “Download” to download them. It also comes with a button to filter images by size, URL, or type. Overall, it’s a great extension if you are looking for something intuitive.

3. Download All Images

True to its name, Download All Images downloads all the images on a page without even giving you an option to choose which images to download. You just click on the extension button and it will immediately download all the images on the page and save them in a .zip file. That’s it, there are no customization options or ability to even view the images in the extension.

I know you must be wondering how this extension could stand a chance against others. Well, it saves all the images in a zip file which is much smaller in size compared to actual images. Furthermore, it also doesn’t clutter your PC with separate images as all the images are saved in a single zip file.

It will also download images in both preview size and original size, so you have a variety of image sizes. It’s a great extension considering its speed and ease of use. You can delete unrequired images after downloading anyway.

Ending words

I personally like Imageye for its clean interface while still having the required customization options to bulk download images. Although if you want even more control or need to download images from a website with restrictions, then Funkun is a really good option. Which one of these bulk image downloader Chrome extensions do you like? Do share in the comments below.

The post 3 Best Bulk Image Downloader Chrome Extensions To Download Images in Bulk appeared first on Gtricks.



via Gtricks https://ift.tt/2Wu9E2v

[Tip] Play Hidden Secret Ninjacat Surf Game in Microsoft Edge

https://ift.tt/eA8V8J Today in this article, we are going to tell you about a hidden secret game called "Let's Surf" in Microsoft Edge...

Read the full article at AskVG.com

via AskVG https://ift.tt/3fLLc4m

How To Add a Reply-To Address in Gmail

By default, any replies to your emails are directly sent to the email that you used to send the email. However, did you know you can change the reply-to address in Gmail to receive replies to a completely different email address from the one you sent the email? This can be very useful if you manage multiple emails but can’t check all of them frequently. You can simply set up a single reply-to address and you will be able to see all the replies in one place.

If you are up for it, then keep reading and I’ll show you how to set up a reply-to address in Gmail.

Add reply-to address in Gmail

You must follow the below instructions on the Gmail desktop version:

Click on the “Gear” icon at the top-right corner of your inbox and select “Settings” from it.

Gmail settings

Now move to the “Accounts and Import” tab.

Accounts and imports

Here, click on the “edit info” link next to your email in the “Send mail as:” section.

edit email info

A new window will open, click on the “Specify a different “reply-to” address” link below your email address and provide the email address where you want the replies. Afterward, click on the “Save Changes” button.

add reply-to address

Now when you will send an email to anyone, their reply will directly go to your reply-to email. Do keep in mind that the recipient will be able to see that the reply is not being sent to the same email as the sender.

If you ever want to undo the changes, simply remove the email address you added in the “edit info” section and click on the “Save Changes” button again.

Ending words

I am sure you will find this feature very helpful for keeping yourself updated with replies from different email addresses. As this doesn’t require any authentication, you can also use this feature to send the reply to a different person if needed. Do let us know in the comments if you found this feature useful.

The post How To Add a Reply-To Address in Gmail appeared first on Gtricks.



via Gtricks https://ift.tt/2T0urbP

A New Journey With Windows Full Screen Message in Windows 10

If you are getting a full screen banner or notification message with the the title as “A new journey with Windows” on your Windows 10 device...