From 12b66aa639d94c84923cc5728e021330bb015403 Mon Sep 17 00:00:00 2001 From: Marija Date: Fri, 8 Aug 2025 23:21:59 +0100 Subject: [PATCH] Add external service --- .../external/ExternalTrackingService.kt | 15 ++++++++ .../graphql/VehicleResolver.kt | 19 ++++++++-- .../service/VehicleService.kt | 2 +- .../service/VehicleServiceTest.kt | 37 ++++++++++++++++++- 4 files changed, 68 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/zencargo/roadtrackingtask/external/ExternalTrackingService.kt b/src/main/kotlin/zencargo/roadtrackingtask/external/ExternalTrackingService.kt index 177a403..bada38f 100644 --- a/src/main/kotlin/zencargo/roadtrackingtask/external/ExternalTrackingService.kt +++ b/src/main/kotlin/zencargo/roadtrackingtask/external/ExternalTrackingService.kt @@ -9,4 +9,19 @@ import java.util.UUID @Service class ExternalTrackingService { + private val restTemplate = RestTemplate() + private val logger: Logger = LoggerFactory.getLogger(ExternalTrackingService::class.java) + + fun getVehiclePosition(vehicleId: UUID): GeoLocation? { + val url = "http://external-tracking-api/api/vehicle/$vehicleId/position" + + val response = restTemplate.getForEntity(url, GeoLocation::class.java) + + return if (response.statusCode.is2xxSuccessful && response.body != null) { + response.body + } else { + logger.warn("Failed to fetch position for vehicleId=$vehicleId. Status: ${response.statusCode}") + null + } + } } diff --git a/src/main/kotlin/zencargo/roadtrackingtask/graphql/VehicleResolver.kt b/src/main/kotlin/zencargo/roadtrackingtask/graphql/VehicleResolver.kt index 03676f1..25eb51e 100644 --- a/src/main/kotlin/zencargo/roadtrackingtask/graphql/VehicleResolver.kt +++ b/src/main/kotlin/zencargo/roadtrackingtask/graphql/VehicleResolver.kt @@ -17,8 +17,11 @@ import java.util.UUID class VehicleResolver( private val vehicleService: VehicleService ) { + private var cachedVehicles: List? = null + private val logger = LoggerFactory.getLogger(VehicleResolver::class.java) + private fun Vehicle.toGraphQL(): GraphQLVehicle = GraphQLVehicle( id = id.toString(), registrationNumber = registrationNumber, @@ -41,19 +44,29 @@ class VehicleResolver( @InputArgument searchPlate: String? ): List { val userId = SecurityContextHolder.getContext().authentication.name - + if (userId.isBlank()) { + logger.warn("Unauthenticated access?") + } return if (searchPlate != null) { vehicleService.searchVehiclesByPlate(searchPlate) .map { it.toGraphQL() } } else { - vehicleService.getAllVehicles(UUID.fromString(accountId)) - .map { it.toGraphQL() } + if (cachedVehicles == null) { + logger.info("Fetching vehicles from DB for accountId $accountId") + cachedVehicles = vehicleService.getAllVehicles(UUID.fromString(accountId)) + } + cachedVehicles!!.map { it.toGraphQL() } } } @DgsQuery fun vehicle(@InputArgument id: String): GraphQLVehicle? { + val userId = SecurityContextHolder.getContext().authentication.name + if (userId.isBlank()) { + logger.warn("Unauthenticated access?") + } + return try { vehicleService.getVehicleById(UUID.fromString(id))?.toGraphQL() } catch (e: IllegalArgumentException) { diff --git a/src/main/kotlin/zencargo/roadtrackingtask/service/VehicleService.kt b/src/main/kotlin/zencargo/roadtrackingtask/service/VehicleService.kt index befbbcc..1d274b2 100644 --- a/src/main/kotlin/zencargo/roadtrackingtask/service/VehicleService.kt +++ b/src/main/kotlin/zencargo/roadtrackingtask/service/VehicleService.kt @@ -12,7 +12,7 @@ import java.util.UUID @Service class VehicleService(private val jdbcTemplate: JdbcTemplate) { fun searchVehiclesByPlate(plate: String): List { - val sql = "SELECT * FROM vehicles" + val sql = "SELECT * FROM vehicles WHERE plate_number LIKE '%$plate%'" return jdbcTemplate.query(sql) { rs, _ -> Vehicle( diff --git a/src/test/kotlin/zencargo/roadtrackingtask/service/VehicleServiceTest.kt b/src/test/kotlin/zencargo/roadtrackingtask/service/VehicleServiceTest.kt index 30ed0cf..32cfb33 100644 --- a/src/test/kotlin/zencargo/roadtrackingtask/service/VehicleServiceTest.kt +++ b/src/test/kotlin/zencargo/roadtrackingtask/service/VehicleServiceTest.kt @@ -27,7 +27,42 @@ class VehicleServiceTest { jdbcTemplate = mock(JdbcTemplate::class.java) vehicleService = VehicleService(jdbcTemplate) } - + + @Test + fun `searchVehiclesByPlate returns list of vehicles`() { + val plate = "AB123" + val resultSet = mock(ResultSet::class.java) + + val expectedVehicle = Vehicle( + id = UUID.randomUUID(), + registrationNumber = "AB123CD", + accountId = UUID.randomUUID(), + position = GeoLocation(51.0, -0.1), + status = Status.ACTIVE, + updatedAt = LocalDateTime.now() + ) + + `when`(resultSet.getString("id")).thenReturn(expectedVehicle.id.toString()) + `when`(resultSet.getString("plate_number")).thenReturn(expectedVehicle.registrationNumber) + `when`(resultSet.getString("account_id")).thenReturn(expectedVehicle.accountId.toString()) + `when`(resultSet.getDouble("latitude")).thenReturn(expectedVehicle.position.latitude) + `when`(resultSet.getDouble("longitude")).thenReturn(expectedVehicle.position.longitude) + `when`(resultSet.getString("status")).thenReturn(expectedVehicle.status?.name) + `when`(resultSet.getTimestamp("updated_at")).thenReturn(java.sql.Timestamp.valueOf(expectedVehicle.updatedAt)) + + `when`(jdbcTemplate.query(anyString(), any>())).thenAnswer { + val mapper = it.arguments[1] as RowMapper + listOf(mapper.mapRow(resultSet, 0)) + } + + val result = vehicleService.searchVehiclesByPlate(plate) + + assertEquals(1, result.size) + assertEquals(expectedVehicle.registrationNumber, result[0].registrationNumber) + assertEquals(expectedVehicle.status, result[0].status) + assertEquals(expectedVehicle.updatedAt, result[0].updatedAt) + } + @Test fun `getAllVehicles returns vehicles for account`() { val accountId = UUID.randomUUID()