Testcontainers etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
Testcontainers etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

14 Aralık 2023 Perşembe

TestContainers LocalStackContainer Sınıfı - SQS İle Kullanım

Örnek
1. Şöyle yaparız. Burada SQS_ENDPOINT_STRATEGY path veriliyor. Böylece kuyruğa erişmek için üretilen URL http://localhost:8701/queue/us-east-1/000000000000/myqueue şeklinde oluyor. Eğer böyle yapmazsak UnknownHostException alırız
2. Eğer istenirse awslocal komutu container içinde çalıştırılabilir.
@ClassRule
public static LocalStackContainer container = 
  new LocalStackContainer(DockerImageName.parse("localstack/localstack:3.0.2"))
  .withServices(LocalStackContainer.Service.SQS)
  .withEnv("SQS_ENDPOINT_STRATEGY", "path"); // Burası

@BeforeClass
public static void beforeClass() {
  container.execInContainer("awslocal",
    "sqs",
    "create-queue",
    "--queue-name",
    "myqueue");
}
SQSClient ile kullanmak için şöyle yaparız. SQSClient  aws.accessKeyId ve aws.secretKey değişkenlerini istiyor. Yoksa  "Unable to load AWS credentials from any provider in the chain ..." hatası alırız
void insertData() throws URISyntaxException {
  System.setProperty("aws.accessKeyId", container.getAccessKey());
  System.setProperty("aws.secretKey", container.getSecretKey());

  SqsClient sqs = SqsClient.builder()
    .endpointOverride(container.getEndpointOverride(LocalStackContainer.Service.SQS))
    .credentialsProvider(
      StaticCredentialsProvider.create(
        AwsBasicCredentials.create(container.getAccessKey(), container.getSecretKey())
      )
    )
    .region(Region.of(container.getRegion()))
    .build();
    ...
}

28 Eylül 2023 Perşembe

Testcontainers ImageFromDockerFile Sınıfı

Giriş
Şu satırı dahil ederiz
import org.testcontainers.images.builder.ImageFromDockerFile;
withDockerfile metodu
Örnek
Şöyle yaparız
ImageFromDockerfile image = new ImageFromDockerfile()
  .withDockerfile(Paths.get("Dockerfile.txt")); 

GenericContainer container = new GenericContainer(image)
  .withEnv(...)
  .withExposedPorts(...);
Dockerfile.txt şöyledir
// Dockerfile

FROM opensearchproject/opensearch:1.1.0

# Install a plugin
RUN /usr/share/opensearch/bin/opensearch-plugin install analysis-phonetic
withDockerfileFromBuilder metodu
Şöyle yaparız
@Rule
public GenericContainer<?> server = new GenericContainer(
  new ImageFromDockerFile()
    .withDockerfileFromBuilder(builder ->
      builder
        .from("alpine:3.16")
        .run("apk add --update nginx")
        .cmd("nginx", "-g", "deamon off;")
        .build()))
  .withExposedPorts(80);



14 Haziran 2023 Çarşamba

ToxiproxyContainers ToxiproxyContainer Sınıfı

Maven
Şu satırı dahil ederiz
<dependency>
<groupId>org.testcontainers</groupId> <artifactId>toxiproxy</artifactId> <version>1.18.3</version> <scope>test</scope> </dependency>
ToxiproxyClient Sınıfı
ToxiproxyContainer kullanılarak yaratılır

latency metodu
Örnek
Şöyle yaparız
import eu.rekawek.toxiproxy.Proxy;
import eu.rekawek.toxiproxy.ToxiproxyClient;
import eu.rekawek.toxiproxy.model.ToxicDirection;

@Testcontainers
public class ToxiproxyExample {

  @Container
  private static ToxiproxyContainer toxiproxy = new ToxiproxyContainer();

  @Container
  private static PostgreSQLContainer<?> database = new PostgreSQLContainer<>("postgres:11.19-bullseye")

  @Rule
  public ToxiproxyClient toxiproxyClient = new ToxiproxyClient(toxiproxy.getHost(), toxiproxy.getControlPort());
   
  @Test
  public void testApplicationWithLatency() {
    // ToxicDirection.DOWNSTREAM is from client to DB
    // Create a toxic that adds 100 milliseconds of latency to the connection to the DB.
    toxiproxyClient.toxics().latency("database", ToxicDirection.DOWNSTREAM, 100);

    // Try to connect to the database.
    try (var connection = DriverManager.getConnection(database.getHost() + ":" + database.getMappedPort(5432), "postgres", "postgres")) {
        // Do something with the connection.
    }
    // Remove the toxic.
    toxiproxyClient.toxics().get("database").remove();
  }
}


