Skip to content

Commit 314c8b1

Browse files
committed
Add Spring Boot 3.3 smoke tests
1 parent 31bfaf7 commit 314c8b1

File tree

12 files changed

+351
-0
lines changed

12 files changed

+351
-0
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Ignore all project specific gradle directories/files
2+
.gradle
3+
gradle
4+
build
5+
gradlew
6+
gradlew.bat
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
plugins {
2+
id 'java'
3+
id 'org.springframework.boot' version '3.3.5'
4+
id 'io.spring.dependency-management' version '1.0.14.RELEASE'
5+
id "com.diffplug.spotless" version "6.13.0"
6+
}
7+
8+
def sharedRootDir = "$rootDir/../../../"
9+
def sharedConfigDirectory = "$sharedRootDir/gradle"
10+
rootProject.ext.sharedConfigDirectory = sharedConfigDirectory
11+
12+
apply from: "$sharedConfigDirectory/repositories.gradle"
13+
apply from: "$sharedConfigDirectory/spotless.gradle"
14+
15+
if (hasProperty('appBuildDir')) {
16+
buildDir = property('appBuildDir')
17+
}
18+
19+
version = ""
20+
21+
dependencies {
22+
implementation 'org.springframework.boot:spring-boot-starter-web'
23+
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
24+
implementation group: 'com.h2database', name: 'h2', version: '2.1.214'
25+
compileOnly group:"com.google.code.findbugs", name:"jsr305", version:"3.0.2"
26+
27+
28+
if (hasProperty('apiJar')) {
29+
implementation files(property('apiJar'))
30+
} else {
31+
implementation "com.datadoghq:dd-trace-api:1.2.0"
32+
}
33+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
pluginManagement {
2+
repositories {
3+
mavenLocal()
4+
mavenCentral()
5+
gradlePluginPortal()
6+
}
7+
}
8+
9+
def isCI = System.getenv("CI") != null
10+
11+
// Don't pollute the dependency cache with the build cache
12+
if (isCI) {
13+
def sharedRootDir = "$rootDir/../../../"
14+
buildCache {
15+
local {
16+
// This needs to line up with the code in the outer project settings.gradle
17+
directory = "$sharedRootDir/workspace/build-cache"
18+
}
19+
}
20+
}
21+
22+
rootProject.name='webmvc-3.3-smoketest'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package datadog.smoketest.springboot;
2+
3+
import datadog.smoketest.springboot.model.Fruit;
4+
import datadog.smoketest.springboot.repository.FruitRepository;
5+
import org.springframework.beans.factory.InitializingBean;
6+
import org.springframework.stereotype.Service;
7+
8+
@Service
9+
public class AppInitializer implements InitializingBean {
10+
private final FruitRepository fruitRepository;
11+
12+
public AppInitializer(FruitRepository fruitRepository) {
13+
this.fruitRepository = fruitRepository;
14+
}
15+
16+
@Override
17+
public void afterPropertiesSet() throws Exception {
18+
fruitRepository.save(new Fruit("apple"));
19+
fruitRepository.save(new Fruit("banana"));
20+
fruitRepository.save(new Fruit("orange"));
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package datadog.smoketest.springboot;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
6+
7+
@SpringBootApplication
8+
@EnableJpaRepositories
9+
public class SpringbootApplication {
10+
11+
public static void main(final String[] args) {
12+
SpringApplication.run(SpringbootApplication.class, args);
13+
}
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package datadog.smoketest.springboot.controller;
2+
3+
import datadog.smoketest.springboot.model.Fruit;
4+
import datadog.smoketest.springboot.repository.FruitRepository;
5+
import org.springframework.http.ResponseEntity;
6+
import org.springframework.web.bind.annotation.GetMapping;
7+
import org.springframework.web.bind.annotation.PathVariable;
8+
import org.springframework.web.bind.annotation.RequestMapping;
9+
import org.springframework.web.bind.annotation.RestController;
10+
11+
@RestController
12+
@RequestMapping("/fruits")
13+
public class FruitController {
14+
15+
private final FruitRepository fruitRepository;
16+
17+
public FruitController(FruitRepository fruitRepository) {
18+
this.fruitRepository = fruitRepository;
19+
}
20+
21+
@GetMapping
22+
public Iterable<Fruit> listFruits() {
23+
return fruitRepository.findAll();
24+
}
25+
26+
@GetMapping("/{name}")
27+
public ResponseEntity<Fruit> findOneFruit(@PathVariable("name") final String name) {
28+
return fruitRepository
29+
.findByName(name)
30+
.map(ResponseEntity::ok)
31+
.orElseGet(() -> ResponseEntity.notFound().build());
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package datadog.smoketest.springboot.model;
2+
3+
import jakarta.persistence.Column;
4+
import jakarta.persistence.Entity;
5+
import jakarta.persistence.GeneratedValue;
6+
import jakarta.persistence.Id;
7+
import jakarta.persistence.Table;
8+
import java.util.Objects;
9+
import javax.annotation.Nonnull;
10+
11+
@Entity
12+
@Table
13+
public class Fruit {
14+
15+
public Fruit() {}
16+
17+
public Fruit(@Nonnull String name) {
18+
this.name = name;
19+
}
20+
21+
@Id @GeneratedValue private Long id;
22+
23+
@Column(nullable = false)
24+
private String name;
25+
26+
public Long getId() {
27+
return id;
28+
}
29+
30+
public void setId(Long id) {
31+
this.id = id;
32+
}
33+
34+
public String getName() {
35+
return name;
36+
}
37+
38+
public void setName(String name) {
39+
this.name = name;
40+
}
41+
42+
@Override
43+
public boolean equals(Object o) {
44+
if (this == o) {
45+
return true;
46+
}
47+
if (o == null || getClass() != o.getClass()) {
48+
return false;
49+
}
50+
Fruit fruit = (Fruit) o;
51+
return Objects.equals(id, fruit.id);
52+
}
53+
54+
@Override
55+
public int hashCode() {
56+
return Objects.hash(id);
57+
}
58+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package datadog.smoketest.springboot.repository;
2+
3+
import datadog.smoketest.springboot.model.Fruit;
4+
import java.util.Optional;
5+
import javax.annotation.Nonnull;
6+
import org.springframework.data.repository.CrudRepository;
7+
import org.springframework.stereotype.Repository;
8+
9+
@Repository
10+
public interface FruitRepository extends CrudRepository<Fruit, Long> {
11+
Optional<Fruit> findByName(@Nonnull final String name);
12+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
logging.level.root=INFO
2+
spring.datasource.url=jdbc:h2:mem:fruitdb
3+
spring.datasource.driverClassName=org.h2.Driver
4+
spring.datasource.username=sa
5+
spring.datasource.password=password
6+
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
7+
spring.jpa.generate-ddl=true
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
ext {
2+
minJavaVersionForTests = JavaVersion.VERSION_17
3+
}
4+
5+
apply from: "$rootDir/gradle/java.gradle"
6+
7+
description = 'Spring Boot 3.3 WebMvc Smoke Tests.'
8+
9+
dependencies {
10+
testImplementation project(':dd-smoke-tests')
11+
}
12+
13+
def appDir = "$projectDir/application"
14+
def appBuildDir = "$buildDir/application"
15+
def isWindows = System.getProperty("os.name").toLowerCase().contains("win")
16+
def gradlewCommand = isWindows ? 'gradlew.bat' : 'gradlew'
17+
18+
// define the task that builds the project
19+
tasks.register('webmvcBuild3', Exec) {
20+
workingDir "$appDir"
21+
def toolchain17 = getJavaLauncherFor(17).get()
22+
environment += ["GRADLE_OPTS": "-Dorg.gradle.jvmargs='-Xmx512M'", "JAVA_HOME": "$toolchain17.metadata.installationPath"]
23+
commandLine "$rootDir/${gradlewCommand}", "bootJar", "--no-daemon", "--max-workers=4", "-PappBuildDir=$appBuildDir", "-PapiJar=${project(':dd-trace-api').tasks.jar.archiveFile.get()}"
24+
25+
outputs.cacheIf { true }
26+
27+
outputs.dir(appBuildDir)
28+
.withPropertyName("applicationJar")
29+
30+
inputs.files(fileTree(appDir) {
31+
include '**/*'
32+
exclude '.gradle/**'
33+
})
34+
.withPropertyName("application")
35+
.withPathSensitivity(PathSensitivity.RELATIVE)
36+
}
37+
38+
compileTestGroovy {
39+
dependsOn project(':dd-trace-api').tasks.named("jar")
40+
}
41+
42+
tasks.named("compileTestGroovy").configure {
43+
dependsOn 'webmvcBuild3'
44+
outputs.upToDateWhen {
45+
!webmvcBuild3.didWork
46+
}
47+
}
48+
49+
tasks.withType(Test).configureEach {
50+
jvmArgs "-Ddatadog.smoketest.springboot.uberJar.path=$appBuildDir/libs/webmvc-3.3-smoketest.jar"
51+
}
52+
53+
spotless {
54+
java {
55+
target "**/*.java"
56+
}
57+
58+
groovyGradle {
59+
target '*.gradle', "**/*.gradle"
60+
}
61+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import datadog.smoketest.AbstractServerSmokeTest
2+
import okhttp3.Request
3+
4+
import java.util.concurrent.atomic.AtomicInteger
5+
import java.util.regex.Pattern
6+
7+
class SpringBootWebmvcIntegrationTest extends AbstractServerSmokeTest {
8+
9+
@Override
10+
ProcessBuilder createProcessBuilder() {
11+
String springBootShadowJar = System.getProperty("datadog.smoketest.springboot.uberJar.path")
12+
13+
List<String> command = new ArrayList<>()
14+
command.add(javaPath())
15+
command.addAll(defaultJavaProperties)
16+
command.addAll((String[]) [
17+
"-Ddd.writer.type=MultiWriter:TraceStructureWriter:${output.getAbsolutePath()}:includeResource,DDAgentWriter",
18+
"-jar",
19+
springBootShadowJar,
20+
"--server.port=${httpPort}"
21+
])
22+
ProcessBuilder processBuilder = new ProcessBuilder(command)
23+
processBuilder.directory(new File(buildDirectory))
24+
}
25+
26+
@Override
27+
File createTemporaryFile() {
28+
return File.createTempFile("trace-structure-docs", "out")
29+
}
30+
31+
@Override
32+
protected Set<String> expectedTraces() {
33+
return [
34+
"\\[servlet\\.request:GET /fruits\\[spring\\.handler:FruitController\\.listFruits\\[repository\\.operation:FruitRepository\\.findAll\\[h2\\.query:.*",
35+
"\\[servlet\\.request:GET /fruits/\\{name}\\[spring\\.handler:FruitController\\.findOneFruit\\[repository\\.operation:FruitRepository\\.findByName\\[h2\\.query:.*"
36+
]
37+
}
38+
39+
@Override
40+
protected Set<String> assertTraceCounts(Set<String> expected, Map<String, AtomicInteger> traceCounts) {
41+
List<Pattern> remaining = expected.collect { Pattern.compile(it) }.toList()
42+
for (def i = remaining.size() - 1; i >= 0; i--) {
43+
for (Map.Entry<String, AtomicInteger> entry : traceCounts.entrySet()) {
44+
if (entry.getValue() > 0 && remaining.get(i).matcher(entry.getKey()).matches()) {
45+
remaining.remove(i)
46+
break
47+
}
48+
}
49+
}
50+
return remaining.collect { it.pattern() }.toSet()
51+
}
52+
53+
def "find all fruits"() {
54+
setup:
55+
String url = "http://localhost:${httpPort}/fruits"
56+
57+
when:
58+
def response = client.newCall(new Request.Builder().url(url).get().build()).execute()
59+
60+
then:
61+
def responseBodyStr = response.body().string()
62+
responseBodyStr != null
63+
["banana", "apple", "orange"].each { responseBodyStr.contains(it) }
64+
waitForTraceCount(1)
65+
}
66+
67+
def "find a banana"() {
68+
setup:
69+
String url = "http://localhost:${httpPort}/fruits/banana"
70+
71+
when:
72+
def response = client.newCall(new Request.Builder().url(url).get().build()).execute()
73+
74+
then:
75+
def responseBodyStr = response.body().string()
76+
responseBodyStr != null
77+
["apple", "orange"].each { !responseBodyStr.contains(it) }
78+
responseBodyStr.contains("banana")
79+
waitForTraceCount(1)
80+
}
81+
82+
}

settings.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ include ':dd-smoke-tests:spring-boot-3.0-webflux'
134134
include ':dd-smoke-tests:spring-boot-2.3-webmvc-jetty'
135135
include ':dd-smoke-tests:spring-boot-2.6-webmvc'
136136
include ':dd-smoke-tests:spring-boot-3.0-webmvc'
137+
include ':dd-smoke-tests:spring-boot-3.3-webmvc'
137138
include ':dd-smoke-tests:spring-boot-rabbit'
138139
include ':dd-smoke-tests:spring-security'
139140
include ':dd-smoke-tests:springboot'

0 commit comments

Comments
 (0)