pcp-mission-planing: Ф3 — правки контента в черновик (PATCH съёмки, DELETE включения, без авто-создания живой миссии)
This commit is contained in:
+236
@@ -0,0 +1,236 @@
|
||||
package space.nstart.pcp.pcp_mission_planing_service.service
|
||||
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import org.mockito.Mockito.doAnswer
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.web.server.ResponseStatusException
|
||||
import space.nstart.pcp.pcp_mission_planing_service.entity.DropModeEntity
|
||||
import space.nstart.pcp.pcp_mission_planing_service.entity.DropModeSurveyEntity
|
||||
import space.nstart.pcp.pcp_mission_planing_service.entity.ModeBookingEntity
|
||||
import space.nstart.pcp.pcp_mission_planing_service.entity.ModeEntity
|
||||
import space.nstart.pcp.pcp_mission_planing_service.entity.PlanEntity
|
||||
import space.nstart.pcp.pcp_mission_planing_service.entity.SurveyModeEntity
|
||||
import space.nstart.pcp.pcp_mission_planing_service.entity.SurveyModeSource
|
||||
import space.nstart.pcp.pcp_mission_planing_service.repository.DropModeRepository
|
||||
import space.nstart.pcp.pcp_mission_planing_service.repository.DropModeSurveyRepository
|
||||
import space.nstart.pcp.pcp_mission_planing_service.repository.MissionRepository
|
||||
import space.nstart.pcp.pcp_mission_planing_service.repository.ModeBookingRepository
|
||||
import space.nstart.pcp.pcp_mission_planing_service.repository.ModeRepository
|
||||
import space.nstart.pcp.pcp_mission_planing_service.repository.PlanRepository
|
||||
import space.nstart.pcp.pcp_mission_planing_service.repository.SurveyModeRepository
|
||||
import space.nstart.pcp.pcp_mission_planing_service.service.satellite_type.DefaultSatelliteMissionType
|
||||
import space.nstart.pcp.pcp_mission_planing_service.service.satellite_type.EmissioSatelliteMissionType
|
||||
import space.nstart.pcp.pcp_mission_planing_service.service.satellite_type.ReflixioSatelliteMissionType
|
||||
import space.nstart.pcp.pcp_mission_planing_service.service.satellite_type.SatelliteMissionTypeFactory
|
||||
import space.nstart.pcp.pcp_types_lib.dto.routes.SurveyModeStatus
|
||||
import space.nstart.pcp.pcp_types_lib.dto.satellite.mission.DropRouteSaveRequestDTO
|
||||
import space.nstart.pcp.pcp_types_lib.dto.satellite.mission.SurveyRouteBuildRequestDTO
|
||||
import java.time.LocalDateTime
|
||||
import java.time.ZoneOffset
|
||||
import java.util.UUID
|
||||
|
||||
class MissionEditModesTest {
|
||||
|
||||
private val surveyStore = linkedMapOf<Long, SurveyModeEntity>()
|
||||
private val dropStore = linkedMapOf<Long, DropModeEntity>()
|
||||
private val dropSurveyStore = mutableListOf<DropModeSurveyEntity>()
|
||||
private val bookingStore = mutableListOf<ModeBookingEntity>()
|
||||
|
||||
private var autoId = 10L
|
||||
|
||||
private val missionRepository = mock(MissionRepository::class.java)
|
||||
|
||||
private val modeRepository = mock(ModeRepository::class.java).also { repo ->
|
||||
`when`(repo.findById(anyLong())).thenAnswer { inv ->
|
||||
val id = inv.arguments[0] as Long
|
||||
java.util.Optional.ofNullable<ModeEntity>(surveyStore[id] ?: dropStore[id])
|
||||
}
|
||||
}
|
||||
|
||||
private val surveyModeRepository = mock(SurveyModeRepository::class.java).also { repo ->
|
||||
doAnswer { inv ->
|
||||
val s = inv.arguments[0] as SurveyModeEntity
|
||||
surveyStore.remove(s.id)
|
||||
null
|
||||
}.`when`(repo).delete(anyNonNull())
|
||||
}
|
||||
|
||||
private val dropModeRepository = mock(DropModeRepository::class.java).also { repo ->
|
||||
doAnswer { inv ->
|
||||
val d = inv.arguments[0] as DropModeEntity
|
||||
dropStore.remove(d.id)
|
||||
null
|
||||
}.`when`(repo).delete(anyNonNull())
|
||||
doAnswer { inv ->
|
||||
dropStore.remove(inv.arguments[0] as Long)
|
||||
null
|
||||
}.`when`(repo).deleteById(anyLong())
|
||||
}
|
||||
|
||||
private val dropModeSurveyRepository = mock(DropModeSurveyRepository::class.java).also { repo ->
|
||||
`when`(repo.findAllBySurveyMode_Id(anyLong())).thenAnswer { inv ->
|
||||
val sid = inv.arguments[0] as Long
|
||||
dropSurveyStore.filter { it.surveyMode?.id == sid }
|
||||
}
|
||||
`when`(repo.findAllByDropMode_IdOrderBySurveyMode_TimeStartAsc(anyLong())).thenAnswer { inv ->
|
||||
val did = inv.arguments[0] as Long
|
||||
dropSurveyStore.filter { it.dropMode?.id == did }
|
||||
}
|
||||
doAnswer { inv ->
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val links = inv.arguments[0] as Iterable<DropModeSurveyEntity>
|
||||
dropSurveyStore.removeAll(links.toSet())
|
||||
null
|
||||
}.`when`(repo).deleteAll(anyNonNull())
|
||||
}
|
||||
|
||||
private val modeBookingRepository = mock(ModeBookingRepository::class.java).also { repo ->
|
||||
`when`(repo.findAllByMode_IdIn(anyNonNull())).thenAnswer { inv ->
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val ids = inv.arguments[0] as Collection<Long>
|
||||
bookingStore.filter { it.mode?.id in ids }
|
||||
}
|
||||
doAnswer { inv ->
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val bs = inv.arguments[0] as Iterable<ModeBookingEntity>
|
||||
bookingStore.removeAll(bs.toSet())
|
||||
null
|
||||
}.`when`(repo).deleteAll(anyNonNull())
|
||||
}
|
||||
|
||||
private val service = MissionPlaningService(
|
||||
missionRepository = missionRepository,
|
||||
modeRepository = modeRepository,
|
||||
planRepository = mock(PlanRepository::class.java),
|
||||
surveyModeRepository = surveyModeRepository,
|
||||
dropModeRepository = dropModeRepository,
|
||||
dropModeSurveyRepository = dropModeSurveyRepository,
|
||||
modeBookingRepository = modeBookingRepository,
|
||||
bookedSlotsEventPublisher = mock(BookedSlotsEventPublisher::class.java),
|
||||
ballisticsService = mock(BallisticsService::class.java),
|
||||
complexMissionService = mock(ComplexMissionService::class.java),
|
||||
satelliteCatalogClient = mock(space.nstart.pcp.pcp_mission_planing_service.service.catalog.SatelliteCatalogClient::class.java),
|
||||
satelliteMissionTypeFactory = SatelliteMissionTypeFactory(
|
||||
listOf(DefaultSatelliteMissionType(), EmissioSatelliteMissionType(), ReflixioSatelliteMissionType()),
|
||||
DefaultSatelliteMissionType()
|
||||
)
|
||||
)
|
||||
|
||||
private val plan = PlanEntity(id = 1L, planNumber = 1)
|
||||
|
||||
// --- DELETE mode ---
|
||||
|
||||
@Test
|
||||
fun `deleting a survey removes its bookings, links and the orphaned drop`() {
|
||||
val survey = survey()
|
||||
val drop = drop()
|
||||
link(drop, survey)
|
||||
booking(survey)
|
||||
|
||||
service.deleteMode(survey.id!!)
|
||||
|
||||
assertFalse(surveyStore.containsKey(survey.id))
|
||||
assertTrue(bookingStore.isEmpty())
|
||||
assertFalse(dropStore.containsKey(drop.id), "сброс без единственной съёмки должен быть удалён")
|
||||
assertTrue(dropSurveyStore.isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `deleting a survey keeps a drop still referenced by another survey`() {
|
||||
val survey1 = survey()
|
||||
val survey2 = survey()
|
||||
val drop = drop()
|
||||
link(drop, survey1)
|
||||
link(drop, survey2)
|
||||
|
||||
service.deleteMode(survey1.id!!)
|
||||
|
||||
assertFalse(surveyStore.containsKey(survey1.id))
|
||||
assertTrue(surveyStore.containsKey(survey2.id))
|
||||
assertTrue(dropStore.containsKey(drop.id), "сброс с оставшейся съёмкой не удаляется")
|
||||
assertEquals(1, dropSurveyStore.size)
|
||||
assertEquals(survey2.id, dropSurveyStore.single().surveyMode?.id)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `deleting a drop removes the drop and its links but keeps surveys`() {
|
||||
val survey = survey()
|
||||
val drop = drop()
|
||||
link(drop, survey)
|
||||
|
||||
service.deleteMode(drop.id!!)
|
||||
|
||||
assertFalse(dropStore.containsKey(drop.id))
|
||||
assertTrue(dropSurveyStore.isEmpty())
|
||||
assertTrue(surveyStore.containsKey(survey.id), "съёмка независима от сброса и сохраняется")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `deleting an unknown mode yields 404`() {
|
||||
val ex = assertThrows<ResponseStatusException> { service.deleteMode(999L) }
|
||||
assertEquals(HttpStatus.NOT_FOUND, ex.statusCode)
|
||||
}
|
||||
|
||||
// --- save routes больше не создают живую миссию ---
|
||||
|
||||
@Test
|
||||
fun `saveSurveyRoute on a missing mission yields 404 instead of auto-creating`() {
|
||||
// missionRepository не застаблен → findById возвращает пустой Optional.
|
||||
val ex = assertThrows<ResponseStatusException> {
|
||||
service.saveSurveyRoute(UUID.randomUUID(), SurveyRouteBuildRequestDTO(satelliteId = 25544))
|
||||
}
|
||||
assertEquals(HttpStatus.NOT_FOUND, ex.statusCode)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `saveDropRoute on a missing mission yields 404 instead of auto-creating`() {
|
||||
val ex = assertThrows<ResponseStatusException> {
|
||||
service.saveDropRoute(
|
||||
UUID.randomUUID(),
|
||||
DropRouteSaveRequestDTO(satelliteId = 25544, surveyModeIds = listOf(1L))
|
||||
)
|
||||
}
|
||||
assertEquals(HttpStatus.NOT_FOUND, ex.statusCode)
|
||||
}
|
||||
|
||||
// --- helpers ---
|
||||
|
||||
private fun survey(): SurveyModeEntity {
|
||||
val id = ++autoId
|
||||
val s = SurveyModeEntity(
|
||||
id = id, plan = plan, timeStart = LocalDateTime.of(2026, 6, 10, 12, 0).atOffset(ZoneOffset.UTC),
|
||||
revolution = id, lat = 55.0, long = 37.0, duration = 60.0, roll = 0.0,
|
||||
status = SurveyModeStatus.PLANNED, source = SurveyModeSource.MANUAL
|
||||
)
|
||||
surveyStore[id] = s
|
||||
return s
|
||||
}
|
||||
|
||||
private fun drop(): DropModeEntity {
|
||||
val id = ++autoId
|
||||
val d = DropModeEntity(
|
||||
id = id, plan = plan, timeStart = LocalDateTime.of(2026, 6, 10, 13, 0).atOffset(ZoneOffset.UTC),
|
||||
revolution = id, station = "102", duration = 60.0
|
||||
)
|
||||
dropStore[id] = d
|
||||
return d
|
||||
}
|
||||
|
||||
private fun link(drop: DropModeEntity, survey: SurveyModeEntity) {
|
||||
dropSurveyStore.add(DropModeSurveyEntity(dropMode = drop, surveyMode = survey))
|
||||
}
|
||||
|
||||
private fun booking(survey: SurveyModeEntity) {
|
||||
bookingStore.add(ModeBookingEntity(id = ++autoId, mode = survey, slotId = autoId))
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun <T> anyNonNull(): T { org.mockito.ArgumentMatchers.any<T>(); return null as T }
|
||||
private fun anyLong(): Long { org.mockito.ArgumentMatchers.anyLong(); return 0L }
|
||||
}
|
||||
Reference in New Issue
Block a user