29 Mart 2023 Çarşamba

Testcontainers CouchbaseContainer Sınıfı

Örnek
Şöyle yaparız
import org.testcontainers.containers.output.Slf4jLogConsumer;
import org.testcontainers.couchbase.BucketDefinition;
import org.testcontainers.couchbase.CouchbaseContainer;

private static final String BUCKET_NAME = "mybucket";

public static final CouchbaseContainer container = new CouchbaseContainer("couchbase/server:7.1.1")
  .withBucket(new BucketDefinition(BUCKET_NAME));
  .withBucket(new BucketDefinition(BUCKET_NAME))
  .withStartupTimeout(Duration.ofSeconds(120))
  .withFileSystemBind("target/couchbase-logs", "/opt/couchbase/var/lib/couchbase/logs")
  .withLogConsumer(new Slf4jLogConsumer(LOGGER).withPrefix("Docker"));


22 Şubat 2023 Çarşamba

TestContainers Neo4jContainer

Giriş
Şu satırı dahil ederiz
import org.testcontainers.containers.Neo4jContainer;
withoutAuthentication metodu
Örnek
Şöyle yaparız
import org.testcontainers.utility.DockerImageName;

Neo4jContainer<?> container = new Neo4jContainer<>(DockerImageName.parse("neo4j:5.5.0"))
  .withoutAuthentication();

String url = container.getBoltUrl()
withLogConsumer metodu
Örnek
Şöyle yaparız
import org.testcontainers.containers.output.Slf4jLogConsumer;

public static final Neo4jContainer<?> container = 
  new Neo4jContainer<>(DockerImageName.parse("neo4j:5.5.0"))
    .withoutAuthentication()
    .withLogConsumer(new Slf4jLogConsumer(LOGGER).withPrefix("Docker"));


9 Şubat 2023 Perşembe

TestContainers LocalStackContainer Sınıfı - S3

Gradle
Şu satırı dahil ederiz
testImplementation "org.testcontainers:testcontainers"
testImplementation 'org.testcontainers:junit-jupiter'
testImplementation "org.testcontainers:localstack"
testImplementation 'org.testcontainers:postgresql'
getAccessKey metodu
Örnek
Şöyle yaparız
import com.amazonaws.services.s3.AmazonS3;
import org.testcontainers.containers.localstack.LocalStackContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Testcontainers
public class UploadControllerAPITest {
  public static final String BUCKET_NAME = "testbucket";
  @LocalServerPort
  private int port;
  @Container
  private static final LocalStackContainer localStackContainer = new LocalStackContainer(
    DockerImageName.parse("localstack/localstack:0.11.3"))
      .withServices(LocalStackContainer.Service.S3);
  @Autowired
  private TestRestTemplate restTemplate;
  @Autowired
  private AmazonS3 s3Client;
  @BeforeAll
  static void beforeAll() {
    System.setProperty("spring.cloud.aws.credentials.access-key", 
      localStackContainer.getAccessKey());
    System.setProperty("spring.cloud.aws.credentials.secret-key", 
      localStackContainer.getSecretKey());
    System.setProperty("spring.cloud.aws.s3.region",localStackContainer.getRegion());
    System.setProperty("cloud.aws.s3.endpoint", 
      localStackContainer.getEndpointOverride(LocalStackContainer.Service.S3)
      .toString());
  }
  @BeforeEach
  void setUp() {
    s3Client.createBucket(BUCKET_NAME);
 }
}
Şöyle yaparız
@Test
void shouldUploadFileSuccessFullyToS3() {
  String fileUploadURI = "/api/upload";
   
  LinkedMultiValueMap<String, Object> parameters = new LinkedMultiValueMap<>();
  parameters.add("file", new ClassPathResource("sample.txt"));

  HttpHeaders headers = new HttpHeaders();
  headers.setContentType(MediaType.MULTIPART_FORM_DATA);

  HttpEntity<LinkedMultiValueMap<String, Object>> entity = 
    new HttpEntity<>(parameters, headers);
  String expected = "{\"status\":\"success\", \"url\":\"/testbucket/sample.txt\"}";

  ResponseEntity<String> responseEntity = restTemplate
    .exchange("http://localhost:" + port + fileUploadURI, POST, entity, String.class);

  assertEquals(HttpStatus.OK, responseEntity.getStatusCode());
  assertEquals(expected, responseEntity.getBody());
}
execInContainer metodu




