diff --git a/build.gradle b/build.gradle index 95fe2bd..7060adb 100644 --- a/build.gradle +++ b/build.gradle @@ -3,6 +3,9 @@ plugins { id 'org.springframework.boot' version '3.5.8' id 'io.spring.dependency-management' version '1.1.7' id 'com.google.protobuf' version '0.9.4' + id 'org.jetbrains.kotlin.jvm' version '2.0.21' + id 'org.jetbrains.kotlin.plugin.spring' version '2.0.21' + id 'org.jetbrains.kotlin.plugin.jpa' version '2.0.21' } group = 'me' @@ -15,6 +18,10 @@ java { } } +kotlin { + jvmToolchain(21) +} + repositories { mavenCentral() } @@ -36,6 +43,12 @@ dependencies { testImplementation 'org.springframework.amqp:spring-rabbit-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + //kotlin + implementation 'org.jetbrains.kotlin:kotlin-reflect' + implementation 'org.jetbrains.kotlin:kotlin-stdlib' + implementation 'com.fasterxml.jackson.module:jackson-module-kotlin' + testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5' + // Actuator implementation 'org.springframework.boot:spring-boot-starter-actuator' @@ -79,6 +92,12 @@ tasks.named('test') { tasks.named('compileJava') { dependsOn(tasks.named('generateProto')) } +tasks.named('compileKotlin') { + dependsOn(tasks.named('generateProto')) +} tasks.named('compileTestJava') { dependsOn(tasks.named('generateTestProto')) -} \ No newline at end of file +} +tasks.named('compileTestKotlin') { + dependsOn(tasks.named('generateTestProto')) +} diff --git a/src/test/java/me/pinitnotification/domain/notification/UpcomingScheduleNotificationTest.kt b/src/test/java/me/pinitnotification/domain/notification/UpcomingScheduleNotificationTest.kt new file mode 100644 index 0000000..b84fa4a --- /dev/null +++ b/src/test/java/me/pinitnotification/domain/notification/UpcomingScheduleNotificationTest.kt @@ -0,0 +1,49 @@ +package me.pinitnotification.domain.notification + +import org.assertj.core.api.Assertions +import org.junit.jupiter.api.Test +import java.time.Clock +import java.time.LocalDateTime +import java.time.OffsetDateTime +import java.time.ZoneId +import java.time.ZoneOffset.UTC + +internal class UpcomingScheduleNotificationTest { + val clock = Clock.fixed( + LocalDateTime.of( + 2026, + 1, + 1, + 0, + 0, + 0 + ).toInstant(UTC), ZoneId.systemDefault() + ) + + @Test + fun updateScheduleStartTime() { + //given + val notification = getSampleUpcomingScheduleNotification() + + //when + notification.updateScheduleStartTime("2024-06-01T10:00:00Z", "123-idempotency-key") + + //then + Assertions.assertThat(notification.scheduleStartTime).isEqualTo("2024-06-01T10:00:00Z") + Assertions.assertThat(notification.idempotentKey).isEqualTo("123-idempotency-key") + } + + @Test + fun isDue() { + //given + val notification = getSampleUpcomingScheduleNotification( + scheduleStartTime = "2024-06-01T10:00:00Z" + ) + + //when + val isDue = notification.isDue(OffsetDateTime.now(clock)) + + //then + Assertions.assertThat(isDue).isTrue() + } +} \ No newline at end of file diff --git a/src/test/java/me/pinitnotification/domain/notification/UpcomingScheduleNotificationUtils.kt b/src/test/java/me/pinitnotification/domain/notification/UpcomingScheduleNotificationUtils.kt new file mode 100644 index 0000000..f1c2ebb --- /dev/null +++ b/src/test/java/me/pinitnotification/domain/notification/UpcomingScheduleNotificationUtils.kt @@ -0,0 +1,29 @@ +package me.pinitnotification.domain.notification + +import org.junit.platform.commons.util.ReflectionUtils + +fun getSampleUpcomingScheduleNotification( + id: Long = 1L, + ownerId: Long = 1L, + scheduleId: Long = 1L, + scheduleTitle: String = "sample", + scheduleStartTime: String = "2024-06-01T10:00:00Z", + idempotencyKey: String = "", +): UpcomingScheduleNotification { + val sample = UpcomingScheduleNotification( + ownerId, + scheduleId, + scheduleTitle, + scheduleStartTime, + idempotencyKey + ) + ReflectionUtils.findFields( + UpcomingScheduleNotification::class.java, + { field -> field.name == "id" }, + ReflectionUtils.HierarchyTraversalMode.TOP_DOWN + ).forEach { field -> + field.isAccessible = true + field.set(sample, id) + } + return sample +} \ No newline at end of file diff --git a/src/test/java/me/pinitnotification/domain/push/PushSubscriptionTest.kt b/src/test/java/me/pinitnotification/domain/push/PushSubscriptionTest.kt new file mode 100644 index 0000000..c982385 --- /dev/null +++ b/src/test/java/me/pinitnotification/domain/push/PushSubscriptionTest.kt @@ -0,0 +1,19 @@ +package me.pinitnotification.domain.push + +import org.assertj.core.api.Assertions +import org.junit.jupiter.api.Test + +internal class PushSubscriptionTest { + + @Test + fun updateToken() { + //given + val subscription = getSamplePushSubscription() + + //when + subscription.updateToken("new-sample-token") + + //then + Assertions.assertThat(subscription.token).isEqualTo("new-sample-token") + } +} \ No newline at end of file diff --git a/src/test/java/me/pinitnotification/domain/push/PushSubscriptionUtils.kt b/src/test/java/me/pinitnotification/domain/push/PushSubscriptionUtils.kt new file mode 100644 index 0000000..905cc8f --- /dev/null +++ b/src/test/java/me/pinitnotification/domain/push/PushSubscriptionUtils.kt @@ -0,0 +1,31 @@ +package me.pinitnotification.domain.push + +import org.junit.platform.commons.util.ReflectionUtils +import java.time.Instant + +fun getSamplePushSubscription( + id: Long = 1L, + memberId: Long = 1L, + deviceId: String = "sample-device-id", + token: String = "sample-token", + modifiedAt: Instant = Instant.EPOCH, +): PushSubscription { + val sample = PushSubscription(memberId, deviceId, token) + ReflectionUtils.findFields( + PushSubscription::class.java, + { field -> field.name == "id" }, + ReflectionUtils.HierarchyTraversalMode.TOP_DOWN + ).forEach { field -> + field.isAccessible = true + field.set(sample, id) + } + ReflectionUtils.findFields( + PushSubscription::class.java, + { field -> field.name == "modifiedAt" }, + ReflectionUtils.HierarchyTraversalMode.TOP_DOWN + ).forEach { field -> + field.isAccessible = true + field.set(sample, modifiedAt) + } + return sample +} \ No newline at end of file