Skip to content

Commit

Permalink
Migrate server tests to JUnit5. Enable parallel test execution. Impro…
Browse files Browse the repository at this point in the history
…ve stuff to fix concurrent tests execution.
  • Loading branch information
ekharkunov committed Jan 7, 2025
1 parent c56dbb0 commit 216baa6
Show file tree
Hide file tree
Showing 19 changed files with 297 additions and 295 deletions.
24 changes: 19 additions & 5 deletions server/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ targetCompatibility = '17'
dependencyManagement {
imports {
mavenBom 'com.google.cloud:spring-cloud-gcp-dependencies:5.8.0'
mavenBom 'org.junit:junit-bom:5.11.4'
}
}

Expand Down Expand Up @@ -72,13 +73,22 @@ dependencies {
implementation('io.micrometer:micrometer-tracing-bridge-otel:1.4.1')
runtimeOnly('net.logstash.logback:logstash-logback-encoder:8.0')
runtimeOnly('io.micrometer:micrometer-registry-influx:1.14.0')
runtimeOnly('io.micrometer:micrometer-registry-prometheus:1.13.2')
runtimeOnly('io.micrometer:micrometer-registry-prometheus:1.13.2') {
exclude group: 'org.junit.jupiter'
}

testImplementation('junit:junit:4.13.2')
testImplementation('org.junit.jupiter:junit-jupiter-engine')
testImplementation('org.junit.jupiter:junit-jupiter-params')
testImplementation('org.springframework:spring-test')
testImplementation('org.springframework.boot:spring-boot-starter-test')
testImplementation('io.micrometer:micrometer-tracing-test')
testImplementation('io.micrometer:micrometer-tracing-integration-test')
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.jupiter'
}
testImplementation('io.micrometer:micrometer-tracing-test') {
exclude group: 'org.junit.jupiter'
}
testImplementation('io.micrometer:micrometer-tracing-integration-test') {
exclude group: 'org.junit.jupiter'
}
testImplementation('org.springframework.security:spring-security-test')

testImplementation('org.smali:dexlib2:2.5.2')
Expand Down Expand Up @@ -187,3 +197,7 @@ task buildStandalone() {
}
}
}

test {
useJUnitPlatform()
}
14 changes: 11 additions & 3 deletions server/docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -211,19 +211,27 @@ services:
extends:
file: common-services.yml
service: test_builder
command: ["--spring.config.location=classpath:./,file:/etc/defold/extender/", "--spring.profiles.active=local-dev-app", "--extender.authentication.platforms=linux", "--extender.authentication.users=file:/etc/defold/users/testusers.txt"]
command: ["--spring.config.location=classpath:./,file:/etc/defold/extender/", "--spring.profiles.active=local-dev-app", "--extender.authentication.platforms=linux", "--extender.authentication.users=file:/etc/defold/users/testusers.txt", "--server.port=9001"]
volumes:
- ./../users:/etc/defold/users:ro
expose:
- "9000"
- "9001"
ports:
- "9000:9000"
- "9001:9001"
profiles:
- auth-test
networks:
default:
aliases:
- frontend
# redefine helathcheck because of another port
# see the same configuration in common-services.yml
healthcheck:
test: wget --no-verbose --tries=1 --spider http://localhost:9001/actuator/health
interval: 10s
timeout: 2s
retries: 10
start_period: 5s
# metrics
grafana:
image: grafana/grafana
Expand Down
15 changes: 14 additions & 1 deletion server/scripts/start-test-server.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ set -x

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

PORT=9000
RUN_ENV=""
if [ "$COMPOSE_PROFILE" == "" ]; then
COMPOSE_PROFILE="test"
Expand All @@ -15,6 +14,9 @@ if [ "$APPLICATION" == "" ]; then
APPLICATION="extender-test"
fi

if [ "$PORT" == "" ]; then
PORT=9000
fi