27 Ocak 2023 Cuma

Testcontainers JDBC URL Kullanımı

Giriş
Açıklaması şöyle
... after making a very simple modification to your system's JDBC URL string, Testcontainers will provide a disposable stand-in database that can be used without requiring modification to your application code.
..
As long as you have Testcontainers and the appropriate JDBC driver on your classpath, you can simply modify regular JDBC connection URLs to get a fresh containerized instance of the database each time your application starts up.
Yani iki tane dependency gerekir.
1. Test containers
2. Veri tabanı için driver

Açıklaması şöyle. Yani JDBC URL kullanımında URL jdbc:tc:... şeklinde olmalı
You should use either
- the JDBC URL with tc: prefix and ContainerDatabaseDriver or
- container instance with getJdbcUrl() and the original driver (or let the system detect the driver for you), not both.

Kullanıcı İsmi ve Şifre
TestContainers normalde kullanıcı ismi ve şifreye gerek duymaz. Yani sadece URL ila bağlanabiliriz.
String jdbcUrl = "jdbc:tc:sqlserver:latest:///mydbName";
try (Connection conn = DriverManager.getConnection(jdbcUrl)) {
  ...
}
Stack trace şöyle. JDBC DriverManager kodu gidip Testcontainers içindeki ContainerDatabaseDriver sınıfını tetikliyor
at org.testcontainers.containers.GenericContainer.doStart(GenericContainer.java:349)
at org.testcontainers.containers.GenericContainer.start(GenericContainer.java:322)
at org.testcontainers.jdbc.ContainerDatabaseDriver.connect(ContainerDatabaseDriver.java:124)
at java.sql.DriverManager.getConnection(DriverManager.java:664)
at java.sql.DriverManager.getConnection(DriverManager.java:270)
Eğer istenirse container şöyle öldürülebilir
ContainerDatabaseDriver.killContainer(jdbcUrl);
ContainerDatabaseDriver.killContainers();
PostgreSQL
Kullanıcı ismi test ve şifresi test olan bir veri tabanı yaratır
Örnek
Şöyle yaparız. Kullanıcı ismi user, şifresi password olan bir veri tabanı yaratır
spring.datasource.url=jdbc:tc:postgresql://localhost/testdb
spring.datasource.driverClassName=org.testcontainers.jdbc.ContainerDatabaseDriver
spring.datasource.username=user
spring.datasource.password=password
MySQL
Kullanıcı ismi root ve şifresi test olan bir veri tabanı yaratır
Örnek
Şöyle yaparız
jdbc:tc:mysql:8.0.29:///mydb?TC_DAEMON=true&sessionVariables=sql_mode=ANSI
Örnek
Şöyle yaparız
jdbc:tc:mysql:8.0.29:///mydb?user=root?password=test?TC_DAEMON=true&sessionVariables=sql_mode=ANSI
MS SQL
Testcontainers JDBC URL Kullanımı yazısına taşıdım

MariaDB
Örnek
Şöyle yaparız
<dependency>
  <groupId>org.testcontainers</groupId>
  <artifactId>mariadb</artifactId>
  <version>1.17.6</version>
<scope>test</scope> </dependency> <dependency> <groupId>org.mariadb.jdbc</groupId> <artifactId>mariadb-java-client</artifactId> <version>3.1.2</version> <scope>test</scope> </dependency>
Şöyle yaparız
String jdbcUrl = 
"jdbc:tc:mariadb:latest:///mydbName?TC_DAEMON=true&sessionVariables=sql_mode=ANSI";
try (Connection conn = DriverManager.getConnection(jdbcUrl)) {
  ...
}

26 Aralık 2022 Pazartesi

Testcontainers GenericContainer Sınıfı

Giriş
Şu satırı dahil ederiz
import org.testcontainers.containers.GenericContainer;
constructor - dockerImageName
Örnek
Şöyle yaparız
GenericContainer redis = new GenericContainer("redis:5.0.8-alpine3.11")
  .withExposedPorts(6379);

