diff --git a/build.gradle.kts b/build.gradle.kts index 0fbde68..04baaba 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -32,6 +32,7 @@ dependencies { testImplementation("org.springframework.boot:spring-boot-starter-test") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") testImplementation("org.springframework.security:spring-security-test") + testImplementation("org.testcontainers:postgresql") testRuntimeOnly("org.junit.platform:junit-platform-launcher") } diff --git a/src/main/kotlin/ru/vyatsu/qr_access_api/repository/QrRepository.kt b/src/main/kotlin/ru/vyatsu/qr_access_api/repository/QrRepository.kt index 75aecb7..a18cbf1 100644 --- a/src/main/kotlin/ru/vyatsu/qr_access_api/repository/QrRepository.kt +++ b/src/main/kotlin/ru/vyatsu/qr_access_api/repository/QrRepository.kt @@ -3,7 +3,7 @@ package ru.vyatsu.qr_access_api.repository import org.springframework.jdbc.core.JdbcTemplate import org.springframework.stereotype.Repository import ru.vyatsu.models.QrCode -import java.time.ZoneOffset +import java.time.ZoneId import java.util.* private const val GET_ACTUAL_QRS_BY_UNIT_ID = """ @@ -16,16 +16,16 @@ private const val GET_ACTUAL_QRS_BY_UNIT_ID = """ @Repository class QrRepository(private val template: JdbcTemplate) { - fun getActualQrCodesByUnitId(unitId: UUID): List { + fun getActualQrCodesByUnitId(unitId: String): List { val query = GET_ACTUAL_QRS_BY_UNIT_ID.trimIndent() return template.query({ conn -> val stmt = conn.prepareStatement(query) - stmt.setString(1, unitId.toString()) + stmt.setString(1, unitId) stmt }, { rs, _ -> QrCode( - rs.getTimestamp("start_date_time").toLocalDateTime().atOffset(ZoneOffset.UTC), - rs.getTimestamp("end_date_time").toLocalDateTime().atOffset(ZoneOffset.UTC), + rs.getTimestamp("start_date_time").toLocalDateTime().atZone(ZoneId.systemDefault()).toOffsetDateTime(), + rs.getTimestamp("end_date_time").toLocalDateTime().atZone(ZoneId.systemDefault()).toOffsetDateTime(), UUID.fromString(rs.getString("door_id")), UUID.fromString(rs.getString("key_code")) ) diff --git a/src/main/kotlin/ru/vyatsu/qr_access_api/service/QrSyncService.kt b/src/main/kotlin/ru/vyatsu/qr_access_api/service/QrSyncService.kt index b09ed91..d9ab3f7 100644 --- a/src/main/kotlin/ru/vyatsu/qr_access_api/service/QrSyncService.kt +++ b/src/main/kotlin/ru/vyatsu/qr_access_api/service/QrSyncService.kt @@ -3,13 +3,12 @@ package ru.vyatsu.qr_access_api.service import org.springframework.stereotype.Service import ru.vyatsu.models.QrCode import ru.vyatsu.qr_access_api.repository.QrRepository -import java.util.* @Service class QrSyncService(val qrRepository: QrRepository) { fun getQrCodes(): List { // TODO: Тут логика с извлечением клайма из jwt в котором идентификатор клиента лежит - val extractedUnitId = UUID.fromString("945c8621-9adc-4a49-bc56-10253d27c581") + val extractedUnitId = "945c8621-9adc-4a49-bc56-10253d27c581" return qrRepository.getActualQrCodesByUnitId(extractedUnitId) } } \ No newline at end of file diff --git a/src/test/kotlin/ru/vyatsu/qr_access_api/QrAccessApiApplicationTests.kt b/src/test/kotlin/ru/vyatsu/qr_access_api/QrAccessApiApplicationTests.kt index baef208..faf7899 100644 --- a/src/test/kotlin/ru/vyatsu/qr_access_api/QrAccessApiApplicationTests.kt +++ b/src/test/kotlin/ru/vyatsu/qr_access_api/QrAccessApiApplicationTests.kt @@ -6,8 +6,7 @@ import org.springframework.boot.test.context.SpringBootTest @SpringBootTest class QrAccessApiApplicationTests { - @Test - fun contextLoads() { - } - + @Test + fun contextLoads() { + } } diff --git a/src/test/kotlin/ru/vyatsu/qr_access_api/database/utils/InsertDatabaseHelper.kt b/src/test/kotlin/ru/vyatsu/qr_access_api/database/utils/InsertDatabaseHelper.kt new file mode 100644 index 0000000..3ff1483 --- /dev/null +++ b/src/test/kotlin/ru/vyatsu/qr_access_api/database/utils/InsertDatabaseHelper.kt @@ -0,0 +1,45 @@ +package ru.vyatsu.qr_access_api.database.utils + +import org.springframework.jdbc.core.JdbcTemplate +import java.time.LocalDateTime +import java.time.OffsetDateTime + +private const val INSERT_CLIENT_QUERY = + """INSERT INTO oauth2_authorized_client(client_registration_id, principal_name, access_token_type, access_token_value, access_token_issued_at, access_token_expires_at, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?)""" + +class InsertDatabaseHelper(private val template: JdbcTemplate) { + fun insertQr( + keyCode: String, + doorId: String, + startDateTime: OffsetDateTime, + endDateTime: OffsetDateTime + ): Int { + return template.update("INSERT INTO qrs(key_code, door_id, start_date_time, end_date_time) VALUES (?, ?, ?, ?)") { ps -> + ps.setString(1, keyCode) + ps.setString(2, doorId) + ps.setObject(3, startDateTime) + ps.setObject(4, endDateTime) + } + } + + fun insertDoor(id: String, unitId: String, principalName: String = ""): Int { + return template.update("INSERT INTO doors(id, unit_id, principal_name) VALUES (?, ?, ?)") { ps -> + ps.setString(1, id) + ps.setString(2, unitId) + ps.setString(3, principalName) + } + } + + fun insertClient(id: String, principalName: String = ""): Int { + return template.update(INSERT_CLIENT_QUERY) { ps -> + ps.setString(1, id) + ps.setString(2, principalName) + ps.setString(3, "Bearer") + ps.setString(4, "Tokenasfgerseawvg") + ps.setObject(5, LocalDateTime.now()) + ps.setObject(6, LocalDateTime.now()) + ps.setObject(7, LocalDateTime.now()) + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/ru/vyatsu/qr_access_api/repository/QrRepositoryTest.kt b/src/test/kotlin/ru/vyatsu/qr_access_api/repository/QrRepositoryTest.kt new file mode 100644 index 0000000..60f3379 --- /dev/null +++ b/src/test/kotlin/ru/vyatsu/qr_access_api/repository/QrRepositoryTest.kt @@ -0,0 +1,137 @@ +package ru.vyatsu.qr_access_api.repository + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.springframework.transaction.annotation.Transactional +import ru.vyatsu.models.QrCode +import java.time.OffsetDateTime +import java.time.temporal.ChronoUnit +import java.util.* + +@Transactional +class QrRepositoryTest : RepositoryTest() { + + + @BeforeEach + fun setUp() { + + } + + @Test + fun checkThatQrCodesReturnedWhenGetActualQrCodesByUnitIdMappingCheck() { + val clientId = "9c0cc999-53b1-4ff1-b13c-5cd1514fec3a" + val doorId = "430141c2-858f-481e-93d9-2dffaf83ea2e" + val keyCode = "e1148f54-96aa-4355-b7f8-6eb0f549f5eb" + val startDateTime = OffsetDateTime.now().minusMinutes(30).truncatedTo(ChronoUnit.MICROS) + val endDateTime = OffsetDateTime.now().plusMinutes(30).truncatedTo(ChronoUnit.MICROS) + insertDatabaseHelper.insertClient(clientId) + insertDatabaseHelper.insertDoor(doorId, clientId) + insertDatabaseHelper.insertQr( + keyCode, + doorId, + startDateTime, + endDateTime + ) + + val codes = qrRepository.getActualQrCodesByUnitId(clientId) + + assertThat(codes).containsOnly( + QrCode( + startDateTime, + endDateTime, + UUID.fromString(doorId), + UUID.fromString(keyCode) + ) + ) + } + + @Test + fun checkThatQrCodesReturnedWhenGetActualQrCodesByUnitIdForOneDoor() { + val clientId = "9c0cc999-53b1-4ff1-b13c-5cd1514fec3a" + val doorId = "430141c2-858f-481e-93d9-2dffaf83ea2e" + insertDatabaseHelper.insertClient(clientId) + insertDatabaseHelper.insertDoor(doorId, clientId) + insertDatabaseHelper.insertQr( + "e1148f54-96aa-4355-b7f8-6eb0f549f5eb", + doorId, + OffsetDateTime.now().minusMinutes(20), + OffsetDateTime.now().plusMinutes(20) + ) + insertDatabaseHelper.insertQr( + "a9fc474b-1871-4257-b174-1b6e36d393a8", + doorId, + OffsetDateTime.now().minusMinutes(30), + OffsetDateTime.now().plusMinutes(30) + ) + insertDatabaseHelper.insertQr( + "b3bfe837-de12-4c07-b39a-4296266f2a8c", + doorId, + OffsetDateTime.now().minusMinutes(30), + OffsetDateTime.now().minusMinutes(20) + ) + + val codes = qrRepository.getActualQrCodesByUnitId(clientId) + + assertThat(codes).hasSize(2) + } + + @Test + fun checkThatQrCodesReturnedWhenGetActualQrCodesByUnitIdForFewDoors() { + val clientId = "9c0cc999-53b1-4ff1-b13c-5cd1514fec3a" + insertDatabaseHelper.insertClient(clientId) + insertDatabaseHelper.insertDoor("430141c2-858f-481e-93d9-2dffaf83ea2e", clientId) + insertDatabaseHelper.insertDoor("259411de-6d90-46a4-92fb-4028a33ad48e", clientId) + insertDatabaseHelper.insertQr( + "e1148f54-96aa-4355-b7f8-6eb0f549f5eb", + "430141c2-858f-481e-93d9-2dffaf83ea2e", + OffsetDateTime.now().minusMinutes(20), + OffsetDateTime.now().plusMinutes(20) + ) + insertDatabaseHelper.insertQr( + "a9fc474b-1871-4257-b174-1b6e36d393a8", + "259411de-6d90-46a4-92fb-4028a33ad48e", + OffsetDateTime.now().minusMinutes(30), + OffsetDateTime.now().plusMinutes(30) + ) + insertDatabaseHelper.insertQr( + "b3bfe837-de12-4c07-b39a-4296266f2a8c", + "430141c2-858f-481e-93d9-2dffaf83ea2e", + OffsetDateTime.now().minusMinutes(30), + OffsetDateTime.now().minusMinutes(20) + ) + insertDatabaseHelper.insertQr( + "90a3de92-33ed-4752-8eff-d425778e1381", + "259411de-6d90-46a4-92fb-4028a33ad48e", + OffsetDateTime.now().minusMinutes(30), + OffsetDateTime.now().minusMinutes(20) + ) + + val codes = qrRepository.getActualQrCodesByUnitId(clientId) + + assertThat(codes).hasSize(2) + } + + @Test + fun checkThatQrCodesEmptyWhenGetActualQrCodesByUnitIdForOneDoor() { + val clientId = "9c0cc999-53b1-4ff1-b13c-5cd1514fec3a" + insertDatabaseHelper.insertClient(clientId) + insertDatabaseHelper.insertDoor("430141c2-858f-481e-93d9-2dffaf83ea2e", clientId) + insertDatabaseHelper.insertQr( + "e1148f54-96aa-4355-b7f8-6eb0f549f5eb", + "430141c2-858f-481e-93d9-2dffaf83ea2e", + OffsetDateTime.now().minusMinutes(30), + OffsetDateTime.now().minusMinutes(20) + ) + insertDatabaseHelper.insertQr( + "b3bfe837-de12-4c07-b39a-4296266f2a8c", + "430141c2-858f-481e-93d9-2dffaf83ea2e", + OffsetDateTime.now().minusMinutes(30), + OffsetDateTime.now().minusMinutes(20) + ) + + val codes = qrRepository.getActualQrCodesByUnitId(clientId) + + assertThat(codes).hasSize(0) + } +} \ No newline at end of file diff --git a/src/test/kotlin/ru/vyatsu/qr_access_api/repository/RepositoryTest.kt b/src/test/kotlin/ru/vyatsu/qr_access_api/repository/RepositoryTest.kt new file mode 100644 index 0000000..1a7a698 --- /dev/null +++ b/src/test/kotlin/ru/vyatsu/qr_access_api/repository/RepositoryTest.kt @@ -0,0 +1,37 @@ +package ru.vyatsu.qr_access_api.repository + +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest +import org.springframework.boot.test.context.TestConfiguration +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Import +import org.springframework.jdbc.core.JdbcTemplate +import ru.vyatsu.qr_access_api.database.utils.InsertDatabaseHelper + +@JdbcTest +@Import(RepositoryTest.Configuration::class) +class RepositoryTest { + + @Autowired + protected lateinit var insertDatabaseHelper: InsertDatabaseHelper + + @Autowired + protected lateinit var qrRepository: QrRepository + + @TestConfiguration + class Configuration { + + @Autowired + private lateinit var template: JdbcTemplate + + @Bean + fun qrRepository(): QrRepository { + return QrRepository(template) + } + + @Bean + fun dbUtils(): InsertDatabaseHelper { + return InsertDatabaseHelper(template) + } + } +} \ No newline at end of file diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties new file mode 100644 index 0000000..dee3c14 --- /dev/null +++ b/src/test/resources/application.properties @@ -0,0 +1 @@ +spring.datasource.url=jdbc:tc:postgresql:17.2:///qr_access \ No newline at end of file