Skip to content

Commit

Permalink
tests to abstract, add integration tests, add Redis o11y
Browse files Browse the repository at this point in the history
  • Loading branch information
dashaun committed Dec 21, 2023
1 parent 2e361bb commit ef0c3ce
Show file tree
Hide file tree
Showing 8 changed files with 297 additions and 170 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,5 @@ build/

### VS Code ###
.vscode/

.envrc
2 changes: 1 addition & 1 deletion .mvn/extensions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.7.0</version>
<version>1.7.1</version>
</extension>
</extensions>
27 changes: 26 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<dependency>
<groupId>com.github.loki4j</groupId>
<artifactId>loki-logback-appender</artifactId>
<version>1.4.1</version>
<version>1.5.0-m1</version>
</dependency>
<dependency>
<groupId>com.rometools</groupId>
Expand Down Expand Up @@ -69,6 +69,12 @@
<version>2.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.shared</groupId>
<artifactId>maven-invoker</artifactId>
<version>3.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-testcontainers</artifactId>
Expand All @@ -89,6 +95,12 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>fr.brouillard.oss</groupId>
<artifactId>jgitver-maven-plugin</artifactId>
<version>1.9.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
Expand Down Expand Up @@ -159,6 +171,19 @@
</image>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.2.3</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
29 changes: 7 additions & 22 deletions src/main/java/com/javagrunt/listener/youtube/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,8 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.observability.MicrometerTracingAdapter;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
import org.springframework.data.repository.CrudRepository;
import org.springframework.web.bind.annotation.*;
Expand Down Expand Up @@ -88,25 +85,13 @@ record YouTubeEvent(@Id String id, String entryXml){}
@Configuration
@EnableRedisRepositories
class ApplicationConfig {

// @Bean
// public RedisConnectionFactory connectionFactory() {
// return new LettuceConnectionFactory();
// }
//
// @Bean
// public RedisTemplate<?, ?> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
// RedisTemplate<byte[], byte[]> template = new RedisTemplate<byte[], byte[]>();
// template.setConnectionFactory(redisConnectionFactory);
// return template;
// }
//
// @Bean
// public ClientResources clientResources(ObservationRegistry observationRegistry) {
// return ClientResources.builder()
// .tracing(new MicrometerTracingAdapter(observationRegistry, "youtube-listener"))
// .build();
// }

@Bean
public ClientResources clientResources(ObservationRegistry observationRegistry) {
return ClientResources.builder()
.tracing(new MicrometerTracingAdapter(observationRegistry, "youtube-listener"))
.build();
}
}
interface EventRepository extends CrudRepository<YouTubeEvent, String> {
}
152 changes: 152 additions & 0 deletions src/test/java/com/javagrunt/listener/youtube/AbstractAppTests.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package com.javagrunt.listener.youtube;

import com.redis.testcontainers.RedisContainer;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.specification.RequestSpecification;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.restdocs.RestDocumentationContextProvider;
import org.springframework.restdocs.RestDocumentationExtension;
import org.testcontainers.containers.Network;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

import static io.restassured.RestAssured.given;
import static org.hamcrest.core.Is.is;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.modifyUris;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;