redis.start();
// run your tests
redis.stop();
Örnek
Şöyle yaparız
@Rule
public GenericContainer<?> server = new GenericContainer(
  new ImageFromDockerFile()
    .withDockerfileFromBuilder(builder ->
      builder
        .from("alpine:3.16")
        .run("apk add --update nginx")
        .cmd("nginx", "-g", "deamon off;")
        .build()))
  .withExposedPorts(80);
getHost metodu
Açıklaması şöyle
When running with a local Docker daemon, exposed ports will usually be reachable on localhost. However, if you ever need to obtain the container address, you can do:
String ipAddress = container.getHost();
getMappedPort metodu
Açıklaması şöyle
We usually don’t want to publish to a specific port on the host, to avoid port collisions with locally running software or in between parallel test runs, so we let the Docker decide on which port to publish.

Since we don’t know the port Docker will pick, Testcontainers has additional APIs to get the actual mapped port after the container starts, so we can inject it into our tests and use it.

This can be done using the getMappedPort method, which takes the original (container) port as an argument, so for the Redis generic container example, you would do the following:

Integer mappedPort = container.getMappedPort(6379);
start metodu
Açıklaması şöyle
The start command is a blocking command, which means that it will wait until the application inside the container is ready. By default, it will wait for the container’s mapped network port to start listening. Of course, readiness can mean different things in different applications, that’s why there are other specific wait strategies that can be used with Testcontainers, but the default behavior should be already enough for most applications.
stop metodu
Açıklaması şöyle
The stop command will shut down and delete the container after the test.
Waiting for containers to start or be ready
Örnek - Http
Şöyle yaparız. Burada nginx sunucusu kullanıldığı için http isteğine cevap vermesi yeterli
GenericContainer nginxWithHttpWait = 
  new GenericContainer(DockerImageName.parse("nginx:1.9.4"))
  .withExposedPorts(80)
  .waitingFor(Wait.forHttp("/"));



Testcontainers ElasticsearchContainer Sınıfı

Gradle
Şu satırı dahil ederiz
dependencies {
...
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.projectreactor:reactor-test'
testImplementation 'org.testcontainers:elasticsearch:1.17.4'
testImplementation "org.testcontainers:testcontainers:1.17.5"
testImplementation 'org.testcontainers:junit-jupiter'
testImplementation 'org.junit.jupiter:junit-jupiter'
}

dependencyManagement {
imports {
mavenBom "org.testcontainers:testcontainers-bom:${testcontainersVersion}"
mavenBom "org.junit:junit-bom:5.8.1"
}
}
Örnek
Elimizde şöyle bir kod olsun
public class ElasticTestContainer extends ElasticsearchContainer {
  private static final String DOCKER_ELASTIC = 
    "docker.elastic.co/elasticsearch/elasticsearch:7.17.6";

  private static final String CLUSTER_NAME = "sample-cluster";

  private static final String ELASTIC_SEARCH = "elasticsearch";

  public ElasticTestContainer() {
    super(DOCKER_ELASTIC);
    this.addFixedExposedPort(9200, 9200);
    this.addFixedExposedPort(9300, 9300);
    this.addEnv(CLUSTER_NAME, ELASTIC_SEARCH);
  }
}
Test kodunda şöyle yaparız
// using the above test container using @container annotation
@Container
protected static ElasticsearchContainer elasticsearchContainer =
  new ElasticTestContainer();




10 Şubat 2022 Perşembe

Testcontainers Kullanımı

Giriş
Test Containers iki şekilde kullanılabilir.
1. Using a specially modified JDBC URL. Testcontainers JDBC URL Kullanımı yazısına taşıdım
2. Anotasyonlar ile kullanılır
3. Tüm container'lar GenericContainer sınıfından kalıtır. Bu yüzden GenericContainer yazısına bakmakta fayda var

JUnit 5 Kullanımı
Maven
Şu satırı dahil ederiz
<dependency>
  <groupId>org.testcontainers</groupId>
  <artifactId>testcontainers</artifactId>
  <scope>test</scope>
</dependency>

<!-- JUnit 5 extension --> 
<dependency>
  <groupId>org.testcontainers</groupId>
  <artifactId>junit-jupiter</artifactId>
  <scope>test</scope>
</dependency>

1. Test sınıfına @TestContainers anotastonu eklenir
2. Teste static veya static olmayan @Generic anotasyonuna sahip bir container eklenir. 
 -- Static ise container tüm testler için bir kere yaratılır, yani paylaşılır. 
-- Static değilse her test için yeni bir container yaratılır

