diff --git a/cameleer-server-app/src/main/java/com/cameleer/server/app/retention/JarRetentionJob.java b/cameleer-server-app/src/main/java/com/cameleer/server/app/retention/JarRetentionJob.java index a0b465d7..60484e6a 100644 --- a/cameleer-server-app/src/main/java/com/cameleer/server/app/retention/JarRetentionJob.java +++ b/cameleer-server-app/src/main/java/com/cameleer/server/app/retention/JarRetentionJob.java @@ -82,7 +82,8 @@ public class JarRetentionJob { // log-and-continue behavior. The DB row still gets cleaned up since // the JAR is no longer pointed at by anything (FilesystemArtifactStore.delete // already handles the racy parent-sweep gracefully). - log.warn("Failed to delete artifact for version {}: {}", version.id(), e.getMessage()); + log.warn("Failed to delete artifact for version v{} of app {} ({})", + version.version(), app.slug(), version.id(), e); } versionRepo.delete(version.id()); deleted++; diff --git a/cameleer-server-app/src/test/java/com/cameleer/server/app/retention/JarRetentionJobTest.java b/cameleer-server-app/src/test/java/com/cameleer/server/app/retention/JarRetentionJobTest.java index 0c9cb14f..c2bfb11c 100644 --- a/cameleer-server-app/src/test/java/com/cameleer/server/app/retention/JarRetentionJobTest.java +++ b/cameleer-server-app/src/test/java/com/cameleer/server/app/retention/JarRetentionJobTest.java @@ -4,6 +4,7 @@ import com.cameleer.server.core.runtime.App; import com.cameleer.server.core.runtime.AppService; import com.cameleer.server.core.runtime.AppVersion; import com.cameleer.server.core.runtime.AppVersionRepository; +import com.cameleer.server.core.runtime.Deployment; import com.cameleer.server.core.runtime.DeploymentRepository; import com.cameleer.server.core.runtime.Environment; import com.cameleer.server.core.runtime.EnvironmentService; @@ -15,7 +16,9 @@ import java.time.Instant; import java.util.List; import java.util.UUID; +import static org.mockito.Mockito.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; @@ -54,4 +57,37 @@ class JarRetentionJobTest { verify(versionRepo).delete(v1.id()); verifyNoMoreInteractions(store); } + + @Test + void skipsCurrentlyDeployedVersion() throws Exception { + EnvironmentService envSvc = mock(EnvironmentService.class); + AppService appSvc = mock(AppService.class); + AppVersionRepository versionRepo = mock(AppVersionRepository.class); + DeploymentRepository deployRepo = mock(DeploymentRepository.class); + ArtifactStore store = mock(ArtifactStore.class); + + UUID envId = UUID.randomUUID(); + UUID appId = UUID.randomUUID(); + Instant now = Instant.now(); + Environment env = new Environment(envId, "dev", "Dev", false, true, + null, 2, "slate", now, 7, 7, 7); + App app = new App(appId, envId, "demo", "Demo", null, now, now); + AppVersion v3 = new AppVersion(UUID.randomUUID(), appId, 3, "ignored", "h", "a.jar", 1L, null, null, null); + AppVersion v2 = new AppVersion(UUID.randomUUID(), appId, 2, "ignored", "h", "a.jar", 1L, null, null, null); + AppVersion v1 = new AppVersion(UUID.randomUUID(), appId, 1, "ignored", "h", "a.jar", 1L, null, null, null); + + when(envSvc.listAll()).thenReturn(List.of(env)); + when(appSvc.listByEnvironment(envId)).thenReturn(List.of(app)); + when(versionRepo.findByAppId(appId)).thenReturn(List.of(v3, v2, v1)); + // v1 is currently deployed — must NOT be touched even though it's beyond the retention=2 cutoff + Deployment deployedV1 = mock(Deployment.class); + when(deployedV1.appVersionId()).thenReturn(v1.id()); + when(deployRepo.findByAppId(appId)).thenReturn(List.of(deployedV1)); + + JarRetentionJob job = new JarRetentionJob(envSvc, appSvc, versionRepo, deployRepo, store); + job.cleanupOldVersions(); + + verify(store, never()).delete(any()); + verify(versionRepo, never()).delete(any()); + } }