Skip to content

Commit

Permalink
Add smoke tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jandro996 committed May 31, 2024
1 parent af857b4 commit 900bce0
Show file tree
Hide file tree
Showing 8 changed files with 399 additions and 0 deletions.
31 changes: 31 additions & 0 deletions dd-smoke-tests/asm-standalone-billing/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
plugins {
id 'java'
id 'org.springframework.boot' version '2.7.15'
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
id 'java-test-fixtures'
}

apply from: "$rootDir/gradle/java.gradle"
description = 'ASM Standalone Billing Tests.'

java {
sourceCompatibility = '1.8'
}

repositories {
mavenCentral()
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation group: 'io.opentracing', name: 'opentracing-api', version: '0.32.0'
implementation group: 'io.opentracing', name: 'opentracing-util', version: '0.32.0'
implementation project(':dd-trace-api')
testImplementation project(':dd-smoke-tests')
testImplementation(testFixtures(project(":dd-smoke-tests:iast-util")))
}

tasks.withType(Test).configureEach {
dependsOn "bootJar"
jvmArgs "-Ddatadog.smoketest.springboot.shadowJar.path=${tasks.bootJar.archiveFile.get()}"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package datadog.smoketest.asmstandalonebilling;

import java.util.EnumSet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.SessionTrackingMode;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {
@Bean
public ServletContextInitializer servletContextInitializer() {
return new SessionTrackingConfig();
}

private class SessionTrackingConfig implements ServletContextInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
EnumSet<SessionTrackingMode> sessionTrackingModes = EnumSet.of(SessionTrackingMode.COOKIE);
servletContext.setSessionTrackingModes(sessionTrackingModes);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package datadog.smoketest.asmstandalonebilling;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import io.opentracing.Span;
import io.opentracing.util.GlobalTracer;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("/rest-api")
public class Controller {

@GetMapping("/greetings")
public String greetings(@RequestParam(name = "forceKeep", required = false) boolean forceKeep) {
if (forceKeep) {
forceKeepSpan();
}
return "Hello I'm service " + System.getProperty("dd.service.name");
}

@GetMapping("/appsec/{id}")
public String pathParam(
@PathVariable("id") String id,
@RequestParam(name = "url", required = false) String url,
@RequestParam(name = "forceKeep", required = false) boolean forceKeep) {
if (forceKeep) {
forceKeepSpan();
}
if (url != null) {
RestTemplate restTemplate = new RestTemplate();
return restTemplate.getForObject(url, String.class);
}
return id;
}

@GetMapping("/iast")
@SuppressFBWarnings
public void write(
@RequestParam(name = "injection", required = false) String injection,
@RequestParam(name = "url", required = false) String url,
@RequestParam(name = "forceKeep", required = false) boolean forceKeep,
final HttpServletResponse response) {
if (forceKeep) {
forceKeepSpan();
}
if (injection != null) {
try {
response.getWriter().write(injection);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if (url != null) {
RestTemplate restTemplate = new RestTemplate();
restTemplate.getForObject(url, String.class);
}
}

/**
* @GetMapping("/forcekeep") public String forceKeep() { return "Span " + forceKeepSpan() + " will
* be kept alive"; } @GetMapping("/call") public String call( @RequestParam(name = "url", required
* = false) String url, @RequestParam(name = "forceKeep", required = false) boolean forceKeep) {
* if (forceKeep) { forceKeepSpan(); } if (url != null) { RestTemplate restTemplate = new
* RestTemplate(); return restTemplate.getForObject(url, String.class); } return "No url
* provided"; }
*/
private String forceKeepSpan() {
// TODO: Configure the keep alive in dd-trace-api
final Span span = GlobalTracer.get().activeSpan();
if (span != null) {
span.setTag("manual.keep", true);
return span.context().toSpanId();
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package datadog.smoketest.asmstandalonebilling;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootApplication.class, args);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package datadog.smoketest.asmstandalonebilling

import datadog.smoketest.AbstractServerSmokeTest
import datadog.trace.api.sampling.PrioritySampling
import datadog.trace.test.agent.decoder.DecodedTrace

abstract class AbstractAsmStandaloneBillingSmokeTest extends AbstractServerSmokeTest {

@Override
File createTemporaryFile(int processIndex) {
return null
}

@Override
String logLevel() {
return 'debug'
}

@Override
Closure decodedTracesCallback() {
return {} // force traces decoding
}

protected ProcessBuilder createProcess(String[] properties){
createProcess(-1, properties)
}


protected ProcessBuilder createProcess(int processIndex, String[] properties){
def port = processIndex == -1 ? httpPort : httpPorts[processIndex]
String springBootShadowJar = System.getProperty("datadog.smoketest.springboot.shadowJar.path")
List<String> command = []
command.add(javaPath())
command.addAll(defaultJavaProperties)
command.addAll(properties)
command.addAll((String[]) ['-jar', springBootShadowJar, "--server.port=${port}"])
ProcessBuilder processBuilder = new ProcessBuilder(command)
processBuilder.directory(new File(buildDirectory))
// Spring will print all environment variables to the log, which may pollute it and affect log assertions.
processBuilder.environment().clear()
return processBuilder
}

protected DecodedTrace getServiceTrace(String serviceName) {
return traces.find { trace ->
trace.spans.find { span ->
span.service == serviceName
}
}
}

protected checkRootSpanPrioritySampling(DecodedTrace trace, byte priority) {
return trace.spans[0].metrics['_sampling_priority_v1'] == priority
}

protected hasAppsecPropagationTag(DecodedTrace trace) {
return trace.spans[0].meta['_dd.p.appsec'] == "1"
}

protected hasApmDisabledTag(DecodedTrace trace) {
return trace.spans[0].metrics['_dd.apm.enabled'] == 0
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package datadog.smoketest.asmstandalonebilling

import datadog.trace.api.sampling.PrioritySampling
import okhttp3.Request

class AsmStandaloneBillingSamplingSmokeTest extends AbstractAsmStandaloneBillingSmokeTest {

@Override
ProcessBuilder createProcessBuilder(){
final String[] processProperties = [
"-Ddd.experimental.appsec.standalone.enabled=true",
"-Ddd.iast.enabled=true",
"-Ddd.iast.detection.mode=FULL",
"-Ddd.iast.debug.enabled=true",
"-Ddd.service.name=asm-standalone-billing-sampling-spring-smoketest-app",
]
return createProcess(processProperties)
}

void 'test force keep call using time sampling'() {
setup:
final vulnerableUrl = "http://localhost:${httpPorts[0]}/rest-api/iast?injection=xss"
final vulnerableRequest = new Request.Builder().url(vulnerableUrl).get().build()
final forceKeepUrl = "http://localhost:${httpPorts[0]}/rest-api/greetings?forceKeep=true"
final forceKeepRequest = new Request.Builder().url(forceKeepUrl).get().build()
final noForceKeepUrl = "http://localhost:${httpPorts[0]}/rest-api/greetings"
final noForceKeepRequest = new Request.Builder().url(noForceKeepUrl).get().build()

when: "firs request with ASM events"
final vulnerableResponse = client.newCall(vulnerableRequest).execute()

then: "First trace should have a root span with USER_KEEP sampling priority due to ASM events"
vulnerableResponse.successful
waitForTraceCount(1)
assert traces.size() == 1
checkRootSpanPrioritySampling(traces[0], PrioritySampling.USER_KEEP)
hasAppsecPropagationTag(traces[0])

when: "Request without ASM events and no force kept span"
final noForceKeepResponse = client.newCall(noForceKeepRequest).execute()

then: "This trace should enter into the sampling mechanism and have a root span with SAMPLER_KEEP sampling priority as it's the first span checked in a minute"
noForceKeepResponse.successful
waitForTraceCount(2)
assert traces.size() == 2
checkRootSpanPrioritySampling(traces[1], PrioritySampling.SAMPLER_KEEP)
!hasAppsecPropagationTag(traces[1])

when: "Request without ASM events and force kept span"
final forceKeepResponse = client.newCall(forceKeepRequest).execute()

then: "This trace should have a root span with USER_KEEP sampling priority as although it's not the first span checked in a minute, it's force kept'"
forceKeepResponse.successful
waitForTraceCount(3)
assert traces.size() == 3
checkRootSpanPrioritySampling(traces[2], PrioritySampling.USER_KEEP)
!hasAppsecPropagationTag(traces[2])

when: "Second request without ASM events and no force kept span"
final noForceKeepResponse2 = client.newCall(noForceKeepRequest).execute()

then: "This trace should enter into the sampling mechanism and have a root span with SAMPLER_DROP sampling priority as it's not the first span checked in a minute"
noForceKeepResponse2.successful
waitForTraceCount(4)
assert traces.size() == 4
checkRootSpanPrioritySampling(traces[3], PrioritySampling.SAMPLER_DROP)
!hasAppsecPropagationTag(traces[3])
}
}
Loading

0 comments on commit 900bce0

Please sign in to comment.