Skip to content

Commit 881bbbe

Browse files
committed
embeddings(test): plumbing for integration tests
1 parent da64c0d commit 881bbbe

14 files changed

Lines changed: 367 additions & 40 deletions

src/main/java/de/uni_passau/fim/se2/scratchlog/ScratchLogApplication.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.boot.CommandLineRunner;
2828
import org.springframework.boot.SpringApplication;
2929
import org.springframework.boot.autoconfigure.SpringBootApplication;
30+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
3031
import org.springframework.context.ApplicationContext;
3132
import org.springframework.scheduling.annotation.EnableScheduling;
3233

@@ -45,6 +46,7 @@
4546
*/
4647
@SpringBootApplication
4748
@EnableScheduling
49+
@EnableConfigurationProperties
4850
public class ScratchLogApplication implements CommandLineRunner {
4951

5052
private static final Logger log = LoggerFactory.getLogger(ScratchLogApplication.class);

src/main/java/de/uni_passau/fim/se2/scratchlog/application/service/EmbeddingModelService.java

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
import org.springframework.stereotype.Service;
2828
import org.springframework.util.ConcurrentLruCache;
2929
import org.springframework.util.StopWatch;
30+
import org.springframework.web.client.ResourceAccessException;
3031
import org.springframework.web.client.RestClient;
32+
import org.springframework.web.client.RestClientResponseException;
3133
import tools.jackson.databind.json.JsonMapper;
3234

3335
import java.io.ByteArrayInputStream;
@@ -93,7 +95,7 @@ public EmbeddingModelService(
9395
this.codeService = codeService;
9496
this.testFitnessService = testFitnessService;
9597

96-
this.restClient = RestClient.create(codeEmbeddingConfiguration.getEmbeddingConnectorUrl());
98+
this.restClient = RestClient.create();
9799

98100
MLPreprocessorCommonOptions mlOptions = new MLPreprocessorCommonOptions(
99101
MLOutputPath.console(),
@@ -141,6 +143,9 @@ public ProgramProjection2D getProgressVarianceProjectionAllLatest(
141143
projectsById.put(project.id(), project.projectJson());
142144
projectIdToStudentId.put(project.id(), project.userId());
143145
});
146+
if (projectsById.isEmpty()) {
147+
return new ProgramProjection2D(Collections.emptyList());
148+
}
144149

145150
final var starterProject = getStarterProject(experimentId);
146151
final var solutionProject = getSolutionProject(experimentId);
@@ -558,16 +563,21 @@ private String getProjectJson(final byte[] programSb3) throws IOException {
558563
private <B, R> R apiRequest(final String path, final B body, final Class<R> responseType) {
559564
final StopWatch watch = new StopWatch();
560565

561-
watch.start();
562-
var response = restClient.post()
563-
.uri(path)
564-
.body(body)
565-
.retrieve()
566-
.body(responseType);
567-
watch.stop();
568-
log.debug("Embedding API request done in {}ms.", watch.getTotalTimeMillis());
569-
570-
return response;
566+
try {
567+
watch.start();
568+
var response = restClient.post()
569+
.uri(codeEmbeddingConfiguration.getEmbeddingConnectorUrl().resolve(path))
570+
.body(body)
571+
.retrieve()
572+
.body(responseType);
573+
watch.stop();
574+
log.debug("Embedding API request done in {}ms.", watch.getTotalTimeMillis());
575+
576+
return response;
577+
} catch (RestClientResponseException | ResourceAccessException e) {
578+
log.error("Could not make API call to embedding model.", e);
579+
throw e;
580+
}
571581
}
572582

573583
public record ProgressVarianceProjectionRequest(
@@ -577,12 +587,12 @@ public record ProgressVarianceProjectionRequest(
577587
) {
578588
}
579589

580-
private record ProgressVarianceProjectionResponse(
590+
public record ProgressVarianceProjectionResponse(
581591
List<Projection> projections
582592
) {
583593
}
584594

585-
private record Projection(int id, List<Double> xy) {
595+
public record Projection(int id, List<Double> xy) {
586596
}
587597

588598
public record ProgramProjection2D(List<DataSeries> data) {

src/main/java/de/uni_passau/fim/se2/scratchlog/application/service/WhiskerService.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,14 @@ public class WhiskerService {
2626

2727
private static final Logger log = LoggerFactory.getLogger(WhiskerService.class);
2828

29+
private final WhiskerConfiguration whiskerConfiguration;
30+
2931
private final RestClient restClient;
3032

3133
@Autowired
3234
public WhiskerService(final WhiskerConfiguration whiskerConfiguration) {
33-
this.restClient = RestClient.create(whiskerConfiguration.getBaseUrl());
35+
this.whiskerConfiguration = whiskerConfiguration;
36+
this.restClient = RestClient.create();
3437
}
3538

3639
/**
@@ -49,7 +52,7 @@ WhiskerApiResponse runTests(final byte[] projectSb3, final String testSuite) {
4952
try {
5053
return restClient
5154
.post()
52-
.uri("/test")
55+
.uri(whiskerConfiguration.getBaseUrl().resolve("/test"))
5356
.body(body)
5457
.retrieve()
5558
.body(WhiskerApiResponse.class);

src/main/java/de/uni_passau/fim/se2/scratchlog/spring/configuration/CodeEmbeddingConfiguration.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,12 @@
11
package de.uni_passau.fim.se2.scratchlog.spring.configuration;
22

3-
import de.uni_passau.fim.se2.scratchlog.util.Constants;
43
import lombok.Getter;
54
import lombok.Setter;
6-
import org.springframework.boot.context.properties.ConfigurationProperties;
7-
import org.springframework.context.annotation.Configuration;
8-
import org.springframework.context.annotation.Profile;
95

106
import java.net.URI;
117

128
@Getter
139
@Setter
14-
@Configuration
15-
@ConfigurationProperties(prefix = "code-embeddings")
16-
@Profile(Constants.PROFILE_CODE_EMBEDDINGS)
1710
public class CodeEmbeddingConfiguration {
1811

1912
private String model;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package de.uni_passau.fim.se2.scratchlog.spring.configuration;
2+
3+
import de.uni_passau.fim.se2.scratchlog.util.Constants;
4+
import org.springframework.boot.context.properties.ConfigurationProperties;
5+
import org.springframework.context.annotation.Bean;
6+
import org.springframework.context.annotation.Configuration;
7+
import org.springframework.context.annotation.Profile;
8+
9+
@Configuration
10+
@Profile("!test")
11+
public class ConfigurationPropertiesFactory {
12+
13+
/**
14+
* Automatically provided code embedding model configuration.
15+
* @return The configuration
16+
*/
17+
@Bean
18+
@Profile(Constants.PROFILE_CODE_EMBEDDINGS)
19+
@ConfigurationProperties(prefix = "code-embeddings")
20+
public CodeEmbeddingConfiguration codeEmbeddingConfiguration() {
21+
return new CodeEmbeddingConfiguration();
22+
}
23+
24+
/**
25+
* Automatically provided Whisker configuration.
26+
* @return The configuration
27+
*/
28+
@Bean
29+
@Profile(Constants.PROFILE_WHISKER)
30+
@ConfigurationProperties(prefix = "whisker")
31+
public WhiskerConfiguration whiskerConfiguration() {
32+
return new WhiskerConfiguration();
33+
}
34+
35+
}

src/main/java/de/uni_passau/fim/se2/scratchlog/spring/configuration/WhiskerConfiguration.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,12 @@
11
package de.uni_passau.fim.se2.scratchlog.spring.configuration;
22

3-
import de.uni_passau.fim.se2.scratchlog.util.Constants;
43
import lombok.Getter;
54
import lombok.Setter;
6-
import org.springframework.boot.context.properties.ConfigurationProperties;
7-
import org.springframework.context.annotation.Configuration;
8-
import org.springframework.context.annotation.Profile;
95

106
import java.net.URI;
117

128
@Getter
139
@Setter
14-
@Configuration
15-
@ConfigurationProperties(prefix = "whisker")
16-
@Profile(Constants.PROFILE_WHISKER)
1710
public class WhiskerConfiguration {
1811

1912
private URI baseUrl;

src/test/java/de/uni_passau/fim/se2/scratchlog/AbstractScratchLogControllerTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@
66
import org.springframework.test.context.junit.jupiter.SpringExtension;
77
import org.springframework.test.web.servlet.MockMvc;
88

9+
/**
10+
* @deprecated New tests should use the {@link AbstractScratchLogTest} with non-mocked services.
11+
*/
912
@AutoConfigureMockMvc
1013
@ExtendWith(SpringExtension.class)
14+
@Deprecated
1115
public abstract class AbstractScratchLogControllerTest extends AbstractScratchLogTest {
1216

1317
@Autowired

src/test/java/de/uni_passau/fim/se2/scratchlog/AbstractScratchLogTest.java

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package de.uni_passau.fim.se2.scratchlog;
22

3+
import de.uni_passau.fim.se2.scratchlog.spring.configuration.CodeEmbeddingConfiguration;
4+
import de.uni_passau.fim.se2.scratchlog.spring.configuration.WhiskerConfiguration;
35
import de.uni_passau.fim.se2.scratchlog.testing_utils.EntityUtilService;
46
import de.uni_passau.fim.se2.scratchlog.testing_utils.EventUtilService;
57
import de.uni_passau.fim.se2.scratchlog.util.ApplicationProperties;
@@ -9,15 +11,20 @@
911
import org.junit.jupiter.api.AfterAll;
1012
import org.junit.jupiter.api.AfterEach;
1113
import org.junit.jupiter.api.BeforeAll;
14+
import org.junit.jupiter.api.BeforeEach;
1215
import org.mockito.Mockito;
1316
import org.springframework.beans.factory.annotation.Autowired;
1417
import org.springframework.boot.test.context.SpringBootTest;
18+
import org.springframework.context.annotation.Bean;
19+
import org.springframework.context.annotation.Configuration;
20+
import org.springframework.core.annotation.Order;
1521
import org.springframework.http.HttpStatus;
1622
import org.springframework.http.HttpStatusCode;
1723
import org.springframework.test.context.ActiveProfiles;
1824
import org.springframework.test.context.bean.override.mockito.MockitoSpyBean;
1925
import org.testcontainers.junit.jupiter.Testcontainers;
2026
import tools.jackson.databind.json.JsonMapper;
27+
import org.springframework.core.Ordered;
2128

2229
import java.io.IOException;
2330

@@ -40,7 +47,7 @@
4047
* the database and/or ScratchLog service/repository/controller beans.
4148
*/
4249
@SpringBootTest
43-
@ActiveProfiles({"test", Constants.PROFILE_WHISKER})
50+
@ActiveProfiles({"test", Constants.PROFILE_WHISKER, Constants.PROFILE_CODE_EMBEDDINGS})
4451
@Testcontainers
4552
public abstract class AbstractScratchLogTest {
4653

@@ -56,6 +63,12 @@ public abstract class AbstractScratchLogTest {
5663
@Autowired
5764
private JsonMapper jsonMapper;
5865

66+
@Autowired
67+
private WhiskerConfiguration whiskerConfiguration;
68+
69+
@Autowired
70+
private CodeEmbeddingConfiguration codeEmbeddingConfiguration;
71+
5972
protected static MockWebServer mockWebServer;
6073

6174
@BeforeAll
@@ -69,6 +82,12 @@ static void afterAll() {
6982
mockWebServer.close();
7083
}
7184

85+
@BeforeEach
86+
void setUp() {
87+
whiskerConfiguration.setBaseUrl(mockWebServer.url("/").uri());
88+
codeEmbeddingConfiguration.setEmbeddingConnectorUrl(mockWebServer.url("/").uri());
89+
}
90+
7291
@AfterEach
7392
void resetMocks() {
7493
Mockito.reset(applicationProperties);
@@ -93,4 +112,25 @@ protected <T> void enqueueMockWebServerJsonResponse(final T response, final Http
93112
);
94113
}
95114

115+
@Configuration
116+
public static class ScratchLogTestConfiguration {
117+
@Bean
118+
@Order(Ordered.HIGHEST_PRECEDENCE)
119+
public CodeEmbeddingConfiguration codeEmbeddingConfiguration () {
120+
final CodeEmbeddingConfiguration configuration = new CodeEmbeddingConfiguration();
121+
configuration.setModel("llm");
122+
configuration.setEmbeddingConnectorUrl(mockWebServer.url("/").uri());
123+
124+
return configuration;
125+
}
126+
127+
@Bean
128+
@Order(Ordered.HIGHEST_PRECEDENCE)
129+
public WhiskerConfiguration whiskerConfiguration () {
130+
final WhiskerConfiguration configuration = new WhiskerConfiguration();
131+
configuration.setBaseUrl(mockWebServer.url("/").uri());
132+
133+
return configuration;
134+
}
135+
}
96136
}

src/test/java/de/uni_passau/fim/se2/scratchlog/application/TestFitnessServiceTest.java

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,12 @@
1212
import de.uni_passau.fim.se2.scratchlog.persistence.repository.TestCaseRepository;
1313
import de.uni_passau.fim.se2.scratchlog.persistence.repository.TestResultRepository;
1414
import de.uni_passau.fim.se2.scratchlog.persistence.repository.TestSuiteRepository;
15-
import de.uni_passau.fim.se2.scratchlog.spring.configuration.WhiskerConfiguration;
1615
import de.uni_passau.fim.se2.scratchlog.util.enums.BlockEventSpecific;
1716
import de.uni_passau.fim.se2.scratchlog.util.enums.BlockEventType;
1817
import org.junit.jupiter.api.BeforeEach;
1918
import org.junit.jupiter.api.Test;
2019
import org.springframework.beans.factory.annotation.Autowired;
2120

22-
import java.net.URI;
2321
import java.util.ArrayList;
2422
import java.util.Collections;
2523
import java.util.List;
@@ -34,9 +32,6 @@ class TestFitnessServiceTest extends AbstractScratchLogTest {
3432
@Autowired
3533
private TestFitnessService testFitnessService;
3634

37-
@Autowired
38-
private WhiskerConfiguration whiskerConfiguration;
39-
4035
@Autowired
4136
private TestSuiteRepository testSuiteRepository;
4237

@@ -54,9 +49,6 @@ class TestFitnessServiceTest extends AbstractScratchLogTest {
5449

5550
@BeforeEach
5651
void setUp() {
57-
final URI uri = URI.create("http://localhost:" + mockWebServer.getPort());
58-
whiskerConfiguration.setBaseUrl(uri);
59-
6052
final User user = entityUtilService.generateUser("testFitness");
6153
final Experiment experiment = entityUtilService.generateExperiment("testFitness");
6254
blockEvent = eventUtilService.generateBlockEvent(

0 commit comments

Comments
 (0)