Skip to content

Commit c8747e1

Browse files
committed
[Testing][JShellAPI] Setting first integration test for /eval endpoint;
Note: this includes changes and improvements in gradle.build files;
1 parent 9dc586e commit c8747e1

File tree

9 files changed

+122
-63
lines changed

9 files changed

+122
-63
lines changed

Diff for: JShellAPI/build.gradle

+21-42
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,18 @@ dependencies {
1414
implementation 'com.github.docker-java:docker-java-core:3.3.6'
1515

1616
testImplementation('org.springframework.boot:spring-boot-starter-test') {
17-
configurations {
18-
all {
19-
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
20-
exclude group: 'ch.qos.logback', module: 'logback-classic'
21-
exclude group: 'org.apache.logging.log4j', module: 'log4j-to-slf4j'
22-
}
23-
}
17+
exclude group: 'ch.qos.logback', module: 'logback-classic'
2418
}
25-
testImplementation gradleTestKit()
19+
testImplementation 'org.springframework.boot:spring-boot-starter-webflux'
2620

2721
annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
2822

2923
}
3024

31-
def imageName = 'togetherjava.org:5001/togetherjava/jshellbackend:master' ?: 'latest';
32-
3325
jib {
3426
from.image = 'eclipse-temurin:21'
3527
to {
36-
image = imageName
28+
image = 'togetherjava.org:5001/togetherjava/jshellbackend:master' ?: 'latest'
3729
auth {
3830
username = System.getenv('ORG_REGISTRY_USER') ?: ''
3931
password = System.getenv('ORG_REGISTRY_PASSWORD') ?: ''
@@ -51,41 +43,28 @@ shadowJar {
5143
archiveVersion.set('')
5244
}
5345

54-
tasks.register('buildDockerImage') {
55-
group = 'Docker'
56-
description = 'builds jshellwrapper as docker image'
57-
dependsOn jibDockerBuild
58-
doFirst{
59-
println('creating docker image...')
60-
}
61-
doLast{
62-
println('docker image is ready for use')
46+
def jshellWrapperImageName = rootProject.ext.jShellWrapperImageName;
47+
48+
processResources {
49+
filesMatching('application.yaml') {
50+
expand(jShellWrapperImageName: jshellWrapperImageName)
6351
}
6452
}
6553

66-
tasks.register('removeDockerImage', Exec) {
67-
group = 'Docker'
68-
description = 'removes jshellwrapper image'
69-
commandLine 'docker', 'rmi', '-f', imageName
70-
doLast{
71-
println('docker image has been removed')
72-
}
54+
55+
def taskBuildDockerImage = tasks.register('buildDockerImage') {
56+
group = 'docker'
57+
description = 'builds jshellwrapper as docker image'
58+
dependsOn project(':JShellWrapper').tasks.named('jibDockerBuild')
7359
}
7460

75-
tasks.named('test') {
76-
dependsOn tasks.named('buildDockerImage')
61+
def taskRemoveDockerImage = tasks.register('removeDockerImage', Exec) {
62+
group = 'docker'
63+
description = 'removes jshellwrapper image'
64+
commandLine 'docker', 'rmi', '-f', jshellWrapperImageName
65+
}
7766

78-
doFirst {
79-
try {
80-
println 'Running JShellAPI tests...'
81-
} catch (Exception e) {
82-
println 'JShellAPI tests failed'
83-
tasks.named('removeDockerImage').get().execute()
84-
throw e
85-
}
86-
}
87-
doLast {
88-
println 'JShellAPI tests completed.'
89-
}
90-
finalizedBy tasks.named('removeDockerImage')
67+
test {
68+
dependsOn taskBuildDockerImage
69+
finalizedBy taskRemoveDockerImage
9170
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.togetherjava.jshellapi.rest;
2+
3+
public final class ApiEndpoints {
4+
private ApiEndpoints() {}
5+
6+
public static final String EVALUATE_CODE_SNIPPET = "/jshell/eval";
7+
}

Diff for: JShellAPI/src/main/java/org/togetherjava/jshellapi/service/DockerService.java

+20-4
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
import com.github.dockerjava.core.DefaultDockerClientConfig;
88
import com.github.dockerjava.core.DockerClientImpl;
99
import com.github.dockerjava.httpclient5.ApacheDockerHttpClient;
10+
import jakarta.el.PropertyNotFoundException;
1011
import org.slf4j.Logger;
1112
import org.slf4j.LoggerFactory;
1213
import org.springframework.beans.factory.DisposableBean;
14+
import org.springframework.beans.factory.annotation.Value;
1315
import org.springframework.lang.Nullable;
1416
import org.springframework.stereotype.Service;
1517

@@ -29,6 +31,9 @@ public class DockerService implements DisposableBean {
2931

3032
private final DockerClient client;
3133

34+
@Value("${jshell-wrapper.image-name}")
35+
private String jshellWrapperImageName;
36+
3237
public DockerService(Config config) {
3338
DefaultDockerClientConfig clientConfig =
3439
DefaultDockerClientConfig.createDefaultConfigBuilder().build();
@@ -59,22 +64,33 @@ private void cleanupLeftovers(UUID currentId) {
5964

6065
public String spawnContainer(long maxMemoryMegs, long cpus, @Nullable String cpuSetCpus,
6166
String name, Duration evalTimeout, long sysoutLimit) throws InterruptedException {
62-
String imageName = "togetherjava.org:5001/togetherjava/jshellwrapper";
67+
String imageName = Optional.ofNullable(this.jshellWrapperImageName)
68+
.orElseThrow(() -> new PropertyNotFoundException(
69+
"unable to find jshellWrapper image name property"));
70+
71+
String[] imageNameParts = imageName.split(":master");
72+
73+
if (imageNameParts.length != 1) {
74+
throw new IllegalArgumentException("invalid jshellWrapper image name");
75+
}
76+
77+
String baseImageName = imageNameParts[0];
78+
6379
boolean presentLocally = client.listImagesCmd()
64-
.withFilter("reference", List.of(imageName))
80+
.withFilter("reference", List.of(baseImageName))
6581
.exec()
6682
.stream()
6783
.flatMap(it -> Arrays.stream(it.getRepoTags()))
6884
.anyMatch(it -> it.endsWith(":master"));
6985

7086
if (!presentLocally) {
71-
client.pullImageCmd(imageName)
87+
client.pullImageCmd(baseImageName)
7288
.withTag("master")
7389
.exec(new PullImageResultCallback())
7490
.awaitCompletion(5, TimeUnit.MINUTES);
7591
}
7692

77-
return client.createContainerCmd(imageName + ":master")
93+
return client.createContainerCmd(baseImageName + ":master")
7894
.withHostConfig(HostConfig.newHostConfig()
7995
.withAutoRemove(true)
8096
.withInit(true)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"properties": [
3+
{
4+
"name": "jshell-wrapper.image-name",
5+
"type": "java.lang.String",
6+
"description": "JShellWrapper image name injected from the top-level gradle build file."
7+
}
8+
] }

Diff for: JShellAPI/src/main/resources/application.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ jshellapi:
2020
dockerResponseTimeout: 60
2121
dockerConnectionTimeout: 60
2222

23+
jshell-wrapper:
24+
image-name: ${jShellWrapperImageName}
25+
2326
server:
2427
error:
2528
include-message: always
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,62 @@
11
package org.togetherjava.jshellapi;
22

3+
import org.junit.jupiter.api.DisplayName;
34
import org.junit.jupiter.api.Test;
5+
import org.springframework.beans.factory.annotation.Autowired;
46
import org.springframework.boot.test.context.SpringBootTest;
7+
import org.springframework.test.context.ContextConfiguration;
8+
import org.springframework.test.web.reactive.server.WebTestClient;
9+
10+
import org.togetherjava.jshellapi.dto.JShellResult;
11+
import org.togetherjava.jshellapi.rest.ApiEndpoints;
12+
13+
import java.time.Duration;
514

615
import static org.assertj.core.api.Assertions.assertThat;
716

8-
// TODO - write some integrations
17+
/**
18+
* This class holds integration tests for JShellAPI. It depends on gradle building image task, fore
19+
* more information check "test" section in gradle.build file.
20+
*
21+
* @author Firas Regaieg
22+
*/
23+
@ContextConfiguration
924
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
1025
public class JShellApiTests {
1126

27+
@Autowired
28+
private WebTestClient webTestClient;
29+
30+
private static final String TEST_EVALUATION_ID = "test";
31+
private static final String TEST_CODE_INPUT = "2+2";
32+
private static final String TEST_CODE_EXPECTED_OUTPUT = "4";
33+
1234
@Test
13-
public void test() {
14-
assertThat(true).isTrue();
35+
@DisplayName("When posting code snippet, evaluate it then returns successfully result")
36+
public void evaluateCodeSnippetTest() {
37+
38+
JShellResult result = this.webTestClient.mutate()
39+
.responseTimeout(Duration.ofSeconds(6))
40+
.build()
41+
.post()
42+
.uri(ApiEndpoints.EVALUATE_CODE_SNIPPET + "/" + TEST_EVALUATION_ID)
43+
.bodyValue(TEST_CODE_INPUT)
44+
.exchange()
45+
.expectStatus()
46+
.isOk()
47+
.expectBody(JShellResult.class)
48+
.value(task -> assertThat(task).isNotNull())
49+
.returnResult()
50+
.getResponseBody();
51+
52+
assertThat(result).isNotNull();
53+
54+
boolean isValidResult = result.snippetsResults()
55+
.stream()
56+
.filter(res -> res.result() != null)
57+
.anyMatch(res -> res.result().equals(TEST_CODE_EXPECTED_OUTPUT));
58+
59+
assertThat(isValidResult).isTrue();
60+
1561
}
1662
}

Diff for: JShellWrapper/build.gradle

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ test {
2424
jib {
2525
from.image = 'eclipse-temurin:22-alpine'
2626
to {
27-
image = 'togetherjava.org:5001/togetherjava/jshellwrapper:master' ?: 'latest'
27+
image = rootProject.ext.jShellWrapperImageName
2828
auth {
2929
username = System.getenv('ORG_REGISTRY_USER') ?: ''
3030
password = System.getenv('ORG_REGISTRY_PASSWORD') ?: ''
@@ -41,4 +41,4 @@ shadowJar {
4141
archiveBaseName.set('JShellWrapper')
4242
archiveClassifier.set('')
4343
archiveVersion.set('')
44-
}
44+
}

Diff for: JShellWrapper/src/test/java/JShellWrapperTest.java

+8-12
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,10 @@ void testHelloWorld() {
4949

5050
@Test
5151
void testExpressionResult() {
52-
evalTest(
53-
"""
54-
eval
55-
1
56-
"Hello world!\"""",
57-
"""
52+
evalTest("""
53+
eval
54+
1
55+
"Hello world!\"""", """
5856
OK
5957
0
6058
OK
@@ -67,12 +65,10 @@ void testExpressionResult() {
6765
6866
false
6967
""");
70-
evalTest(
71-
"""
72-
eval
73-
1
74-
2+2""",
75-
"""
68+
evalTest("""
69+
eval
70+
1
71+
2+2""", """
7672
OK
7773
0
7874
OK

Diff for: build.gradle

+4
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,7 @@ subprojects {
6868
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.2'
6969
}
7070
}
71+
72+
ext {
73+
jShellWrapperImageName = 'togetherjava.org:5001/togetherjava/jshellwrapper:master' ?: 'latest'
74+
}

0 commit comments

Comments
 (0)