JUnit 4 Kullanımı
JUnit 4 için @Rule/@ClassRule anotayonları kullanılır 

@Testcontainers Anotasyonu
Şu satırı dahil ederiz
import org.testcontainers.junit.jupiter.Testcontainers;
Açıklaması şöyle. Jupiter anotasyonudur. @Container olarak işaretli container'ın start() metodunu çağırır.
Jupiter integration is provided by means of the @Testcontainers annotation.

The extension finds all fields that are annotated with @Container and calls their container lifecycle methods (methods on the Startable interface). 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.

Note: This extension has only been tested with sequential test execution. Using it with parallel test execution is unsupported and may have unintended side effects.

Her Test İçin Yeni Container
Örnek
Şöyle yaparız
private RedisBackedCache underTest;

  @Container
  public GenericContainer redis = new GenericContainer("redis:5.0.8-alpine3.11")
    .withExposedPorts(6379);

  @BeforeEach
  public void setUp() {
    String address = redis.getHost();
    Integer port = redis.getFirstMappedPort();

    underTest = new RedisBackedCache(address, port);
  }

Diğer

Örnek - Testcontainers GCloud Module
Şöyle yaparız
//TestContainers
testImplementation 'org.testcontainers:testcontainers:1.17.3'
testImplementation group: 'org.testcontainers', name: 'junit-jupiter', version: '1.17.3'
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.9.0'
implementation 'org.testcontainers:gcloud:1.17.3'
Şöyle yaparız
@Container
private static final SpannerEmulatorContainer spannerEmulatorContainer =
  new SpannerEmulatorContainer(
    DockerImageName.parse("gcr.io/cloud-spanner-emulator/emulator:1.1.1"));

//for testing, there is no need to use credentials
@TestConfiguration
static class EmulatorConfiguration {
  @Bean
  NoCredentialsProvider googleCredentials() {
    return NoCredentialsProvider.create();
  }
}

@DynamicPropertySource
static void emulatorProperties(DynamicPropertyRegistry registry) {
  registry.add(
    "spring.cloud.gcp.spanner.emulator-host", 
    spannerEmulatorContainer::getEmulatorGrpcEndpoint);
}
Yardımcı metodlar için şöyle yaparız
private InstanceId createInstance(Spanner spanner) throws InterruptedException, ExecutionException {
  InstanceConfigId instanceConfig = InstanceConfigId.of(PROJECT_ID, "emulator-config");
  InstanceId instanceId = InstanceId.of(PROJECT_ID, INSTANCE_ID);
  InstanceAdminClient insAdminClient = spanner.getInstanceAdminClient();
  Instance instance = insAdminClient
    .createInstance(
      InstanceInfo
        .newBuilder(instanceId)
        .setNodeCount(1)
        .setDisplayName("Test instance")
        .setInstanceConfigId(instanceConfig)
        .build()
       )
   .get();
  return instanceId;
}

private void createDatabase(Spanner spanner) throws InterruptedException, ExecutionException {
  DatabaseAdminClient dbAdminClient = spanner.getDatabaseAdminClient();
  Database database = dbAdminClient
    .createDatabase(
      INSTANCE_ID,
      "order_schema",
      Arrays.asList("CREATE TABLE Orders (orderId INT64 NOT NULL, name STRING(255), order_status STRING(255)) PRIMARY KEY (orderId)")
    )
    .get();
}

private Spanner spanner(){
  SpannerOptions options = SpannerOptions
    .newBuilder()
    .setEmulatorHost(spannerEmulatorContainer.getEmulatorGrpcEndpoint())
    .setCredentials(NoCredentials.getInstance())
    .setProjectId(PROJECT_ID)
    .build();
  Spanner spanner = options.getService();
  return spanner;
}
Test için şöyle yaparız
@Test
public void testOrders() throws ExecutionException, InterruptedException {
    //Create Spanner Instance, DB, Table
    Spanner spanner = spanner();
    InstanceId instanceId = createInstance(spanner);
    createDatabase(spanner);

    //Create Order and Save
    Order order = new Order();
    order.setOrder_status("COMPLETED");
    order.setName("Order1");
    String message = this.orderService.save(order);
    assertEquals("Order Saved Successfully", message);

    //Validate
    List<Order> orders = this.orderService.findOrdersByName("Order1");
    assertTrue(orders.size() == 1);
    assertTrue(orders.get(0).getOrder_status().equals("COMPLETED"));
 }