From ded4e3519928d223dcb4fc3c0ea1db508aed1618 Mon Sep 17 00:00:00 2001 From: tonisives Date: Tue, 20 Feb 2024 06:54:17 +0700 Subject: [PATCH 1/2] add static data request --- hmkit-fleet-consumer | 2 +- .../com/highmobility/hmkitfleet/HMKitFleet.kt | 16 ++++ .../hmkitfleet/network/VehicleDataRequests.kt | 24 ++++++ .../highmobility/hmkitfleet/HMKitFleetTest.kt | 35 ++++++++ .../network/VehicleDataRequestsTest.kt | 84 ++++++++++++++++--- 5 files changed, 148 insertions(+), 13 deletions(-) diff --git a/hmkit-fleet-consumer b/hmkit-fleet-consumer index 904c185..58e5cf8 160000 --- a/hmkit-fleet-consumer +++ b/hmkit-fleet-consumer @@ -1 +1 @@ -Subproject commit 904c1855c4786c9dc1409b5c0054d9124972f8ae +Subproject commit 58e5cf89ef916ccb7cf2573211170ad4d74fa8ac diff --git a/hmkit-fleet/src/main/kotlin/com/highmobility/hmkitfleet/HMKitFleet.kt b/hmkit-fleet/src/main/kotlin/com/highmobility/hmkitfleet/HMKitFleet.kt index a693d2b..44ee09c 100644 --- a/hmkit-fleet/src/main/kotlin/com/highmobility/hmkitfleet/HMKitFleet.kt +++ b/hmkit-fleet/src/main/kotlin/com/highmobility/hmkitfleet/HMKitFleet.kt @@ -135,12 +135,28 @@ class HMKitFleet constructor( koin.get().deleteClearance(vin) } + /** + * Get vehicle status JSON string from the [Vehicle Data API](https://docs.high-mobility.com/api-references/code-references/vehicle-data/reference/v1/) + * + * Read more in the [Vehicle Data API Tutorial](https://docs.high-mobility.com/guides/getting-started/rest/) + */ fun getVehicleState( vin: String ): CompletableFuture> = scope.future { koin.get().getVehicleStatus(vin) } + /** + * Get the static information about a vehicle. Static data can include the vehicle's brand, equipment and more. + * + * Read more in the [Static Data API Tutorial](https://docs.high-mobility.com/guides/getting-started/static-data-api/) + */ + fun getVehicleStaticData( + vin: String + ): CompletableFuture> = scope.future { + koin.get().getStaticData(vin) + } + /** * The Fleet SDK environment. * diff --git a/hmkit-fleet/src/main/kotlin/com/highmobility/hmkitfleet/network/VehicleDataRequests.kt b/hmkit-fleet/src/main/kotlin/com/highmobility/hmkitfleet/network/VehicleDataRequests.kt index 5e92265..6d60fe8 100644 --- a/hmkit-fleet/src/main/kotlin/com/highmobility/hmkitfleet/network/VehicleDataRequests.kt +++ b/hmkit-fleet/src/main/kotlin/com/highmobility/hmkitfleet/network/VehicleDataRequests.kt @@ -62,4 +62,28 @@ internal class VehicleDataRequests( Response(responseBody, null) } } + + suspend fun getStaticData( + vin: String, + ): Response { + val authToken = accessTokenRequests.getAccessToken() + + if (authToken.error != null) return Response(null, authToken.error) + + val request = Request.Builder() + .url("$baseUrl/vehicle-static-data/$vin") + .header("Content-Type", "application/json") + .header("Authorization", "Bearer ${authToken.response?.accessToken}") + .get() + .build() + + printRequest(request) + + val call = client.newCall(request) + val response = call.await() + + return tryParseResponse(response, HttpURLConnection.HTTP_OK) { responseBody -> + Response(responseBody, null) + } + } } diff --git a/hmkit-fleet/src/test/kotlin/com/highmobility/hmkitfleet/HMKitFleetTest.kt b/hmkit-fleet/src/test/kotlin/com/highmobility/hmkitfleet/HMKitFleetTest.kt index 9cdee1d..4d90de0 100644 --- a/hmkit-fleet/src/test/kotlin/com/highmobility/hmkitfleet/HMKitFleetTest.kt +++ b/hmkit-fleet/src/test/kotlin/com/highmobility/hmkitfleet/HMKitFleetTest.kt @@ -41,6 +41,7 @@ import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runTest import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonPrimitive import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.MockWebServer @@ -145,6 +146,40 @@ class HMKitFleetTest : BaseTest() { assertTrue(json["vin"]?.jsonPrimitive?.content == "vin1") } + @Test + fun getVehicleStaticData() = runTest { + coEvery { + vehicleDataRequests.getStaticData("vin1") + } returns Response( + """ + { + "manufacturer": { + "brand": "Jeep", + "sub_model": "80th Anniversary Plug-In Hybrid 4WD", + "type_group_name": "Compass", + "model": "Compass (M7)(2020->)", + "sales_description": "Compass 1.3 Plug-In Hybrid (EURO 6d) 80th Annivers" + }, + "equipment": { + "series_equipment": [ + { + "description": "airbag driver side/passenger side", + "positions": [], + "manufacturer_id": null + } + ] + } + } + """.trimIndent(), + null + ) + + val hmkit = HMKitFleet(oauthCredentials) + val staticData = hmkit.getVehicleStaticData("vin1").get() + val json = Json.decodeFromString(staticData.response ?: "") + assertTrue(json["manufacturer"]?.jsonObject?.get("brand")?.jsonPrimitive?.content == "Jeep") + } + @Test fun canSetCustomWebUrl() { stopKoin() diff --git a/hmkit-fleet/src/test/kotlin/com/highmobility/hmkitfleet/network/VehicleDataRequestsTest.kt b/hmkit-fleet/src/test/kotlin/com/highmobility/hmkitfleet/network/VehicleDataRequestsTest.kt index e830852..09c7664 100644 --- a/hmkit-fleet/src/test/kotlin/com/highmobility/hmkitfleet/network/VehicleDataRequestsTest.kt +++ b/hmkit-fleet/src/test/kotlin/com/highmobility/hmkitfleet/network/VehicleDataRequestsTest.kt @@ -74,7 +74,7 @@ internal class VehicleDataRequestsTest : BaseTest() { ) @Test - fun getSuccess() { + fun vehicleStatusSuccess() { successResponses.forEach { val responseJson = it @@ -82,10 +82,10 @@ internal class VehicleDataRequestsTest : BaseTest() { mockWebServer.enqueue(mockResponse) val mockUrl = mockWebServer.url("").toString() - val webService = VehicleDataRequests(client, mockLogger, mockUrl, accessTokenRequests) + val requests = VehicleDataRequests(client, mockLogger, mockUrl, accessTokenRequests) val response = runBlocking { - webService.getVehicleStatus(testVin) + requests.getVehicleStatus(testVin) } coVerify { accessTokenRequests.getAccessToken() } @@ -103,31 +103,91 @@ internal class VehicleDataRequestsTest : BaseTest() { } @Test - fun authTokenError() = runBlocking { + fun vehicleStatusAuthTokenError() = runBlocking { testAuthTokenErrorReturned(mockWebServer, accessTokenRequests) { mockUrl -> - val webService = VehicleDataRequests(client, mockLogger, mockUrl, accessTokenRequests) - webService.getVehicleStatus( + val requests = VehicleDataRequests(client, mockLogger, mockUrl, accessTokenRequests) + requests.getVehicleStatus( testVin, ) } } @Test - fun requestClearanceErrorResponse() = runBlocking { + fun vehicleStatusErrorResponse() = runBlocking { testErrorResponseReturned(mockWebServer) { mockUrl -> - val webService = VehicleDataRequests(client, mockLogger, mockUrl, accessTokenRequests) + val requests = VehicleDataRequests(client, mockLogger, mockUrl, accessTokenRequests) - webService.getVehicleStatus( + requests.getVehicleStatus( testVin, ) } } @Test - fun requestClearanceUnknownResponse() = runBlocking { + fun vehicleStatusUnknownResponse() = runBlocking { testForUnknownResponseGenericErrorReturned(mockWebServer) { mockUrl -> - val webService = VehicleDataRequests(client, mockLogger, mockUrl, accessTokenRequests) - webService.getVehicleStatus( + val requests = VehicleDataRequests(client, mockLogger, mockUrl, accessTokenRequests) + requests.getVehicleStatus( + testVin, + ) + } + } + + @Test + fun vehicleStaticDataSuccess() { + successResponses.forEach { + val responseJson = it + + val mockResponse = MockResponse().setResponseCode(HttpURLConnection.HTTP_OK).setBody(responseJson) + + mockWebServer.enqueue(mockResponse) + val mockUrl = mockWebServer.url("").toString() + val requests = VehicleDataRequests(client, mockLogger, mockUrl, accessTokenRequests) + + val response = runBlocking { + requests.getStaticData(testVin) + } + + coVerify { accessTokenRequests.getAccessToken() } + + val recordedRequest: RecordedRequest = mockWebServer.takeRequest() + assertTrue(recordedRequest.path!!.endsWith("/vehicle-static-data/$testVin")) + + // verify request + assertTrue(recordedRequest.headers["Authorization"] == "Bearer ${authToken.accessToken}") + + // verify response + val status = response.response!! + assertTrue(status == responseJson) + } + } + + @Test + fun vehicleStaticDataAuthTokenError() = runBlocking { + testAuthTokenErrorReturned(mockWebServer, accessTokenRequests) { mockUrl -> + val requests = VehicleDataRequests(client, mockLogger, mockUrl, accessTokenRequests) + requests.getStaticData( + testVin, + ) + } + } + + @Test + fun vehicleStaticDataErrorResponse() = runBlocking { + testErrorResponseReturned(mockWebServer) { mockUrl -> + val requests = VehicleDataRequests(client, mockLogger, mockUrl, accessTokenRequests) + + requests.getStaticData( + testVin, + ) + } + } + + @Test + fun vehicleStaticDataUnknownResponse() = runBlocking { + testForUnknownResponseGenericErrorReturned(mockWebServer) { mockUrl -> + val requests = VehicleDataRequests(client, mockLogger, mockUrl, accessTokenRequests) + requests.getStaticData( testVin, ) } From 8026546accb12649aa6cd17d09b82f7676114c27 Mon Sep 17 00:00:00 2001 From: tonisives Date: Tue, 23 Apr 2024 08:34:36 +0700 Subject: [PATCH 2/2] update version --- CHANGELOG.md | 6 ++++++ gradle.properties | 2 +- gradle/deploy-ossrh.gradle | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3bd40d..4d04cf9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ This is the changelog for v2 releases. See v0/v1 releases in appropriate branches. +## [2.1.0] - 2024-4-23 + +### Added + +- Vehicle static data request + ## [2.0.4] - 2024-3-14 ### Added diff --git a/gradle.properties b/gradle.properties index 585d9b9..b846d4b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ -version=2.0.4 +version=2.1.0 kotlin.code.style=official \ No newline at end of file diff --git a/gradle/deploy-ossrh.gradle b/gradle/deploy-ossrh.gradle index 66a9aa5..ffa7352 100644 --- a/gradle/deploy-ossrh.gradle +++ b/gradle/deploy-ossrh.gradle @@ -37,7 +37,7 @@ def deployGitUrl="https://github.com/highmobility/hmkit-fleet" def deployGroupId="com.high-mobility" def deployLicenseName="MIT" def deployLicenseUrl="https://opensource.org/licenses/MIT" -def deployId=name +def deployId="hmkit-fleet" def isAndroid = project.plugins.findPlugin("com.android.library")