diff --git a/db/changelog/v-1/02-changeset-agent-status-table.xml b/db/changelog/v-1/02-changeset-agent-status-table.xml
index 81cc8bd7df..56a10aa5f1 100644
--- a/db/changelog/v-1/02-changeset-agent-status-table.xml
+++ b/db/changelog/v-1/02-changeset-agent-status-table.xml
@@ -18,10 +18,10 @@
-
+
-
+
diff --git a/db/changelog/v-1/03-changeset-test-execution-table.xml b/db/changelog/v-1/03-changeset-test-execution-table.xml
index 13c65fdc87..20511f4106 100644
--- a/db/changelog/v-1/03-changeset-test-execution-table.xml
+++ b/db/changelog/v-1/03-changeset-test-execution-table.xml
@@ -27,10 +27,10 @@
-
+
-
+
diff --git a/db/changelog/v-1/11-changeset-test-agent-insert-data.xml b/db/changelog/v-1/11-changeset-test-agent-insert-data.xml
index ec2164d827..270acf14c9 100644
--- a/db/changelog/v-1/11-changeset-test-agent-insert-data.xml
+++ b/db/changelog/v-1/11-changeset-test-agent-insert-data.xml
@@ -88,8 +88,8 @@
-
-
+
+
diff --git a/save-backend/src/main/kotlin/org/cqfn/save/backend/controllers/AgentsController.kt b/save-backend/src/main/kotlin/org/cqfn/save/backend/controllers/AgentsController.kt
index a13dfa641e..44eb368590 100644
--- a/save-backend/src/main/kotlin/org/cqfn/save/backend/controllers/AgentsController.kt
+++ b/save-backend/src/main/kotlin/org/cqfn/save/backend/controllers/AgentsController.kt
@@ -7,7 +7,6 @@ import org.cqfn.save.entities.Agent
import org.cqfn.save.entities.AgentStatus
import org.cqfn.save.entities.AgentStatusDto
import org.cqfn.save.entities.AgentStatusesForExecution
-import org.cqfn.save.entities.Execution
import org.slf4j.LoggerFactory
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.bind.annotation.GetMapping
@@ -60,7 +59,7 @@ class AgentsController(private val agentStatusRepository: AgentStatusRepository,
@Transactional
fun updateAgentStatusesWithDto(@RequestBody agentStates: List) {
agentStates.forEach { dto ->
- val agentStatus = agentStatusRepository.findTopByAgentContainerIdOrderByEndTimeDesc(dto.containerId)
+ val agentStatus = agentStatusRepository.findTopByAgentContainerIdOrderByEndTimeDescIdDesc(dto.containerId)
if (agentStatus != null && agentStatus.state == dto.state) {
// updating time
agentStatus.endTime = dto.time
@@ -85,11 +84,9 @@ class AgentsController(private val agentStatusRepository: AgentStatusRepository,
@Suppress("UnsafeCallOnNullableType") // id will be available because it's retrieved from DB
fun findAllAgentStatusesForSameExecution(@RequestParam agentId: String): AgentStatusesForExecution {
val execution = getAgentByContainerId(agentId).execution
- val agentStatuses = agentRepository.findAll { root, cq, cb ->
- cb.equal(root.get("execution"), execution)
- }.map { agent ->
+ val agentStatuses = agentRepository.findByExecutionId(execution.id!!).map { agent ->
val latestStatus = requireNotNull(
- agentStatusRepository.findTopByAgentContainerIdOrderByEndTimeDesc(agent.containerId)
+ agentStatusRepository.findTopByAgentContainerIdOrderByEndTimeDescIdDesc(agent.containerId)
) {
"AgentStatus not found for agent id=${agent.containerId}"
}
diff --git a/save-backend/src/main/kotlin/org/cqfn/save/backend/controllers/TestExecutionController.kt b/save-backend/src/main/kotlin/org/cqfn/save/backend/controllers/TestExecutionController.kt
index f2fd8fc1a7..a706d18c3b 100644
--- a/save-backend/src/main/kotlin/org/cqfn/save/backend/controllers/TestExecutionController.kt
+++ b/save-backend/src/main/kotlin/org/cqfn/save/backend/controllers/TestExecutionController.kt
@@ -2,6 +2,7 @@ package org.cqfn.save.backend.controllers
import org.cqfn.save.agent.TestExecutionDto
import org.cqfn.save.backend.service.TestExecutionService
+import org.cqfn.save.test.TestDto
import org.springframework.dao.DataAccessException
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
@@ -45,6 +46,15 @@ class TestExecutionController(private val testExecutionService: TestExecutionSer
fun getTestExecutionsCount(@RequestParam executionId: Long) =
testExecutionService.getTestExecutionsCount(executionId)
+ /**
+ * @param agentContainerId id of an agent
+ * @param testDtos test that will be executed by [agentContainerId] agent
+ */
+ @PostMapping(value = ["/testExecution/assignAgent"])
+ fun assignAgentByTest(@RequestParam agentContainerId: String, @RequestBody testDtos: List) {
+ testExecutionService.assignAgentByTest(agentContainerId, testDtos)
+ }
+
/**
* @param testExecutionsDto
* @return response
diff --git a/save-backend/src/main/kotlin/org/cqfn/save/backend/repository/AgentStatusRepository.kt b/save-backend/src/main/kotlin/org/cqfn/save/backend/repository/AgentStatusRepository.kt
index b62020cffa..44ff9a17e5 100644
--- a/save-backend/src/main/kotlin/org/cqfn/save/backend/repository/AgentStatusRepository.kt
+++ b/save-backend/src/main/kotlin/org/cqfn/save/backend/repository/AgentStatusRepository.kt
@@ -20,7 +20,7 @@ interface AgentStatusRepository : BaseEntityRepository, JpaSpecific
* @param containerId id of an agent
* @return [AgentStatus] of an agent
*/
- fun findTopByAgentContainerIdOrderByEndTimeDesc(containerId: String): AgentStatus?
+ fun findTopByAgentContainerIdOrderByEndTimeDescIdDesc(containerId: String): AgentStatus?
}
/**
diff --git a/save-backend/src/main/kotlin/org/cqfn/save/backend/service/TestExecutionService.kt b/save-backend/src/main/kotlin/org/cqfn/save/backend/service/TestExecutionService.kt
index 0cf0dfcc8a..429ce77245 100644
--- a/save-backend/src/main/kotlin/org/cqfn/save/backend/service/TestExecutionService.kt
+++ b/save-backend/src/main/kotlin/org/cqfn/save/backend/service/TestExecutionService.kt
@@ -8,11 +8,13 @@ import org.cqfn.save.backend.repository.TestRepository
import org.cqfn.save.backend.utils.secondsToLocalDateTime
import org.cqfn.save.domain.TestResultStatus
import org.cqfn.save.entities.TestExecution
+import org.cqfn.save.test.TestDto
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.domain.PageRequest
import org.springframework.stereotype.Service
+import org.springframework.transaction.annotation.Transactional
/**
* Service for test result
@@ -56,6 +58,7 @@ class TestExecutionService(private val testExecutionRepository: TestExecutionRep
*/
@Suppress("TOO_MANY_LINES_IN_LAMBDA", "UnsafeCallOnNullableType")
fun saveTestResult(testExecutionsDtos: List): List {
+ log.debug("Saving ${testExecutionsDtos.size} test results from agent ${testExecutionsDtos.first().agentContainerId}")
// we take agent id only from first element, because all test executions have same execution
val agentContainerId = requireNotNull(testExecutionsDtos.first().agentContainerId) {
"Attempt to save test results without assigned agent. testExecutionDtos=$testExecutionsDtos"
@@ -111,4 +114,33 @@ class TestExecutionService(private val testExecutionRepository: TestExecutionRep
)
}
}
+
+ /**
+ * Set `agent` field of test executions corresponding to [testDtos] to [agentContainerId]
+ *
+ * @param agentContainerId id of an agent
+ * @param testDtos test that will be executed by [agentContainerId] agent
+ */
+ @Transactional
+ @Suppress("UnsafeCallOnNullableType")
+ fun assignAgentByTest(agentContainerId: String, testDtos: List) {
+ val agent = requireNotNull(agentRepository.findByContainerId(agentContainerId)) {
+ "Agent with containerId=[$agentContainerId] was not found in the DB"
+ }
+ val executionId = agent.execution.id!!
+ testDtos.forEach { test ->
+ val testExecution = testExecutionRepository.findByExecutionIdAndTestPluginNameAndTestFilePath(
+ executionId,
+ test.pluginName,
+ test.filePath
+ )
+ .orElseThrow {
+ log.error("Can't find test_execution for executionId=$executionId, test.pluginName=${test.pluginName}, test.filePath=${test.filePath}")
+ NoSuchElementException()
+ }
+ testExecutionRepository.save(testExecution.apply {
+ this.agent = agent
+ })
+ }
+ }
}
diff --git a/save-backend/src/main/resources/logback.xml b/save-backend/src/main/resources/logback.xml
index 9429c13fbb..8cf986a72c 100644
--- a/save-backend/src/main/resources/logback.xml
+++ b/save-backend/src/main/resources/logback.xml
@@ -5,6 +5,8 @@
+
+
diff --git a/save-cloud-common/src/commonMain/kotlin/org/cqfn/save/agent/AgentState.kt b/save-cloud-common/src/commonMain/kotlin/org/cqfn/save/agent/AgentState.kt
index 8c2af5f036..928dae93f9 100644
--- a/save-cloud-common/src/commonMain/kotlin/org/cqfn/save/agent/AgentState.kt
+++ b/save-cloud-common/src/commonMain/kotlin/org/cqfn/save/agent/AgentState.kt
@@ -41,5 +41,10 @@ enum class AgentState {
* Agent has just started and hasn't received any heartbeats yet
*/
STARTING,
+
+ /**
+ * Agent has been stopped by save-orchestartor, because there is no more work left
+ */
+ STOPPED_BY_ORCH,
;
}
diff --git a/save-orchestrator/src/main/kotlin/org/cqfn/save/orchestrator/config/ConfigProperties.kt b/save-orchestrator/src/main/kotlin/org/cqfn/save/orchestrator/config/ConfigProperties.kt
index 206d12a0af..50bbe01092 100644
--- a/save-orchestrator/src/main/kotlin/org/cqfn/save/orchestrator/config/ConfigProperties.kt
+++ b/save-orchestrator/src/main/kotlin/org/cqfn/save/orchestrator/config/ConfigProperties.kt
@@ -15,6 +15,7 @@ import org.springframework.boot.context.properties.ConstructorBinding
* @property docker configuration for docker API
* @property agentsCount a number of agents to start for every [Execution]
* @property executionLogs path to folder to store cli logs
+ * @property shutdownChecksIntervalMillis interval between checks whether agents are really finished
*/
@ConstructorBinding
@ConfigurationProperties(prefix = "orchestrator")
@@ -24,6 +25,7 @@ data class ConfigProperties(
val docker: DockerSettings,
val agentsCount: Int,
val executionLogs: String,
+ val shutdownChecksIntervalMillis: Long,
)
/**
diff --git a/save-orchestrator/src/main/kotlin/org/cqfn/save/orchestrator/controller/HeartbeatController.kt b/save-orchestrator/src/main/kotlin/org/cqfn/save/orchestrator/controller/HeartbeatController.kt
index 2d5ae22022..9c901a9202 100644
--- a/save-orchestrator/src/main/kotlin/org/cqfn/save/orchestrator/controller/HeartbeatController.kt
+++ b/save-orchestrator/src/main/kotlin/org/cqfn/save/orchestrator/controller/HeartbeatController.kt
@@ -3,7 +3,6 @@ package org.cqfn.save.orchestrator.controller
import org.cqfn.save.agent.AgentState
import org.cqfn.save.agent.ContinueResponse
import org.cqfn.save.agent.Heartbeat
-import org.cqfn.save.agent.NewJobResponse
import org.cqfn.save.agent.WaitResponse
import org.cqfn.save.entities.AgentStatusDto
import org.cqfn.save.orchestrator.config.ConfigProperties
@@ -15,8 +14,8 @@ import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RestController
import reactor.core.publisher.Mono
-import reactor.core.scheduler.Schedulers
+import java.time.Duration
import java.time.LocalDateTime
import kotlinx.serialization.ExperimentalSerializationApi
@@ -34,7 +33,6 @@ class HeartbeatController(private val agentService: AgentService,
private val dockerService: DockerService,
private val configProperties: ConfigProperties) {
private val logger = LoggerFactory.getLogger(HeartbeatController::class.java)
- private val scheduler = Schedulers.boundedElastic().also { it.start() }
/**
* This controller accepts heartbeat and depending on the state it returns the needed response
@@ -66,8 +64,6 @@ class HeartbeatController(private val agentService: AgentService,
.doOnSuccess {
if (it is WaitResponse) {
initiateShutdownSequence(heartbeat.agentId)
- } else if (it is NewJobResponse) {
- logger.debug("Agent ${heartbeat.agentId} will receive the following job: $it")
}
}
AgentState.FINISHED -> {
@@ -75,9 +71,7 @@ class HeartbeatController(private val agentService: AgentService,
Mono.just(WaitResponse)
}
AgentState.BUSY -> Mono.just(ContinueResponse)
- AgentState.BACKEND_FAILURE -> Mono.just(WaitResponse)
- AgentState.BACKEND_UNREACHABLE -> Mono.just(WaitResponse)
- AgentState.CLI_FAILED -> Mono.just(WaitResponse)
+ AgentState.BACKEND_FAILURE, AgentState.BACKEND_UNREACHABLE, AgentState.CLI_FAILED, AgentState.STOPPED_BY_ORCH -> Mono.just(WaitResponse)
}
)
.map {
@@ -93,8 +87,18 @@ class HeartbeatController(private val agentService: AgentService,
* @param agentId an ID of the agent from the execution, that will be checked.
*/
private fun initiateShutdownSequence(agentId: String) {
- agentService.getAgentsAwaitingStop(agentId).doOnSuccess { (executionId, finishedAgentIds) ->
- scheduler.schedule {
+ agentService.getAgentsAwaitingStop(agentId).flatMap { (_, finishedAgentIds) ->
+ if (finishedAgentIds.isNotEmpty()) {
+ // need to retry after some time, because for other agents BUSY state might have not been written completely
+ logger.debug("Waiting for ${configProperties.shutdownChecksIntervalMillis} seconds to repeat `getAgentsAwaitingStop` call for agentId=$agentId")
+ Mono.delay(Duration.ofMillis(configProperties.shutdownChecksIntervalMillis)).then(
+ agentService.getAgentsAwaitingStop(agentId)
+ )
+ } else {
+ Mono.empty()
+ }
+ }
+ .flatMap { (executionId, finishedAgentIds) ->
if (finishedAgentIds.isNotEmpty()) {
logger.debug("Agents ids=$finishedAgentIds have completed execution, will make an attempt to terminate them")
val areAgentsStopped = dockerService.stopAgents(finishedAgentIds)
@@ -102,12 +106,16 @@ class HeartbeatController(private val agentService: AgentService,
logger.info("Agents have been stopped, will mark execution id=$executionId and agents $finishedAgentIds as FINISHED")
agentService
.markAgentsAndExecutionAsFinished(executionId, finishedAgentIds)
- .block()
+ } else {
+ logger.warn("Agents $finishedAgentIds are not stopped after stop command")
+ Mono.empty()
}
+ } else {
+ logger.debug("Agents other than $agentId are still running, so won't try to stop them")
+ Mono.empty()
}
}
- }
- .subscribeOn(scheduler)
+ .subscribeOn(agentService.scheduler)
.subscribe()
}
}
diff --git a/save-orchestrator/src/main/kotlin/org/cqfn/save/orchestrator/service/AgentService.kt b/save-orchestrator/src/main/kotlin/org/cqfn/save/orchestrator/service/AgentService.kt
index ed37c6e4cf..5760f8710f 100644
--- a/save-orchestrator/src/main/kotlin/org/cqfn/save/orchestrator/service/AgentService.kt
+++ b/save-orchestrator/src/main/kotlin/org/cqfn/save/orchestrator/service/AgentService.kt
@@ -12,6 +12,7 @@ import org.cqfn.save.execution.ExecutionStatus
import org.cqfn.save.execution.ExecutionUpdateDto
import org.cqfn.save.orchestrator.BodilessResponseEntity
import org.cqfn.save.test.TestBatch
+import org.cqfn.save.test.TestDto
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Qualifier
@@ -20,6 +21,7 @@ import org.springframework.web.reactive.function.BodyInserters
import org.springframework.web.reactive.function.client.WebClient
import org.springframework.web.reactive.function.client.bodyToMono
import reactor.core.publisher.Mono
+import reactor.core.scheduler.Schedulers
import reactor.util.Loggers
import java.time.LocalDateTime
@@ -30,6 +32,11 @@ import java.util.logging.Level
*/
@Service
class AgentService {
+ /**
+ * A scheduler that executes long-running background tasks
+ */
+ internal val scheduler = Schedulers.boundedElastic().also { it.start() }
+
@Autowired
@Qualifier("webClientBackend")
private lateinit var webClientBackend: WebClient
@@ -46,19 +53,10 @@ class AgentService {
.uri("/getTestBatches?agentId=$agentId")
.retrieve()
.bodyToMono()
- .map { batch ->
- if (batch.tests.isNotEmpty()) {
- // fixme: do we still need suitesToArgs, since we have execFlags in save.toml?
- NewJobResponse(
- batch.tests,
- batch.suitesToArgs.values.first() +
- " --report-type json" +
- " --result-output file" +
- " " + batch.tests.joinToString(separator = " ") { it.filePath }
- )
- } else {
- log.info("Next test batch for agentId=$agentId is empty, setting it to wait")
- WaitResponse
+ .map { batch -> batch.toHeartbeatResponse(agentId) }
+ .doOnSuccess {
+ if (it is NewJobResponse) {
+ updateAssignedAgent(agentId, it)
}
}
@@ -130,7 +128,7 @@ class AgentService {
fun markAgentsAndExecutionAsFinished(executionId: Long, finishedAgentIds: List): Mono =
updateAgentStatusesWithDto(
finishedAgentIds.map { agentId ->
- AgentStatusDto(LocalDateTime.now(), AgentState.FINISHED, agentId)
+ AgentStatusDto(LocalDateTime.now(), AgentState.STOPPED_BY_ORCH, agentId)
}
)
.then(
@@ -170,6 +168,7 @@ class AgentService {
.retrieve()
.bodyToMono()
.map { (executionId, agentStatuses) ->
+ log.debug("For executionId=$executionId agent statuses are $agentStatuses")
executionId to if (agentStatuses.areIdleOrFinished()) {
// We assume, that all agents will eventually have one of these statuses.
// Situations when agent gets stuck with a different status and for whatever reason is unable to update
@@ -181,6 +180,50 @@ class AgentService {
}
}
+ /**
+ * Perform two operations in arbitrary order: assign `agentContainerId` agent to test executions
+ * and mark this agent as BUSY
+ *
+ * @param agentContainerId id of an agent that receives tests
+ * @param newJobResponse a heartbeat response with tests
+ */
+ internal fun updateAssignedAgent(agentContainerId: String, newJobResponse: NewJobResponse) {
+ updateTestExecutionsWithAgent(agentContainerId, newJobResponse.tests).zipWith(
+ updateAgentStatusesWithDto(listOf(
+ AgentStatusDto(LocalDateTime.now(), AgentState.BUSY, agentContainerId)
+ ))
+ )
+ .doOnSuccess {
+ log.debug("Agent $agentContainerId has been set as executor for tests ${newJobResponse.tests} and its status has been set to BUSY")
+ }
+ .subscribeOn(scheduler)
+ .subscribe()
+ }
+
+ private fun updateTestExecutionsWithAgent(agentId: String, testDtos: List): Mono {
+ log.debug("Attempt to update test executions for tests=$testDtos for agent $agentId")
+ return webClientBackend.post()
+ .uri("/testExecution/assignAgent?agentContainerId=$agentId")
+ .bodyValue(testDtos)
+ .retrieve()
+ .toBodilessEntity()
+ }
+
+ private fun TestBatch.toHeartbeatResponse(agentId: String) =
+ if (tests.isNotEmpty()) {
+ // fixme: do we still need suitesToArgs, since we have execFlags in save.toml?
+ NewJobResponse(
+ tests,
+ suitesToArgs.values.first() +
+ " --report-type json" +
+ " --result-output file" +
+ " " + tests.joinToString(separator = " ") { it.filePath }
+ )
+ } else {
+ log.info("Next test batch for agentId=$agentId is empty, setting it to wait")
+ WaitResponse
+ }
+
private fun Collection.areIdleOrFinished() = all {
it.state == AgentState.IDLE || it.state == AgentState.FINISHED
}
diff --git a/save-orchestrator/src/main/resources/application.properties b/save-orchestrator/src/main/resources/application.properties
index d0fd109b24..5228aed68d 100644
--- a/save-orchestrator/src/main/resources/application.properties
+++ b/save-orchestrator/src/main/resources/application.properties
@@ -2,6 +2,7 @@ spring.profiles.default=dev
orchestrator.backendUrl=http://backend:5000
orchestrator.executionLogs=/home/cnb/executionLogs/
orchestrator.testResources.basePath=/home/cnb/repositories
+orchestrator.shutdownChecksIntervalMillis=5000
server.port = 5100
management.endpoints.web.exposure.include=health,info,prometheus
orchestrator.docker.host=unix:///var/run/docker.sock
diff --git a/save-orchestrator/src/main/resources/logback.xml b/save-orchestrator/src/main/resources/logback.xml
index 9429c13fbb..47825a3160 100644
--- a/save-orchestrator/src/main/resources/logback.xml
+++ b/save-orchestrator/src/main/resources/logback.xml
@@ -5,6 +5,8 @@
+
+
diff --git a/save-orchestrator/src/test/kotlin/org/cqfn/save/orchestrator/controller/heartbeat/HeartbeatControllerTest.kt b/save-orchestrator/src/test/kotlin/org/cqfn/save/orchestrator/controller/heartbeat/HeartbeatControllerTest.kt
index b7253846a9..be9e3928ba 100644
--- a/save-orchestrator/src/test/kotlin/org/cqfn/save/orchestrator/controller/heartbeat/HeartbeatControllerTest.kt
+++ b/save-orchestrator/src/test/kotlin/org/cqfn/save/orchestrator/controller/heartbeat/HeartbeatControllerTest.kt
@@ -145,15 +145,26 @@ class HeartbeatControllerTest {
@Test
fun `should shutdown idle agents when there are no tests left`() {
whenever(dockerService.stopAgents(any())).thenReturn(true)
+ val agentStatusDtos = listOf(
+ AgentStatusDto(LocalDateTime.now(), AgentState.IDLE, "test-1"),
+ AgentStatusDto(LocalDateTime.now(), AgentState.IDLE, "test-2"),
+ )
testHeartbeat(
- agentStatusDtos = listOf(
- AgentStatusDto(LocalDateTime.now(), AgentState.IDLE, "test-1"),
- AgentStatusDto(LocalDateTime.now(), AgentState.IDLE, "test-2"),
- ),
+ agentStatusDtos = agentStatusDtos,
heartbeat = Heartbeat("test-1", AgentState.IDLE, ExecutionProgress(100)),
testBatch = TestBatch(emptyList(), emptyMap()),
mockAgentStatuses = true,
{
+ // /getAgentsStatusesForSameExecution after shutdownIntervalMillis
+ mockServer.enqueue(
+ MockResponse()
+ .setBody(
+ objectMapper.writeValueAsString(
+ AgentStatusesForExecution(0, agentStatusDtos)
+ )
+ )
+ .addHeader("Content-Type", "application/json")
+ )
// additional setup for marking stuff as FINISHED
// /updateAgentStatuses
mockServer.enqueue(
@@ -193,16 +204,29 @@ class HeartbeatControllerTest {
@Test
fun `should shutdown agents even if there are some already FINISHED`() {
+ val agentStatusDtos = listOf(
+ AgentStatusDto(LocalDateTime.now(), AgentState.IDLE, "test-1"),
+ AgentStatusDto(LocalDateTime.now(), AgentState.IDLE, "test-2"),
+ AgentStatusDto(LocalDateTime.parse("2021-01-01T00:00:00"), AgentState.FINISHED, "test-1"),
+ AgentStatusDto(LocalDateTime.parse("2021-01-01T00:00:00"), AgentState.FINISHED, "test-2"),
+ )
testHeartbeat(
- agentStatusDtos = listOf(
- AgentStatusDto(LocalDateTime.now(), AgentState.IDLE, "test-1"),
- AgentStatusDto(LocalDateTime.now(), AgentState.IDLE, "test-2"),
- AgentStatusDto(LocalDateTime.parse("2021-01-01T00:00:00"), AgentState.FINISHED, "test-1"),
- AgentStatusDto(LocalDateTime.parse("2021-01-01T00:00:00"), AgentState.FINISHED, "test-2"),
- ),
+ agentStatusDtos = agentStatusDtos,
heartbeat = Heartbeat("test-1", AgentState.IDLE, ExecutionProgress(100)),
testBatch = TestBatch(emptyList(), emptyMap()),
mockAgentStatuses = true,
+ {
+ // /getAgentsStatusesForSameExecution after shutdownIntervalMillis
+ mockServer.enqueue(
+ MockResponse()
+ .setBody(
+ objectMapper.writeValueAsString(
+ AgentStatusesForExecution(0, agentStatusDtos)
+ )
+ )
+ .addHeader("Content-Type", "application/json")
+ )
+ }
) {
verify(dockerService, times(1)).stopAgents(any())
}
diff --git a/save-orchestrator/src/test/resources/application.properties b/save-orchestrator/src/test/resources/application.properties
index a372d7870a..53048e0fad 100644
--- a/save-orchestrator/src/test/resources/application.properties
+++ b/save-orchestrator/src/test/resources/application.properties
@@ -1,6 +1,7 @@
orchestrator.backendUrl=http://backend:5000
orchestrator.executionLogs=/home/cnb/executionLogs/
orchestrator.testResources.basePath=/home/cnb/repositories
+orchestrator.shutdownChecksIntervalMillis=100
server.port = 5100
management.endpoints.web.exposure.include=health,info,prometheus
# use IP from WSL on windows (`ip a | grep eth0`), because runsc can't be installed on windows
diff --git a/save-preprocessor/src/test/kotlin/org/cqfn/save/preprocessor/service/TestDiscoveringServiceTest.kt b/save-preprocessor/src/test/kotlin/org/cqfn/save/preprocessor/service/TestDiscoveringServiceTest.kt
index 2b328b1d52..588720699e 100644
--- a/save-preprocessor/src/test/kotlin/org/cqfn/save/preprocessor/service/TestDiscoveringServiceTest.kt
+++ b/save-preprocessor/src/test/kotlin/org/cqfn/save/preprocessor/service/TestDiscoveringServiceTest.kt
@@ -90,7 +90,7 @@ class TestDiscoveringServiceTest {
)
println("Discovered the following tests: $testDtos")
- Assertions.assertEquals(13, testDtos.size)
+ Assertions.assertEquals(14, testDtos.size)
Assertions.assertEquals(testDtos.size, testDtos.map { it.hash + it.filePath + it.testSuiteId }.distinct().size) {
"Some tests have the same hash/filePath/testSuiteId combination in $testDtos"
}