@ExtendWith(RestDocumentationExtension.class)
@Testcontainers
public abstract class AbstractAppTests {

static Logger logger = LoggerFactory.getLogger(AbstractAppTests.class);

abstract int getPort();

private RequestSpecification spec;
private static final Network network = Network.newNetwork();

static Network getNetwork(){
return network;
}

@Container
@ServiceConnection(name = "redis")
static final RedisContainer redis = new RedisContainer(
RedisContainer.DEFAULT_IMAGE_NAME.withTag(RedisContainer.DEFAULT_TAG))
.withExposedPorts(6379)
.withNetworkAliases("redis")
.withNetwork(network);

@BeforeEach
void setUp(RestDocumentationContextProvider restDocumentation) {
this.spec = new RequestSpecBuilder()
.addFilter(documentationConfiguration(restDocumentation))
.build();
}
@Test
public void getShouldEchoHubChallenge() {
given(this.spec)
.filter(document("hello",
preprocessRequest(modifyUris()
.scheme("https")
.host("youtube-listener.javagrunt.com")
.removePort())))
.when()
.port(getPort())
.get("/api/?hub.mode=subscribe&hub.challenge=CHALLENGE_STRING&hub.topic=somthingcool")
.then()
.assertThat().statusCode(is(200))
.assertThat().body(is("CHALLENGE_STRING"));
}

@Test
void postShouldReturnSuccess() throws Exception {
String exampleEvent = """
<feed xmlns:yt="http://www.youtube.com/xml/schemas/2015"
xmlns="http://www.w3.org/2005/Atom">
<link rel="hub" href="https://pubsubhubbub.appspot.com"/>
<link rel="self" href="https://www.youtube.com/xml/feeds/videos.xml?channel_id=CHANNEL_ID"/>
<title>YouTube video feed</title>
<updated>2015-04-01T19:05:24.552394234+00:00</updated>
<entry>
<id>yt:video:VIDEO_ID</id>
<yt:videoId>VIDEO_ID</yt:videoId>
<yt:channelId>CHANNEL_ID</yt:channelId>
<title>Video title</title>
<link rel="alternate" href="http://www.youtube.com/watch?v=VIDEO_ID"/>
<author>
<name>Channel title</name>
<uri>http://www.youtube.com/channel/CHANNEL_ID</uri>
</author>
<published>2015-03-06T21:40:57+00:00</published>
<updated>2015-03-09T19:05:24.552394234+00:00</updated>
</entry>
</feed>
""";
given(this.spec)
.filter(document("listen",
preprocessRequest(modifyUris()
.scheme("https")
.host("youtube-listener.javagrunt.com")
.removePort())))
.contentType("application/atom+xml")
.body(exampleEvent)
.when()
.port(getPort())
.post("/api/")
.then()
.assertThat()
.statusCode(is(200));
}

@Test
public void actuatorInfo() {
given(this.spec)
.filter(document("info",
preprocessRequest(modifyUris()
.scheme("https")
.host("youtube-listener.javagrunt.com")
.removePort())))
.when()
.port(getPort())
.get("/actuator/info")
.then()
.assertThat().statusCode(is(200));
}

@Test
public void actuatorHealth() {
given(this.spec)
.filter(document("health",
preprocessRequest(modifyUris()
.scheme("https")
.host("youtube-listener.javagrunt.com")
.removePort())))
.when()
.port(getPort())
.get("/actuator/health")
.then()
.assertThat().statusCode(is(200));
}

@Test
void redisShouldBeRunning() {
Assertions.assertTrue(redis.isRunning());
}

@AfterAll
static void tearDown() {
redis.stop();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.javagrunt.listener.youtube;

import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;

@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
class JavaVirtualMachineTest extends AbstractAppTests {

@LocalServerPort
private int port;

@Override
int getPort() {
return this.port;
}
}
93 changes: 93 additions & 0 deletions src/test/java/com/javagrunt/listener/youtube/NativeImageIT.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package com.javagrunt.listener.youtube;

import fr.brouillard.oss.jgitver.GitVersionCalculator;
import org.apache.maven.shared.invoker.DefaultInvocationRequest;
import org.apache.maven.shared.invoker.DefaultInvoker;
import org.apache.maven.shared.invoker.InvocationResult;
import org.apache.maven.shared.invoker.MavenInvocationException;
import org.junit.jupiter.api.BeforeAll;
import org.testcontainers.DockerClientFactory;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.utility.LazyFuture;

import java.io.File;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.concurrent.Future;

public class NativeImageIT extends AbstractAppTests {

private static final Future<String> IMAGE_FUTURE = new LazyFuture<>() {
@Override
protected String resolve() {
// Find project's root dir
File cwd;
cwd = new File(".");
while (!new File(cwd, "mvnw").isFile()) {
cwd = cwd.getParentFile();
}

var request = new DefaultInvocationRequest()
.addShellEnvironment("DOCKER_HOST", DockerClientFactory.instance().getTransportConfig().getDockerHost().toString())
.setPomFile(new File(cwd, "pom.xml"))
.setGoals(List.of("spring-boot:build-image"))
.setMavenExecutable(new File(cwd, "mvnw"))
.setProfiles(List.of("native"));

InvocationResult invocationResult;
try {
invocationResult = new DefaultInvoker().execute(request);
} catch (MavenInvocationException e) {
throw new RuntimeException(e);
}

if (invocationResult.getExitCode() != 0) {
throw new RuntimeException(invocationResult.getExecutionException());
}

String semanticVersion = null;
File workDir = new File(System.getProperty("user.dir"));

try (GitVersionCalculator jgitver = GitVersionCalculator.location(workDir)) {
semanticVersion = jgitver.getVersion().split("-")[0];
} catch (Exception e) {
logger.error("Error getting semantic version", e);
}

if (System.getProperty("os.arch").contains("aarch")) {
return String.format("dashaun/com.javagrunt.listener.youtube:v%s-aarch_64", semanticVersion);
} else {
return String.format("dashaun/com.javagrunt.listener.youtube:v%s-amd_64", semanticVersion);
}
}
};

private static int port;

@Override
int getPort() {
return port;
}


@Container
static final GenericContainer<?> APP = new GenericContainer<>(IMAGE_FUTURE)
.withExposedPorts(8080)
.withNetworkAliases("app")
.withNetwork(getNetwork())
.withEnv("REDIS_PORT", "6379")
.withEnv("REDIS_HOST", "redis")
.waitingFor(Wait.forHttp("/actuator/health"))
.withStartupTimeout(Duration.of(600, ChronoUnit.SECONDS))
.dependsOn(redis);

@BeforeAll
static void setUp() {
APP.start();
port = APP.getFirstMappedPort();
}

}
Loading

0 comments on commit ef0c3ce

Please sign in to comment.