echo "Using RUN_ENV: ${RUN_ENV}"
echo "Using compose profile: ${COMPOSE_PROFILE}"
Expand Down Expand Up @@ -48,12 +50,23 @@ check_containers_health() {
all_healthy=true

for container in $(docker ps -q); do
health_field=$(docker inspect --format='{{.State.Health}}' "$container")
if [ "$health_field" == "<nil>" ]; then
echo "Container has no health status. Skipped."
continue
fi
name=$(docker inspect --format='{{.Name}}' "$container" | sed 's/\///')
app_name=$(docker inspect "$container" | jq -r '.[0].Config.Labels["com.docker.compose.project"]')
health_status=$(docker inspect --format='{{.State.Health.Status}}' "$container")

if [ "$app_name" != "$APPLICATION" ]; then
echo "Skip health check of unrelated container."
fi

# If health status is empty, container doesn't have a health check defined
if [ -z "$health_status" ]; then
health_status="no health check"
continue
fi

echo "$name: $health_status"
Expand Down
90 changes: 42 additions & 48 deletions server/src/test/java/com/defold/extender/AuthenticationTest.java
Original file line number Diff line number Diff line change
@@ -1,31 +1,37 @@
package com.defold.extender;

import com.defold.extender.client.*;
import com.defold.extender.client.ExtenderClient;
import com.defold.extender.client.ExtenderClientException;
import com.defold.extender.client.ExtenderResource;
import com.defold.extender.client.FileExtenderResource;
import com.google.common.collect.Lists;
import org.apache.commons.io.FileUtils;
import org.junit.*;
import org.junit.rules.TestName;
import org.junit.rules.ExpectedException;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.slf4j.Logger;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggingSystem;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.*;

import static org.junit.Assert.*;
import java.util.List;
import java.util.stream.Collectors;

public class AuthenticationTest {
public class AuthenticationTest implements AfterEachCallback {

private static final int EXTENDER_PORT = 9000;
private static final int EXTENDER_PORT = 9001;
private static final String SDK_VERSION = "d6882f432beca85d460ec42497888157c356d058"; // 1.9.0
private static final String PLATFORM_ARMV7_ANDROID = "armv7-android";
private static final String PLATFORM_LINUX = "x86_64-linux";

private long startTime;

private static final List<ExtenderResource> SOURCE_FILES = Lists.newArrayList(
new FileExtenderResource("test-data/AndroidManifest.xml", "AndroidManifest.xml"),
new FileExtenderResource("test-data/ext_basic/ext.manifest"),
Expand All @@ -36,26 +42,22 @@ public class AuthenticationTest {
LoggingSystem.get(ClassLoader.getSystemClassLoader()).setLogLevel(Logger.ROOT_LOGGER_NAME, LogLevel.INFO);
}

@Rule
public TestName name = new TestName();

@Rule
public ExpectedException exceptionRule = ExpectedException.none();

public AuthenticationTest() {}

@BeforeClass
@BeforeAll
public static void beforeClass() throws IOException, InterruptedException {
ProcessExecutor processExecutor = new ProcessExecutor();
processExecutor.putEnv("COMPOSE_PROFILE", "auth-test");
processExecutor.putEnv("APPLICATION", "extender-test-auth");
processExecutor.putEnv("PORT", String.valueOf(EXTENDER_PORT));
processExecutor.execute("scripts/start-test-server.sh");
System.out.println(processExecutor.getOutput());

long startTime = System.currentTimeMillis();

// Wait for server to start in container.
File cacheDir = new File("build");
File cacheDir = Files.createTempDirectory("health_check").toFile();
cacheDir.deleteOnExit();
ExtenderClient extenderClient = new ExtenderClient("http://localhost:" + EXTENDER_PORT, cacheDir);

int count = 100;
Expand All @@ -75,40 +77,28 @@ public static void beforeClass() throws IOException, InterruptedException {
}
}

@AfterClass
@AfterAll
public static void afterClass() throws IOException, InterruptedException {
ProcessExecutor processExecutor = new ProcessExecutor();
processExecutor.putEnv("APPLICATION", "extender-test-auth");
processExecutor.execute("scripts/stop-test-server.sh");
System.out.println(processExecutor.getOutput());
}

@Before
public void beforeTest() throws IOException {
startTime = System.currentTimeMillis();
}

@After
public void afterTest()
{
@Override
public void afterEach(ExtensionContext context) throws Exception {
File buildDir = new File("build" + File.separator + SDK_VERSION);
if (buildDir.exists()) {
try {
FileUtils.deleteDirectory(buildDir);
} catch (IOException e) {
}
}

System.out.println(String.format("Test %s took: %.2f seconds", name.getMethodName(), (System.currentTimeMillis() - startTime) / 1000.f));
}

private void doBuild(String user, String password, File destination, File log, String platform) throws IOException, ExtenderClientException {
File cachedBuild = new File(String.format("build/%s/build.zip", platform));
if (cachedBuild.exists())
cachedBuild.delete();
assertFalse(cachedBuild.exists());

File cacheDir = new File("build");
File cacheDir = Files.createTempDirectory(platform).toFile();
cacheDir.deleteOnExit();
String url;
if (user != null) {
url = String.format("http://%s:%s@localhost:%d", user, password, EXTENDER_PORT);
Expand All @@ -119,10 +109,14 @@ private void doBuild(String user, String password, File destination, File log, S
System.out.println("URL " + url);
ExtenderClient extenderClient = new ExtenderClient(url, cacheDir);
try {
// make a copy because several builds can happened concurrenlty. During the build extender client
// sort source list to calculate hash
List<ExtenderResource> sourcesCopy = SOURCE_FILES.stream()
.collect(Collectors.toList());
extenderClient.build(
platform,
SDK_VERSION,
SOURCE_FILES,
sourcesCopy,
destination,
log
);
Expand All @@ -138,35 +132,35 @@ public void buildLinuxWithAuthenticatedUser() throws IOException, ExtenderClient
File destination = Files.createTempFile("dmengine", ".zip").toFile();
File log = Files.createTempFile("dmengine", ".log").toFile();
doBuild("bobuser", "bobpassword", destination, log, PLATFORM_LINUX);
assertTrue("Resulting engine should be of a size greater than zero.", destination.length() > 0);
assertEquals("Log should be of size zero if successful.", 0, log.length());
assertTrue(destination.length() > 0, "Resulting engine should be of a size greater than zero.");
assertEquals(0, log.length(), "Log should be of size zero if successful.");
}

@Test
public void buildLinuxWithWrongPassword() throws IOException, ExtenderClientException {
exceptionRule.expect(ExtenderClientException.class);

File destination = Files.createTempFile("dmengine", ".zip").toFile();
File log = Files.createTempFile("dmengine", ".log").toFile();
doBuild("bobuser", "wrongpassword", destination, log, PLATFORM_LINUX);
assertTrue("Resulting engine should be of a size equal to zero.", destination.length() == 0);
assertThrows(ExtenderClientException.class, () -> {
doBuild("bobuser", "wrongpassword", destination, log, PLATFORM_LINUX);
});
assertTrue(destination.length() == 0, "Resulting engine should be of a size equal to zero.");
}

@Test
public void buildLinuxWithNoUser() throws IOException, ExtenderClientException {
exceptionRule.expect(ExtenderClientException.class);

File destination = Files.createTempFile("dmengine", ".zip").toFile();
File log = Files.createTempFile("dmengine", ".log").toFile();
doBuild(null, null, destination, log, PLATFORM_LINUX);
assertTrue("Resulting engine should be of a size equal to zero.", destination.length() == 0);
assertThrows(ExtenderClientException.class, () -> {
doBuild(null, null, destination, log, PLATFORM_LINUX);
});
assertTrue(destination.length() == 0, "Resulting engine should be of a size equal to zero.");
}

@Test
public void buildAndroidWithNoUser() throws IOException, ExtenderClientException {
File destination = Files.createTempFile("dmengine", ".zip").toFile();
File log = Files.createTempFile("dmengine", ".log").toFile();
doBuild(null, null, destination, log, PLATFORM_ARMV7_ANDROID);
assertTrue("Resulting engine should be of a size greater than zero.", destination.length() > 0);
assertTrue(destination.length() > 0, "Resulting engine should be of a size greater than zero.");
}
}
Loading

0 comments on commit 216baa6

Please sign in to comment.