From ed6e3cd07d56007d04a2d1e37e454192093a82da Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Wed, 19 Mar 2025 12:24:31 +0400 Subject: [PATCH 01/82] #430: Add testcontainers dependencies --- core/build.gradle.kts | 7 +++++++ core/jvm/test/testcontainers/TimeZoneTest.kt | 21 ++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 core/jvm/test/testcontainers/TimeZoneTest.kt diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 64697efd2..992ec7b07 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -221,6 +221,13 @@ kotlin { runtimeOnly(project(":kotlinx-datetime-zoneinfo")) } } + + val jvmTest by getting { + dependencies { + implementation("org.testcontainers:testcontainers:1.19.7") + implementation("org.testcontainers:junit-jupiter:1.19.7") + } + } } } diff --git a/core/jvm/test/testcontainers/TimeZoneTest.kt b/core/jvm/test/testcontainers/TimeZoneTest.kt new file mode 100644 index 000000000..a6fe2015f --- /dev/null +++ b/core/jvm/test/testcontainers/TimeZoneTest.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2019-2025 JetBrains s.r.o. and contributors. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +package testcontainers + +import kotlinx.datetime.* +import org.testcontainers.junit.jupiter.Testcontainers +import kotlin.test.Test +import kotlin.test.assertNotEquals + +@Testcontainers +class TimeZoneTest { + @Test + fun test() { + val tz = TimeZone.currentSystemDefault() + assertNotEquals(TimeZone.UTC, tz) + println("System time zone: $tz") + } +} \ No newline at end of file From 37e67fed2b403e5a382ecfde3c7d1cbdd6637d48 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Wed, 19 Mar 2025 12:38:32 +0400 Subject: [PATCH 02/82] #430: Add dockerfiles --- core/jvm/test/testcontainers/TimeZoneTest.kt | 8 ++++++++ core/jvm/test/testcontainers/modified/Dockerfile | 12 ++++++++++++ core/jvm/test/testcontainers/original/Dockerfile | 8 ++++++++ 3 files changed, 28 insertions(+) create mode 100644 core/jvm/test/testcontainers/modified/Dockerfile create mode 100644 core/jvm/test/testcontainers/original/Dockerfile diff --git a/core/jvm/test/testcontainers/TimeZoneTest.kt b/core/jvm/test/testcontainers/TimeZoneTest.kt index a6fe2015f..7f5703861 100644 --- a/core/jvm/test/testcontainers/TimeZoneTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneTest.kt @@ -7,15 +7,23 @@ package testcontainers import kotlinx.datetime.* import org.testcontainers.junit.jupiter.Testcontainers +import java.nio.file.Paths +import java.nio.file.Files import kotlin.test.Test import kotlin.test.assertNotEquals @Testcontainers class TimeZoneTest { + @Test fun test() { val tz = TimeZone.currentSystemDefault() assertNotEquals(TimeZone.UTC, tz) println("System time zone: $tz") + + val filePath = Paths.get("./jvm/test/testcontainers/original/Dockerfile") + val content = String(Files.readAllBytes(filePath), Charsets.UTF_8) + println("Dockerfile content: \n$content") + } } \ No newline at end of file diff --git a/core/jvm/test/testcontainers/modified/Dockerfile b/core/jvm/test/testcontainers/modified/Dockerfile new file mode 100644 index 000000000..175624f95 --- /dev/null +++ b/core/jvm/test/testcontainers/modified/Dockerfile @@ -0,0 +1,12 @@ +FROM --platform=linux/amd64 ubuntu:24.04 + +RUN apt-get update && apt-get install -y tzdata + +# 4: Arctic/Longyearbyen +RUN echo 4 | dpkg-reconfigure tzdata + +# Modification like in Debian Jessie +RUN rm /etc/localtime +RUN cp /usr/share/zoneinfo/$(cat /etc/timezone) /etc/localtime + +WORKDIR /app \ No newline at end of file diff --git a/core/jvm/test/testcontainers/original/Dockerfile b/core/jvm/test/testcontainers/original/Dockerfile new file mode 100644 index 000000000..94b2b3787 --- /dev/null +++ b/core/jvm/test/testcontainers/original/Dockerfile @@ -0,0 +1,8 @@ +FROM --platform=linux/amd64 ubuntu:24.04 + +RUN apt-get update && apt-get install -y tzdata + +# 4: Arctic/Longyearbyen +RUN echo 4 | dpkg-reconfigure tzdata + +WORKDIR /app \ No newline at end of file From 0e4aaddd3b2599dc8e7d454e0c2c7520813ac9e0 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Wed, 19 Mar 2025 13:17:05 +0400 Subject: [PATCH 03/82] #430: Fix build.gradle.kts to depend on JUnit 5 to correct running of containers --- core/build.gradle.kts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 992ec7b07..1672292a0 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -226,6 +226,8 @@ kotlin { dependencies { implementation("org.testcontainers:testcontainers:1.19.7") implementation("org.testcontainers:junit-jupiter:1.19.7") + implementation("org.junit.jupiter:junit-jupiter-api:5.10.2") + runtimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.2") } } } @@ -234,6 +236,7 @@ kotlin { tasks { val jvmTest by existing(Test::class) { // maxHeapSize = "1024m" + useJUnitPlatform() } val compileJavaModuleInfo by registering(JavaCompile::class) { From 20dc7bc3ed8a02035d8ef60ccabda68de2869fb8 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Wed, 19 Mar 2025 13:17:52 +0400 Subject: [PATCH 04/82] #430: Add container initialization, run simple commant inside container and print the result of them --- core/jvm/test/testcontainers/TimeZoneTest.kt | 30 +++++++++++-------- .../testcontainers/TimezoneTestContainer.kt | 23 ++++++++++++++ 2 files changed, 41 insertions(+), 12 deletions(-) create mode 100644 core/jvm/test/testcontainers/TimezoneTestContainer.kt diff --git a/core/jvm/test/testcontainers/TimeZoneTest.kt b/core/jvm/test/testcontainers/TimeZoneTest.kt index 7f5703861..78dcf8494 100644 --- a/core/jvm/test/testcontainers/TimeZoneTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneTest.kt @@ -5,25 +5,31 @@ package testcontainers -import kotlinx.datetime.* +import org.testcontainers.junit.jupiter.Container import org.testcontainers.junit.jupiter.Testcontainers import java.nio.file.Paths -import java.nio.file.Files -import kotlin.test.Test -import kotlin.test.assertNotEquals +import org.junit.jupiter.api.Test @Testcontainers class TimeZoneTest { - @Test - fun test() { - val tz = TimeZone.currentSystemDefault() - assertNotEquals(TimeZone.UTC, tz) - println("System time zone: $tz") + @Container + val originalContainer = TimezoneTestContainer( + Paths.get("./jvm/test/testcontainers/original/Dockerfile"), + "ubuntu-arctic-longyearbyen" + ) - val filePath = Paths.get("./jvm/test/testcontainers/original/Dockerfile") - val content = String(Files.readAllBytes(filePath), Charsets.UTF_8) - println("Dockerfile content: \n$content") + @Container + val modifiedContainer = TimezoneTestContainer( + Paths.get("./jvm/test/testcontainers/modified/Dockerfile"), + "ubuntu-new-longyearbyen-modified" + ) + @Test + fun test() { + val originalExecResult = originalContainer.runTest() + val modifiedExecResult = modifiedContainer.runTest() + println(originalExecResult.stdout) + println(modifiedExecResult.stdout) } } \ No newline at end of file diff --git a/core/jvm/test/testcontainers/TimezoneTestContainer.kt b/core/jvm/test/testcontainers/TimezoneTestContainer.kt new file mode 100644 index 000000000..738aa6227 --- /dev/null +++ b/core/jvm/test/testcontainers/TimezoneTestContainer.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2019-2025 JetBrains s.r.o. and contributors. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +package testcontainers + +import org.testcontainers.containers.Container.ExecResult +import org.testcontainers.containers.GenericContainer +import org.testcontainers.images.builder.ImageFromDockerfile +import java.nio.file.Path + +class TimezoneTestContainer(dockerfilePath: Path, val imageName: String) : + GenericContainer(ImageFromDockerfile(imageName).withDockerfile(dockerfilePath)) { + + init { + withCommand("tail -f /dev/null") + } + + fun runTest(): ExecResult { + return execInContainer("bash", "-c", "echo Inside container $imageName, system time zone: $(date -R)") + } +} \ No newline at end of file From fbbd55fd8aff310b0fac927ed0af0bebafc0e116 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Wed, 19 Mar 2025 13:45:35 +0400 Subject: [PATCH 05/82] #430: Add logger configuration --- core/build.gradle.kts | 1 + core/jvm/test/testcontainers/TimeZoneTest.kt | 7 +++++-- core/jvm/testResources/logback-test.xml | 16 ++++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 core/jvm/testResources/logback-test.xml diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 1672292a0..1d0b54736 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -228,6 +228,7 @@ kotlin { implementation("org.testcontainers:junit-jupiter:1.19.7") implementation("org.junit.jupiter:junit-jupiter-api:5.10.2") runtimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.2") + implementation("ch.qos.logback:logback-classic:1.2.13") } } } diff --git a/core/jvm/test/testcontainers/TimeZoneTest.kt b/core/jvm/test/testcontainers/TimeZoneTest.kt index 78dcf8494..0e60529ab 100644 --- a/core/jvm/test/testcontainers/TimeZoneTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneTest.kt @@ -9,10 +9,13 @@ import org.testcontainers.junit.jupiter.Container import org.testcontainers.junit.jupiter.Testcontainers import java.nio.file.Paths import org.junit.jupiter.api.Test +import org.slf4j.LoggerFactory @Testcontainers class TimeZoneTest { + private val logger = LoggerFactory.getLogger(javaClass) + @Container val originalContainer = TimezoneTestContainer( Paths.get("./jvm/test/testcontainers/original/Dockerfile"), @@ -29,7 +32,7 @@ class TimeZoneTest { fun test() { val originalExecResult = originalContainer.runTest() val modifiedExecResult = modifiedContainer.runTest() - println(originalExecResult.stdout) - println(modifiedExecResult.stdout) + logger.info("Original container stdout: ${originalExecResult.stdout}") + logger.info("Modified container stdout: ${modifiedExecResult.stdout}") } } \ No newline at end of file diff --git a/core/jvm/testResources/logback-test.xml b/core/jvm/testResources/logback-test.xml new file mode 100644 index 000000000..07d3b34bd --- /dev/null +++ b/core/jvm/testResources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + \ No newline at end of file From 5facbfac36c33367fea5583cb3dcacc5ebc4664b Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Wed, 19 Mar 2025 14:20:10 +0400 Subject: [PATCH 06/82] #430: dockerfilePath refactoring --- core/jvm/test/testcontainers/TimeZoneTest.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/jvm/test/testcontainers/TimeZoneTest.kt b/core/jvm/test/testcontainers/TimeZoneTest.kt index 0e60529ab..fca666901 100644 --- a/core/jvm/test/testcontainers/TimeZoneTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneTest.kt @@ -16,15 +16,17 @@ class TimeZoneTest { private val logger = LoggerFactory.getLogger(javaClass) + private val dockerfilePath = "./jvm/test/testcontainers/%s/Dockerfile" + @Container val originalContainer = TimezoneTestContainer( - Paths.get("./jvm/test/testcontainers/original/Dockerfile"), + Paths.get(String.format(dockerfilePath, "original")), "ubuntu-arctic-longyearbyen" ) @Container val modifiedContainer = TimezoneTestContainer( - Paths.get("./jvm/test/testcontainers/modified/Dockerfile"), + Paths.get(String.format(dockerfilePath, "modified")), "ubuntu-new-longyearbyen-modified" ) From 8cfd36d98fe3f7ecb2dea765905969c14c1a04bc Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Wed, 19 Mar 2025 16:15:54 +0400 Subject: [PATCH 07/82] #430: Run tests inside containers --- core/jvm/test/testcontainers/TimeZoneTest.kt | 13 ++----------- .../test/testcontainers/TimezoneTestContainer.kt | 15 +++++++++++++-- core/jvm/test/testcontainers/modified/Dockerfile | 2 +- core/jvm/test/testcontainers/original/Dockerfile | 2 +- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/core/jvm/test/testcontainers/TimeZoneTest.kt b/core/jvm/test/testcontainers/TimeZoneTest.kt index fca666901..d55c68037 100644 --- a/core/jvm/test/testcontainers/TimeZoneTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneTest.kt @@ -7,7 +7,6 @@ package testcontainers import org.testcontainers.junit.jupiter.Container import org.testcontainers.junit.jupiter.Testcontainers -import java.nio.file.Paths import org.junit.jupiter.api.Test import org.slf4j.LoggerFactory @@ -16,19 +15,11 @@ class TimeZoneTest { private val logger = LoggerFactory.getLogger(javaClass) - private val dockerfilePath = "./jvm/test/testcontainers/%s/Dockerfile" - @Container - val originalContainer = TimezoneTestContainer( - Paths.get(String.format(dockerfilePath, "original")), - "ubuntu-arctic-longyearbyen" - ) + val originalContainer = createTimezoneTestContainer("original") @Container - val modifiedContainer = TimezoneTestContainer( - Paths.get(String.format(dockerfilePath, "modified")), - "ubuntu-new-longyearbyen-modified" - ) + val modifiedContainer = createTimezoneTestContainer("modified") @Test fun test() { diff --git a/core/jvm/test/testcontainers/TimezoneTestContainer.kt b/core/jvm/test/testcontainers/TimezoneTestContainer.kt index 738aa6227..d45939d1c 100644 --- a/core/jvm/test/testcontainers/TimezoneTestContainer.kt +++ b/core/jvm/test/testcontainers/TimezoneTestContainer.kt @@ -5,19 +5,30 @@ package testcontainers +import org.testcontainers.containers.BindMode import org.testcontainers.containers.Container.ExecResult import org.testcontainers.containers.GenericContainer import org.testcontainers.images.builder.ImageFromDockerfile import java.nio.file.Path +import java.nio.file.Paths -class TimezoneTestContainer(dockerfilePath: Path, val imageName: String) : +class TimezoneTestContainer(dockerfilePath: Path, binaryDir: String, imageName: String) : GenericContainer(ImageFromDockerfile(imageName).withDockerfile(dockerfilePath)) { init { withCommand("tail -f /dev/null") + withFileSystemBind(binaryDir, "/app", BindMode.READ_WRITE) } fun runTest(): ExecResult { - return execInContainer("bash", "-c", "echo Inside container $imageName, system time zone: $(date -R)") + return execInContainer("bash", "-c", "chmod +x /app/test.kexe && /app/test.kexe") } +} + +fun createTimezoneTestContainer(typeName: String): TimezoneTestContainer { + return TimezoneTestContainer( + Paths.get("./jvm/test/testcontainers/$typeName/Dockerfile"), + "./build/bin/linuxArm64/debugTest/", + "ubuntu-arctic-longyearbyen-$typeName" + ) } \ No newline at end of file diff --git a/core/jvm/test/testcontainers/modified/Dockerfile b/core/jvm/test/testcontainers/modified/Dockerfile index 175624f95..2ac9eb086 100644 --- a/core/jvm/test/testcontainers/modified/Dockerfile +++ b/core/jvm/test/testcontainers/modified/Dockerfile @@ -1,4 +1,4 @@ -FROM --platform=linux/amd64 ubuntu:24.04 +FROM --platform=linux/arm64 ubuntu:24.04 RUN apt-get update && apt-get install -y tzdata diff --git a/core/jvm/test/testcontainers/original/Dockerfile b/core/jvm/test/testcontainers/original/Dockerfile index 94b2b3787..bc4af2eb9 100644 --- a/core/jvm/test/testcontainers/original/Dockerfile +++ b/core/jvm/test/testcontainers/original/Dockerfile @@ -1,4 +1,4 @@ -FROM --platform=linux/amd64 ubuntu:24.04 +FROM --platform=linux/arm64 ubuntu:24.04 RUN apt-get update && apt-get install -y tzdata From 683ce09ee53670ced0a3c5d895d85eb41f9817d0 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Wed, 19 Mar 2025 16:50:03 +0400 Subject: [PATCH 08/82] #430: Add defaultTimeZoneTest that runs inside containers --- core/common/test/TimeZoneTest.kt | 7 +++++++ core/jvm/test/testcontainers/TimezoneTestContainer.kt | 6 +++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/core/common/test/TimeZoneTest.kt b/core/common/test/TimeZoneTest.kt index 24c6d9e87..73b480c83 100644 --- a/core/common/test/TimeZoneTest.kt +++ b/core/common/test/TimeZoneTest.kt @@ -12,6 +12,13 @@ import kotlin.test.* class TimeZoneTest { + @Test + fun defaultTimeZoneTest() { + val tz = TimeZone.currentSystemDefault() + println("TIMEZONE: $tz") + assertEquals(TimeZone.of("Europe/Oslo"), tz) + } + @Test fun utc() { val utc: FixedOffsetTimeZone = TimeZone.UTC diff --git a/core/jvm/test/testcontainers/TimezoneTestContainer.kt b/core/jvm/test/testcontainers/TimezoneTestContainer.kt index d45939d1c..52f3690e9 100644 --- a/core/jvm/test/testcontainers/TimezoneTestContainer.kt +++ b/core/jvm/test/testcontainers/TimezoneTestContainer.kt @@ -21,7 +21,11 @@ class TimezoneTestContainer(dockerfilePath: Path, binaryDir: String, imageName: } fun runTest(): ExecResult { - return execInContainer("bash", "-c", "chmod +x /app/test.kexe && /app/test.kexe") + return execInContainer( + "bash", + "-c", + "chmod +x /app/test.kexe && /app/test.kexe --ktest_filter=kotlinx.datetime.test.TimeZoneTest.defaultTimeZoneTest" + ) } } From e638490dc650be420aef33db957ebf7eceb7c17c Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Wed, 19 Mar 2025 17:19:49 +0400 Subject: [PATCH 09/82] #430: Split test on 2, pass cantainer as parameter --- core/build.gradle.kts | 1 + core/jvm/test/testcontainers/TimeZoneTest.kt | 34 +++++++++++++------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 1d0b54736..0de0c7d6a 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -227,6 +227,7 @@ kotlin { implementation("org.testcontainers:testcontainers:1.19.7") implementation("org.testcontainers:junit-jupiter:1.19.7") implementation("org.junit.jupiter:junit-jupiter-api:5.10.2") + implementation("org.junit.jupiter:junit-jupiter-params:5.10.2") runtimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.2") implementation("ch.qos.logback:logback-classic:1.2.13") } diff --git a/core/jvm/test/testcontainers/TimeZoneTest.kt b/core/jvm/test/testcontainers/TimeZoneTest.kt index d55c68037..b7ea14143 100644 --- a/core/jvm/test/testcontainers/TimeZoneTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneTest.kt @@ -7,7 +7,8 @@ package testcontainers import org.testcontainers.junit.jupiter.Container import org.testcontainers.junit.jupiter.Testcontainers -import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.MethodSource import org.slf4j.LoggerFactory @Testcontainers @@ -15,17 +16,28 @@ class TimeZoneTest { private val logger = LoggerFactory.getLogger(javaClass) - @Container - val originalContainer = createTimezoneTestContainer("original") + @ParameterizedTest + @MethodSource("containers") + fun test(container: TimezoneTestContainer) { + val execResult = container.runTest() - @Container - val modifiedContainer = createTimezoneTestContainer("modified") + logger.info("Container stdout: ${execResult.stdout}") + logger.info("Container stderr: ${execResult.stderr}") + logger.info("Container exit code: ${execResult.exitCode}") + } + + companion object { + @JvmStatic + @Container + val originalContainer = createTimezoneTestContainer("original") + + @JvmStatic + @Container + val modifiedContainer = createTimezoneTestContainer("modified") - @Test - fun test() { - val originalExecResult = originalContainer.runTest() - val modifiedExecResult = modifiedContainer.runTest() - logger.info("Original container stdout: ${originalExecResult.stdout}") - logger.info("Modified container stdout: ${modifiedExecResult.stdout}") + @JvmStatic + fun containers(): List { + return listOf(originalContainer, modifiedContainer) + } } } \ No newline at end of file From 3d59b39b8b0e12d4a5f2b58590a88507aadaa11d Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Wed, 19 Mar 2025 17:55:47 +0400 Subject: [PATCH 10/82] #430: Add BeforeAll buildTestBinary --- core/jvm/test/testcontainers/TimeZoneTest.kt | 29 ++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/core/jvm/test/testcontainers/TimeZoneTest.kt b/core/jvm/test/testcontainers/TimeZoneTest.kt index b7ea14143..8c2d4ef8c 100644 --- a/core/jvm/test/testcontainers/TimeZoneTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneTest.kt @@ -5,6 +5,7 @@ package testcontainers +import org.junit.jupiter.api.BeforeAll import org.testcontainers.junit.jupiter.Container import org.testcontainers.junit.jupiter.Testcontainers import org.junit.jupiter.params.ParameterizedTest @@ -14,8 +15,6 @@ import org.slf4j.LoggerFactory @Testcontainers class TimeZoneTest { - private val logger = LoggerFactory.getLogger(javaClass) - @ParameterizedTest @MethodSource("containers") fun test(container: TimezoneTestContainer) { @@ -27,6 +26,8 @@ class TimeZoneTest { } companion object { + private val logger = LoggerFactory.getLogger(javaClass) + @JvmStatic @Container val originalContainer = createTimezoneTestContainer("original") @@ -39,5 +40,29 @@ class TimeZoneTest { fun containers(): List { return listOf(originalContainer, modifiedContainer) } + + @JvmStatic + @BeforeAll + fun buildTestBinary() { + logger.info("Building test binary...") + + val process = ProcessBuilder() + .command("../gradlew", "linkDebugTestLinuxArm64") + .redirectErrorStream(true) + .start() + + process.inputStream.bufferedReader().use { reader -> + reader.lines().forEach { line -> + logger.info("Build: {}", line) + } + } + + val exitCode = process.waitFor() + if (exitCode != 0) { + throw IllegalStateException("Failed to build test binary: exit code $exitCode") + } + + logger.info("Test binary built successfully") + } } } \ No newline at end of file From 0614e6158f2f3fc6998adf9553d1902d6cc5a6bb Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Wed, 19 Mar 2025 17:57:24 +0400 Subject: [PATCH 11/82] #430: Fix container stdout --- core/jvm/test/testcontainers/TimeZoneTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/jvm/test/testcontainers/TimeZoneTest.kt b/core/jvm/test/testcontainers/TimeZoneTest.kt index 8c2d4ef8c..4a29e138a 100644 --- a/core/jvm/test/testcontainers/TimeZoneTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneTest.kt @@ -20,8 +20,8 @@ class TimeZoneTest { fun test(container: TimezoneTestContainer) { val execResult = container.runTest() - logger.info("Container stdout: ${execResult.stdout}") - logger.info("Container stderr: ${execResult.stderr}") + logger.info("Container stdout:\n${execResult.stdout}") + logger.info("Container stderr:\n${execResult.stderr}") logger.info("Container exit code: ${execResult.exitCode}") } From d294ac1700a344787178f97ad120b8eac50d32cd Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Wed, 19 Mar 2025 20:21:49 +0400 Subject: [PATCH 12/82] #430: Move defaultTimeZoneTest from common to linux/native --- core/common/test/TimeZoneTest.kt | 7 ------- .../testcontainers/TimezoneTestContainer.kt | 2 +- core/linux/test/TimeZoneLinuxNativeTest.kt | 18 ++++++++++++++++++ 3 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 core/linux/test/TimeZoneLinuxNativeTest.kt diff --git a/core/common/test/TimeZoneTest.kt b/core/common/test/TimeZoneTest.kt index 73b480c83..24c6d9e87 100644 --- a/core/common/test/TimeZoneTest.kt +++ b/core/common/test/TimeZoneTest.kt @@ -12,13 +12,6 @@ import kotlin.test.* class TimeZoneTest { - @Test - fun defaultTimeZoneTest() { - val tz = TimeZone.currentSystemDefault() - println("TIMEZONE: $tz") - assertEquals(TimeZone.of("Europe/Oslo"), tz) - } - @Test fun utc() { val utc: FixedOffsetTimeZone = TimeZone.UTC diff --git a/core/jvm/test/testcontainers/TimezoneTestContainer.kt b/core/jvm/test/testcontainers/TimezoneTestContainer.kt index 52f3690e9..1e98537df 100644 --- a/core/jvm/test/testcontainers/TimezoneTestContainer.kt +++ b/core/jvm/test/testcontainers/TimezoneTestContainer.kt @@ -24,7 +24,7 @@ class TimezoneTestContainer(dockerfilePath: Path, binaryDir: String, imageName: return execInContainer( "bash", "-c", - "chmod +x /app/test.kexe && /app/test.kexe --ktest_filter=kotlinx.datetime.test.TimeZoneTest.defaultTimeZoneTest" + "chmod +x /app/test.kexe && /app/test.kexe --ktest_filter=kotlinx.datetime.test.TimeZoneLinuxNativeTest.*" ) } } diff --git a/core/linux/test/TimeZoneLinuxNativeTest.kt b/core/linux/test/TimeZoneLinuxNativeTest.kt new file mode 100644 index 000000000..43e91e82c --- /dev/null +++ b/core/linux/test/TimeZoneLinuxNativeTest.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2019-2025 JetBrains s.r.o. and contributors. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +package kotlinx.datetime.test + +import kotlinx.datetime.* +import kotlin.test.* + +class TimeZoneLinuxNativeTest { + @Test + fun defaultTimeZoneTest() { + val tz = TimeZone.currentSystemDefault() + println("LINUX TIMEZONE: $tz") + assertEquals(TimeZone.of("Europe/Oslo"), tz) + } +} \ No newline at end of file From fc08cb90226f82fe5459de28e5d7956c8fbf9bc9 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Wed, 19 Mar 2025 20:53:20 +0400 Subject: [PATCH 13/82] #430: Check INSIDE_TESTCONTAINERS env var to run test only in testcontainer --- core/jvm/test/testcontainers/modified/Dockerfile | 2 ++ core/jvm/test/testcontainers/original/Dockerfile | 2 ++ core/linux/test/TimeZoneLinuxNativeTest.kt | 16 +++++++++++++++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/core/jvm/test/testcontainers/modified/Dockerfile b/core/jvm/test/testcontainers/modified/Dockerfile index 2ac9eb086..6594e4c1c 100644 --- a/core/jvm/test/testcontainers/modified/Dockerfile +++ b/core/jvm/test/testcontainers/modified/Dockerfile @@ -2,6 +2,8 @@ FROM --platform=linux/arm64 ubuntu:24.04 RUN apt-get update && apt-get install -y tzdata +ENV INSIDE_TESTCONTAINERS=true + # 4: Arctic/Longyearbyen RUN echo 4 | dpkg-reconfigure tzdata diff --git a/core/jvm/test/testcontainers/original/Dockerfile b/core/jvm/test/testcontainers/original/Dockerfile index bc4af2eb9..df5b0e83e 100644 --- a/core/jvm/test/testcontainers/original/Dockerfile +++ b/core/jvm/test/testcontainers/original/Dockerfile @@ -2,6 +2,8 @@ FROM --platform=linux/arm64 ubuntu:24.04 RUN apt-get update && apt-get install -y tzdata +ENV INSIDE_TESTCONTAINERS=true + # 4: Arctic/Longyearbyen RUN echo 4 | dpkg-reconfigure tzdata diff --git a/core/linux/test/TimeZoneLinuxNativeTest.kt b/core/linux/test/TimeZoneLinuxNativeTest.kt index 43e91e82c..c12b137dc 100644 --- a/core/linux/test/TimeZoneLinuxNativeTest.kt +++ b/core/linux/test/TimeZoneLinuxNativeTest.kt @@ -5,14 +5,28 @@ package kotlinx.datetime.test +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.toKString import kotlinx.datetime.* import kotlin.test.* +import platform.posix.getenv class TimeZoneLinuxNativeTest { + + private var shouldRunTests = false + + @OptIn(ExperimentalForeignApi::class) + @BeforeTest + fun setup() { + shouldRunTests = getenv("INSIDE_TESTCONTAINERS")?.toKString() != null + } + @Test fun defaultTimeZoneTest() { + if (!shouldRunTests) return + val tz = TimeZone.currentSystemDefault() - println("LINUX TIMEZONE: $tz") + println("TIMEZONE: $tz") assertEquals(TimeZone.of("Europe/Oslo"), tz) } } \ No newline at end of file From 403ebf943056d77944b75bd4cea86f83fb752ecc Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Thu, 20 Mar 2025 10:19:11 +0400 Subject: [PATCH 14/82] #430: Replace shouldRunTests check to Testcontainers.runIfAvailable --- core/linux/test/TestcontainersSupport.kt | 21 +++++++++++++++++++++ core/linux/test/TimeZoneLinuxNativeTest.kt | 15 +-------------- 2 files changed, 22 insertions(+), 14 deletions(-) create mode 100644 core/linux/test/TestcontainersSupport.kt diff --git a/core/linux/test/TestcontainersSupport.kt b/core/linux/test/TestcontainersSupport.kt new file mode 100644 index 000000000..9a09e1722 --- /dev/null +++ b/core/linux/test/TestcontainersSupport.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2019-2025 JetBrains s.r.o. and contributors. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +package kotlinx.datetime.test + +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.toKString +import platform.posix.getenv + +object Testcontainers { + + @OptIn(ExperimentalForeignApi::class) + val available: Boolean + get() = getenv("INSIDE_TESTCONTAINERS")?.toKString()?.toBoolean() == true + + inline fun runIfAvailable(block: () -> Unit) { + if (available) block() else println("Skipping test that requires testcontainers...") + } +} \ No newline at end of file diff --git a/core/linux/test/TimeZoneLinuxNativeTest.kt b/core/linux/test/TimeZoneLinuxNativeTest.kt index c12b137dc..90ab900d4 100644 --- a/core/linux/test/TimeZoneLinuxNativeTest.kt +++ b/core/linux/test/TimeZoneLinuxNativeTest.kt @@ -5,26 +5,13 @@ package kotlinx.datetime.test -import kotlinx.cinterop.ExperimentalForeignApi -import kotlinx.cinterop.toKString import kotlinx.datetime.* import kotlin.test.* -import platform.posix.getenv class TimeZoneLinuxNativeTest { - private var shouldRunTests = false - - @OptIn(ExperimentalForeignApi::class) - @BeforeTest - fun setup() { - shouldRunTests = getenv("INSIDE_TESTCONTAINERS")?.toKString() != null - } - @Test - fun defaultTimeZoneTest() { - if (!shouldRunTests) return - + fun defaultTimeZoneTest() = Testcontainers.runIfAvailable { val tz = TimeZone.currentSystemDefault() println("TIMEZONE: $tz") assertEquals(TimeZone.of("Europe/Oslo"), tz) From 54ad22707188a691b7144d5270836630cbd7ca0b Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Thu, 20 Mar 2025 10:24:00 +0400 Subject: [PATCH 15/82] #430: Refactor Skipping test message --- core/linux/test/TestcontainersSupport.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/linux/test/TestcontainersSupport.kt b/core/linux/test/TestcontainersSupport.kt index 9a09e1722..f9f735ee1 100644 --- a/core/linux/test/TestcontainersSupport.kt +++ b/core/linux/test/TestcontainersSupport.kt @@ -16,6 +16,6 @@ object Testcontainers { get() = getenv("INSIDE_TESTCONTAINERS")?.toKString()?.toBoolean() == true inline fun runIfAvailable(block: () -> Unit) { - if (available) block() else println("Skipping test that requires testcontainers...") + if (available) block() else println("[----------] Skipping test that requires testcontainers...") } } \ No newline at end of file From 1d0ff833b8dc6f7fec0f96b7add432da7c6be5a7 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Thu, 20 Mar 2025 11:35:43 +0400 Subject: [PATCH 16/82] #430: Rename TimeZoneTest to TimeZoneConfigurationTest --- .../{TimeZoneTest.kt => TimeZoneConfigurationTest.kt} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename core/jvm/test/testcontainers/{TimeZoneTest.kt => TimeZoneConfigurationTest.kt} (94%) diff --git a/core/jvm/test/testcontainers/TimeZoneTest.kt b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt similarity index 94% rename from core/jvm/test/testcontainers/TimeZoneTest.kt rename to core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt index 4a29e138a..d957cdfb1 100644 --- a/core/jvm/test/testcontainers/TimeZoneTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt @@ -13,7 +13,7 @@ import org.junit.jupiter.params.provider.MethodSource import org.slf4j.LoggerFactory @Testcontainers -class TimeZoneTest { +class TimeZoneConfigurationTest { @ParameterizedTest @MethodSource("containers") @@ -26,7 +26,7 @@ class TimeZoneTest { } companion object { - private val logger = LoggerFactory.getLogger(javaClass) + private val logger = LoggerFactory.getLogger(TimeZoneConfigurationTest::class.java) @JvmStatic @Container From 62e4f5b2a94df6f5e8c1eced59e6f7955b78dbd1 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Thu, 20 Mar 2025 12:13:08 +0400 Subject: [PATCH 17/82] #430: Split runTest to runTimeZoneTests and runAllTests --- .../TimeZoneConfigurationTest.kt | 47 +++++++++++-------- .../testcontainers/TimezoneTestContainer.kt | 30 ++++++++---- .../{modified => custom}/Dockerfile | 0 .../{original => default}/Dockerfile | 0 4 files changed, 49 insertions(+), 28 deletions(-) rename core/jvm/test/testcontainers/{modified => custom}/Dockerfile (100%) rename core/jvm/test/testcontainers/{original => default}/Dockerfile (100%) diff --git a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt index d957cdfb1..2954e8c4c 100644 --- a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt @@ -8,18 +8,40 @@ package testcontainers import org.junit.jupiter.api.BeforeAll import org.testcontainers.junit.jupiter.Container import org.testcontainers.junit.jupiter.Testcontainers -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.MethodSource +import org.junit.jupiter.api.Test import org.slf4j.LoggerFactory +import org.testcontainers.containers.Container.ExecResult @Testcontainers class TimeZoneConfigurationTest { - @ParameterizedTest - @MethodSource("containers") - fun test(container: TimezoneTestContainer) { - val execResult = container.runTest() + @Container + private val defaultTimeZoneContainer = createTimezoneTestContainer("default") + @Container + private val customTimeZoneContainer = createTimezoneTestContainer("custom") + + @Test + fun testDefaultContainerTimeZoneTests() { + logExecResult(defaultTimeZoneContainer.runTimeZoneTests()) + } + + @Test + fun testCustomContainerTimeZoneTests() { + logExecResult(customTimeZoneContainer.runTimeZoneTests()) + } + + @Test + fun testDefaultContainerAllTests() { + logExecResult(defaultTimeZoneContainer.runAllTests()) + } + + @Test + fun testCustomContainerAllTests() { + logExecResult(customTimeZoneContainer.runAllTests()) + } + + private fun logExecResult(execResult: ExecResult) { logger.info("Container stdout:\n${execResult.stdout}") logger.info("Container stderr:\n${execResult.stderr}") logger.info("Container exit code: ${execResult.exitCode}") @@ -28,19 +50,6 @@ class TimeZoneConfigurationTest { companion object { private val logger = LoggerFactory.getLogger(TimeZoneConfigurationTest::class.java) - @JvmStatic - @Container - val originalContainer = createTimezoneTestContainer("original") - - @JvmStatic - @Container - val modifiedContainer = createTimezoneTestContainer("modified") - - @JvmStatic - fun containers(): List { - return listOf(originalContainer, modifiedContainer) - } - @JvmStatic @BeforeAll fun buildTestBinary() { diff --git a/core/jvm/test/testcontainers/TimezoneTestContainer.kt b/core/jvm/test/testcontainers/TimezoneTestContainer.kt index 1e98537df..a1dbeb4b9 100644 --- a/core/jvm/test/testcontainers/TimezoneTestContainer.kt +++ b/core/jvm/test/testcontainers/TimezoneTestContainer.kt @@ -20,19 +20,31 @@ class TimezoneTestContainer(dockerfilePath: Path, binaryDir: String, imageName: withFileSystemBind(binaryDir, "/app", BindMode.READ_WRITE) } - fun runTest(): ExecResult { - return execInContainer( - "bash", - "-c", - "chmod +x /app/test.kexe && /app/test.kexe --ktest_filter=kotlinx.datetime.test.TimeZoneLinuxNativeTest.*" - ) + fun runTimeZoneTests(): ExecResult { + return executeTest("--ktest_filter=kotlinx.datetime.test.TimeZoneLinuxNativeTest.*") + } + + fun runAllTests(): ExecResult { + return executeTest() + } + + private fun executeTest(testFilter: String? = null): ExecResult { + val command = buildString { + append("chmod +x /app/test.kexe && /app/test.kexe") + testFilter?.also { + append(" ") + append(it) + } + } + + return execInContainer("bash", "-c", command) } } -fun createTimezoneTestContainer(typeName: String): TimezoneTestContainer { +fun createTimezoneTestContainer(configType: String): TimezoneTestContainer { return TimezoneTestContainer( - Paths.get("./jvm/test/testcontainers/$typeName/Dockerfile"), + Paths.get("./jvm/test/testcontainers/$configType/Dockerfile"), "./build/bin/linuxArm64/debugTest/", - "ubuntu-arctic-longyearbyen-$typeName" + "ubuntu-arctic-longyearbyen-$configType" ) } \ No newline at end of file diff --git a/core/jvm/test/testcontainers/modified/Dockerfile b/core/jvm/test/testcontainers/custom/Dockerfile similarity index 100% rename from core/jvm/test/testcontainers/modified/Dockerfile rename to core/jvm/test/testcontainers/custom/Dockerfile diff --git a/core/jvm/test/testcontainers/original/Dockerfile b/core/jvm/test/testcontainers/default/Dockerfile similarity index 100% rename from core/jvm/test/testcontainers/original/Dockerfile rename to core/jvm/test/testcontainers/default/Dockerfile From 6d84895d2c4a450a236e962d46d041022a86f011 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Thu, 20 Mar 2025 12:34:22 +0400 Subject: [PATCH 18/82] #430: Test fail is execResult.exitCode != 0 --- .../TimeZoneConfigurationTest.kt | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt index 2954e8c4c..05061d4c8 100644 --- a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt @@ -23,28 +23,40 @@ class TimeZoneConfigurationTest { @Test fun testDefaultContainerTimeZoneTests() { - logExecResult(defaultTimeZoneContainer.runTimeZoneTests()) + assertExecSuccess(defaultTimeZoneContainer.runTimeZoneTests()) } @Test fun testCustomContainerTimeZoneTests() { - logExecResult(customTimeZoneContainer.runTimeZoneTests()) + assertExecSuccess(customTimeZoneContainer.runTimeZoneTests()) } @Test fun testDefaultContainerAllTests() { - logExecResult(defaultTimeZoneContainer.runAllTests()) + assertExecSuccess(defaultTimeZoneContainer.runAllTests()) } @Test fun testCustomContainerAllTests() { - logExecResult(customTimeZoneContainer.runAllTests()) + assertExecSuccess(customTimeZoneContainer.runAllTests()) } - private fun logExecResult(execResult: ExecResult) { + private fun assertExecSuccess(execResult: ExecResult) { logger.info("Container stdout:\n${execResult.stdout}") logger.info("Container stderr:\n${execResult.stderr}") logger.info("Container exit code: ${execResult.exitCode}") + + if (execResult.exitCode != 0) { + throw AssertionError( + """ + |Command execution failed with exit code ${execResult.exitCode}. + |Stdout: + |${execResult.stdout} + |Stderr: + |${execResult.stderr} + """.trimMargin() + ) + } } companion object { From 7d620bd6594c058df16f10bb8ff3924a07bc98aa Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Thu, 20 Mar 2025 12:37:07 +0400 Subject: [PATCH 19/82] #430: Removed unnecessary dependency junit-params --- core/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 0de0c7d6a..1d0b54736 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -227,7 +227,6 @@ kotlin { implementation("org.testcontainers:testcontainers:1.19.7") implementation("org.testcontainers:junit-jupiter:1.19.7") implementation("org.junit.jupiter:junit-jupiter-api:5.10.2") - implementation("org.junit.jupiter:junit-jupiter-params:5.10.2") runtimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.2") implementation("ch.qos.logback:logback-classic:1.2.13") } From 269db7f2f87f88e1705def1c099358bd2c25f52d Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Thu, 20 Mar 2025 14:53:29 +0400 Subject: [PATCH 20/82] #430: First working iteration --- core/linux/src/internal/TimeZoneNative.kt | 29 +++++++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/core/linux/src/internal/TimeZoneNative.kt b/core/linux/src/internal/TimeZoneNative.kt index 745023aa4..980ce5075 100644 --- a/core/linux/src/internal/TimeZoneNative.kt +++ b/core/linux/src/internal/TimeZoneNative.kt @@ -5,6 +5,8 @@ package kotlinx.datetime.internal +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.toKString import kotlinx.datetime.IllegalTimeZoneException import kotlinx.datetime.TimeZone @@ -16,10 +18,27 @@ internal actual fun getAvailableZoneIds(): Set = private val tzdb = runCatching { TzdbOnFilesystem() } +@OptIn(ExperimentalForeignApi::class) +private fun getTimezoneFromEtcTimezone(): String? { + val timezoneContent = Path.fromString("/etc/timezone").readBytes()?.toKString()?.trim() ?: return null + return chaseSymlinks("/usr/share/zoneinfo/$timezoneContent")?.splitTimeZonePath()?.second?.toString() +} + internal actual fun currentSystemDefaultZone(): Pair { - // according to https://www.man7.org/linux/man-pages/man5/localtime.5.html, when there is no symlink, UTC is used - val zonePath = currentSystemTimeZonePath ?: return "Z" to null - val zoneId = zonePath.splitTimeZonePath()?.second?.toString() - ?: throw IllegalTimeZoneException("Could not determine the timezone ID that `$zonePath` corresponds to") - return zoneId to null + val zonePath = currentSystemTimeZonePath + if (zonePath != null) { + var zoneId = zonePath.splitTimeZonePath()?.second?.toString() + if (zoneId != null) { + return zoneId to null + } else { + zoneId = getTimezoneFromEtcTimezone() + if (zoneId != null) { + return zoneId to null + } else { + throw IllegalTimeZoneException("Could not determine the timezone ID that `$zonePath` corresponds to") + } + } + } + + return "Z" to null } From acfc23563f227fa327402115b6e1c8287e4d74b6 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Thu, 20 Mar 2025 15:20:11 +0400 Subject: [PATCH 21/82] #430: Add file comparison + some refactoring --- core/linux/src/internal/TimeZoneNative.kt | 41 ++++++++++++++--------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/core/linux/src/internal/TimeZoneNative.kt b/core/linux/src/internal/TimeZoneNative.kt index 980ce5075..5acd59b1f 100644 --- a/core/linux/src/internal/TimeZoneNative.kt +++ b/core/linux/src/internal/TimeZoneNative.kt @@ -21,24 +21,33 @@ private val tzdb = runCatching { TzdbOnFilesystem() } @OptIn(ExperimentalForeignApi::class) private fun getTimezoneFromEtcTimezone(): String? { val timezoneContent = Path.fromString("/etc/timezone").readBytes()?.toKString()?.trim() ?: return null - return chaseSymlinks("/usr/share/zoneinfo/$timezoneContent")?.splitTimeZonePath()?.second?.toString() + val zoneId = chaseSymlinks("/usr/share/zoneinfo/$timezoneContent") + ?.splitTimeZonePath()?.second?.toString() + ?: return null + + val zoneInfoFile = Path.fromString("/usr/share/zoneinfo/$zoneId").readBytes() ?: return null + val etcLocaltime = Path.fromString("/etc/localtime").readBytes() ?: return null + + if (!etcLocaltime.contentEquals(zoneInfoFile)) { + throw IllegalTimeZoneException( + "Timezone mismatch: /etc/timezone specifies " + + "'${if (timezoneContent != zoneId) timezoneContent else zoneId}' " + + "but /etc/localtime content differs from /usr/share/zoneinfo/$zoneId" + ) + } + + return zoneId } internal actual fun currentSystemDefaultZone(): Pair { - val zonePath = currentSystemTimeZonePath - if (zonePath != null) { - var zoneId = zonePath.splitTimeZonePath()?.second?.toString() - if (zoneId != null) { - return zoneId to null - } else { - zoneId = getTimezoneFromEtcTimezone() - if (zoneId != null) { - return zoneId to null - } else { - throw IllegalTimeZoneException("Could not determine the timezone ID that `$zonePath` corresponds to") - } - } + val zonePath = currentSystemTimeZonePath ?: return "Z" to null + zonePath.splitTimeZonePath()?.second?.toString()?.let { zoneId -> + return zoneId to null } - return "Z" to null -} + getTimezoneFromEtcTimezone()?.let { zoneId -> + return zoneId to null + } + + throw IllegalTimeZoneException("Could not determine the timezone ID that `$zonePath` corresponds to") +} \ No newline at end of file From c52b60a618e543ae9dc02a06ba80b372e0a37f0b Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Thu, 20 Mar 2025 15:44:54 +0400 Subject: [PATCH 22/82] #430: Minor refactoring --- core/linux/src/internal/TimeZoneNative.kt | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/core/linux/src/internal/TimeZoneNative.kt b/core/linux/src/internal/TimeZoneNative.kt index 5acd59b1f..df5669b29 100644 --- a/core/linux/src/internal/TimeZoneNative.kt +++ b/core/linux/src/internal/TimeZoneNative.kt @@ -25,13 +25,16 @@ private fun getTimezoneFromEtcTimezone(): String? { ?.splitTimeZonePath()?.second?.toString() ?: return null - val zoneInfoFile = Path.fromString("/usr/share/zoneinfo/$zoneId").readBytes() ?: return null - val etcLocaltime = Path.fromString("/etc/localtime").readBytes() ?: return null - - if (!etcLocaltime.contentEquals(zoneInfoFile)) { + val zoneInfoBytes = Path.fromString("/usr/share/zoneinfo/$zoneId").readBytes() ?: return null + val localtimeBytes = Path.fromString("/etc/localtime").readBytes() ?: return null + + if (!localtimeBytes.contentEquals(zoneInfoBytes)) { + val displayTimezone = when (timezoneContent) { + zoneId -> "'$zoneId'" + else -> "'$timezoneContent' (resolved to '$zoneId')" + } throw IllegalTimeZoneException( - "Timezone mismatch: /etc/timezone specifies " + - "'${if (timezoneContent != zoneId) timezoneContent else zoneId}' " + + "Timezone mismatch: /etc/timezone specifies $displayTimezone " + "but /etc/localtime content differs from /usr/share/zoneinfo/$zoneId" ) } @@ -41,6 +44,7 @@ private fun getTimezoneFromEtcTimezone(): String? { internal actual fun currentSystemDefaultZone(): Pair { val zonePath = currentSystemTimeZonePath ?: return "Z" to null + zonePath.splitTimeZonePath()?.second?.toString()?.let { zoneId -> return zoneId to null } From e36db1b44a5fae99fbc5b234d1eee08de3cc5ef6 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Thu, 20 Mar 2025 17:27:16 +0400 Subject: [PATCH 23/82] #430: Add 3 tests --- .../TimeZoneConfigurationTest.kt | 19 +++++------- .../testcontainers/TimezoneTestContainer.kt | 31 +++++++++++-------- core/linux/test/TimeZoneLinuxNativeTest.kt | 30 +++++++++++++++++- 3 files changed, 54 insertions(+), 26 deletions(-) diff --git a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt index 05061d4c8..0a57ff37e 100644 --- a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt @@ -16,29 +16,24 @@ import org.testcontainers.containers.Container.ExecResult class TimeZoneConfigurationTest { @Container - private val defaultTimeZoneContainer = createTimezoneTestContainer("default") + private val timeZoneContainer = createTimezoneTestContainer("default") @Container private val customTimeZoneContainer = createTimezoneTestContainer("custom") @Test - fun testDefaultContainerTimeZoneTests() { - assertExecSuccess(defaultTimeZoneContainer.runTimeZoneTests()) + fun debianCopyTimeZoneTest() { + assertExecSuccess(timeZoneContainer.runDebianCopyTimeZoneTest()) } @Test - fun testCustomContainerTimeZoneTests() { - assertExecSuccess(customTimeZoneContainer.runTimeZoneTests()) + fun timezoneMismatchTest() { + assertExecSuccess(timeZoneContainer.runTimezoneMismatchTest()) } @Test - fun testDefaultContainerAllTests() { - assertExecSuccess(defaultTimeZoneContainer.runAllTests()) - } - - @Test - fun testCustomContainerAllTests() { - assertExecSuccess(customTimeZoneContainer.runAllTests()) + fun missingEtcTimezoneTest() { + assertExecSuccess(timeZoneContainer.runMissingEtcTimezoneTest()) } private fun assertExecSuccess(execResult: ExecResult) { diff --git a/core/jvm/test/testcontainers/TimezoneTestContainer.kt b/core/jvm/test/testcontainers/TimezoneTestContainer.kt index a1dbeb4b9..a8babbf96 100644 --- a/core/jvm/test/testcontainers/TimezoneTestContainer.kt +++ b/core/jvm/test/testcontainers/TimezoneTestContainer.kt @@ -20,25 +20,30 @@ class TimezoneTestContainer(dockerfilePath: Path, binaryDir: String, imageName: withFileSystemBind(binaryDir, "/app", BindMode.READ_WRITE) } - fun runTimeZoneTests(): ExecResult { - return executeTest("--ktest_filter=kotlinx.datetime.test.TimeZoneLinuxNativeTest.*") + fun runDebianCopyTimeZoneTest(): ExecResult { + exec("rm /etc/localtime") + exec("cp /usr/share/zoneinfo/Europe/Berlin /etc/localtime") + exec("echo 'Europe/Berlin' > /etc/timezone") + return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.debianCopyTimeZoneTest") } - fun runAllTests(): ExecResult { - return executeTest() + fun runTimezoneMismatchTest(): ExecResult { + exec("rm -f /etc/localtime") + exec("cp /usr/share/zoneinfo/Europe/Berlin /etc/localtime") + exec("echo 'Europe/Paris' > /etc/timezone") + return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.timezoneMismatchTest") } - private fun executeTest(testFilter: String? = null): ExecResult { - val command = buildString { - append("chmod +x /app/test.kexe && /app/test.kexe") - testFilter?.also { - append(" ") - append(it) - } - } + fun runMissingEtcTimezoneTest(): ExecResult { + exec("rm -f /etc/timezone") + return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.missingEtcTimezoneTest") + } - return execInContainer("bash", "-c", command) + private fun execTest(testFilter: String): ExecResult { + return exec("chmod +x /app/test.kexe && /app/test.kexe --ktest_filter=$testFilter") } + + private fun exec(command: String): ExecResult = execInContainer("bash", "-c", command) } fun createTimezoneTestContainer(configType: String): TimezoneTestContainer { diff --git a/core/linux/test/TimeZoneLinuxNativeTest.kt b/core/linux/test/TimeZoneLinuxNativeTest.kt index 90ab900d4..f3a2ed7c3 100644 --- a/core/linux/test/TimeZoneLinuxNativeTest.kt +++ b/core/linux/test/TimeZoneLinuxNativeTest.kt @@ -13,7 +13,35 @@ class TimeZoneLinuxNativeTest { @Test fun defaultTimeZoneTest() = Testcontainers.runIfAvailable { val tz = TimeZone.currentSystemDefault() - println("TIMEZONE: $tz") + assertEquals(TimeZone.of("Europe/Oslo"), tz) + } + + /** + * Tests Debian behavior where /etc/localtime is a copy instead of a symlink + * but /etc/timezone contains the correct timezone identifier + */ + @Test + fun debianCopyTimeZoneTest() = Testcontainers.runIfAvailable { + val tz = TimeZone.currentSystemDefault() + assertEquals(TimeZone.of("Europe/Berlin"), tz) + } + + /** + * Tests behavior when /etc/localtime and /etc/timezone mismatch + */ + @Test + fun timezoneMismatchTest() = Testcontainers.runIfAvailable { + assertFailsWith { + TimeZone.currentSystemDefault() + } + } + + /** + * Tests UTC fallback when /etc/timezone is missing + */ + @Test + fun missingEtcTimezoneTest() = Testcontainers.runIfAvailable { + val tz = TimeZone.currentSystemDefault() assertEquals(TimeZone.of("Europe/Oslo"), tz) } } \ No newline at end of file From ddb105dbc1d2b7846b09de4c3a5d2d90d174bb14 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Thu, 20 Mar 2025 17:36:49 +0400 Subject: [PATCH 24/82] #430: Refactoring --- .../testcontainers/{default => }/Dockerfile | 0 .../TimeZoneConfigurationTest.kt | 14 +++++++----- .../testcontainers/TimezoneTestContainer.kt | 22 +++++++++++-------- .../jvm/test/testcontainers/custom/Dockerfile | 14 ------------ core/linux/test/TimeZoneLinuxNativeTest.kt | 4 ++++ 5 files changed, 25 insertions(+), 29 deletions(-) rename core/jvm/test/testcontainers/{default => }/Dockerfile (100%) delete mode 100644 core/jvm/test/testcontainers/custom/Dockerfile diff --git a/core/jvm/test/testcontainers/default/Dockerfile b/core/jvm/test/testcontainers/Dockerfile similarity index 100% rename from core/jvm/test/testcontainers/default/Dockerfile rename to core/jvm/test/testcontainers/Dockerfile diff --git a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt index 0a57ff37e..db8b8f82d 100644 --- a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt @@ -16,24 +16,26 @@ import org.testcontainers.containers.Container.ExecResult class TimeZoneConfigurationTest { @Container - private val timeZoneContainer = createTimezoneTestContainer("default") + private val container = createTimezoneTestContainer() - @Container - private val customTimeZoneContainer = createTimezoneTestContainer("custom") + @Test + fun defaultTimeZoneTest() { + assertExecSuccess(container.execDefaultTimeZoneTest()) + } @Test fun debianCopyTimeZoneTest() { - assertExecSuccess(timeZoneContainer.runDebianCopyTimeZoneTest()) + assertExecSuccess(container.execDebianCopyTimeZoneTest()) } @Test fun timezoneMismatchTest() { - assertExecSuccess(timeZoneContainer.runTimezoneMismatchTest()) + assertExecSuccess(container.execTimezoneMismatchTest()) } @Test fun missingEtcTimezoneTest() { - assertExecSuccess(timeZoneContainer.runMissingEtcTimezoneTest()) + assertExecSuccess(container.execMissingEtcTimezoneTest()) } private fun assertExecSuccess(execResult: ExecResult) { diff --git a/core/jvm/test/testcontainers/TimezoneTestContainer.kt b/core/jvm/test/testcontainers/TimezoneTestContainer.kt index a8babbf96..419cabe0a 100644 --- a/core/jvm/test/testcontainers/TimezoneTestContainer.kt +++ b/core/jvm/test/testcontainers/TimezoneTestContainer.kt @@ -20,36 +20,40 @@ class TimezoneTestContainer(dockerfilePath: Path, binaryDir: String, imageName: withFileSystemBind(binaryDir, "/app", BindMode.READ_WRITE) } - fun runDebianCopyTimeZoneTest(): ExecResult { + fun execDefaultTimeZoneTest(): ExecResult { + return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.defaultTimeZoneTest") + } + + fun execDebianCopyTimeZoneTest(): ExecResult { exec("rm /etc/localtime") exec("cp /usr/share/zoneinfo/Europe/Berlin /etc/localtime") exec("echo 'Europe/Berlin' > /etc/timezone") return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.debianCopyTimeZoneTest") } - fun runTimezoneMismatchTest(): ExecResult { + fun execTimezoneMismatchTest(): ExecResult { exec("rm -f /etc/localtime") exec("cp /usr/share/zoneinfo/Europe/Berlin /etc/localtime") exec("echo 'Europe/Paris' > /etc/timezone") return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.timezoneMismatchTest") } - fun runMissingEtcTimezoneTest(): ExecResult { + fun execMissingEtcTimezoneTest(): ExecResult { exec("rm -f /etc/timezone") return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.missingEtcTimezoneTest") } - private fun execTest(testFilter: String): ExecResult { - return exec("chmod +x /app/test.kexe && /app/test.kexe --ktest_filter=$testFilter") - } + private fun execTest(testFilter: String): ExecResult = + exec("chmod +x /app/test.kexe && /app/test.kexe --ktest_filter=$testFilter") + private fun exec(command: String): ExecResult = execInContainer("bash", "-c", command) } -fun createTimezoneTestContainer(configType: String): TimezoneTestContainer { +fun createTimezoneTestContainer(): TimezoneTestContainer { return TimezoneTestContainer( - Paths.get("./jvm/test/testcontainers/$configType/Dockerfile"), + Paths.get("./jvm/test/testcontainers/Dockerfile"), "./build/bin/linuxArm64/debugTest/", - "ubuntu-arctic-longyearbyen-$configType" + "ubuntu-arctic-longyearbyen" ) } \ No newline at end of file diff --git a/core/jvm/test/testcontainers/custom/Dockerfile b/core/jvm/test/testcontainers/custom/Dockerfile deleted file mode 100644 index 6594e4c1c..000000000 --- a/core/jvm/test/testcontainers/custom/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM --platform=linux/arm64 ubuntu:24.04 - -RUN apt-get update && apt-get install -y tzdata - -ENV INSIDE_TESTCONTAINERS=true - -# 4: Arctic/Longyearbyen -RUN echo 4 | dpkg-reconfigure tzdata - -# Modification like in Debian Jessie -RUN rm /etc/localtime -RUN cp /usr/share/zoneinfo/$(cat /etc/timezone) /etc/localtime - -WORKDIR /app \ No newline at end of file diff --git a/core/linux/test/TimeZoneLinuxNativeTest.kt b/core/linux/test/TimeZoneLinuxNativeTest.kt index f3a2ed7c3..ddb329af5 100644 --- a/core/linux/test/TimeZoneLinuxNativeTest.kt +++ b/core/linux/test/TimeZoneLinuxNativeTest.kt @@ -10,6 +10,10 @@ import kotlin.test.* class TimeZoneLinuxNativeTest { + /** + * Verifies that the default system time zone is recognized correctly + * and matches the expected value. + */ @Test fun defaultTimeZoneTest() = Testcontainers.runIfAvailable { val tz = TimeZone.currentSystemDefault() From 733158dbbaa9df3e05713999cc492b73f5ec8563 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Thu, 20 Mar 2025 17:47:32 +0400 Subject: [PATCH 25/82] #430: Add allTimeZoneFilesMissingTest test, fails because of Expected , actual --- .../jvm/test/testcontainers/TimeZoneConfigurationTest.kt | 5 +++++ core/jvm/test/testcontainers/TimezoneTestContainer.kt | 6 ++++++ core/linux/test/TimeZoneLinuxNativeTest.kt | 9 +++++++++ 3 files changed, 20 insertions(+) diff --git a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt index db8b8f82d..62f0e8af0 100644 --- a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt @@ -38,6 +38,11 @@ class TimeZoneConfigurationTest { assertExecSuccess(container.execMissingEtcTimezoneTest()) } + @Test + fun allTimeZoneFilesMissingTest() { + assertExecSuccess(container.execAllTimeZoneFilesMissingTest()) + } + private fun assertExecSuccess(execResult: ExecResult) { logger.info("Container stdout:\n${execResult.stdout}") logger.info("Container stderr:\n${execResult.stderr}") diff --git a/core/jvm/test/testcontainers/TimezoneTestContainer.kt b/core/jvm/test/testcontainers/TimezoneTestContainer.kt index 419cabe0a..11244656b 100644 --- a/core/jvm/test/testcontainers/TimezoneTestContainer.kt +++ b/core/jvm/test/testcontainers/TimezoneTestContainer.kt @@ -43,6 +43,12 @@ class TimezoneTestContainer(dockerfilePath: Path, binaryDir: String, imageName: return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.missingEtcTimezoneTest") } + fun execAllTimeZoneFilesMissingTest(): ExecResult { + exec("rm -f /etc/localtime") + exec("rm -f /etc/timezone") + return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.allTimeZoneFilesMissingTest") + } + private fun execTest(testFilter: String): ExecResult = exec("chmod +x /app/test.kexe && /app/test.kexe --ktest_filter=$testFilter") diff --git a/core/linux/test/TimeZoneLinuxNativeTest.kt b/core/linux/test/TimeZoneLinuxNativeTest.kt index ddb329af5..59ee29511 100644 --- a/core/linux/test/TimeZoneLinuxNativeTest.kt +++ b/core/linux/test/TimeZoneLinuxNativeTest.kt @@ -48,4 +48,13 @@ class TimeZoneLinuxNativeTest { val tz = TimeZone.currentSystemDefault() assertEquals(TimeZone.of("Europe/Oslo"), tz) } + + /** + * Tests UTC fallback when all timezone files are missing + */ + @Test + fun allTimeZoneFilesMissingTest() = Testcontainers.runIfAvailable { + val tz = TimeZone.currentSystemDefault() + assertEquals(TimeZone.of("UTC"), tz) + } } \ No newline at end of file From a156cad534d8dec2f3006ff74cb5782eae3e6359 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Thu, 20 Mar 2025 18:00:17 +0400 Subject: [PATCH 26/82] #430: Add symlinkTimeZoneTest --- .../jvm/test/testcontainers/TimeZoneConfigurationTest.kt | 5 +++++ core/jvm/test/testcontainers/TimezoneTestContainer.kt | 8 +++++++- core/linux/test/TimeZoneLinuxNativeTest.kt | 9 +++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt index 62f0e8af0..f108e5243 100644 --- a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt @@ -43,6 +43,11 @@ class TimeZoneConfigurationTest { assertExecSuccess(container.execAllTimeZoneFilesMissingTest()) } + @Test + fun symlinkTimeZoneTest() { + assertExecSuccess(container.execSymlinkTimeZoneTest()) + } + private fun assertExecSuccess(execResult: ExecResult) { logger.info("Container stdout:\n${execResult.stdout}") logger.info("Container stderr:\n${execResult.stderr}") diff --git a/core/jvm/test/testcontainers/TimezoneTestContainer.kt b/core/jvm/test/testcontainers/TimezoneTestContainer.kt index 11244656b..4139f29a7 100644 --- a/core/jvm/test/testcontainers/TimezoneTestContainer.kt +++ b/core/jvm/test/testcontainers/TimezoneTestContainer.kt @@ -49,10 +49,16 @@ class TimezoneTestContainer(dockerfilePath: Path, binaryDir: String, imageName: return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.allTimeZoneFilesMissingTest") } + fun execSymlinkTimeZoneTest(): ExecResult { + exec("rm -f /etc/localtime") + exec("ln -sf /usr/share/zoneinfo/Europe/Paris /etc/localtime") + exec("echo 'Europe/Paris' > /etc/timezone") + return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.symlinkTimeZoneTest") + } + private fun execTest(testFilter: String): ExecResult = exec("chmod +x /app/test.kexe && /app/test.kexe --ktest_filter=$testFilter") - private fun exec(command: String): ExecResult = execInContainer("bash", "-c", command) } diff --git a/core/linux/test/TimeZoneLinuxNativeTest.kt b/core/linux/test/TimeZoneLinuxNativeTest.kt index 59ee29511..4cbb9a1ce 100644 --- a/core/linux/test/TimeZoneLinuxNativeTest.kt +++ b/core/linux/test/TimeZoneLinuxNativeTest.kt @@ -57,4 +57,13 @@ class TimeZoneLinuxNativeTest { val tz = TimeZone.currentSystemDefault() assertEquals(TimeZone.of("UTC"), tz) } + + /** + * Verifies behavior when /etc/localtime is a symlink to the correct timezone file. + */ + @Test + fun symlinkTimeZoneTest() = Testcontainers.runIfAvailable { + val tz = TimeZone.currentSystemDefault() + assertEquals(TimeZone.of("Europe/Paris"), tz) + } } \ No newline at end of file From efc67b81cfd9cb7228f3fc5b9849beac2b9e0ace Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Thu, 20 Mar 2025 18:04:21 +0400 Subject: [PATCH 27/82] #430: Add invalidTimezoneFormatTest --- .../test/testcontainers/TimeZoneConfigurationTest.kt | 5 +++++ core/jvm/test/testcontainers/TimezoneTestContainer.kt | 7 +++++++ core/linux/test/TimeZoneLinuxNativeTest.kt | 10 ++++++++++ 3 files changed, 22 insertions(+) diff --git a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt index f108e5243..e7948d7d8 100644 --- a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt @@ -48,6 +48,11 @@ class TimeZoneConfigurationTest { assertExecSuccess(container.execSymlinkTimeZoneTest()) } + @Test + fun invalidTimezoneFormatTest() { + assertExecSuccess(container.execInvalidTimezoneFormatTest()) + } + private fun assertExecSuccess(execResult: ExecResult) { logger.info("Container stdout:\n${execResult.stdout}") logger.info("Container stderr:\n${execResult.stderr}") diff --git a/core/jvm/test/testcontainers/TimezoneTestContainer.kt b/core/jvm/test/testcontainers/TimezoneTestContainer.kt index 4139f29a7..4c44841c5 100644 --- a/core/jvm/test/testcontainers/TimezoneTestContainer.kt +++ b/core/jvm/test/testcontainers/TimezoneTestContainer.kt @@ -56,6 +56,13 @@ class TimezoneTestContainer(dockerfilePath: Path, binaryDir: String, imageName: return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.symlinkTimeZoneTest") } + fun execInvalidTimezoneFormatTest(): ExecResult { + exec("rm -f /etc/localtime") + exec("cp /usr/share/zoneinfo/Europe/Berlin /etc/localtime") + exec("echo 'Invalid/Timezone/Format' > /etc/timezone") + return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.invalidTimezoneFormatTest") + } + private fun execTest(testFilter: String): ExecResult = exec("chmod +x /app/test.kexe && /app/test.kexe --ktest_filter=$testFilter") diff --git a/core/linux/test/TimeZoneLinuxNativeTest.kt b/core/linux/test/TimeZoneLinuxNativeTest.kt index 4cbb9a1ce..ccce47638 100644 --- a/core/linux/test/TimeZoneLinuxNativeTest.kt +++ b/core/linux/test/TimeZoneLinuxNativeTest.kt @@ -66,4 +66,14 @@ class TimeZoneLinuxNativeTest { val tz = TimeZone.currentSystemDefault() assertEquals(TimeZone.of("Europe/Paris"), tz) } + + /** + * Tests that an invalid timezone format triggers an `IllegalTimeZoneException`. + */ + @Test + fun invalidTimezoneFormatTest() = Testcontainers.runIfAvailable { + assertFailsWith { + TimeZone.currentSystemDefault() + } + } } \ No newline at end of file From 59023990f2f5483956b61939851b0049ef7528e0 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Thu, 20 Mar 2025 18:11:04 +0400 Subject: [PATCH 28/82] #430: Add commonTimeZoneTests --- core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt | 5 +++++ core/jvm/test/testcontainers/TimezoneTestContainer.kt | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt index e7948d7d8..aa66ea7a1 100644 --- a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt @@ -53,6 +53,11 @@ class TimeZoneConfigurationTest { assertExecSuccess(container.execInvalidTimezoneFormatTest()) } + @Test + fun commonTimeZoneTests() { + assertExecSuccess(container.execCommonTimeZoneTests()) + } + private fun assertExecSuccess(execResult: ExecResult) { logger.info("Container stdout:\n${execResult.stdout}") logger.info("Container stderr:\n${execResult.stderr}") diff --git a/core/jvm/test/testcontainers/TimezoneTestContainer.kt b/core/jvm/test/testcontainers/TimezoneTestContainer.kt index 4c44841c5..28ac8781e 100644 --- a/core/jvm/test/testcontainers/TimezoneTestContainer.kt +++ b/core/jvm/test/testcontainers/TimezoneTestContainer.kt @@ -63,6 +63,12 @@ class TimezoneTestContainer(dockerfilePath: Path, binaryDir: String, imageName: return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.invalidTimezoneFormatTest") } + fun execCommonTimeZoneTests(): ExecResult { + exec("rm -f /etc/localtime") + exec("cp /usr/share/zoneinfo/$(cat /etc/timezone) /etc/localtime") + return execTest("kotlinx.datetime.test.TimeZoneTest.*") + } + private fun execTest(testFilter: String): ExecResult = exec("chmod +x /app/test.kexe && /app/test.kexe --ktest_filter=$testFilter") From 325f92b25346159934acf5498301781f5f622b4c Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Thu, 20 Mar 2025 18:20:19 +0400 Subject: [PATCH 29/82] #430: Change Z to UTC in currentSystemDefaultZone() --- core/linux/src/internal/TimeZoneNative.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/linux/src/internal/TimeZoneNative.kt b/core/linux/src/internal/TimeZoneNative.kt index df5669b29..64c51e9ac 100644 --- a/core/linux/src/internal/TimeZoneNative.kt +++ b/core/linux/src/internal/TimeZoneNative.kt @@ -43,7 +43,7 @@ private fun getTimezoneFromEtcTimezone(): String? { } internal actual fun currentSystemDefaultZone(): Pair { - val zonePath = currentSystemTimeZonePath ?: return "Z" to null + val zonePath = currentSystemTimeZonePath ?: return "UTC" to null zonePath.splitTimeZonePath()?.second?.toString()?.let { zoneId -> return zoneId to null From 03e03c762402ec9c81bc9954e021b506c59c97d1 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Fri, 21 Mar 2025 14:28:19 +0400 Subject: [PATCH 30/82] #430: UTC -> Z --- core/linux/src/internal/TimeZoneNative.kt | 2 +- core/linux/test/TimeZoneLinuxNativeTest.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/linux/src/internal/TimeZoneNative.kt b/core/linux/src/internal/TimeZoneNative.kt index 64c51e9ac..df5669b29 100644 --- a/core/linux/src/internal/TimeZoneNative.kt +++ b/core/linux/src/internal/TimeZoneNative.kt @@ -43,7 +43,7 @@ private fun getTimezoneFromEtcTimezone(): String? { } internal actual fun currentSystemDefaultZone(): Pair { - val zonePath = currentSystemTimeZonePath ?: return "UTC" to null + val zonePath = currentSystemTimeZonePath ?: return "Z" to null zonePath.splitTimeZonePath()?.second?.toString()?.let { zoneId -> return zoneId to null diff --git a/core/linux/test/TimeZoneLinuxNativeTest.kt b/core/linux/test/TimeZoneLinuxNativeTest.kt index ccce47638..55882b8a4 100644 --- a/core/linux/test/TimeZoneLinuxNativeTest.kt +++ b/core/linux/test/TimeZoneLinuxNativeTest.kt @@ -55,7 +55,7 @@ class TimeZoneLinuxNativeTest { @Test fun allTimeZoneFilesMissingTest() = Testcontainers.runIfAvailable { val tz = TimeZone.currentSystemDefault() - assertEquals(TimeZone.of("UTC"), tz) + assertEquals(TimeZone.UTC, tz) } /** From 9f8aac8aa1b994cbea9c3d3918002518d4ba4e8d Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Fri, 21 Mar 2025 17:04:25 +0400 Subject: [PATCH 31/82] #430: Add 2 new Dockerfile for Debian Jessie and Ubuntu 24.04 --- core/jvm/test/testcontainers/debian-jessie/Dockerfile | 6 ++++++ core/jvm/test/testcontainers/ubuntu-noble/Dockerfile | 8 ++++++++ 2 files changed, 14 insertions(+) create mode 100644 core/jvm/test/testcontainers/debian-jessie/Dockerfile create mode 100644 core/jvm/test/testcontainers/ubuntu-noble/Dockerfile diff --git a/core/jvm/test/testcontainers/debian-jessie/Dockerfile b/core/jvm/test/testcontainers/debian-jessie/Dockerfile new file mode 100644 index 000000000..00c852940 --- /dev/null +++ b/core/jvm/test/testcontainers/debian-jessie/Dockerfile @@ -0,0 +1,6 @@ +FROM --platform=linux/arm64 debian/eol:jessie + +# 5: Arctic/Longyearbyen +RUN echo 5 | dpkg-reconfigure tzdata + +WORKDIR /app \ No newline at end of file diff --git a/core/jvm/test/testcontainers/ubuntu-noble/Dockerfile b/core/jvm/test/testcontainers/ubuntu-noble/Dockerfile new file mode 100644 index 000000000..94b2b3787 --- /dev/null +++ b/core/jvm/test/testcontainers/ubuntu-noble/Dockerfile @@ -0,0 +1,8 @@ +FROM --platform=linux/amd64 ubuntu:24.04 + +RUN apt-get update && apt-get install -y tzdata + +# 4: Arctic/Longyearbyen +RUN echo 4 | dpkg-reconfigure tzdata + +WORKDIR /app \ No newline at end of file From 0697ae8d6cc3e9e5ea022bdd5fdc604affc4b045 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Fri, 21 Mar 2025 17:15:23 +0400 Subject: [PATCH 32/82] #430: Fix platform for ubuntu --- core/jvm/test/testcontainers/ubuntu-noble/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/jvm/test/testcontainers/ubuntu-noble/Dockerfile b/core/jvm/test/testcontainers/ubuntu-noble/Dockerfile index 94b2b3787..bc4af2eb9 100644 --- a/core/jvm/test/testcontainers/ubuntu-noble/Dockerfile +++ b/core/jvm/test/testcontainers/ubuntu-noble/Dockerfile @@ -1,4 +1,4 @@ -FROM --platform=linux/amd64 ubuntu:24.04 +FROM --platform=linux/arm64 ubuntu:24.04 RUN apt-get update && apt-get install -y tzdata From dfdcb2a616fec525c87648d63209193c261c3a48 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Fri, 21 Mar 2025 18:02:39 +0400 Subject: [PATCH 33/82] #430: Remove some tests, run 2 tests on Debian Jessie --- core/jvm/test/testcontainers/Dockerfile | 10 --- .../TimeZoneConfigurationTest.kt | 32 +--------- .../testcontainers/TimezoneTestContainer.kt | 62 ++++--------------- core/linux/test/TimeZoneLinuxNativeTest.kt | 57 ----------------- 4 files changed, 13 insertions(+), 148 deletions(-) delete mode 100644 core/jvm/test/testcontainers/Dockerfile diff --git a/core/jvm/test/testcontainers/Dockerfile b/core/jvm/test/testcontainers/Dockerfile deleted file mode 100644 index df5b0e83e..000000000 --- a/core/jvm/test/testcontainers/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM --platform=linux/arm64 ubuntu:24.04 - -RUN apt-get update && apt-get install -y tzdata - -ENV INSIDE_TESTCONTAINERS=true - -# 4: Arctic/Longyearbyen -RUN echo 4 | dpkg-reconfigure tzdata - -WORKDIR /app \ No newline at end of file diff --git a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt index aa66ea7a1..53f437e32 100644 --- a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt @@ -16,43 +16,13 @@ import org.testcontainers.containers.Container.ExecResult class TimeZoneConfigurationTest { @Container - private val container = createTimezoneTestContainer() + private val container = createTimezoneTestContainer(ContainerType.DEBIAN_JESSIE) @Test fun defaultTimeZoneTest() { assertExecSuccess(container.execDefaultTimeZoneTest()) } - @Test - fun debianCopyTimeZoneTest() { - assertExecSuccess(container.execDebianCopyTimeZoneTest()) - } - - @Test - fun timezoneMismatchTest() { - assertExecSuccess(container.execTimezoneMismatchTest()) - } - - @Test - fun missingEtcTimezoneTest() { - assertExecSuccess(container.execMissingEtcTimezoneTest()) - } - - @Test - fun allTimeZoneFilesMissingTest() { - assertExecSuccess(container.execAllTimeZoneFilesMissingTest()) - } - - @Test - fun symlinkTimeZoneTest() { - assertExecSuccess(container.execSymlinkTimeZoneTest()) - } - - @Test - fun invalidTimezoneFormatTest() { - assertExecSuccess(container.execInvalidTimezoneFormatTest()) - } - @Test fun commonTimeZoneTests() { assertExecSuccess(container.execCommonTimeZoneTests()) diff --git a/core/jvm/test/testcontainers/TimezoneTestContainer.kt b/core/jvm/test/testcontainers/TimezoneTestContainer.kt index 28ac8781e..7220ac64c 100644 --- a/core/jvm/test/testcontainers/TimezoneTestContainer.kt +++ b/core/jvm/test/testcontainers/TimezoneTestContainer.kt @@ -9,11 +9,18 @@ import org.testcontainers.containers.BindMode import org.testcontainers.containers.Container.ExecResult import org.testcontainers.containers.GenericContainer import org.testcontainers.images.builder.ImageFromDockerfile -import java.nio.file.Path import java.nio.file.Paths -class TimezoneTestContainer(dockerfilePath: Path, binaryDir: String, imageName: String) : - GenericContainer(ImageFromDockerfile(imageName).withDockerfile(dockerfilePath)) { +enum class ContainerType(val dockerfilePath: String, val imageName: String) { + DEBIAN_JESSIE("./jvm/test/testcontainers/debian-jessie/Dockerfile", "debian-jessie-timezone-test"), + UBUNTU_NOBLE("./jvm/test/testcontainers/ubuntu-noble/Dockerfile", "ubuntu-noble-timezone-test") +} + +class TimezoneTestContainer(containerType: ContainerType, binaryDir: String) : + GenericContainer( + ImageFromDockerfile(containerType.imageName) + .withDockerfile(Paths.get(containerType.dockerfilePath)) + ) { init { withCommand("tail -f /dev/null") @@ -24,48 +31,7 @@ class TimezoneTestContainer(dockerfilePath: Path, binaryDir: String, imageName: return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.defaultTimeZoneTest") } - fun execDebianCopyTimeZoneTest(): ExecResult { - exec("rm /etc/localtime") - exec("cp /usr/share/zoneinfo/Europe/Berlin /etc/localtime") - exec("echo 'Europe/Berlin' > /etc/timezone") - return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.debianCopyTimeZoneTest") - } - - fun execTimezoneMismatchTest(): ExecResult { - exec("rm -f /etc/localtime") - exec("cp /usr/share/zoneinfo/Europe/Berlin /etc/localtime") - exec("echo 'Europe/Paris' > /etc/timezone") - return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.timezoneMismatchTest") - } - - fun execMissingEtcTimezoneTest(): ExecResult { - exec("rm -f /etc/timezone") - return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.missingEtcTimezoneTest") - } - - fun execAllTimeZoneFilesMissingTest(): ExecResult { - exec("rm -f /etc/localtime") - exec("rm -f /etc/timezone") - return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.allTimeZoneFilesMissingTest") - } - - fun execSymlinkTimeZoneTest(): ExecResult { - exec("rm -f /etc/localtime") - exec("ln -sf /usr/share/zoneinfo/Europe/Paris /etc/localtime") - exec("echo 'Europe/Paris' > /etc/timezone") - return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.symlinkTimeZoneTest") - } - - fun execInvalidTimezoneFormatTest(): ExecResult { - exec("rm -f /etc/localtime") - exec("cp /usr/share/zoneinfo/Europe/Berlin /etc/localtime") - exec("echo 'Invalid/Timezone/Format' > /etc/timezone") - return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.invalidTimezoneFormatTest") - } - fun execCommonTimeZoneTests(): ExecResult { - exec("rm -f /etc/localtime") - exec("cp /usr/share/zoneinfo/$(cat /etc/timezone) /etc/localtime") return execTest("kotlinx.datetime.test.TimeZoneTest.*") } @@ -75,10 +41,6 @@ class TimezoneTestContainer(dockerfilePath: Path, binaryDir: String, imageName: private fun exec(command: String): ExecResult = execInContainer("bash", "-c", command) } -fun createTimezoneTestContainer(): TimezoneTestContainer { - return TimezoneTestContainer( - Paths.get("./jvm/test/testcontainers/Dockerfile"), - "./build/bin/linuxArm64/debugTest/", - "ubuntu-arctic-longyearbyen" - ) +fun createTimezoneTestContainer(containerType: ContainerType): TimezoneTestContainer { + return TimezoneTestContainer(containerType, "./build/bin/linuxArm64/debugTest/") } \ No newline at end of file diff --git a/core/linux/test/TimeZoneLinuxNativeTest.kt b/core/linux/test/TimeZoneLinuxNativeTest.kt index 55882b8a4..f92aa70ed 100644 --- a/core/linux/test/TimeZoneLinuxNativeTest.kt +++ b/core/linux/test/TimeZoneLinuxNativeTest.kt @@ -19,61 +19,4 @@ class TimeZoneLinuxNativeTest { val tz = TimeZone.currentSystemDefault() assertEquals(TimeZone.of("Europe/Oslo"), tz) } - - /** - * Tests Debian behavior where /etc/localtime is a copy instead of a symlink - * but /etc/timezone contains the correct timezone identifier - */ - @Test - fun debianCopyTimeZoneTest() = Testcontainers.runIfAvailable { - val tz = TimeZone.currentSystemDefault() - assertEquals(TimeZone.of("Europe/Berlin"), tz) - } - - /** - * Tests behavior when /etc/localtime and /etc/timezone mismatch - */ - @Test - fun timezoneMismatchTest() = Testcontainers.runIfAvailable { - assertFailsWith { - TimeZone.currentSystemDefault() - } - } - - /** - * Tests UTC fallback when /etc/timezone is missing - */ - @Test - fun missingEtcTimezoneTest() = Testcontainers.runIfAvailable { - val tz = TimeZone.currentSystemDefault() - assertEquals(TimeZone.of("Europe/Oslo"), tz) - } - - /** - * Tests UTC fallback when all timezone files are missing - */ - @Test - fun allTimeZoneFilesMissingTest() = Testcontainers.runIfAvailable { - val tz = TimeZone.currentSystemDefault() - assertEquals(TimeZone.UTC, tz) - } - - /** - * Verifies behavior when /etc/localtime is a symlink to the correct timezone file. - */ - @Test - fun symlinkTimeZoneTest() = Testcontainers.runIfAvailable { - val tz = TimeZone.currentSystemDefault() - assertEquals(TimeZone.of("Europe/Paris"), tz) - } - - /** - * Tests that an invalid timezone format triggers an `IllegalTimeZoneException`. - */ - @Test - fun invalidTimezoneFormatTest() = Testcontainers.runIfAvailable { - assertFailsWith { - TimeZone.currentSystemDefault() - } - } } \ No newline at end of file From bff21b1d9d19e7ce5827fbaf0f96c7d76ba63dac Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Fri, 21 Mar 2025 18:15:02 +0400 Subject: [PATCH 34/82] #430: Add INSIDE_TESTCONTAINERS env var to Dockerfiles --- core/jvm/test/testcontainers/debian-jessie/Dockerfile | 2 ++ core/jvm/test/testcontainers/ubuntu-noble/Dockerfile | 2 ++ 2 files changed, 4 insertions(+) diff --git a/core/jvm/test/testcontainers/debian-jessie/Dockerfile b/core/jvm/test/testcontainers/debian-jessie/Dockerfile index 00c852940..8d52ae86a 100644 --- a/core/jvm/test/testcontainers/debian-jessie/Dockerfile +++ b/core/jvm/test/testcontainers/debian-jessie/Dockerfile @@ -1,5 +1,7 @@ FROM --platform=linux/arm64 debian/eol:jessie +ENV INSIDE_TESTCONTAINERS=true + # 5: Arctic/Longyearbyen RUN echo 5 | dpkg-reconfigure tzdata diff --git a/core/jvm/test/testcontainers/ubuntu-noble/Dockerfile b/core/jvm/test/testcontainers/ubuntu-noble/Dockerfile index bc4af2eb9..7159de8bf 100644 --- a/core/jvm/test/testcontainers/ubuntu-noble/Dockerfile +++ b/core/jvm/test/testcontainers/ubuntu-noble/Dockerfile @@ -1,5 +1,7 @@ FROM --platform=linux/arm64 ubuntu:24.04 +ENV INSIDE_TESTCONTAINERS=true + RUN apt-get update && apt-get install -y tzdata # 4: Arctic/Longyearbyen From 6b15d793929c021a3fa85fa43df863c3bfdb4054 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Fri, 21 Mar 2025 18:23:43 +0400 Subject: [PATCH 35/82] #430: Fix defaultTimeZoneTest test --- core/linux/test/TimeZoneLinuxNativeTest.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/linux/test/TimeZoneLinuxNativeTest.kt b/core/linux/test/TimeZoneLinuxNativeTest.kt index f92aa70ed..467456984 100644 --- a/core/linux/test/TimeZoneLinuxNativeTest.kt +++ b/core/linux/test/TimeZoneLinuxNativeTest.kt @@ -17,6 +17,7 @@ class TimeZoneLinuxNativeTest { @Test fun defaultTimeZoneTest() = Testcontainers.runIfAvailable { val tz = TimeZone.currentSystemDefault() - assertEquals(TimeZone.of("Europe/Oslo"), tz) + println("Default timezone: $tz") + assertTrue(tz == TimeZone.of("Europe/Oslo") || tz == TimeZone.of("Arctic/Longyearbyen")) } } \ No newline at end of file From 0ee491f565bed6f5e4ca4d286b5c1b5a5e69a787 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Fri, 21 Mar 2025 18:31:30 +0400 Subject: [PATCH 36/82] #430: Run tests on both containers --- .../TimeZoneConfigurationTest.kt | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt index 53f437e32..bc46ad833 100644 --- a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt @@ -16,16 +16,29 @@ import org.testcontainers.containers.Container.ExecResult class TimeZoneConfigurationTest { @Container - private val container = createTimezoneTestContainer(ContainerType.DEBIAN_JESSIE) + private val jessieContainer = createTimezoneTestContainer(ContainerType.DEBIAN_JESSIE) + + @Container + private val nobleContainer = createTimezoneTestContainer(ContainerType.UBUNTU_NOBLE) + + @Test + fun defaultTimeZoneTestJessie() { + assertExecSuccess(jessieContainer.execDefaultTimeZoneTest()) + } + + @Test + fun defaultTimeZoneTestNoble() { + assertExecSuccess(nobleContainer.execDefaultTimeZoneTest()) + } @Test - fun defaultTimeZoneTest() { - assertExecSuccess(container.execDefaultTimeZoneTest()) + fun commonTimeZoneTestsJessie() { + assertExecSuccess(jessieContainer.execCommonTimeZoneTests()) } @Test - fun commonTimeZoneTests() { - assertExecSuccess(container.execCommonTimeZoneTests()) + fun commonTimeZoneTestsNoble() { + assertExecSuccess(nobleContainer.execCommonTimeZoneTests()) } private fun assertExecSuccess(execResult: ExecResult) { From 548ed680535eeb538214f8770ef3c205102e7768 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Fri, 21 Mar 2025 19:16:41 +0400 Subject: [PATCH 37/82] #430: Refactoring --- .../test/testcontainers/TimezoneTestContainer.kt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/core/jvm/test/testcontainers/TimezoneTestContainer.kt b/core/jvm/test/testcontainers/TimezoneTestContainer.kt index 7220ac64c..b6ec40917 100644 --- a/core/jvm/test/testcontainers/TimezoneTestContainer.kt +++ b/core/jvm/test/testcontainers/TimezoneTestContainer.kt @@ -12,8 +12,17 @@ import org.testcontainers.images.builder.ImageFromDockerfile import java.nio.file.Paths enum class ContainerType(val dockerfilePath: String, val imageName: String) { - DEBIAN_JESSIE("./jvm/test/testcontainers/debian-jessie/Dockerfile", "debian-jessie-timezone-test"), - UBUNTU_NOBLE("./jvm/test/testcontainers/ubuntu-noble/Dockerfile", "ubuntu-noble-timezone-test") + // Standard Jessie with Arctic/Longyearbyen timezone + DEBIAN_JESSIE( + "./jvm/test/testcontainers/debian-jessie/Dockerfile", + "debian-jessie-timezone-test" + ), + + // Standard Noble with Arctic/Longyearbyen timezone + UBUNTU_NOBLE( + "./jvm/test/testcontainers/ubuntu-noble/Dockerfile", + "ubuntu-noble-timezone-test" + ) } class TimezoneTestContainer(containerType: ContainerType, binaryDir: String) : From c9cf31257fa9d4c5803812c1386db16c2aa95d32 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Fri, 21 Mar 2025 19:43:49 +0400 Subject: [PATCH 38/82] #430: Refactor tests --- .../TimeZoneConfigurationTest.kt | 12 ++--- .../testcontainers/TimezoneTestContainer.kt | 16 ++++++- core/linux/test/TimeZoneLinuxNativeTest.kt | 47 +++++++++++++++++-- 3 files changed, 63 insertions(+), 12 deletions(-) diff --git a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt index bc46ad833..de08b859f 100644 --- a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt @@ -22,22 +22,22 @@ class TimeZoneConfigurationTest { private val nobleContainer = createTimezoneTestContainer(ContainerType.UBUNTU_NOBLE) @Test - fun defaultTimeZoneTestJessie() { - assertExecSuccess(jessieContainer.execDefaultTimeZoneTest()) + fun currentSystemTimeZoneJessieTest() { + assertExecSuccess(jessieContainer.execCurrentSystemTimeZoneTest()) } @Test - fun defaultTimeZoneTestNoble() { - assertExecSuccess(nobleContainer.execDefaultTimeZoneTest()) + fun currentSystemTimeZoneNobleTest() { + assertExecSuccess(nobleContainer.execCurrentSystemTimeZoneTest()) } @Test - fun commonTimeZoneTestsJessie() { + fun commonTimeZoneJessieTests() { assertExecSuccess(jessieContainer.execCommonTimeZoneTests()) } @Test - fun commonTimeZoneTestsNoble() { + fun commonTimeZoneNobleTests() { assertExecSuccess(nobleContainer.execCommonTimeZoneTests()) } diff --git a/core/jvm/test/testcontainers/TimezoneTestContainer.kt b/core/jvm/test/testcontainers/TimezoneTestContainer.kt index b6ec40917..c7e1a6ade 100644 --- a/core/jvm/test/testcontainers/TimezoneTestContainer.kt +++ b/core/jvm/test/testcontainers/TimezoneTestContainer.kt @@ -36,8 +36,20 @@ class TimezoneTestContainer(containerType: ContainerType, binaryDir: String) : withFileSystemBind(binaryDir, "/app", BindMode.READ_WRITE) } - fun execDefaultTimeZoneTest(): ExecResult { - return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.defaultTimeZoneTest") + fun execCurrentSystemTimeZoneTest(): ExecResult { + return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.currentSystemTimeZoneTest") + } + + fun execFallbackToUTCTest(): ExecResult { + return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.fallbackToUTCTest") + } + + fun execUndeterminedTimeZoneExceptionTest(): ExecResult { + return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.undeterminedTimeZoneExceptionTest") + } + + fun execInconsistentTimeZoneExceptionTest(): ExecResult { + return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.inconsistentTimeZoneExceptionTest") } fun execCommonTimeZoneTests(): ExecResult { diff --git a/core/linux/test/TimeZoneLinuxNativeTest.kt b/core/linux/test/TimeZoneLinuxNativeTest.kt index 467456984..265213b7b 100644 --- a/core/linux/test/TimeZoneLinuxNativeTest.kt +++ b/core/linux/test/TimeZoneLinuxNativeTest.kt @@ -11,13 +11,52 @@ import kotlin.test.* class TimeZoneLinuxNativeTest { /** - * Verifies that the default system time zone is recognized correctly - * and matches the expected value. + * Verifies that the current system time zone is recognized correctly + * and matches one of the expected values for the test environment. */ @Test - fun defaultTimeZoneTest() = Testcontainers.runIfAvailable { + fun currentSystemTimeZoneTest() = Testcontainers.runIfAvailable { val tz = TimeZone.currentSystemDefault() - println("Default timezone: $tz") assertTrue(tz == TimeZone.of("Europe/Oslo") || tz == TimeZone.of("Arctic/Longyearbyen")) } + + /** + * Verifies that the system time zone defaults to UTC + * when no valid time zone can be determined. + */ + @Test + fun fallbackToUTCTest() = Testcontainers.runIfAvailable { + val tz = TimeZone.currentSystemDefault() + assertEquals(TimeZone.UTC, tz) + } + + /** + * Verifies that TimeZone.currentSystemDefault() throws IllegalTimeZoneException + * with the expected error message when the time zone ID cannot be determined. + */ + @Test + fun undeterminedTimeZoneExceptionTest() = Testcontainers.runIfAvailable { + val exception = assertFailsWith { + TimeZone.currentSystemDefault() + } + assertTrue( + exception.message?.startsWith("Could not determine the timezone ID") == true, + "Exception message did not match" + ) + } + + /** + * Verifies that TimeZone.currentSystemDefault() throws IllegalTimeZoneException + * with the expected error message when time zone settings are inconsistent. + */ + @Test + fun inconsistentTimeZoneExceptionTest() = Testcontainers.runIfAvailable { + val exception = assertFailsWith { + TimeZone.currentSystemDefault() + } + assertTrue( + exception.message?.startsWith("Timezone mismatch") == true, + "Exception message did not start with 'Timezone mismatch'" + ) + } } \ No newline at end of file From 0e7a3c91a8a2a941c32aca93876a7992040dc9f0 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 24 Mar 2025 11:12:01 +0400 Subject: [PATCH 39/82] #430: Refactor tests --- .../testcontainers/TimeZoneConfigurationTest.kt | 4 ++-- .../test/testcontainers/TimezoneTestContainer.kt | 16 ++++++++-------- core/linux/test/TimeZoneLinuxNativeTest.kt | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt index de08b859f..ad4703c40 100644 --- a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt @@ -23,12 +23,12 @@ class TimeZoneConfigurationTest { @Test fun currentSystemTimeZoneJessieTest() { - assertExecSuccess(jessieContainer.execCurrentSystemTimeZoneTest()) + assertExecSuccess(jessieContainer.execCorrectRecognizesCurrentSystemTimeZone()) } @Test fun currentSystemTimeZoneNobleTest() { - assertExecSuccess(nobleContainer.execCurrentSystemTimeZoneTest()) + assertExecSuccess(nobleContainer.execCorrectRecognizesCurrentSystemTimeZone()) } @Test diff --git a/core/jvm/test/testcontainers/TimezoneTestContainer.kt b/core/jvm/test/testcontainers/TimezoneTestContainer.kt index c7e1a6ade..e5f55fc42 100644 --- a/core/jvm/test/testcontainers/TimezoneTestContainer.kt +++ b/core/jvm/test/testcontainers/TimezoneTestContainer.kt @@ -36,20 +36,20 @@ class TimezoneTestContainer(containerType: ContainerType, binaryDir: String) : withFileSystemBind(binaryDir, "/app", BindMode.READ_WRITE) } - fun execCurrentSystemTimeZoneTest(): ExecResult { - return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.currentSystemTimeZoneTest") + fun execCorrectRecognizesCurrentSystemTimeZone(): ExecResult { + return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.correctRecognizesCurrentSystemTimeZone") } - fun execFallbackToUTCTest(): ExecResult { - return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.fallbackToUTCTest") + fun execFallsBackToUTC(): ExecResult { + return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.fallsBackToUTC") } - fun execUndeterminedTimeZoneExceptionTest(): ExecResult { - return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.undeterminedTimeZoneExceptionTest") + fun execThrowsExceptionWhenTimeZoneUndetermined(): ExecResult { + return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.throwsExceptionWhenTimeZoneUndetermined") } - fun execInconsistentTimeZoneExceptionTest(): ExecResult { - return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.inconsistentTimeZoneExceptionTest") + fun execThrowsExceptionWhenTimeZoneInconsistent(): ExecResult { + return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.throwsExceptionWhenTimeZoneInconsistent") } fun execCommonTimeZoneTests(): ExecResult { diff --git a/core/linux/test/TimeZoneLinuxNativeTest.kt b/core/linux/test/TimeZoneLinuxNativeTest.kt index 265213b7b..12b132e66 100644 --- a/core/linux/test/TimeZoneLinuxNativeTest.kt +++ b/core/linux/test/TimeZoneLinuxNativeTest.kt @@ -15,7 +15,7 @@ class TimeZoneLinuxNativeTest { * and matches one of the expected values for the test environment. */ @Test - fun currentSystemTimeZoneTest() = Testcontainers.runIfAvailable { + fun correctRecognizesCurrentSystemTimeZone() = Testcontainers.runIfAvailable { val tz = TimeZone.currentSystemDefault() assertTrue(tz == TimeZone.of("Europe/Oslo") || tz == TimeZone.of("Arctic/Longyearbyen")) } @@ -25,7 +25,7 @@ class TimeZoneLinuxNativeTest { * when no valid time zone can be determined. */ @Test - fun fallbackToUTCTest() = Testcontainers.runIfAvailable { + fun fallsBackToUTC() = Testcontainers.runIfAvailable { val tz = TimeZone.currentSystemDefault() assertEquals(TimeZone.UTC, tz) } @@ -35,7 +35,7 @@ class TimeZoneLinuxNativeTest { * with the expected error message when the time zone ID cannot be determined. */ @Test - fun undeterminedTimeZoneExceptionTest() = Testcontainers.runIfAvailable { + fun throwsExceptionWhenTimeZoneUndetermined() = Testcontainers.runIfAvailable { val exception = assertFailsWith { TimeZone.currentSystemDefault() } @@ -50,7 +50,7 @@ class TimeZoneLinuxNativeTest { * with the expected error message when time zone settings are inconsistent. */ @Test - fun inconsistentTimeZoneExceptionTest() = Testcontainers.runIfAvailable { + fun throwsExceptionWhenTimeZoneInconsistent() = Testcontainers.runIfAvailable { val exception = assertFailsWith { TimeZone.currentSystemDefault() } From 0240f4952b2b01087d3f70ed9fb0b2d87f965c3e Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 24 Mar 2025 11:51:54 +0400 Subject: [PATCH 40/82] #430: Add jessieDefaultConfigTest, jessieMissingLocaltimeTest, nobleDefaultConfigTest --- .../TimeZoneConfigurationTest.kt | 40 +++++++++++++++---- .../testcontainers/TimezoneTestContainer.kt | 27 +++++++++++-- .../{ => correct-config}/Dockerfile | 0 .../debian-jessie/default-config/Dockerfile | 5 +++ .../missing-localtime/Dockerfile | 7 ++++ .../{ => correct-config}/Dockerfile | 0 .../ubuntu-noble/default-config/Dockerfile | 5 +++ core/linux/test/TimeZoneLinuxNativeTest.kt | 6 +++ 8 files changed, 78 insertions(+), 12 deletions(-) rename core/jvm/test/testcontainers/debian-jessie/{ => correct-config}/Dockerfile (100%) create mode 100644 core/jvm/test/testcontainers/debian-jessie/default-config/Dockerfile create mode 100644 core/jvm/test/testcontainers/debian-jessie/missing-localtime/Dockerfile rename core/jvm/test/testcontainers/ubuntu-noble/{ => correct-config}/Dockerfile (100%) create mode 100644 core/jvm/test/testcontainers/ubuntu-noble/default-config/Dockerfile diff --git a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt index ad4703c40..0d4b37fae 100644 --- a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt @@ -16,29 +16,53 @@ import org.testcontainers.containers.Container.ExecResult class TimeZoneConfigurationTest { @Container - private val jessieContainer = createTimezoneTestContainer(ContainerType.DEBIAN_JESSIE) + private val jessieCorrectConfigContainer = createTimezoneTestContainer(ContainerType.DEBIAN_JESSIE_CORRECT) @Container - private val nobleContainer = createTimezoneTestContainer(ContainerType.UBUNTU_NOBLE) + private val jessieDefaultConfigContainer = createTimezoneTestContainer(ContainerType.DEBIAN_JESSIE_DEFAULT) + + @Container + private val jessieMissingLocaltimeContainer = createTimezoneTestContainer(ContainerType.DEBIAN_JESSIE_MISSING_LOCALTIME) + + @Container + private val nobleCorrectConfigContainer = createTimezoneTestContainer(ContainerType.UBUNTU_NOBLE_CORRECT) + + @Container + private val nobleDefaultConfigContainer = createTimezoneTestContainer(ContainerType.UBUNTU_NOBLE_DEFAULT) + + @Test + fun debianJessieCorrectConfigTest() { + assertExecSuccess(jessieCorrectConfigContainer.execCorrectRecognizesCurrentSystemTimeZone()) + } + + @Test + fun nobleCorrectConfigTest() { + assertExecSuccess(nobleCorrectConfigContainer.execCorrectRecognizesCurrentSystemTimeZone()) + } + + @Test + fun jessieDefaultConfigTest() { + assertExecSuccess(jessieDefaultConfigContainer.execFallsBackToUniversal()) + } @Test - fun currentSystemTimeZoneJessieTest() { - assertExecSuccess(jessieContainer.execCorrectRecognizesCurrentSystemTimeZone()) + fun jessieMissingLocaltimeTest() { + assertExecSuccess(jessieMissingLocaltimeContainer.execFallsBackToUTC()) } @Test - fun currentSystemTimeZoneNobleTest() { - assertExecSuccess(nobleContainer.execCorrectRecognizesCurrentSystemTimeZone()) + fun nobleDefaultConfigTest() { + assertExecSuccess(nobleDefaultConfigContainer.execFallsBackToUTC()) } @Test fun commonTimeZoneJessieTests() { - assertExecSuccess(jessieContainer.execCommonTimeZoneTests()) + assertExecSuccess(jessieCorrectConfigContainer.execCommonTimeZoneTests()) } @Test fun commonTimeZoneNobleTests() { - assertExecSuccess(nobleContainer.execCommonTimeZoneTests()) + assertExecSuccess(nobleCorrectConfigContainer.execCommonTimeZoneTests()) } private fun assertExecSuccess(execResult: ExecResult) { diff --git a/core/jvm/test/testcontainers/TimezoneTestContainer.kt b/core/jvm/test/testcontainers/TimezoneTestContainer.kt index e5f55fc42..054426124 100644 --- a/core/jvm/test/testcontainers/TimezoneTestContainer.kt +++ b/core/jvm/test/testcontainers/TimezoneTestContainer.kt @@ -13,15 +13,30 @@ import java.nio.file.Paths enum class ContainerType(val dockerfilePath: String, val imageName: String) { // Standard Jessie with Arctic/Longyearbyen timezone - DEBIAN_JESSIE( - "./jvm/test/testcontainers/debian-jessie/Dockerfile", + DEBIAN_JESSIE_CORRECT( + "./jvm/test/testcontainers/debian-jessie/correct-config/Dockerfile", "debian-jessie-timezone-test" ), + DEBIAN_JESSIE_DEFAULT( + "./jvm/test/testcontainers/debian-jessie/default-config/Dockerfile", + "debian-jessie-timezone-test-default" + ), + + DEBIAN_JESSIE_MISSING_LOCALTIME( + "./jvm/test/testcontainers/debian-jessie/missing-localtime/Dockerfile", + "debian-jessie-timezone-test-missing-localtime" + ), + // Standard Noble with Arctic/Longyearbyen timezone - UBUNTU_NOBLE( - "./jvm/test/testcontainers/ubuntu-noble/Dockerfile", + UBUNTU_NOBLE_CORRECT( + "./jvm/test/testcontainers/ubuntu-noble/correct-config/Dockerfile", "ubuntu-noble-timezone-test" + ), + + UBUNTU_NOBLE_DEFAULT( + "./jvm/test/testcontainers/ubuntu-noble/default-config/Dockerfile", + "ubuntu-noble-timezone-test-default" ) } @@ -44,6 +59,10 @@ class TimezoneTestContainer(containerType: ContainerType, binaryDir: String) : return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.fallsBackToUTC") } + fun execFallsBackToUniversal(): ExecResult { + return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.fallsBackToUniversal") + } + fun execThrowsExceptionWhenTimeZoneUndetermined(): ExecResult { return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.throwsExceptionWhenTimeZoneUndetermined") } diff --git a/core/jvm/test/testcontainers/debian-jessie/Dockerfile b/core/jvm/test/testcontainers/debian-jessie/correct-config/Dockerfile similarity index 100% rename from core/jvm/test/testcontainers/debian-jessie/Dockerfile rename to core/jvm/test/testcontainers/debian-jessie/correct-config/Dockerfile diff --git a/core/jvm/test/testcontainers/debian-jessie/default-config/Dockerfile b/core/jvm/test/testcontainers/debian-jessie/default-config/Dockerfile new file mode 100644 index 000000000..2c402dd7a --- /dev/null +++ b/core/jvm/test/testcontainers/debian-jessie/default-config/Dockerfile @@ -0,0 +1,5 @@ +FROM --platform=linux/arm64 debian/eol:jessie + +ENV INSIDE_TESTCONTAINERS=true + +WORKDIR /app \ No newline at end of file diff --git a/core/jvm/test/testcontainers/debian-jessie/missing-localtime/Dockerfile b/core/jvm/test/testcontainers/debian-jessie/missing-localtime/Dockerfile new file mode 100644 index 000000000..83fb41bc1 --- /dev/null +++ b/core/jvm/test/testcontainers/debian-jessie/missing-localtime/Dockerfile @@ -0,0 +1,7 @@ +FROM --platform=linux/arm64 debian/eol:jessie + +ENV INSIDE_TESTCONTAINERS=true + +RUN rm -f /etc/localtime + +WORKDIR /app \ No newline at end of file diff --git a/core/jvm/test/testcontainers/ubuntu-noble/Dockerfile b/core/jvm/test/testcontainers/ubuntu-noble/correct-config/Dockerfile similarity index 100% rename from core/jvm/test/testcontainers/ubuntu-noble/Dockerfile rename to core/jvm/test/testcontainers/ubuntu-noble/correct-config/Dockerfile diff --git a/core/jvm/test/testcontainers/ubuntu-noble/default-config/Dockerfile b/core/jvm/test/testcontainers/ubuntu-noble/default-config/Dockerfile new file mode 100644 index 000000000..91709036c --- /dev/null +++ b/core/jvm/test/testcontainers/ubuntu-noble/default-config/Dockerfile @@ -0,0 +1,5 @@ +FROM --platform=linux/arm64 ubuntu:24.04 + +ENV INSIDE_TESTCONTAINERS=true + +WORKDIR /app \ No newline at end of file diff --git a/core/linux/test/TimeZoneLinuxNativeTest.kt b/core/linux/test/TimeZoneLinuxNativeTest.kt index 12b132e66..e4916b152 100644 --- a/core/linux/test/TimeZoneLinuxNativeTest.kt +++ b/core/linux/test/TimeZoneLinuxNativeTest.kt @@ -30,6 +30,12 @@ class TimeZoneLinuxNativeTest { assertEquals(TimeZone.UTC, tz) } + @Test + fun fallsBackToUniversal() = Testcontainers.runIfAvailable { + val tz = TimeZone.currentSystemDefault() + assertEquals(TimeZone.of("Universal"), tz) + } + /** * Verifies that TimeZone.currentSystemDefault() throws IllegalTimeZoneException * with the expected error message when the time zone ID cannot be determined. From c007bac6cbdb54a4ed859e17281d321870bddd05 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 24 Mar 2025 11:53:34 +0400 Subject: [PATCH 41/82] #430: Move ContainerType --- core/jvm/test/testcontainers/ContainerType.kt | 35 +++++++++++++++++++ .../testcontainers/TimezoneTestContainer.kt | 29 --------------- 2 files changed, 35 insertions(+), 29 deletions(-) create mode 100644 core/jvm/test/testcontainers/ContainerType.kt diff --git a/core/jvm/test/testcontainers/ContainerType.kt b/core/jvm/test/testcontainers/ContainerType.kt new file mode 100644 index 000000000..8808e40c1 --- /dev/null +++ b/core/jvm/test/testcontainers/ContainerType.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2019-2025 JetBrains s.r.o. and contributors. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +package testcontainers + +enum class ContainerType(val dockerfilePath: String, val imageName: String) { + // Standard Jessie with Arctic/Longyearbyen timezone + DEBIAN_JESSIE_CORRECT( + "./jvm/test/testcontainers/debian-jessie/correct-config/Dockerfile", + "debian-jessie-timezone-test" + ), + + DEBIAN_JESSIE_DEFAULT( + "./jvm/test/testcontainers/debian-jessie/default-config/Dockerfile", + "debian-jessie-timezone-test-default" + ), + + DEBIAN_JESSIE_MISSING_LOCALTIME( + "./jvm/test/testcontainers/debian-jessie/missing-localtime/Dockerfile", + "debian-jessie-timezone-test-missing-localtime" + ), + + // Standard Noble with Arctic/Longyearbyen timezone + UBUNTU_NOBLE_CORRECT( + "./jvm/test/testcontainers/ubuntu-noble/correct-config/Dockerfile", + "ubuntu-noble-timezone-test" + ), + + UBUNTU_NOBLE_DEFAULT( + "./jvm/test/testcontainers/ubuntu-noble/default-config/Dockerfile", + "ubuntu-noble-timezone-test-default" + ) +} \ No newline at end of file diff --git a/core/jvm/test/testcontainers/TimezoneTestContainer.kt b/core/jvm/test/testcontainers/TimezoneTestContainer.kt index 054426124..8c89179ff 100644 --- a/core/jvm/test/testcontainers/TimezoneTestContainer.kt +++ b/core/jvm/test/testcontainers/TimezoneTestContainer.kt @@ -11,35 +11,6 @@ import org.testcontainers.containers.GenericContainer import org.testcontainers.images.builder.ImageFromDockerfile import java.nio.file.Paths -enum class ContainerType(val dockerfilePath: String, val imageName: String) { - // Standard Jessie with Arctic/Longyearbyen timezone - DEBIAN_JESSIE_CORRECT( - "./jvm/test/testcontainers/debian-jessie/correct-config/Dockerfile", - "debian-jessie-timezone-test" - ), - - DEBIAN_JESSIE_DEFAULT( - "./jvm/test/testcontainers/debian-jessie/default-config/Dockerfile", - "debian-jessie-timezone-test-default" - ), - - DEBIAN_JESSIE_MISSING_LOCALTIME( - "./jvm/test/testcontainers/debian-jessie/missing-localtime/Dockerfile", - "debian-jessie-timezone-test-missing-localtime" - ), - - // Standard Noble with Arctic/Longyearbyen timezone - UBUNTU_NOBLE_CORRECT( - "./jvm/test/testcontainers/ubuntu-noble/correct-config/Dockerfile", - "ubuntu-noble-timezone-test" - ), - - UBUNTU_NOBLE_DEFAULT( - "./jvm/test/testcontainers/ubuntu-noble/default-config/Dockerfile", - "ubuntu-noble-timezone-test-default" - ) -} - class TimezoneTestContainer(containerType: ContainerType, binaryDir: String) : GenericContainer( ImageFromDockerfile(containerType.imageName) From 95dd6d987521c4a0c9a1e5bf9f9d3b2e1a0cdb56 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 24 Mar 2025 11:57:52 +0400 Subject: [PATCH 42/82] #430: Refactor dockerfiles --- core/jvm/test/testcontainers/ContainerType.kt | 10 +++++----- .../Dockerfile => correct-config.dockerfile} | 0 .../Dockerfile => default-config.dockerfile} | 0 .../Dockerfile => missing-localtime.dockerfile} | 0 .../Dockerfile => correct-config.dockerfile} | 0 .../Dockerfile => default-config.dockerfile} | 0 6 files changed, 5 insertions(+), 5 deletions(-) rename core/jvm/test/testcontainers/debian-jessie/{correct-config/Dockerfile => correct-config.dockerfile} (100%) rename core/jvm/test/testcontainers/debian-jessie/{default-config/Dockerfile => default-config.dockerfile} (100%) rename core/jvm/test/testcontainers/debian-jessie/{missing-localtime/Dockerfile => missing-localtime.dockerfile} (100%) rename core/jvm/test/testcontainers/ubuntu-noble/{correct-config/Dockerfile => correct-config.dockerfile} (100%) rename core/jvm/test/testcontainers/ubuntu-noble/{default-config/Dockerfile => default-config.dockerfile} (100%) diff --git a/core/jvm/test/testcontainers/ContainerType.kt b/core/jvm/test/testcontainers/ContainerType.kt index 8808e40c1..a16be6599 100644 --- a/core/jvm/test/testcontainers/ContainerType.kt +++ b/core/jvm/test/testcontainers/ContainerType.kt @@ -8,28 +8,28 @@ package testcontainers enum class ContainerType(val dockerfilePath: String, val imageName: String) { // Standard Jessie with Arctic/Longyearbyen timezone DEBIAN_JESSIE_CORRECT( - "./jvm/test/testcontainers/debian-jessie/correct-config/Dockerfile", + "./jvm/test/testcontainers/debian-jessie/correct-config.dockerfile", "debian-jessie-timezone-test" ), DEBIAN_JESSIE_DEFAULT( - "./jvm/test/testcontainers/debian-jessie/default-config/Dockerfile", + "./jvm/test/testcontainers/debian-jessie/default-config.dockerfile", "debian-jessie-timezone-test-default" ), DEBIAN_JESSIE_MISSING_LOCALTIME( - "./jvm/test/testcontainers/debian-jessie/missing-localtime/Dockerfile", + "./jvm/test/testcontainers/debian-jessie/missing-localtime.dockerfile", "debian-jessie-timezone-test-missing-localtime" ), // Standard Noble with Arctic/Longyearbyen timezone UBUNTU_NOBLE_CORRECT( - "./jvm/test/testcontainers/ubuntu-noble/correct-config/Dockerfile", + "./jvm/test/testcontainers/ubuntu-noble/correct-config.dockerfile", "ubuntu-noble-timezone-test" ), UBUNTU_NOBLE_DEFAULT( - "./jvm/test/testcontainers/ubuntu-noble/default-config/Dockerfile", + "./jvm/test/testcontainers/ubuntu-noble/default-config.dockerfile", "ubuntu-noble-timezone-test-default" ) } \ No newline at end of file diff --git a/core/jvm/test/testcontainers/debian-jessie/correct-config/Dockerfile b/core/jvm/test/testcontainers/debian-jessie/correct-config.dockerfile similarity index 100% rename from core/jvm/test/testcontainers/debian-jessie/correct-config/Dockerfile rename to core/jvm/test/testcontainers/debian-jessie/correct-config.dockerfile diff --git a/core/jvm/test/testcontainers/debian-jessie/default-config/Dockerfile b/core/jvm/test/testcontainers/debian-jessie/default-config.dockerfile similarity index 100% rename from core/jvm/test/testcontainers/debian-jessie/default-config/Dockerfile rename to core/jvm/test/testcontainers/debian-jessie/default-config.dockerfile diff --git a/core/jvm/test/testcontainers/debian-jessie/missing-localtime/Dockerfile b/core/jvm/test/testcontainers/debian-jessie/missing-localtime.dockerfile similarity index 100% rename from core/jvm/test/testcontainers/debian-jessie/missing-localtime/Dockerfile rename to core/jvm/test/testcontainers/debian-jessie/missing-localtime.dockerfile diff --git a/core/jvm/test/testcontainers/ubuntu-noble/correct-config/Dockerfile b/core/jvm/test/testcontainers/ubuntu-noble/correct-config.dockerfile similarity index 100% rename from core/jvm/test/testcontainers/ubuntu-noble/correct-config/Dockerfile rename to core/jvm/test/testcontainers/ubuntu-noble/correct-config.dockerfile diff --git a/core/jvm/test/testcontainers/ubuntu-noble/default-config/Dockerfile b/core/jvm/test/testcontainers/ubuntu-noble/default-config.dockerfile similarity index 100% rename from core/jvm/test/testcontainers/ubuntu-noble/default-config/Dockerfile rename to core/jvm/test/testcontainers/ubuntu-noble/default-config.dockerfile From 38cab9328d831846aa4d9ca2701d78adca696766 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 24 Mar 2025 11:59:51 +0400 Subject: [PATCH 43/82] #430: Refactor ContainerType --- core/jvm/test/testcontainers/ContainerType.kt | 10 +++++----- .../test/testcontainers/TimeZoneConfigurationTest.kt | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/jvm/test/testcontainers/ContainerType.kt b/core/jvm/test/testcontainers/ContainerType.kt index a16be6599..2e7a0084d 100644 --- a/core/jvm/test/testcontainers/ContainerType.kt +++ b/core/jvm/test/testcontainers/ContainerType.kt @@ -7,28 +7,28 @@ package testcontainers enum class ContainerType(val dockerfilePath: String, val imageName: String) { // Standard Jessie with Arctic/Longyearbyen timezone - DEBIAN_JESSIE_CORRECT( + JESSIE_CORRECT( "./jvm/test/testcontainers/debian-jessie/correct-config.dockerfile", "debian-jessie-timezone-test" ), - DEBIAN_JESSIE_DEFAULT( + JESSIE_DEFAULT( "./jvm/test/testcontainers/debian-jessie/default-config.dockerfile", "debian-jessie-timezone-test-default" ), - DEBIAN_JESSIE_MISSING_LOCALTIME( + JESSIE_MISSING_LOCALTIME( "./jvm/test/testcontainers/debian-jessie/missing-localtime.dockerfile", "debian-jessie-timezone-test-missing-localtime" ), // Standard Noble with Arctic/Longyearbyen timezone - UBUNTU_NOBLE_CORRECT( + NOBLE_CORRECT( "./jvm/test/testcontainers/ubuntu-noble/correct-config.dockerfile", "ubuntu-noble-timezone-test" ), - UBUNTU_NOBLE_DEFAULT( + NOBLE_DEFAULT( "./jvm/test/testcontainers/ubuntu-noble/default-config.dockerfile", "ubuntu-noble-timezone-test-default" ) diff --git a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt index 0d4b37fae..44fbd172d 100644 --- a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt @@ -16,19 +16,19 @@ import org.testcontainers.containers.Container.ExecResult class TimeZoneConfigurationTest { @Container - private val jessieCorrectConfigContainer = createTimezoneTestContainer(ContainerType.DEBIAN_JESSIE_CORRECT) + private val jessieCorrectConfigContainer = createTimezoneTestContainer(ContainerType.JESSIE_CORRECT) @Container - private val jessieDefaultConfigContainer = createTimezoneTestContainer(ContainerType.DEBIAN_JESSIE_DEFAULT) + private val jessieDefaultConfigContainer = createTimezoneTestContainer(ContainerType.JESSIE_DEFAULT) @Container - private val jessieMissingLocaltimeContainer = createTimezoneTestContainer(ContainerType.DEBIAN_JESSIE_MISSING_LOCALTIME) + private val jessieMissingLocaltimeContainer = createTimezoneTestContainer(ContainerType.JESSIE_MISSING_LOCALTIME) @Container - private val nobleCorrectConfigContainer = createTimezoneTestContainer(ContainerType.UBUNTU_NOBLE_CORRECT) + private val nobleCorrectConfigContainer = createTimezoneTestContainer(ContainerType.NOBLE_CORRECT) @Container - private val nobleDefaultConfigContainer = createTimezoneTestContainer(ContainerType.UBUNTU_NOBLE_DEFAULT) + private val nobleDefaultConfigContainer = createTimezoneTestContainer(ContainerType.NOBLE_DEFAULT) @Test fun debianJessieCorrectConfigTest() { From 9ee58d79adf711a1fbf0014463d462c7a1d15703 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 24 Mar 2025 12:37:13 +0400 Subject: [PATCH 44/82] #430: Add nobleIncorrectSymlinkTest --- core/jvm/test/testcontainers/ContainerType.kt | 5 +++++ .../TimeZoneConfigurationTest.kt | 20 +++++++++++++------ .../ubuntu-noble/incorrect-symlink.dockerfile | 7 +++++++ 3 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 core/jvm/test/testcontainers/ubuntu-noble/incorrect-symlink.dockerfile diff --git a/core/jvm/test/testcontainers/ContainerType.kt b/core/jvm/test/testcontainers/ContainerType.kt index 2e7a0084d..dbfd375a3 100644 --- a/core/jvm/test/testcontainers/ContainerType.kt +++ b/core/jvm/test/testcontainers/ContainerType.kt @@ -31,5 +31,10 @@ enum class ContainerType(val dockerfilePath: String, val imageName: String) { NOBLE_DEFAULT( "./jvm/test/testcontainers/ubuntu-noble/default-config.dockerfile", "ubuntu-noble-timezone-test-default" + ), + + NOBLE_INCORRECT_SYMLINK( + "./jvm/test/testcontainers/ubuntu-noble/incorrect-symlink.dockerfile", + "ubuntu-noble-timezone-test-incorrect-symlink" ) } \ No newline at end of file diff --git a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt index 44fbd172d..1f761ea4f 100644 --- a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt @@ -30,14 +30,12 @@ class TimeZoneConfigurationTest { @Container private val nobleDefaultConfigContainer = createTimezoneTestContainer(ContainerType.NOBLE_DEFAULT) - @Test - fun debianJessieCorrectConfigTest() { - assertExecSuccess(jessieCorrectConfigContainer.execCorrectRecognizesCurrentSystemTimeZone()) - } + @Container + private val nobleIncorrectSymlinkContainer = createTimezoneTestContainer(ContainerType.NOBLE_INCORRECT_SYMLINK) @Test - fun nobleCorrectConfigTest() { - assertExecSuccess(nobleCorrectConfigContainer.execCorrectRecognizesCurrentSystemTimeZone()) + fun jessieCorrectConfigTest() { + assertExecSuccess(jessieCorrectConfigContainer.execCorrectRecognizesCurrentSystemTimeZone()) } @Test @@ -50,11 +48,21 @@ class TimeZoneConfigurationTest { assertExecSuccess(jessieMissingLocaltimeContainer.execFallsBackToUTC()) } + @Test + fun nobleCorrectConfigTest() { + assertExecSuccess(nobleCorrectConfigContainer.execCorrectRecognizesCurrentSystemTimeZone()) + } + @Test fun nobleDefaultConfigTest() { assertExecSuccess(nobleDefaultConfigContainer.execFallsBackToUTC()) } + @Test + fun nobleIncorrectSymlinkTest() { + assertExecSuccess(nobleIncorrectSymlinkContainer.execThrowsExceptionWhenTimeZoneUndetermined()) + } + @Test fun commonTimeZoneJessieTests() { assertExecSuccess(jessieCorrectConfigContainer.execCommonTimeZoneTests()) diff --git a/core/jvm/test/testcontainers/ubuntu-noble/incorrect-symlink.dockerfile b/core/jvm/test/testcontainers/ubuntu-noble/incorrect-symlink.dockerfile new file mode 100644 index 000000000..d3a3d92f5 --- /dev/null +++ b/core/jvm/test/testcontainers/ubuntu-noble/incorrect-symlink.dockerfile @@ -0,0 +1,7 @@ +FROM --platform=linux/arm64 ubuntu:24.04 + +ENV INSIDE_TESTCONTAINERS=true + +RUN ln -s /app /etc/localtime + +WORKDIR /app \ No newline at end of file From 192f1a2f65af2a68970e342fb9394b5af21297d8 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 24 Mar 2025 12:45:40 +0400 Subject: [PATCH 45/82] #430: Add disabledWithoutDocker = true (may help to users that don't have docker) --- core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt index 1f761ea4f..f04763cf1 100644 --- a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt @@ -12,7 +12,7 @@ import org.junit.jupiter.api.Test import org.slf4j.LoggerFactory import org.testcontainers.containers.Container.ExecResult -@Testcontainers +@Testcontainers(disabledWithoutDocker = true) class TimeZoneConfigurationTest { @Container From 1dc04aa0036a49fff8609f9e4c451e1bcaa9747c Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 24 Mar 2025 12:51:28 +0400 Subject: [PATCH 46/82] #430: Add @TestInstance(PER_CLASS) to TimeZoneConfigurationTest --- core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt index f04763cf1..054251a3f 100644 --- a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt @@ -9,10 +9,13 @@ import org.junit.jupiter.api.BeforeAll import org.testcontainers.junit.jupiter.Container import org.testcontainers.junit.jupiter.Testcontainers import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS import org.slf4j.LoggerFactory import org.testcontainers.containers.Container.ExecResult @Testcontainers(disabledWithoutDocker = true) +@TestInstance(PER_CLASS) class TimeZoneConfigurationTest { @Container From df35ba0bba2440907ba77550c63bdcf7587fb714 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 24 Mar 2025 12:55:24 +0400 Subject: [PATCH 47/82] #430: Add jessieMissingTimezoneTest --- core/jvm/test/testcontainers/ContainerType.kt | 5 +++++ core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt | 8 ++++++++ .../debian-jessie/missing-timezone.dockerfile | 7 +++++++ 3 files changed, 20 insertions(+) create mode 100644 core/jvm/test/testcontainers/debian-jessie/missing-timezone.dockerfile diff --git a/core/jvm/test/testcontainers/ContainerType.kt b/core/jvm/test/testcontainers/ContainerType.kt index dbfd375a3..00bd4f985 100644 --- a/core/jvm/test/testcontainers/ContainerType.kt +++ b/core/jvm/test/testcontainers/ContainerType.kt @@ -22,6 +22,11 @@ enum class ContainerType(val dockerfilePath: String, val imageName: String) { "debian-jessie-timezone-test-missing-localtime" ), + JESSIE_MISSING_TIMEZONE( + "./jvm/test/testcontainers/debian-jessie/missing-timezone.dockerfile", + "debian-jessie-timezone-test-missing-timezone" + ), + // Standard Noble with Arctic/Longyearbyen timezone NOBLE_CORRECT( "./jvm/test/testcontainers/ubuntu-noble/correct-config.dockerfile", diff --git a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt index 054251a3f..9a56d937b 100644 --- a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt @@ -27,6 +27,9 @@ class TimeZoneConfigurationTest { @Container private val jessieMissingLocaltimeContainer = createTimezoneTestContainer(ContainerType.JESSIE_MISSING_LOCALTIME) + @Container + private val jessieMissingTimezoneContainer = createTimezoneTestContainer(ContainerType.JESSIE_MISSING_TIMEZONE) + @Container private val nobleCorrectConfigContainer = createTimezoneTestContainer(ContainerType.NOBLE_CORRECT) @@ -51,6 +54,11 @@ class TimeZoneConfigurationTest { assertExecSuccess(jessieMissingLocaltimeContainer.execFallsBackToUTC()) } + @Test + fun jessieMissingTimezoneTest() { + assertExecSuccess(jessieMissingTimezoneContainer.execThrowsExceptionWhenTimeZoneUndetermined()) + } + @Test fun nobleCorrectConfigTest() { assertExecSuccess(nobleCorrectConfigContainer.execCorrectRecognizesCurrentSystemTimeZone()) diff --git a/core/jvm/test/testcontainers/debian-jessie/missing-timezone.dockerfile b/core/jvm/test/testcontainers/debian-jessie/missing-timezone.dockerfile new file mode 100644 index 000000000..3aad47270 --- /dev/null +++ b/core/jvm/test/testcontainers/debian-jessie/missing-timezone.dockerfile @@ -0,0 +1,7 @@ +FROM --platform=linux/arm64 debian/eol:jessie + +ENV INSIDE_TESTCONTAINERS=true + +RUN rm -f /etc/timezone + +WORKDIR /app \ No newline at end of file From 2234375f1282be4a83c4d795e36766362e84a8fd Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 24 Mar 2025 13:00:43 +0400 Subject: [PATCH 48/82] #430: Add jessieIncorrectTimezoneTest --- core/jvm/test/testcontainers/ContainerType.kt | 5 +++++ core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt | 8 ++++++++ .../debian-jessie/incorrect-timezone.dockerfile | 7 +++++++ 3 files changed, 20 insertions(+) create mode 100644 core/jvm/test/testcontainers/debian-jessie/incorrect-timezone.dockerfile diff --git a/core/jvm/test/testcontainers/ContainerType.kt b/core/jvm/test/testcontainers/ContainerType.kt index 00bd4f985..cadb4bb19 100644 --- a/core/jvm/test/testcontainers/ContainerType.kt +++ b/core/jvm/test/testcontainers/ContainerType.kt @@ -27,6 +27,11 @@ enum class ContainerType(val dockerfilePath: String, val imageName: String) { "debian-jessie-timezone-test-missing-timezone" ), + JESSIE_INCORRECT_TIMEZONE( + "./jvm/test/testcontainers/debian-jessie/incorrect-timezone.dockerfile", + "debian-jessie-timezone-test-incorrect-timezone" + ), + // Standard Noble with Arctic/Longyearbyen timezone NOBLE_CORRECT( "./jvm/test/testcontainers/ubuntu-noble/correct-config.dockerfile", diff --git a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt index 9a56d937b..91e52110f 100644 --- a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt @@ -30,6 +30,9 @@ class TimeZoneConfigurationTest { @Container private val jessieMissingTimezoneContainer = createTimezoneTestContainer(ContainerType.JESSIE_MISSING_TIMEZONE) + @Container + private val jessieIncorrectTimezoneContainer = createTimezoneTestContainer(ContainerType.JESSIE_INCORRECT_TIMEZONE) + @Container private val nobleCorrectConfigContainer = createTimezoneTestContainer(ContainerType.NOBLE_CORRECT) @@ -59,6 +62,11 @@ class TimeZoneConfigurationTest { assertExecSuccess(jessieMissingTimezoneContainer.execThrowsExceptionWhenTimeZoneUndetermined()) } + @Test + fun jessieIncorrectTimezoneTest() { + assertExecSuccess(jessieIncorrectTimezoneContainer.execThrowsExceptionWhenTimeZoneUndetermined()) + } + @Test fun nobleCorrectConfigTest() { assertExecSuccess(nobleCorrectConfigContainer.execCorrectRecognizesCurrentSystemTimeZone()) diff --git a/core/jvm/test/testcontainers/debian-jessie/incorrect-timezone.dockerfile b/core/jvm/test/testcontainers/debian-jessie/incorrect-timezone.dockerfile new file mode 100644 index 000000000..9de111408 --- /dev/null +++ b/core/jvm/test/testcontainers/debian-jessie/incorrect-timezone.dockerfile @@ -0,0 +1,7 @@ +FROM --platform=linux/arm64 debian/eol:jessie + +ENV INSIDE_TESTCONTAINERS=true + +RUN echo incorrect/data > /etc/timezone + +WORKDIR /app \ No newline at end of file From 7a388748243e2ad800abaaa45a0c9cc6fa690a1b Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 24 Mar 2025 13:07:06 +0400 Subject: [PATCH 49/82] #430: Add jessieDifferentTimezonesTest --- core/jvm/test/testcontainers/ContainerType.kt | 5 +++++ .../jvm/test/testcontainers/TimeZoneConfigurationTest.kt | 8 ++++++++ .../debian-jessie/different-timezones.dockerfile | 9 +++++++++ 3 files changed, 22 insertions(+) create mode 100644 core/jvm/test/testcontainers/debian-jessie/different-timezones.dockerfile diff --git a/core/jvm/test/testcontainers/ContainerType.kt b/core/jvm/test/testcontainers/ContainerType.kt index cadb4bb19..b4c09185b 100644 --- a/core/jvm/test/testcontainers/ContainerType.kt +++ b/core/jvm/test/testcontainers/ContainerType.kt @@ -32,6 +32,11 @@ enum class ContainerType(val dockerfilePath: String, val imageName: String) { "debian-jessie-timezone-test-incorrect-timezone" ), + JESSIE_DIFFERENT_TIMEZONES( + "./jvm/test/testcontainers/debian-jessie/different-timezones.dockerfile", + "debian-jessie-timezone-test-different-timezones" + ), + // Standard Noble with Arctic/Longyearbyen timezone NOBLE_CORRECT( "./jvm/test/testcontainers/ubuntu-noble/correct-config.dockerfile", diff --git a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt index 91e52110f..c2533d4a7 100644 --- a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt @@ -33,6 +33,9 @@ class TimeZoneConfigurationTest { @Container private val jessieIncorrectTimezoneContainer = createTimezoneTestContainer(ContainerType.JESSIE_INCORRECT_TIMEZONE) + @Container + private val jessieDifferentTimezonesContainer = createTimezoneTestContainer(ContainerType.JESSIE_DIFFERENT_TIMEZONES) + @Container private val nobleCorrectConfigContainer = createTimezoneTestContainer(ContainerType.NOBLE_CORRECT) @@ -67,6 +70,11 @@ class TimeZoneConfigurationTest { assertExecSuccess(jessieIncorrectTimezoneContainer.execThrowsExceptionWhenTimeZoneUndetermined()) } + @Test + fun jessieDifferentTimezonesTest() { + assertExecSuccess(jessieDifferentTimezonesContainer.execThrowsExceptionWhenTimeZoneInconsistent()) + } + @Test fun nobleCorrectConfigTest() { assertExecSuccess(nobleCorrectConfigContainer.execCorrectRecognizesCurrentSystemTimeZone()) diff --git a/core/jvm/test/testcontainers/debian-jessie/different-timezones.dockerfile b/core/jvm/test/testcontainers/debian-jessie/different-timezones.dockerfile new file mode 100644 index 000000000..4109c2dce --- /dev/null +++ b/core/jvm/test/testcontainers/debian-jessie/different-timezones.dockerfile @@ -0,0 +1,9 @@ +FROM --platform=linux/arm64 debian/eol:jessie + +ENV INSIDE_TESTCONTAINERS=true + +# 5: Arctic/Longyearbyen +RUN echo 5 | dpkg-reconfigure tzdata +RUN echo Europe/Berlin > /etc/timezone + +WORKDIR /app \ No newline at end of file From 7cc417f53812316af38cc54df94a113c84ffaba3 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 24 Mar 2025 13:08:57 +0400 Subject: [PATCH 50/82] #430: Add comment to fallsBackToUniversal --- core/linux/test/TimeZoneLinuxNativeTest.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/linux/test/TimeZoneLinuxNativeTest.kt b/core/linux/test/TimeZoneLinuxNativeTest.kt index e4916b152..fe3f70fae 100644 --- a/core/linux/test/TimeZoneLinuxNativeTest.kt +++ b/core/linux/test/TimeZoneLinuxNativeTest.kt @@ -30,6 +30,11 @@ class TimeZoneLinuxNativeTest { assertEquals(TimeZone.UTC, tz) } + /** + * Verifies that the system time zone falls back to "Universal" + * when a specific time zone cannot be determined. + * This behavior is specific to Debian Jessie. + */ @Test fun fallsBackToUniversal() = Testcontainers.runIfAvailable { val tz = TimeZone.currentSystemDefault() From d678adfb00f0bb241e49329b4169e986521460b5 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 24 Mar 2025 13:18:09 +0400 Subject: [PATCH 51/82] #430: Add container descriptions in ContainerType --- core/jvm/test/testcontainers/ContainerType.kt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/core/jvm/test/testcontainers/ContainerType.kt b/core/jvm/test/testcontainers/ContainerType.kt index b4c09185b..31128405e 100644 --- a/core/jvm/test/testcontainers/ContainerType.kt +++ b/core/jvm/test/testcontainers/ContainerType.kt @@ -6,48 +6,56 @@ package testcontainers enum class ContainerType(val dockerfilePath: String, val imageName: String) { - // Standard Jessie with Arctic/Longyearbyen timezone + // Standard Debian Jessie container with Arctic/Longyearbyen timezone JESSIE_CORRECT( "./jvm/test/testcontainers/debian-jessie/correct-config.dockerfile", "debian-jessie-timezone-test" ), + // Debian Jessie container with default system configuration JESSIE_DEFAULT( "./jvm/test/testcontainers/debian-jessie/default-config.dockerfile", "debian-jessie-timezone-test-default" ), + // Debian Jessie container with missing /etc/localtime file JESSIE_MISSING_LOCALTIME( "./jvm/test/testcontainers/debian-jessie/missing-localtime.dockerfile", "debian-jessie-timezone-test-missing-localtime" ), + // Debian Jessie container with missing /etc/timezone file JESSIE_MISSING_TIMEZONE( "./jvm/test/testcontainers/debian-jessie/missing-timezone.dockerfile", "debian-jessie-timezone-test-missing-timezone" ), + // Debian Jessie container with garbage inside /etc/timezone file JESSIE_INCORRECT_TIMEZONE( "./jvm/test/testcontainers/debian-jessie/incorrect-timezone.dockerfile", "debian-jessie-timezone-test-incorrect-timezone" ), + // Debian Jessie container with conflicting timezone configurations + // `/etc/localtime` and `/usr/share/zoneinfo/$(cat /etc/timezone)` files are different JESSIE_DIFFERENT_TIMEZONES( "./jvm/test/testcontainers/debian-jessie/different-timezones.dockerfile", "debian-jessie-timezone-test-different-timezones" ), - // Standard Noble with Arctic/Longyearbyen timezone + // Standard Ubuntu Noble container with Arctic/Longyearbyen timezone NOBLE_CORRECT( "./jvm/test/testcontainers/ubuntu-noble/correct-config.dockerfile", "ubuntu-noble-timezone-test" ), + // Ubuntu Noble container with default system configuration NOBLE_DEFAULT( "./jvm/test/testcontainers/ubuntu-noble/default-config.dockerfile", "ubuntu-noble-timezone-test-default" ), + // Ubuntu Noble container with incorrect symbolic link for /etc/localtime NOBLE_INCORRECT_SYMLINK( "./jvm/test/testcontainers/ubuntu-noble/incorrect-symlink.dockerfile", "ubuntu-noble-timezone-test-incorrect-symlink" From 7f48fc35f89c8c0099177d55c4624a058246b35b Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 24 Mar 2025 15:20:28 +0400 Subject: [PATCH 52/82] #430: Remove WORKDIR from dockerfiles --- .../testcontainers/debian-jessie/correct-config.dockerfile | 4 +--- .../testcontainers/debian-jessie/default-config.dockerfile | 4 +--- .../debian-jessie/different-timezones.dockerfile | 4 +--- .../debian-jessie/incorrect-timezone.dockerfile | 4 +--- .../testcontainers/debian-jessie/missing-localtime.dockerfile | 4 +--- .../testcontainers/debian-jessie/missing-timezone.dockerfile | 4 +--- .../testcontainers/ubuntu-noble/correct-config.dockerfile | 4 +--- .../testcontainers/ubuntu-noble/default-config.dockerfile | 4 +--- .../testcontainers/ubuntu-noble/incorrect-symlink.dockerfile | 4 +--- 9 files changed, 9 insertions(+), 27 deletions(-) diff --git a/core/jvm/test/testcontainers/debian-jessie/correct-config.dockerfile b/core/jvm/test/testcontainers/debian-jessie/correct-config.dockerfile index 8d52ae86a..c0fe2cf91 100644 --- a/core/jvm/test/testcontainers/debian-jessie/correct-config.dockerfile +++ b/core/jvm/test/testcontainers/debian-jessie/correct-config.dockerfile @@ -3,6 +3,4 @@ FROM --platform=linux/arm64 debian/eol:jessie ENV INSIDE_TESTCONTAINERS=true # 5: Arctic/Longyearbyen -RUN echo 5 | dpkg-reconfigure tzdata - -WORKDIR /app \ No newline at end of file +RUN echo 5 | dpkg-reconfigure tzdata \ No newline at end of file diff --git a/core/jvm/test/testcontainers/debian-jessie/default-config.dockerfile b/core/jvm/test/testcontainers/debian-jessie/default-config.dockerfile index 2c402dd7a..b986089e8 100644 --- a/core/jvm/test/testcontainers/debian-jessie/default-config.dockerfile +++ b/core/jvm/test/testcontainers/debian-jessie/default-config.dockerfile @@ -1,5 +1,3 @@ FROM --platform=linux/arm64 debian/eol:jessie -ENV INSIDE_TESTCONTAINERS=true - -WORKDIR /app \ No newline at end of file +ENV INSIDE_TESTCONTAINERS=true \ No newline at end of file diff --git a/core/jvm/test/testcontainers/debian-jessie/different-timezones.dockerfile b/core/jvm/test/testcontainers/debian-jessie/different-timezones.dockerfile index 4109c2dce..2eb7710f5 100644 --- a/core/jvm/test/testcontainers/debian-jessie/different-timezones.dockerfile +++ b/core/jvm/test/testcontainers/debian-jessie/different-timezones.dockerfile @@ -4,6 +4,4 @@ ENV INSIDE_TESTCONTAINERS=true # 5: Arctic/Longyearbyen RUN echo 5 | dpkg-reconfigure tzdata -RUN echo Europe/Berlin > /etc/timezone - -WORKDIR /app \ No newline at end of file +RUN echo Europe/Berlin > /etc/timezone \ No newline at end of file diff --git a/core/jvm/test/testcontainers/debian-jessie/incorrect-timezone.dockerfile b/core/jvm/test/testcontainers/debian-jessie/incorrect-timezone.dockerfile index 9de111408..804f903a2 100644 --- a/core/jvm/test/testcontainers/debian-jessie/incorrect-timezone.dockerfile +++ b/core/jvm/test/testcontainers/debian-jessie/incorrect-timezone.dockerfile @@ -2,6 +2,4 @@ FROM --platform=linux/arm64 debian/eol:jessie ENV INSIDE_TESTCONTAINERS=true -RUN echo incorrect/data > /etc/timezone - -WORKDIR /app \ No newline at end of file +RUN echo incorrect/data > /etc/timezone \ No newline at end of file diff --git a/core/jvm/test/testcontainers/debian-jessie/missing-localtime.dockerfile b/core/jvm/test/testcontainers/debian-jessie/missing-localtime.dockerfile index 83fb41bc1..1efea7d9c 100644 --- a/core/jvm/test/testcontainers/debian-jessie/missing-localtime.dockerfile +++ b/core/jvm/test/testcontainers/debian-jessie/missing-localtime.dockerfile @@ -2,6 +2,4 @@ FROM --platform=linux/arm64 debian/eol:jessie ENV INSIDE_TESTCONTAINERS=true -RUN rm -f /etc/localtime - -WORKDIR /app \ No newline at end of file +RUN rm -f /etc/localtime \ No newline at end of file diff --git a/core/jvm/test/testcontainers/debian-jessie/missing-timezone.dockerfile b/core/jvm/test/testcontainers/debian-jessie/missing-timezone.dockerfile index 3aad47270..357898b26 100644 --- a/core/jvm/test/testcontainers/debian-jessie/missing-timezone.dockerfile +++ b/core/jvm/test/testcontainers/debian-jessie/missing-timezone.dockerfile @@ -2,6 +2,4 @@ FROM --platform=linux/arm64 debian/eol:jessie ENV INSIDE_TESTCONTAINERS=true -RUN rm -f /etc/timezone - -WORKDIR /app \ No newline at end of file +RUN rm -f /etc/timezone \ No newline at end of file diff --git a/core/jvm/test/testcontainers/ubuntu-noble/correct-config.dockerfile b/core/jvm/test/testcontainers/ubuntu-noble/correct-config.dockerfile index 7159de8bf..bb1f0928b 100644 --- a/core/jvm/test/testcontainers/ubuntu-noble/correct-config.dockerfile +++ b/core/jvm/test/testcontainers/ubuntu-noble/correct-config.dockerfile @@ -5,6 +5,4 @@ ENV INSIDE_TESTCONTAINERS=true RUN apt-get update && apt-get install -y tzdata # 4: Arctic/Longyearbyen -RUN echo 4 | dpkg-reconfigure tzdata - -WORKDIR /app \ No newline at end of file +RUN echo 4 | dpkg-reconfigure tzdata \ No newline at end of file diff --git a/core/jvm/test/testcontainers/ubuntu-noble/default-config.dockerfile b/core/jvm/test/testcontainers/ubuntu-noble/default-config.dockerfile index 91709036c..32aaa7987 100644 --- a/core/jvm/test/testcontainers/ubuntu-noble/default-config.dockerfile +++ b/core/jvm/test/testcontainers/ubuntu-noble/default-config.dockerfile @@ -1,5 +1,3 @@ FROM --platform=linux/arm64 ubuntu:24.04 -ENV INSIDE_TESTCONTAINERS=true - -WORKDIR /app \ No newline at end of file +ENV INSIDE_TESTCONTAINERS=true \ No newline at end of file diff --git a/core/jvm/test/testcontainers/ubuntu-noble/incorrect-symlink.dockerfile b/core/jvm/test/testcontainers/ubuntu-noble/incorrect-symlink.dockerfile index d3a3d92f5..7ccc80446 100644 --- a/core/jvm/test/testcontainers/ubuntu-noble/incorrect-symlink.dockerfile +++ b/core/jvm/test/testcontainers/ubuntu-noble/incorrect-symlink.dockerfile @@ -2,6 +2,4 @@ FROM --platform=linux/arm64 ubuntu:24.04 ENV INSIDE_TESTCONTAINERS=true -RUN ln -s /app /etc/localtime - -WORKDIR /app \ No newline at end of file +RUN ln -s / /etc/localtime \ No newline at end of file From d6aa9236163d17bdc86e1355bc82be7f405b9321 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 24 Mar 2025 15:27:42 +0400 Subject: [PATCH 53/82] #430: Remove logging duplication --- core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt index c2533d4a7..ca7d61e0c 100644 --- a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt @@ -102,15 +102,11 @@ class TimeZoneConfigurationTest { private fun assertExecSuccess(execResult: ExecResult) { logger.info("Container stdout:\n${execResult.stdout}") - logger.info("Container stderr:\n${execResult.stderr}") - logger.info("Container exit code: ${execResult.exitCode}") if (execResult.exitCode != 0) { throw AssertionError( """ |Command execution failed with exit code ${execResult.exitCode}. - |Stdout: - |${execResult.stdout} |Stderr: |${execResult.stderr} """.trimMargin() From d7acacaf4a435d3524f96df70ae74ec2894380bc Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 24 Mar 2025 15:30:32 +0400 Subject: [PATCH 54/82] #430: Add comment to currentSystemDefaultZone --- core/linux/src/internal/TimeZoneNative.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/linux/src/internal/TimeZoneNative.kt b/core/linux/src/internal/TimeZoneNative.kt index df5669b29..71c46cff7 100644 --- a/core/linux/src/internal/TimeZoneNative.kt +++ b/core/linux/src/internal/TimeZoneNative.kt @@ -43,6 +43,9 @@ private fun getTimezoneFromEtcTimezone(): String? { } internal actual fun currentSystemDefaultZone(): Pair { + // According to https://www.man7.org/linux/man-pages/man5/localtime.5.html, UTC is used when /etc/localtime is missing. + // If /etc/localtime exists but isn't a symlink, we check if it's a copy of a timezone file by examining /etc/timezone + // (which is a Debian-specific approach used in older distributions). val zonePath = currentSystemTimeZonePath ?: return "Z" to null zonePath.splitTimeZonePath()?.second?.toString()?.let { zoneId -> From 27d73061c5066fa786318031d5d1ee3159b08869 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Tue, 25 Mar 2025 11:18:20 +0400 Subject: [PATCH 55/82] #430: Add internal root field --- core/linux/src/internal/TimeZoneNative.kt | 12 ++++++------ .../src/internal/TzdbOnFilesystem.kt | 4 +++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/core/linux/src/internal/TimeZoneNative.kt b/core/linux/src/internal/TimeZoneNative.kt index 71c46cff7..b9ee49304 100644 --- a/core/linux/src/internal/TimeZoneNative.kt +++ b/core/linux/src/internal/TimeZoneNative.kt @@ -20,13 +20,13 @@ private val tzdb = runCatching { TzdbOnFilesystem() } @OptIn(ExperimentalForeignApi::class) private fun getTimezoneFromEtcTimezone(): String? { - val timezoneContent = Path.fromString("/etc/timezone").readBytes()?.toKString()?.trim() ?: return null - val zoneId = chaseSymlinks("/usr/share/zoneinfo/$timezoneContent") + val timezoneContent = Path.fromString("${root}etc/timezone").readBytes()?.toKString()?.trim() ?: return null + val zoneId = chaseSymlinks("${root}usr/share/zoneinfo/$timezoneContent") ?.splitTimeZonePath()?.second?.toString() ?: return null - val zoneInfoBytes = Path.fromString("/usr/share/zoneinfo/$zoneId").readBytes() ?: return null - val localtimeBytes = Path.fromString("/etc/localtime").readBytes() ?: return null + val zoneInfoBytes = Path.fromString("${root}usr/share/zoneinfo/$zoneId").readBytes() ?: return null + val localtimeBytes = Path.fromString("${root}etc/localtime").readBytes() ?: return null if (!localtimeBytes.contentEquals(zoneInfoBytes)) { val displayTimezone = when (timezoneContent) { @@ -34,8 +34,8 @@ private fun getTimezoneFromEtcTimezone(): String? { else -> "'$timezoneContent' (resolved to '$zoneId')" } throw IllegalTimeZoneException( - "Timezone mismatch: /etc/timezone specifies $displayTimezone " + - "but /etc/localtime content differs from /usr/share/zoneinfo/$zoneId" + "Timezone mismatch: ${root}etc/timezone specifies $displayTimezone " + + "but ${root}etc/localtime content differs from ${root}usr/share/zoneinfo/$zoneId" ) } diff --git a/core/tzdbOnFilesystem/src/internal/TzdbOnFilesystem.kt b/core/tzdbOnFilesystem/src/internal/TzdbOnFilesystem.kt index 0032197a1..229323419 100644 --- a/core/tzdbOnFilesystem/src/internal/TzdbOnFilesystem.kt +++ b/core/tzdbOnFilesystem/src/internal/TzdbOnFilesystem.kt @@ -47,7 +47,9 @@ internal fun tzdbPaths(defaultTzdbPath: Path?) = sequence { currentSystemTimeZonePath?.splitTimeZonePath()?.first?.let { yield(it) } } -internal val currentSystemTimeZonePath get() = chaseSymlinks("/etc/localtime") +internal var root: String = "/" + +internal val currentSystemTimeZonePath get() = chaseSymlinks("${root}etc/localtime") /** * Given a path like `/usr/share/zoneinfo/Europe/Berlin`, produces `/usr/share/zoneinfo to Europe/Berlin`. From 816f2affed4826d6c7631100071f7e4762e49f6f Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Wed, 26 Mar 2025 18:21:58 +0400 Subject: [PATCH 56/82] #430: Add correctSymlinkTest --- core/linux/test/TimeZoneNativeTest.kt | 22 ++++++++++++++++++ .../correct-symlink/etc/localtime | 1 + .../usr/share/zoneinfo/Europe/Oslo | Bin 0 -> 2228 bytes 3 files changed, 23 insertions(+) create mode 100644 core/linux/test/TimeZoneNativeTest.kt create mode 120000 core/linux/test/time-zone-native-test-resources/correct-symlink/etc/localtime create mode 100644 core/linux/test/time-zone-native-test-resources/correct-symlink/usr/share/zoneinfo/Europe/Oslo diff --git a/core/linux/test/TimeZoneNativeTest.kt b/core/linux/test/TimeZoneNativeTest.kt new file mode 100644 index 000000000..fb8f16f46 --- /dev/null +++ b/core/linux/test/TimeZoneNativeTest.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2019-2025 JetBrains s.r.o. and contributors. + * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. + */ + +package kotlinx.datetime.test + +import kotlinx.datetime.TimeZone +import kotlinx.datetime.internal.root +import kotlin.test.Test +import kotlin.test.assertEquals + +class TimeZoneNativeTest { + + @Test + fun correctSymlinkTest() { + root = "./core/linux/test/time-zone-native-test-resources/correct-symlink/" + + val tz = TimeZone.currentSystemDefault() + assertEquals(TimeZone.of("Europe/Oslo"), tz) + } +} \ No newline at end of file diff --git a/core/linux/test/time-zone-native-test-resources/correct-symlink/etc/localtime b/core/linux/test/time-zone-native-test-resources/correct-symlink/etc/localtime new file mode 120000 index 000000000..302adea9f --- /dev/null +++ b/core/linux/test/time-zone-native-test-resources/correct-symlink/etc/localtime @@ -0,0 +1 @@ +../usr/share/zoneinfo/Europe/Oslo \ No newline at end of file diff --git a/core/linux/test/time-zone-native-test-resources/correct-symlink/usr/share/zoneinfo/Europe/Oslo b/core/linux/test/time-zone-native-test-resources/correct-symlink/usr/share/zoneinfo/Europe/Oslo new file mode 100644 index 0000000000000000000000000000000000000000..15a34c3cedb7c9ca519c195f5ec0ce9d8d1885a5 GIT binary patch literal 2228 zcmdtiUrd#C9LMp4h!iXLF@<9RLLs4r{0IL8nH_C^m}%m*Ry9k7iT-4 zcWA|i+8p2CPPBW&hx3^G@O5K9#*!!t)WmCH>KQ8zjHx8*Ju6N5 zT&06wX;I{xTGZF0n+9Ic;?9>;*87G9ceQHCf#>Yzh6dfzy3Ll}_NXnZUuWgB>n&7P zYPb5A*z)w5wtO_pDq>4i@$qGL`^XHfcigfP10_yE9$h`i(a+$iDv7+e#+{`!nUEO+3q|Yvb*-LwEA~9>h7II*3eO| zd+L(x-W~bcxU^8=TEFhgo~BL3KkNQUJ~d{>TI0|cYMMA|O~>C+^WZ6a;FS(-?(4QK zyWg^{oqO!T=6%+(tHs7ejEjgI{|{Hxg#Z5X`C_KH|FAD1IbyueH&MQe|GfY4=CAi< z!H_RdT+S`THzM3Y_YnFQi}}r+@Zj`%WI3L0J;;KP6(LJP)`TnySrxJ@WL?O@kd+}z zL)L~Y4p|+tJY;>y0+AIWOGMU)EYj1hl3&g;k#!;qMOKO|)zhsNSuC Date: Wed, 26 Mar 2025 18:31:33 +0400 Subject: [PATCH 57/82] #430: Add TimeZoneConfigurationTest Ignore --- core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt index ca7d61e0c..32333ea19 100644 --- a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt +++ b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt @@ -5,6 +5,7 @@ package testcontainers +import org.junit.Ignore import org.junit.jupiter.api.BeforeAll import org.testcontainers.junit.jupiter.Container import org.testcontainers.junit.jupiter.Testcontainers @@ -14,6 +15,7 @@ import org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS import org.slf4j.LoggerFactory import org.testcontainers.containers.Container.ExecResult +@Ignore @Testcontainers(disabledWithoutDocker = true) @TestInstance(PER_CLASS) class TimeZoneConfigurationTest { From 2964b49ca801f1cf8ec9210482c813f1352a28b7 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Wed, 26 Mar 2025 18:38:11 +0400 Subject: [PATCH 58/82] #430: Add fallsBackToUTC test --- core/linux/test/TimeZoneNativeTest.kt | 8 ++++++++ .../usr/share/zoneinfo/Europe/Oslo | Bin 0 -> 2228 bytes 2 files changed, 8 insertions(+) create mode 100644 core/linux/test/time-zone-native-test-resources/missing-localtime/usr/share/zoneinfo/Europe/Oslo diff --git a/core/linux/test/TimeZoneNativeTest.kt b/core/linux/test/TimeZoneNativeTest.kt index fb8f16f46..21768b251 100644 --- a/core/linux/test/TimeZoneNativeTest.kt +++ b/core/linux/test/TimeZoneNativeTest.kt @@ -19,4 +19,12 @@ class TimeZoneNativeTest { val tz = TimeZone.currentSystemDefault() assertEquals(TimeZone.of("Europe/Oslo"), tz) } + + @Test + fun fallsBackToUTC() { + root = "./core/linux/test/time-zone-native-test-resources/missing-localtime/" + + val tz = TimeZone.currentSystemDefault() + assertEquals(TimeZone.UTC, tz) + } } \ No newline at end of file diff --git a/core/linux/test/time-zone-native-test-resources/missing-localtime/usr/share/zoneinfo/Europe/Oslo b/core/linux/test/time-zone-native-test-resources/missing-localtime/usr/share/zoneinfo/Europe/Oslo new file mode 100644 index 0000000000000000000000000000000000000000..15a34c3cedb7c9ca519c195f5ec0ce9d8d1885a5 GIT binary patch literal 2228 zcmdtiUrd#C9LMp4h!iXLF@<9RLLs4r{0IL8nH_C^m}%m*Ry9k7iT-4 zcWA|i+8p2CPPBW&hx3^G@O5K9#*!!t)WmCH>KQ8zjHx8*Ju6N5 zT&06wX;I{xTGZF0n+9Ic;?9>;*87G9ceQHCf#>Yzh6dfzy3Ll}_NXnZUuWgB>n&7P zYPb5A*z)w5wtO_pDq>4i@$qGL`^XHfcigfP10_yE9$h`i(a+$iDv7+e#+{`!nUEO+3q|Yvb*-LwEA~9>h7II*3eO| zd+L(x-W~bcxU^8=TEFhgo~BL3KkNQUJ~d{>TI0|cYMMA|O~>C+^WZ6a;FS(-?(4QK zyWg^{oqO!T=6%+(tHs7ejEjgI{|{Hxg#Z5X`C_KH|FAD1IbyueH&MQe|GfY4=CAi< z!H_RdT+S`THzM3Y_YnFQi}}r+@Zj`%WI3L0J;;KP6(LJP)`TnySrxJ@WL?O@kd+}z zL)L~Y4p|+tJY;>y0+AIWOGMU)EYj1hl3&g;k#!;qMOKO|)zhsNSuC Date: Wed, 26 Mar 2025 18:59:22 +0400 Subject: [PATCH 59/82] #430: Add pwd --- core/linux/test/TimeZoneNativeTest.kt | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/core/linux/test/TimeZoneNativeTest.kt b/core/linux/test/TimeZoneNativeTest.kt index 21768b251..b8e61de94 100644 --- a/core/linux/test/TimeZoneNativeTest.kt +++ b/core/linux/test/TimeZoneNativeTest.kt @@ -5,19 +5,42 @@ package kotlinx.datetime.test +import kotlinx.cinterop.ByteVar +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.UnsafeNumber +import kotlinx.cinterop.allocArray +import kotlinx.cinterop.convert +import kotlinx.cinterop.memScoped +import kotlinx.cinterop.toKString import kotlinx.datetime.TimeZone import kotlinx.datetime.internal.root import kotlin.test.Test import kotlin.test.assertEquals +import platform.posix.* class TimeZoneNativeTest { + @OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) + private fun pwd(): String { + val PATH_MAX = 4096 + return memScoped { + val buffer = allocArray(PATH_MAX) + if (getcwd(buffer, PATH_MAX.convert()) != null) { + buffer.toKString() + } else { + throw Exception("Failed to get current directory: ${strerror(errno)?.toKString()}") + } + } + } + @Test fun correctSymlinkTest() { root = "./core/linux/test/time-zone-native-test-resources/correct-symlink/" + println("PWD: ${pwd()}") + val tz = TimeZone.currentSystemDefault() - assertEquals(TimeZone.of("Europe/Oslo"), tz) + assertEquals(TimeZone.of("Europe/Oslo"), tz, "PWD: ${pwd()}") } @Test From 12f56d9cf29e4af969dc1c2900d0f81f72f82012 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Wed, 26 Mar 2025 19:26:45 +0400 Subject: [PATCH 60/82] #430: Remove 'core' from path --- core/linux/test/TimeZoneNativeTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/linux/test/TimeZoneNativeTest.kt b/core/linux/test/TimeZoneNativeTest.kt index b8e61de94..0fe37ddbc 100644 --- a/core/linux/test/TimeZoneNativeTest.kt +++ b/core/linux/test/TimeZoneNativeTest.kt @@ -35,7 +35,7 @@ class TimeZoneNativeTest { @Test fun correctSymlinkTest() { - root = "./core/linux/test/time-zone-native-test-resources/correct-symlink/" + root = "./linux/test/time-zone-native-test-resources/correct-symlink/" println("PWD: ${pwd()}") @@ -45,7 +45,7 @@ class TimeZoneNativeTest { @Test fun fallsBackToUTC() { - root = "./core/linux/test/time-zone-native-test-resources/missing-localtime/" + root = "./linux/test/time-zone-native-test-resources/missing-localtime/" val tz = TimeZone.currentSystemDefault() assertEquals(TimeZone.UTC, tz) From bf689b38571981d5148efc07a6e2a1f1728118b7 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Thu, 27 Mar 2025 14:42:28 +0400 Subject: [PATCH 61/82] #430: Add missingTimezoneTest --- core/linux/test/TimeZoneNativeTest.kt | 25 +++++++++++++++++-- .../missing-timezone/etc/localtime | 1 + 2 files changed, 24 insertions(+), 2 deletions(-) create mode 120000 core/linux/test/time-zone-native-test-resources/missing-timezone/etc/localtime diff --git a/core/linux/test/TimeZoneNativeTest.kt b/core/linux/test/TimeZoneNativeTest.kt index 0fe37ddbc..5e928e0dd 100644 --- a/core/linux/test/TimeZoneNativeTest.kt +++ b/core/linux/test/TimeZoneNativeTest.kt @@ -12,11 +12,14 @@ import kotlinx.cinterop.allocArray import kotlinx.cinterop.convert import kotlinx.cinterop.memScoped import kotlinx.cinterop.toKString +import kotlinx.datetime.IllegalTimeZoneException import kotlinx.datetime.TimeZone import kotlinx.datetime.internal.root import kotlin.test.Test import kotlin.test.assertEquals import platform.posix.* +import kotlin.test.assertFailsWith +import kotlin.test.assertTrue class TimeZoneNativeTest { @@ -35,7 +38,7 @@ class TimeZoneNativeTest { @Test fun correctSymlinkTest() { - root = "./linux/test/time-zone-native-test-resources/correct-symlink/" + root = "${RESOURCES}correct-symlink/" println("PWD: ${pwd()}") @@ -45,9 +48,27 @@ class TimeZoneNativeTest { @Test fun fallsBackToUTC() { - root = "./linux/test/time-zone-native-test-resources/missing-localtime/" + root = "${RESOURCES}missing-localtime/" val tz = TimeZone.currentSystemDefault() assertEquals(TimeZone.UTC, tz) } + + @Test + fun missingTimezoneTest() { + root = "${RESOURCES}missing-timezone/" + + val exception = assertFailsWith { + TimeZone.currentSystemDefault() + } + + assertTrue( + exception.message?.startsWith("Could not determine the timezone ID") == true, + "Exception message did not match" + ) + } + + companion object { + const val RESOURCES = "./linux/test/time-zone-native-test-resources/" + } } \ No newline at end of file diff --git a/core/linux/test/time-zone-native-test-resources/missing-timezone/etc/localtime b/core/linux/test/time-zone-native-test-resources/missing-timezone/etc/localtime new file mode 120000 index 000000000..cad230910 --- /dev/null +++ b/core/linux/test/time-zone-native-test-resources/missing-timezone/etc/localtime @@ -0,0 +1 @@ +/tmp \ No newline at end of file From ed277ba21a46ddbd5773d82d982b8825a4b44ab6 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Thu, 27 Mar 2025 15:07:34 +0400 Subject: [PATCH 62/82] #430: Add incorrectTimezoneTest --- core/linux/test/TimeZoneNativeTest.kt | 14 ++++++++++++++ .../incorrect-timezone/etc/localtime | 0 .../incorrect-timezone/etc/timezone | 1 + .../missing-timezone/etc/localtime | 1 - 4 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 core/linux/test/time-zone-native-test-resources/incorrect-timezone/etc/localtime create mode 100644 core/linux/test/time-zone-native-test-resources/incorrect-timezone/etc/timezone mode change 120000 => 100644 core/linux/test/time-zone-native-test-resources/missing-timezone/etc/localtime diff --git a/core/linux/test/TimeZoneNativeTest.kt b/core/linux/test/TimeZoneNativeTest.kt index 5e928e0dd..b478bac80 100644 --- a/core/linux/test/TimeZoneNativeTest.kt +++ b/core/linux/test/TimeZoneNativeTest.kt @@ -68,6 +68,20 @@ class TimeZoneNativeTest { ) } + @Test + fun incorrectTimezoneTest() { + root = "${RESOURCES}incorrect-timezone/" + + val exception = assertFailsWith { + TimeZone.currentSystemDefault() + } + + assertTrue( + exception.message?.startsWith("Could not determine the timezone ID") == true, + "Exception message did not match" + ) + } + companion object { const val RESOURCES = "./linux/test/time-zone-native-test-resources/" } diff --git a/core/linux/test/time-zone-native-test-resources/incorrect-timezone/etc/localtime b/core/linux/test/time-zone-native-test-resources/incorrect-timezone/etc/localtime new file mode 100644 index 000000000..e69de29bb diff --git a/core/linux/test/time-zone-native-test-resources/incorrect-timezone/etc/timezone b/core/linux/test/time-zone-native-test-resources/incorrect-timezone/etc/timezone new file mode 100644 index 000000000..6bdbd727d --- /dev/null +++ b/core/linux/test/time-zone-native-test-resources/incorrect-timezone/etc/timezone @@ -0,0 +1 @@ +incorrect/timezone diff --git a/core/linux/test/time-zone-native-test-resources/missing-timezone/etc/localtime b/core/linux/test/time-zone-native-test-resources/missing-timezone/etc/localtime deleted file mode 120000 index cad230910..000000000 --- a/core/linux/test/time-zone-native-test-resources/missing-timezone/etc/localtime +++ /dev/null @@ -1 +0,0 @@ -/tmp \ No newline at end of file diff --git a/core/linux/test/time-zone-native-test-resources/missing-timezone/etc/localtime b/core/linux/test/time-zone-native-test-resources/missing-timezone/etc/localtime new file mode 100644 index 000000000..e69de29bb From 6cb1b0c714e88d0287ab3c82f29f933bc7f8a182 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Thu, 27 Mar 2025 15:08:40 +0400 Subject: [PATCH 63/82] #430: Remove Oslo file from missing-localtime test --- .../usr/share/zoneinfo/Europe/Oslo | Bin 2228 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 core/linux/test/time-zone-native-test-resources/missing-localtime/usr/share/zoneinfo/Europe/Oslo diff --git a/core/linux/test/time-zone-native-test-resources/missing-localtime/usr/share/zoneinfo/Europe/Oslo b/core/linux/test/time-zone-native-test-resources/missing-localtime/usr/share/zoneinfo/Europe/Oslo deleted file mode 100644 index 15a34c3cedb7c9ca519c195f5ec0ce9d8d1885a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2228 zcmdtiUrd#C9LMp4h!iXLF@<9RLLs4r{0IL8nH_C^m}%m*Ry9k7iT-4 zcWA|i+8p2CPPBW&hx3^G@O5K9#*!!t)WmCH>KQ8zjHx8*Ju6N5 zT&06wX;I{xTGZF0n+9Ic;?9>;*87G9ceQHCf#>Yzh6dfzy3Ll}_NXnZUuWgB>n&7P zYPb5A*z)w5wtO_pDq>4i@$qGL`^XHfcigfP10_yE9$h`i(a+$iDv7+e#+{`!nUEO+3q|Yvb*-LwEA~9>h7II*3eO| zd+L(x-W~bcxU^8=TEFhgo~BL3KkNQUJ~d{>TI0|cYMMA|O~>C+^WZ6a;FS(-?(4QK zyWg^{oqO!T=6%+(tHs7ejEjgI{|{Hxg#Z5X`C_KH|FAD1IbyueH&MQe|GfY4=CAi< z!H_RdT+S`THzM3Y_YnFQi}}r+@Zj`%WI3L0J;;KP6(LJP)`TnySrxJ@WL?O@kd+}z zL)L~Y4p|+tJY;>y0+AIWOGMU)EYj1hl3&g;k#!;qMOKO|)zhsNSuC Date: Thu, 27 Mar 2025 15:14:01 +0400 Subject: [PATCH 64/82] #430: Add differentTimezonesTest --- core/linux/test/TimeZoneNativeTest.kt | 14 ++++++++++++++ .../different-timezones/etc/localtime | Bin 0 -> 2298 bytes .../usr/share/zoneinfo/Europe/Berlin | Bin 0 -> 2298 bytes .../usr/share/zoneinfo/Europe/Oslo | Bin 0 -> 2228 bytes 4 files changed, 14 insertions(+) create mode 100644 core/linux/test/time-zone-native-test-resources/different-timezones/etc/localtime create mode 100644 core/linux/test/time-zone-native-test-resources/different-timezones/usr/share/zoneinfo/Europe/Berlin create mode 100644 core/linux/test/time-zone-native-test-resources/different-timezones/usr/share/zoneinfo/Europe/Oslo diff --git a/core/linux/test/TimeZoneNativeTest.kt b/core/linux/test/TimeZoneNativeTest.kt index b478bac80..2f7043db5 100644 --- a/core/linux/test/TimeZoneNativeTest.kt +++ b/core/linux/test/TimeZoneNativeTest.kt @@ -82,6 +82,20 @@ class TimeZoneNativeTest { ) } + @Test + fun differentTimezonesTest() = Testcontainers.runIfAvailable { + root = "${RESOURCES}different-timezones/" + + val exception = assertFailsWith { + TimeZone.currentSystemDefault() + } + + assertTrue( + exception.message?.startsWith("Timezone mismatch") == true, + "Exception message did not start with 'Timezone mismatch'" + ) + } + companion object { const val RESOURCES = "./linux/test/time-zone-native-test-resources/" } diff --git a/core/linux/test/time-zone-native-test-resources/different-timezones/etc/localtime b/core/linux/test/time-zone-native-test-resources/different-timezones/etc/localtime new file mode 100644 index 0000000000000000000000000000000000000000..7f6d958f8630cba512d8e58ca8edfbd516291522 GIT binary patch literal 2298 zcmd_qe@xVM9LMqR@gs$id#k~jfKV49cEa&9G05x$W^kHv8L5N>f)-(%#-KDTnRAWV zyT))1$saLh&944HTSIO3YqXF=yX-92mMgNFb2F#aSbd(~wrcCI{^_4Sci->hd-vz< zUQhqZ^$j`JKTeGKhKuupxpfX*>IvmrYBje?A z@>Qpf9`MR1FXhRp=h9>>kRW46daTn`$G4u|zf{iDCF-Z;E)5lqrG^^EHFR*J^;yQC zoOREX&trNd9C1R!7u#gIZ;{-T`-{fAe$a&JU#c_mq&lx0*BKYy(3{Wf)0ywRsEJ39 zNz$R9B=6ZPv$|ALHa{z=O#!)Ob)DQ=;TKm?iQMKckhG+9xjk-%q(^%-{c4`h{w7T` zLJ2zOgGqYF;B|HPU(~tX=QOkPW6j!hR6X^tYj$;5asq>rTRbFr%X=h0xlamm+N5Bj zL*^xR>%8-|Quu4D&OhdryS}K>qJbJM9-6OrZ(pbjdXw~?2A3}EER=goqt#oVD2vj@ zwZuCirO_X0nd>VlyY#IrjyxfYM~CIU3$I9d@HMFzc}IOayJX3s{kpWdS?=%Jrpq3D zUY9qm)yg}Y)L&7i4>*_T3U`LCxaQHS_)@7lJ53+DI$KsA`AJuWVrBKdsZu@oqdeSk zMQXZ7Wlc>;YPWo^k1Tjg>Z(VyK4rJ8Ee>kK;FOKovt(1r&+_C{OIowywe|AX(l+Iqww-!k z+AoFmsW%7Y>CqwGy!&0<6717w+WWO*XNN{OA|j*yd__BWzQMjnO`81Qzbq?mhxs>K zNvVz~%bFtm!T;5E&sdL|ZdPWRSLIl*llVaUuh?H6yh(Lq*1l z3>FzJGF)3TUVaG%jEoo=GBRdl(6(mO$gq)dBLhc9jtm_cJ2H4=^vLj$@go61B7lSd zi2)J>Bnq}B3`iW1Kp>GoLV?5r2?i1kBpgUQkboc&K|+GW1PKZf6*ovf`dc{2@etf)-(%#-KDTnRAWV zyT))1$saLh&944HTSIO3YqXF=yX-92mMgNFb2F#aSbd(~wrcCI{^_4Sci->hd-vz< zUQhqZ^$j`JKTeGKhKuupxpfX*>IvmrYBje?A z@>Qpf9`MR1FXhRp=h9>>kRW46daTn`$G4u|zf{iDCF-Z;E)5lqrG^^EHFR*J^;yQC zoOREX&trNd9C1R!7u#gIZ;{-T`-{fAe$a&JU#c_mq&lx0*BKYy(3{Wf)0ywRsEJ39 zNz$R9B=6ZPv$|ALHa{z=O#!)Ob)DQ=;TKm?iQMKckhG+9xjk-%q(^%-{c4`h{w7T` zLJ2zOgGqYF;B|HPU(~tX=QOkPW6j!hR6X^tYj$;5asq>rTRbFr%X=h0xlamm+N5Bj zL*^xR>%8-|Quu4D&OhdryS}K>qJbJM9-6OrZ(pbjdXw~?2A3}EER=goqt#oVD2vj@ zwZuCirO_X0nd>VlyY#IrjyxfYM~CIU3$I9d@HMFzc}IOayJX3s{kpWdS?=%Jrpq3D zUY9qm)yg}Y)L&7i4>*_T3U`LCxaQHS_)@7lJ53+DI$KsA`AJuWVrBKdsZu@oqdeSk zMQXZ7Wlc>;YPWo^k1Tjg>Z(VyK4rJ8Ee>kK;FOKovt(1r&+_C{OIowywe|AX(l+Iqww-!k z+AoFmsW%7Y>CqwGy!&0<6717w+WWO*XNN{OA|j*yd__BWzQMjnO`81Qzbq?mhxs>K zNvVz~%bFtm!T;5E&sdL|ZdPWRSLIl*llVaUuh?H6yh(Lq*1l z3>FzJGF)3TUVaG%jEoo=GBRdl(6(mO$gq)dBLhc9jtm_cJ2H4=^vLj$@go61B7lSd zi2)J>Bnq}B3`iW1Kp>GoLV?5r2?i1kBpgUQkboc&K|+GW1PKZf6*ovf`dc{2@etC^m}%m*Ry9k7iT-4 zcWA|i+8p2CPPBW&hx3^G@O5K9#*!!t)WmCH>KQ8zjHx8*Ju6N5 zT&06wX;I{xTGZF0n+9Ic;?9>;*87G9ceQHCf#>Yzh6dfzy3Ll}_NXnZUuWgB>n&7P zYPb5A*z)w5wtO_pDq>4i@$qGL`^XHfcigfP10_yE9$h`i(a+$iDv7+e#+{`!nUEO+3q|Yvb*-LwEA~9>h7II*3eO| zd+L(x-W~bcxU^8=TEFhgo~BL3KkNQUJ~d{>TI0|cYMMA|O~>C+^WZ6a;FS(-?(4QK zyWg^{oqO!T=6%+(tHs7ejEjgI{|{Hxg#Z5X`C_KH|FAD1IbyueH&MQe|GfY4=CAi< z!H_RdT+S`THzM3Y_YnFQi}}r+@Zj`%WI3L0J;;KP6(LJP)`TnySrxJ@WL?O@kd+}z zL)L~Y4p|+tJY;>y0+AIWOGMU)EYj1hl3&g;k#!;qMOKO|)zhsNSuC Date: Thu, 27 Mar 2025 15:23:48 +0400 Subject: [PATCH 65/82] #430: Add differentTimezonesTest --- core/linux/test/TimeZoneNativeTest.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/linux/test/TimeZoneNativeTest.kt b/core/linux/test/TimeZoneNativeTest.kt index 2f7043db5..74e6d42cd 100644 --- a/core/linux/test/TimeZoneNativeTest.kt +++ b/core/linux/test/TimeZoneNativeTest.kt @@ -46,6 +46,14 @@ class TimeZoneNativeTest { assertEquals(TimeZone.of("Europe/Oslo"), tz, "PWD: ${pwd()}") } + @Test + fun correctLocaltimeCopyTest() { + root = "${RESOURCES}correct-localtime-copy/" + + val tz = TimeZone.currentSystemDefault() + assertEquals(TimeZone.of("Europe/Oslo"), tz) + } + @Test fun fallsBackToUTC() { root = "${RESOURCES}missing-localtime/" From da587752b5e80696d60eb975add62b60fe7ec920 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Thu, 27 Mar 2025 15:24:24 +0400 Subject: [PATCH 66/82] #430: Remove pwd --- core/linux/test/TimeZoneNativeTest.kt | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/core/linux/test/TimeZoneNativeTest.kt b/core/linux/test/TimeZoneNativeTest.kt index 74e6d42cd..3dded83ab 100644 --- a/core/linux/test/TimeZoneNativeTest.kt +++ b/core/linux/test/TimeZoneNativeTest.kt @@ -5,45 +5,22 @@ package kotlinx.datetime.test -import kotlinx.cinterop.ByteVar -import kotlinx.cinterop.ExperimentalForeignApi -import kotlinx.cinterop.UnsafeNumber -import kotlinx.cinterop.allocArray -import kotlinx.cinterop.convert -import kotlinx.cinterop.memScoped -import kotlinx.cinterop.toKString import kotlinx.datetime.IllegalTimeZoneException import kotlinx.datetime.TimeZone import kotlinx.datetime.internal.root import kotlin.test.Test import kotlin.test.assertEquals -import platform.posix.* import kotlin.test.assertFailsWith import kotlin.test.assertTrue class TimeZoneNativeTest { - @OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) - private fun pwd(): String { - val PATH_MAX = 4096 - return memScoped { - val buffer = allocArray(PATH_MAX) - if (getcwd(buffer, PATH_MAX.convert()) != null) { - buffer.toKString() - } else { - throw Exception("Failed to get current directory: ${strerror(errno)?.toKString()}") - } - } - } - @Test fun correctSymlinkTest() { root = "${RESOURCES}correct-symlink/" - println("PWD: ${pwd()}") - val tz = TimeZone.currentSystemDefault() - assertEquals(TimeZone.of("Europe/Oslo"), tz, "PWD: ${pwd()}") + assertEquals(TimeZone.of("Europe/Oslo"), tz) } @Test From 1180d0321542d77c8c6049f429bbd66cf2cfcfb2 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Thu, 27 Mar 2025 15:25:33 +0400 Subject: [PATCH 67/82] #430: Add test related files --- .../correct-localtime-copy/etc/localtime | Bin 0 -> 2228 bytes .../correct-localtime-copy/etc/timezone | 1 + .../usr/share/zoneinfo/Europe/Oslo | Bin 0 -> 2228 bytes .../different-timezones/etc/timezone | 1 + 4 files changed, 2 insertions(+) create mode 100644 core/linux/test/time-zone-native-test-resources/correct-localtime-copy/etc/localtime create mode 100644 core/linux/test/time-zone-native-test-resources/correct-localtime-copy/etc/timezone create mode 100644 core/linux/test/time-zone-native-test-resources/correct-localtime-copy/usr/share/zoneinfo/Europe/Oslo create mode 100644 core/linux/test/time-zone-native-test-resources/different-timezones/etc/timezone diff --git a/core/linux/test/time-zone-native-test-resources/correct-localtime-copy/etc/localtime b/core/linux/test/time-zone-native-test-resources/correct-localtime-copy/etc/localtime new file mode 100644 index 0000000000000000000000000000000000000000..15a34c3cedb7c9ca519c195f5ec0ce9d8d1885a5 GIT binary patch literal 2228 zcmdtiUrd#C9LMp4h!iXLF@<9RLLs4r{0IL8nH_C^m}%m*Ry9k7iT-4 zcWA|i+8p2CPPBW&hx3^G@O5K9#*!!t)WmCH>KQ8zjHx8*Ju6N5 zT&06wX;I{xTGZF0n+9Ic;?9>;*87G9ceQHCf#>Yzh6dfzy3Ll}_NXnZUuWgB>n&7P zYPb5A*z)w5wtO_pDq>4i@$qGL`^XHfcigfP10_yE9$h`i(a+$iDv7+e#+{`!nUEO+3q|Yvb*-LwEA~9>h7II*3eO| zd+L(x-W~bcxU^8=TEFhgo~BL3KkNQUJ~d{>TI0|cYMMA|O~>C+^WZ6a;FS(-?(4QK zyWg^{oqO!T=6%+(tHs7ejEjgI{|{Hxg#Z5X`C_KH|FAD1IbyueH&MQe|GfY4=CAi< z!H_RdT+S`THzM3Y_YnFQi}}r+@Zj`%WI3L0J;;KP6(LJP)`TnySrxJ@WL?O@kd+}z zL)L~Y4p|+tJY;>y0+AIWOGMU)EYj1hl3&g;k#!;qMOKO|)zhsNSuCC^m}%m*Ry9k7iT-4 zcWA|i+8p2CPPBW&hx3^G@O5K9#*!!t)WmCH>KQ8zjHx8*Ju6N5 zT&06wX;I{xTGZF0n+9Ic;?9>;*87G9ceQHCf#>Yzh6dfzy3Ll}_NXnZUuWgB>n&7P zYPb5A*z)w5wtO_pDq>4i@$qGL`^XHfcigfP10_yE9$h`i(a+$iDv7+e#+{`!nUEO+3q|Yvb*-LwEA~9>h7II*3eO| zd+L(x-W~bcxU^8=TEFhgo~BL3KkNQUJ~d{>TI0|cYMMA|O~>C+^WZ6a;FS(-?(4QK zyWg^{oqO!T=6%+(tHs7ejEjgI{|{Hxg#Z5X`C_KH|FAD1IbyueH&MQe|GfY4=CAi< z!H_RdT+S`THzM3Y_YnFQi}}r+@Zj`%WI3L0J;;KP6(LJP)`TnySrxJ@WL?O@kd+}z zL)L~Y4p|+tJY;>y0+AIWOGMU)EYj1hl3&g;k#!;qMOKO|)zhsNSuC Date: Thu, 27 Mar 2025 15:28:18 +0400 Subject: [PATCH 68/82] #430: Remove testcontainers relaited files --- core/jvm/test/testcontainers/ContainerType.kt | 63 -------- .../TimeZoneConfigurationTest.kt | 146 ------------------ .../testcontainers/TimezoneTestContainer.kt | 57 ------- .../debian-jessie/correct-config.dockerfile | 6 - .../debian-jessie/default-config.dockerfile | 3 - .../different-timezones.dockerfile | 7 - .../incorrect-timezone.dockerfile | 5 - .../missing-localtime.dockerfile | 5 - .../debian-jessie/missing-timezone.dockerfile | 5 - .../ubuntu-noble/correct-config.dockerfile | 8 - .../ubuntu-noble/default-config.dockerfile | 3 - .../ubuntu-noble/incorrect-symlink.dockerfile | 5 - core/linux/test/TestcontainersSupport.kt | 21 --- core/linux/test/TimeZoneLinuxNativeTest.kt | 73 --------- core/linux/test/TimeZoneNativeTest.kt | 2 +- 15 files changed, 1 insertion(+), 408 deletions(-) delete mode 100644 core/jvm/test/testcontainers/ContainerType.kt delete mode 100644 core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt delete mode 100644 core/jvm/test/testcontainers/TimezoneTestContainer.kt delete mode 100644 core/jvm/test/testcontainers/debian-jessie/correct-config.dockerfile delete mode 100644 core/jvm/test/testcontainers/debian-jessie/default-config.dockerfile delete mode 100644 core/jvm/test/testcontainers/debian-jessie/different-timezones.dockerfile delete mode 100644 core/jvm/test/testcontainers/debian-jessie/incorrect-timezone.dockerfile delete mode 100644 core/jvm/test/testcontainers/debian-jessie/missing-localtime.dockerfile delete mode 100644 core/jvm/test/testcontainers/debian-jessie/missing-timezone.dockerfile delete mode 100644 core/jvm/test/testcontainers/ubuntu-noble/correct-config.dockerfile delete mode 100644 core/jvm/test/testcontainers/ubuntu-noble/default-config.dockerfile delete mode 100644 core/jvm/test/testcontainers/ubuntu-noble/incorrect-symlink.dockerfile delete mode 100644 core/linux/test/TestcontainersSupport.kt delete mode 100644 core/linux/test/TimeZoneLinuxNativeTest.kt diff --git a/core/jvm/test/testcontainers/ContainerType.kt b/core/jvm/test/testcontainers/ContainerType.kt deleted file mode 100644 index 31128405e..000000000 --- a/core/jvm/test/testcontainers/ContainerType.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2019-2025 JetBrains s.r.o. and contributors. - * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. - */ - -package testcontainers - -enum class ContainerType(val dockerfilePath: String, val imageName: String) { - // Standard Debian Jessie container with Arctic/Longyearbyen timezone - JESSIE_CORRECT( - "./jvm/test/testcontainers/debian-jessie/correct-config.dockerfile", - "debian-jessie-timezone-test" - ), - - // Debian Jessie container with default system configuration - JESSIE_DEFAULT( - "./jvm/test/testcontainers/debian-jessie/default-config.dockerfile", - "debian-jessie-timezone-test-default" - ), - - // Debian Jessie container with missing /etc/localtime file - JESSIE_MISSING_LOCALTIME( - "./jvm/test/testcontainers/debian-jessie/missing-localtime.dockerfile", - "debian-jessie-timezone-test-missing-localtime" - ), - - // Debian Jessie container with missing /etc/timezone file - JESSIE_MISSING_TIMEZONE( - "./jvm/test/testcontainers/debian-jessie/missing-timezone.dockerfile", - "debian-jessie-timezone-test-missing-timezone" - ), - - // Debian Jessie container with garbage inside /etc/timezone file - JESSIE_INCORRECT_TIMEZONE( - "./jvm/test/testcontainers/debian-jessie/incorrect-timezone.dockerfile", - "debian-jessie-timezone-test-incorrect-timezone" - ), - - // Debian Jessie container with conflicting timezone configurations - // `/etc/localtime` and `/usr/share/zoneinfo/$(cat /etc/timezone)` files are different - JESSIE_DIFFERENT_TIMEZONES( - "./jvm/test/testcontainers/debian-jessie/different-timezones.dockerfile", - "debian-jessie-timezone-test-different-timezones" - ), - - // Standard Ubuntu Noble container with Arctic/Longyearbyen timezone - NOBLE_CORRECT( - "./jvm/test/testcontainers/ubuntu-noble/correct-config.dockerfile", - "ubuntu-noble-timezone-test" - ), - - // Ubuntu Noble container with default system configuration - NOBLE_DEFAULT( - "./jvm/test/testcontainers/ubuntu-noble/default-config.dockerfile", - "ubuntu-noble-timezone-test-default" - ), - - // Ubuntu Noble container with incorrect symbolic link for /etc/localtime - NOBLE_INCORRECT_SYMLINK( - "./jvm/test/testcontainers/ubuntu-noble/incorrect-symlink.dockerfile", - "ubuntu-noble-timezone-test-incorrect-symlink" - ) -} \ No newline at end of file diff --git a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt b/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt deleted file mode 100644 index 32333ea19..000000000 --- a/core/jvm/test/testcontainers/TimeZoneConfigurationTest.kt +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2019-2025 JetBrains s.r.o. and contributors. - * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. - */ - -package testcontainers - -import org.junit.Ignore -import org.junit.jupiter.api.BeforeAll -import org.testcontainers.junit.jupiter.Container -import org.testcontainers.junit.jupiter.Testcontainers -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance -import org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS -import org.slf4j.LoggerFactory -import org.testcontainers.containers.Container.ExecResult - -@Ignore -@Testcontainers(disabledWithoutDocker = true) -@TestInstance(PER_CLASS) -class TimeZoneConfigurationTest { - - @Container - private val jessieCorrectConfigContainer = createTimezoneTestContainer(ContainerType.JESSIE_CORRECT) - - @Container - private val jessieDefaultConfigContainer = createTimezoneTestContainer(ContainerType.JESSIE_DEFAULT) - - @Container - private val jessieMissingLocaltimeContainer = createTimezoneTestContainer(ContainerType.JESSIE_MISSING_LOCALTIME) - - @Container - private val jessieMissingTimezoneContainer = createTimezoneTestContainer(ContainerType.JESSIE_MISSING_TIMEZONE) - - @Container - private val jessieIncorrectTimezoneContainer = createTimezoneTestContainer(ContainerType.JESSIE_INCORRECT_TIMEZONE) - - @Container - private val jessieDifferentTimezonesContainer = createTimezoneTestContainer(ContainerType.JESSIE_DIFFERENT_TIMEZONES) - - @Container - private val nobleCorrectConfigContainer = createTimezoneTestContainer(ContainerType.NOBLE_CORRECT) - - @Container - private val nobleDefaultConfigContainer = createTimezoneTestContainer(ContainerType.NOBLE_DEFAULT) - - @Container - private val nobleIncorrectSymlinkContainer = createTimezoneTestContainer(ContainerType.NOBLE_INCORRECT_SYMLINK) - - @Test - fun jessieCorrectConfigTest() { - assertExecSuccess(jessieCorrectConfigContainer.execCorrectRecognizesCurrentSystemTimeZone()) - } - - @Test - fun jessieDefaultConfigTest() { - assertExecSuccess(jessieDefaultConfigContainer.execFallsBackToUniversal()) - } - - @Test - fun jessieMissingLocaltimeTest() { - assertExecSuccess(jessieMissingLocaltimeContainer.execFallsBackToUTC()) - } - - @Test - fun jessieMissingTimezoneTest() { - assertExecSuccess(jessieMissingTimezoneContainer.execThrowsExceptionWhenTimeZoneUndetermined()) - } - - @Test - fun jessieIncorrectTimezoneTest() { - assertExecSuccess(jessieIncorrectTimezoneContainer.execThrowsExceptionWhenTimeZoneUndetermined()) - } - - @Test - fun jessieDifferentTimezonesTest() { - assertExecSuccess(jessieDifferentTimezonesContainer.execThrowsExceptionWhenTimeZoneInconsistent()) - } - - @Test - fun nobleCorrectConfigTest() { - assertExecSuccess(nobleCorrectConfigContainer.execCorrectRecognizesCurrentSystemTimeZone()) - } - - @Test - fun nobleDefaultConfigTest() { - assertExecSuccess(nobleDefaultConfigContainer.execFallsBackToUTC()) - } - - @Test - fun nobleIncorrectSymlinkTest() { - assertExecSuccess(nobleIncorrectSymlinkContainer.execThrowsExceptionWhenTimeZoneUndetermined()) - } - - @Test - fun commonTimeZoneJessieTests() { - assertExecSuccess(jessieCorrectConfigContainer.execCommonTimeZoneTests()) - } - - @Test - fun commonTimeZoneNobleTests() { - assertExecSuccess(nobleCorrectConfigContainer.execCommonTimeZoneTests()) - } - - private fun assertExecSuccess(execResult: ExecResult) { - logger.info("Container stdout:\n${execResult.stdout}") - - if (execResult.exitCode != 0) { - throw AssertionError( - """ - |Command execution failed with exit code ${execResult.exitCode}. - |Stderr: - |${execResult.stderr} - """.trimMargin() - ) - } - } - - companion object { - private val logger = LoggerFactory.getLogger(TimeZoneConfigurationTest::class.java) - - @JvmStatic - @BeforeAll - fun buildTestBinary() { - logger.info("Building test binary...") - - val process = ProcessBuilder() - .command("../gradlew", "linkDebugTestLinuxArm64") - .redirectErrorStream(true) - .start() - - process.inputStream.bufferedReader().use { reader -> - reader.lines().forEach { line -> - logger.info("Build: {}", line) - } - } - - val exitCode = process.waitFor() - if (exitCode != 0) { - throw IllegalStateException("Failed to build test binary: exit code $exitCode") - } - - logger.info("Test binary built successfully") - } - } -} \ No newline at end of file diff --git a/core/jvm/test/testcontainers/TimezoneTestContainer.kt b/core/jvm/test/testcontainers/TimezoneTestContainer.kt deleted file mode 100644 index 8c89179ff..000000000 --- a/core/jvm/test/testcontainers/TimezoneTestContainer.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2019-2025 JetBrains s.r.o. and contributors. - * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. - */ - -package testcontainers - -import org.testcontainers.containers.BindMode -import org.testcontainers.containers.Container.ExecResult -import org.testcontainers.containers.GenericContainer -import org.testcontainers.images.builder.ImageFromDockerfile -import java.nio.file.Paths - -class TimezoneTestContainer(containerType: ContainerType, binaryDir: String) : - GenericContainer( - ImageFromDockerfile(containerType.imageName) - .withDockerfile(Paths.get(containerType.dockerfilePath)) - ) { - - init { - withCommand("tail -f /dev/null") - withFileSystemBind(binaryDir, "/app", BindMode.READ_WRITE) - } - - fun execCorrectRecognizesCurrentSystemTimeZone(): ExecResult { - return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.correctRecognizesCurrentSystemTimeZone") - } - - fun execFallsBackToUTC(): ExecResult { - return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.fallsBackToUTC") - } - - fun execFallsBackToUniversal(): ExecResult { - return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.fallsBackToUniversal") - } - - fun execThrowsExceptionWhenTimeZoneUndetermined(): ExecResult { - return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.throwsExceptionWhenTimeZoneUndetermined") - } - - fun execThrowsExceptionWhenTimeZoneInconsistent(): ExecResult { - return execTest("kotlinx.datetime.test.TimeZoneLinuxNativeTest.throwsExceptionWhenTimeZoneInconsistent") - } - - fun execCommonTimeZoneTests(): ExecResult { - return execTest("kotlinx.datetime.test.TimeZoneTest.*") - } - - private fun execTest(testFilter: String): ExecResult = - exec("chmod +x /app/test.kexe && /app/test.kexe --ktest_filter=$testFilter") - - private fun exec(command: String): ExecResult = execInContainer("bash", "-c", command) -} - -fun createTimezoneTestContainer(containerType: ContainerType): TimezoneTestContainer { - return TimezoneTestContainer(containerType, "./build/bin/linuxArm64/debugTest/") -} \ No newline at end of file diff --git a/core/jvm/test/testcontainers/debian-jessie/correct-config.dockerfile b/core/jvm/test/testcontainers/debian-jessie/correct-config.dockerfile deleted file mode 100644 index c0fe2cf91..000000000 --- a/core/jvm/test/testcontainers/debian-jessie/correct-config.dockerfile +++ /dev/null @@ -1,6 +0,0 @@ -FROM --platform=linux/arm64 debian/eol:jessie - -ENV INSIDE_TESTCONTAINERS=true - -# 5: Arctic/Longyearbyen -RUN echo 5 | dpkg-reconfigure tzdata \ No newline at end of file diff --git a/core/jvm/test/testcontainers/debian-jessie/default-config.dockerfile b/core/jvm/test/testcontainers/debian-jessie/default-config.dockerfile deleted file mode 100644 index b986089e8..000000000 --- a/core/jvm/test/testcontainers/debian-jessie/default-config.dockerfile +++ /dev/null @@ -1,3 +0,0 @@ -FROM --platform=linux/arm64 debian/eol:jessie - -ENV INSIDE_TESTCONTAINERS=true \ No newline at end of file diff --git a/core/jvm/test/testcontainers/debian-jessie/different-timezones.dockerfile b/core/jvm/test/testcontainers/debian-jessie/different-timezones.dockerfile deleted file mode 100644 index 2eb7710f5..000000000 --- a/core/jvm/test/testcontainers/debian-jessie/different-timezones.dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -FROM --platform=linux/arm64 debian/eol:jessie - -ENV INSIDE_TESTCONTAINERS=true - -# 5: Arctic/Longyearbyen -RUN echo 5 | dpkg-reconfigure tzdata -RUN echo Europe/Berlin > /etc/timezone \ No newline at end of file diff --git a/core/jvm/test/testcontainers/debian-jessie/incorrect-timezone.dockerfile b/core/jvm/test/testcontainers/debian-jessie/incorrect-timezone.dockerfile deleted file mode 100644 index 804f903a2..000000000 --- a/core/jvm/test/testcontainers/debian-jessie/incorrect-timezone.dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM --platform=linux/arm64 debian/eol:jessie - -ENV INSIDE_TESTCONTAINERS=true - -RUN echo incorrect/data > /etc/timezone \ No newline at end of file diff --git a/core/jvm/test/testcontainers/debian-jessie/missing-localtime.dockerfile b/core/jvm/test/testcontainers/debian-jessie/missing-localtime.dockerfile deleted file mode 100644 index 1efea7d9c..000000000 --- a/core/jvm/test/testcontainers/debian-jessie/missing-localtime.dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM --platform=linux/arm64 debian/eol:jessie - -ENV INSIDE_TESTCONTAINERS=true - -RUN rm -f /etc/localtime \ No newline at end of file diff --git a/core/jvm/test/testcontainers/debian-jessie/missing-timezone.dockerfile b/core/jvm/test/testcontainers/debian-jessie/missing-timezone.dockerfile deleted file mode 100644 index 357898b26..000000000 --- a/core/jvm/test/testcontainers/debian-jessie/missing-timezone.dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM --platform=linux/arm64 debian/eol:jessie - -ENV INSIDE_TESTCONTAINERS=true - -RUN rm -f /etc/timezone \ No newline at end of file diff --git a/core/jvm/test/testcontainers/ubuntu-noble/correct-config.dockerfile b/core/jvm/test/testcontainers/ubuntu-noble/correct-config.dockerfile deleted file mode 100644 index bb1f0928b..000000000 --- a/core/jvm/test/testcontainers/ubuntu-noble/correct-config.dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -FROM --platform=linux/arm64 ubuntu:24.04 - -ENV INSIDE_TESTCONTAINERS=true - -RUN apt-get update && apt-get install -y tzdata - -# 4: Arctic/Longyearbyen -RUN echo 4 | dpkg-reconfigure tzdata \ No newline at end of file diff --git a/core/jvm/test/testcontainers/ubuntu-noble/default-config.dockerfile b/core/jvm/test/testcontainers/ubuntu-noble/default-config.dockerfile deleted file mode 100644 index 32aaa7987..000000000 --- a/core/jvm/test/testcontainers/ubuntu-noble/default-config.dockerfile +++ /dev/null @@ -1,3 +0,0 @@ -FROM --platform=linux/arm64 ubuntu:24.04 - -ENV INSIDE_TESTCONTAINERS=true \ No newline at end of file diff --git a/core/jvm/test/testcontainers/ubuntu-noble/incorrect-symlink.dockerfile b/core/jvm/test/testcontainers/ubuntu-noble/incorrect-symlink.dockerfile deleted file mode 100644 index 7ccc80446..000000000 --- a/core/jvm/test/testcontainers/ubuntu-noble/incorrect-symlink.dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM --platform=linux/arm64 ubuntu:24.04 - -ENV INSIDE_TESTCONTAINERS=true - -RUN ln -s / /etc/localtime \ No newline at end of file diff --git a/core/linux/test/TestcontainersSupport.kt b/core/linux/test/TestcontainersSupport.kt deleted file mode 100644 index f9f735ee1..000000000 --- a/core/linux/test/TestcontainersSupport.kt +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2019-2025 JetBrains s.r.o. and contributors. - * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. - */ - -package kotlinx.datetime.test - -import kotlinx.cinterop.ExperimentalForeignApi -import kotlinx.cinterop.toKString -import platform.posix.getenv - -object Testcontainers { - - @OptIn(ExperimentalForeignApi::class) - val available: Boolean - get() = getenv("INSIDE_TESTCONTAINERS")?.toKString()?.toBoolean() == true - - inline fun runIfAvailable(block: () -> Unit) { - if (available) block() else println("[----------] Skipping test that requires testcontainers...") - } -} \ No newline at end of file diff --git a/core/linux/test/TimeZoneLinuxNativeTest.kt b/core/linux/test/TimeZoneLinuxNativeTest.kt deleted file mode 100644 index fe3f70fae..000000000 --- a/core/linux/test/TimeZoneLinuxNativeTest.kt +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2019-2025 JetBrains s.r.o. and contributors. - * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. - */ - -package kotlinx.datetime.test - -import kotlinx.datetime.* -import kotlin.test.* - -class TimeZoneLinuxNativeTest { - - /** - * Verifies that the current system time zone is recognized correctly - * and matches one of the expected values for the test environment. - */ - @Test - fun correctRecognizesCurrentSystemTimeZone() = Testcontainers.runIfAvailable { - val tz = TimeZone.currentSystemDefault() - assertTrue(tz == TimeZone.of("Europe/Oslo") || tz == TimeZone.of("Arctic/Longyearbyen")) - } - - /** - * Verifies that the system time zone defaults to UTC - * when no valid time zone can be determined. - */ - @Test - fun fallsBackToUTC() = Testcontainers.runIfAvailable { - val tz = TimeZone.currentSystemDefault() - assertEquals(TimeZone.UTC, tz) - } - - /** - * Verifies that the system time zone falls back to "Universal" - * when a specific time zone cannot be determined. - * This behavior is specific to Debian Jessie. - */ - @Test - fun fallsBackToUniversal() = Testcontainers.runIfAvailable { - val tz = TimeZone.currentSystemDefault() - assertEquals(TimeZone.of("Universal"), tz) - } - - /** - * Verifies that TimeZone.currentSystemDefault() throws IllegalTimeZoneException - * with the expected error message when the time zone ID cannot be determined. - */ - @Test - fun throwsExceptionWhenTimeZoneUndetermined() = Testcontainers.runIfAvailable { - val exception = assertFailsWith { - TimeZone.currentSystemDefault() - } - assertTrue( - exception.message?.startsWith("Could not determine the timezone ID") == true, - "Exception message did not match" - ) - } - - /** - * Verifies that TimeZone.currentSystemDefault() throws IllegalTimeZoneException - * with the expected error message when time zone settings are inconsistent. - */ - @Test - fun throwsExceptionWhenTimeZoneInconsistent() = Testcontainers.runIfAvailable { - val exception = assertFailsWith { - TimeZone.currentSystemDefault() - } - assertTrue( - exception.message?.startsWith("Timezone mismatch") == true, - "Exception message did not start with 'Timezone mismatch'" - ) - } -} \ No newline at end of file diff --git a/core/linux/test/TimeZoneNativeTest.kt b/core/linux/test/TimeZoneNativeTest.kt index 3dded83ab..f6e357907 100644 --- a/core/linux/test/TimeZoneNativeTest.kt +++ b/core/linux/test/TimeZoneNativeTest.kt @@ -68,7 +68,7 @@ class TimeZoneNativeTest { } @Test - fun differentTimezonesTest() = Testcontainers.runIfAvailable { + fun differentTimezonesTest() { root = "${RESOURCES}different-timezones/" val exception = assertFailsWith { From 33e3c7f06bfdf16a22298774fa4122de81c887a5 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Thu, 27 Mar 2025 15:29:34 +0400 Subject: [PATCH 69/82] #430: Remove testcontainers dependencies --- core/build.gradle.kts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 1d0b54736..64697efd2 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -221,23 +221,12 @@ kotlin { runtimeOnly(project(":kotlinx-datetime-zoneinfo")) } } - - val jvmTest by getting { - dependencies { - implementation("org.testcontainers:testcontainers:1.19.7") - implementation("org.testcontainers:junit-jupiter:1.19.7") - implementation("org.junit.jupiter:junit-jupiter-api:5.10.2") - runtimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.2") - implementation("ch.qos.logback:logback-classic:1.2.13") - } - } } } tasks { val jvmTest by existing(Test::class) { // maxHeapSize = "1024m" - useJUnitPlatform() } val compileJavaModuleInfo by registering(JavaCompile::class) { From 49480b83233e6c2d72b69ee59c8a83aacea6403e Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Thu, 27 Mar 2025 15:31:20 +0400 Subject: [PATCH 70/82] #430: Remove logback-test.xml --- core/jvm/testResources/logback-test.xml | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 core/jvm/testResources/logback-test.xml diff --git a/core/jvm/testResources/logback-test.xml b/core/jvm/testResources/logback-test.xml deleted file mode 100644 index 07d3b34bd..000000000 --- a/core/jvm/testResources/logback-test.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - - - - \ No newline at end of file From 27128e844298c9dedfe5cc61e7b9b221cac26c5c Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Thu, 27 Mar 2025 16:10:13 +0400 Subject: [PATCH 71/82] #430: Introduce withFakeRoot helper method --- core/linux/test/TimeZoneNativeTest.kt | 34 +++++++++++++-------------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/core/linux/test/TimeZoneNativeTest.kt b/core/linux/test/TimeZoneNativeTest.kt index f6e357907..81ab32df4 100644 --- a/core/linux/test/TimeZoneNativeTest.kt +++ b/core/linux/test/TimeZoneNativeTest.kt @@ -16,33 +16,25 @@ import kotlin.test.assertTrue class TimeZoneNativeTest { @Test - fun correctSymlinkTest() { - root = "${RESOURCES}correct-symlink/" - + fun correctSymlinkTest() = withFakeRoot("${RESOURCES}correct-symlink/") { val tz = TimeZone.currentSystemDefault() assertEquals(TimeZone.of("Europe/Oslo"), tz) } @Test - fun correctLocaltimeCopyTest() { - root = "${RESOURCES}correct-localtime-copy/" - + fun correctLocaltimeCopyTest() = withFakeRoot("${RESOURCES}correct-localtime-copy/") { val tz = TimeZone.currentSystemDefault() assertEquals(TimeZone.of("Europe/Oslo"), tz) } @Test - fun fallsBackToUTC() { - root = "${RESOURCES}missing-localtime/" - + fun fallsBackToUTC() = withFakeRoot("${RESOURCES}falls-back-to-utc/") { val tz = TimeZone.currentSystemDefault() assertEquals(TimeZone.UTC, tz) } @Test - fun missingTimezoneTest() { - root = "${RESOURCES}missing-timezone/" - + fun missingTimezoneTest() = withFakeRoot("${RESOURCES}missing-timezone/") { val exception = assertFailsWith { TimeZone.currentSystemDefault() } @@ -54,9 +46,7 @@ class TimeZoneNativeTest { } @Test - fun incorrectTimezoneTest() { - root = "${RESOURCES}incorrect-timezone/" - + fun incorrectTimezoneTest() = withFakeRoot("${RESOURCES}incorrect-timezone/") { val exception = assertFailsWith { TimeZone.currentSystemDefault() } @@ -68,9 +58,7 @@ class TimeZoneNativeTest { } @Test - fun differentTimezonesTest() { - root = "${RESOURCES}different-timezones/" - + fun differentTimezonesTest() = withFakeRoot("${RESOURCES}different-timezones/") { val exception = assertFailsWith { TimeZone.currentSystemDefault() } @@ -83,5 +71,15 @@ class TimeZoneNativeTest { companion object { const val RESOURCES = "./linux/test/time-zone-native-test-resources/" + + private fun withFakeRoot(fakeRoot: String, action: () -> Unit) { + val defaultRoot = root + root = fakeRoot + try { + action() + } finally { + root = defaultRoot + } + } } } \ No newline at end of file From 219882197b3ba6d4b618219923c9aa527912b08e Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 31 Mar 2025 16:28:14 +0400 Subject: [PATCH 72/82] #430: Add comment about workaround --- core/linux/src/internal/TimeZoneNative.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/linux/src/internal/TimeZoneNative.kt b/core/linux/src/internal/TimeZoneNative.kt index b9ee49304..d9c7b9793 100644 --- a/core/linux/src/internal/TimeZoneNative.kt +++ b/core/linux/src/internal/TimeZoneNative.kt @@ -18,6 +18,8 @@ internal actual fun getAvailableZoneIds(): Set = private val tzdb = runCatching { TzdbOnFilesystem() } +// This workaround is needed for Debian versions Etch (4.0) - Jessie (8.0), where the timezone data is organized differently. +// See: https://github.com/Kotlin/kotlinx-datetime/issues/430 @OptIn(ExperimentalForeignApi::class) private fun getTimezoneFromEtcTimezone(): String? { val timezoneContent = Path.fromString("${root}etc/timezone").readBytes()?.toKString()?.trim() ?: return null From 7105210473b546ba2164bdfe0ac595bce02ffce8 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 31 Mar 2025 16:30:28 +0400 Subject: [PATCH 73/82] #430: Rename root to systemTimezoneSearchRoot --- core/linux/src/internal/TimeZoneNative.kt | 12 ++++++------ core/linux/test/TimeZoneNativeTest.kt | 8 ++++---- .../src/internal/TzdbOnFilesystem.kt | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/core/linux/src/internal/TimeZoneNative.kt b/core/linux/src/internal/TimeZoneNative.kt index d9c7b9793..388579183 100644 --- a/core/linux/src/internal/TimeZoneNative.kt +++ b/core/linux/src/internal/TimeZoneNative.kt @@ -22,13 +22,13 @@ private val tzdb = runCatching { TzdbOnFilesystem() } // See: https://github.com/Kotlin/kotlinx-datetime/issues/430 @OptIn(ExperimentalForeignApi::class) private fun getTimezoneFromEtcTimezone(): String? { - val timezoneContent = Path.fromString("${root}etc/timezone").readBytes()?.toKString()?.trim() ?: return null - val zoneId = chaseSymlinks("${root}usr/share/zoneinfo/$timezoneContent") + val timezoneContent = Path.fromString("${systemTimezoneSearchRoot}etc/timezone").readBytes()?.toKString()?.trim() ?: return null + val zoneId = chaseSymlinks("${systemTimezoneSearchRoot}usr/share/zoneinfo/$timezoneContent") ?.splitTimeZonePath()?.second?.toString() ?: return null - val zoneInfoBytes = Path.fromString("${root}usr/share/zoneinfo/$zoneId").readBytes() ?: return null - val localtimeBytes = Path.fromString("${root}etc/localtime").readBytes() ?: return null + val zoneInfoBytes = Path.fromString("${systemTimezoneSearchRoot}usr/share/zoneinfo/$zoneId").readBytes() ?: return null + val localtimeBytes = Path.fromString("${systemTimezoneSearchRoot}etc/localtime").readBytes() ?: return null if (!localtimeBytes.contentEquals(zoneInfoBytes)) { val displayTimezone = when (timezoneContent) { @@ -36,8 +36,8 @@ private fun getTimezoneFromEtcTimezone(): String? { else -> "'$timezoneContent' (resolved to '$zoneId')" } throw IllegalTimeZoneException( - "Timezone mismatch: ${root}etc/timezone specifies $displayTimezone " + - "but ${root}etc/localtime content differs from ${root}usr/share/zoneinfo/$zoneId" + "Timezone mismatch: ${systemTimezoneSearchRoot}etc/timezone specifies $displayTimezone " + + "but ${systemTimezoneSearchRoot}etc/localtime content differs from ${systemTimezoneSearchRoot}usr/share/zoneinfo/$zoneId" ) } diff --git a/core/linux/test/TimeZoneNativeTest.kt b/core/linux/test/TimeZoneNativeTest.kt index 81ab32df4..7b6d28d3d 100644 --- a/core/linux/test/TimeZoneNativeTest.kt +++ b/core/linux/test/TimeZoneNativeTest.kt @@ -7,7 +7,7 @@ package kotlinx.datetime.test import kotlinx.datetime.IllegalTimeZoneException import kotlinx.datetime.TimeZone -import kotlinx.datetime.internal.root +import kotlinx.datetime.internal.systemTimezoneSearchRoot import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFailsWith @@ -73,12 +73,12 @@ class TimeZoneNativeTest { const val RESOURCES = "./linux/test/time-zone-native-test-resources/" private fun withFakeRoot(fakeRoot: String, action: () -> Unit) { - val defaultRoot = root - root = fakeRoot + val defaultRoot = systemTimezoneSearchRoot + systemTimezoneSearchRoot = fakeRoot try { action() } finally { - root = defaultRoot + systemTimezoneSearchRoot = defaultRoot } } } diff --git a/core/tzdbOnFilesystem/src/internal/TzdbOnFilesystem.kt b/core/tzdbOnFilesystem/src/internal/TzdbOnFilesystem.kt index 229323419..e3968c172 100644 --- a/core/tzdbOnFilesystem/src/internal/TzdbOnFilesystem.kt +++ b/core/tzdbOnFilesystem/src/internal/TzdbOnFilesystem.kt @@ -47,9 +47,9 @@ internal fun tzdbPaths(defaultTzdbPath: Path?) = sequence { currentSystemTimeZonePath?.splitTimeZonePath()?.first?.let { yield(it) } } -internal var root: String = "/" +internal var systemTimezoneSearchRoot: String = "/" -internal val currentSystemTimeZonePath get() = chaseSymlinks("${root}etc/localtime") +internal val currentSystemTimeZonePath get() = chaseSymlinks("${systemTimezoneSearchRoot}etc/localtime") /** * Given a path like `/usr/share/zoneinfo/Europe/Berlin`, produces `/usr/share/zoneinfo to Europe/Berlin`. From 3866fbfbfd12f6716d13417088698f428645facc Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 31 Mar 2025 16:39:29 +0400 Subject: [PATCH 74/82] #430: Rename fallbackToUTCWhenNoLocaltime test --- core/linux/test/TimeZoneNativeTest.kt | 2 +- .../time-zone-native-test-resources/missing-localtime/etc/.keep | 0 .../missing-localtime/usr/share/zoneinfo/Europe/.keep | 0 3 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 core/linux/test/time-zone-native-test-resources/missing-localtime/etc/.keep create mode 100644 core/linux/test/time-zone-native-test-resources/missing-localtime/usr/share/zoneinfo/Europe/.keep diff --git a/core/linux/test/TimeZoneNativeTest.kt b/core/linux/test/TimeZoneNativeTest.kt index 7b6d28d3d..333f2d308 100644 --- a/core/linux/test/TimeZoneNativeTest.kt +++ b/core/linux/test/TimeZoneNativeTest.kt @@ -28,7 +28,7 @@ class TimeZoneNativeTest { } @Test - fun fallsBackToUTC() = withFakeRoot("${RESOURCES}falls-back-to-utc/") { + fun fallbackToUTCWhenNoLocaltime() = withFakeRoot("${RESOURCES}missing-localtime/") { val tz = TimeZone.currentSystemDefault() assertEquals(TimeZone.UTC, tz) } diff --git a/core/linux/test/time-zone-native-test-resources/missing-localtime/etc/.keep b/core/linux/test/time-zone-native-test-resources/missing-localtime/etc/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/core/linux/test/time-zone-native-test-resources/missing-localtime/usr/share/zoneinfo/Europe/.keep b/core/linux/test/time-zone-native-test-resources/missing-localtime/usr/share/zoneinfo/Europe/.keep new file mode 100644 index 000000000..e69de29bb From f64b3bd8824619ee3af937ad5818a7d49441499a Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 31 Mar 2025 16:43:27 +0400 Subject: [PATCH 75/82] #430: Rename missingTimezoneWhenLocaltimeIsNotSymlinkTest test --- core/linux/test/TimeZoneNativeTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/linux/test/TimeZoneNativeTest.kt b/core/linux/test/TimeZoneNativeTest.kt index 333f2d308..be7df598f 100644 --- a/core/linux/test/TimeZoneNativeTest.kt +++ b/core/linux/test/TimeZoneNativeTest.kt @@ -34,7 +34,7 @@ class TimeZoneNativeTest { } @Test - fun missingTimezoneTest() = withFakeRoot("${RESOURCES}missing-timezone/") { + fun missingTimezoneWhenLocaltimeIsNotSymlinkTest() = withFakeRoot("${RESOURCES}missing-timezone/") { val exception = assertFailsWith { TimeZone.currentSystemDefault() } From d2a9dca39bce26a2bd1a56f497fafe594b5d768b Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 31 Mar 2025 16:45:29 +0400 Subject: [PATCH 76/82] #430: Remove exception message checks --- core/linux/test/TimeZoneNativeTest.kt | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/core/linux/test/TimeZoneNativeTest.kt b/core/linux/test/TimeZoneNativeTest.kt index be7df598f..fb79503d7 100644 --- a/core/linux/test/TimeZoneNativeTest.kt +++ b/core/linux/test/TimeZoneNativeTest.kt @@ -35,26 +35,16 @@ class TimeZoneNativeTest { @Test fun missingTimezoneWhenLocaltimeIsNotSymlinkTest() = withFakeRoot("${RESOURCES}missing-timezone/") { - val exception = assertFailsWith { + assertFailsWith { TimeZone.currentSystemDefault() } - - assertTrue( - exception.message?.startsWith("Could not determine the timezone ID") == true, - "Exception message did not match" - ) } @Test fun incorrectTimezoneTest() = withFakeRoot("${RESOURCES}incorrect-timezone/") { - val exception = assertFailsWith { + assertFailsWith { TimeZone.currentSystemDefault() } - - assertTrue( - exception.message?.startsWith("Could not determine the timezone ID") == true, - "Exception message did not match" - ) } @Test From d429aa8475ac686fd307548129edc5728f97b343 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 31 Mar 2025 16:46:50 +0400 Subject: [PATCH 77/82] #430: Rename timezoneFileAgreesWithLocaltimeContents --- core/linux/test/TimeZoneNativeTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/linux/test/TimeZoneNativeTest.kt b/core/linux/test/TimeZoneNativeTest.kt index fb79503d7..214a9f8b5 100644 --- a/core/linux/test/TimeZoneNativeTest.kt +++ b/core/linux/test/TimeZoneNativeTest.kt @@ -22,7 +22,7 @@ class TimeZoneNativeTest { } @Test - fun correctLocaltimeCopyTest() = withFakeRoot("${RESOURCES}correct-localtime-copy/") { + fun timezoneFileAgreesWithLocaltimeContents() = withFakeRoot("${RESOURCES}correct-localtime-copy/") { val tz = TimeZone.currentSystemDefault() assertEquals(TimeZone.of("Europe/Oslo"), tz) } From c446aa9c16b26f2645aa638d9d6c4d302456cfe1 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 31 Mar 2025 16:47:50 +0400 Subject: [PATCH 78/82] #430: Rename nonExistentTimezoneInTimezoneFile --- core/linux/test/TimeZoneNativeTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/linux/test/TimeZoneNativeTest.kt b/core/linux/test/TimeZoneNativeTest.kt index 214a9f8b5..d017b0d42 100644 --- a/core/linux/test/TimeZoneNativeTest.kt +++ b/core/linux/test/TimeZoneNativeTest.kt @@ -41,7 +41,7 @@ class TimeZoneNativeTest { } @Test - fun incorrectTimezoneTest() = withFakeRoot("${RESOURCES}incorrect-timezone/") { + fun nonExistentTimezoneInTimezoneFile() = withFakeRoot("${RESOURCES}incorrect-timezone/") { assertFailsWith { TimeZone.currentSystemDefault() } From ea2b11f2192de628c13939fc5df99e4951639410 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 31 Mar 2025 16:48:58 +0400 Subject: [PATCH 79/82] #430: Rename timezoneFileDisagreesWithLocaltimeContentsTest --- core/linux/test/TimeZoneNativeTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/linux/test/TimeZoneNativeTest.kt b/core/linux/test/TimeZoneNativeTest.kt index d017b0d42..b8e01235a 100644 --- a/core/linux/test/TimeZoneNativeTest.kt +++ b/core/linux/test/TimeZoneNativeTest.kt @@ -48,7 +48,7 @@ class TimeZoneNativeTest { } @Test - fun differentTimezonesTest() = withFakeRoot("${RESOURCES}different-timezones/") { + fun timezoneFileDisagreesWithLocaltimeContentsTest() = withFakeRoot("${RESOURCES}different-timezones/") { val exception = assertFailsWith { TimeZone.currentSystemDefault() } From 756c89e28474223d7831fa787418a4c522230e77 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 31 Mar 2025 16:54:18 +0400 Subject: [PATCH 80/82] #430: Refactoring --- core/linux/test/TimeZoneNativeTest.kt | 10 +++++----- .../etc/.keep | 0 .../usr/share/zoneinfo/Europe/.keep | 0 .../etc/localtime | 0 .../etc/localtime | 0 .../etc/timezone | 0 .../etc/localtime | Bin .../etc/timezone | 0 .../usr/share/zoneinfo/Europe/Oslo | Bin .../etc/localtime | Bin .../etc/timezone | 0 .../usr/share/zoneinfo/Europe/Berlin | Bin .../usr/share/zoneinfo/Europe/Oslo | Bin 13 files changed, 5 insertions(+), 5 deletions(-) rename core/linux/test/time-zone-native-test-resources/{missing-localtime => fallback-to-utc-when-no-localtime}/etc/.keep (100%) rename core/linux/test/time-zone-native-test-resources/{missing-localtime => fallback-to-utc-when-no-localtime}/usr/share/zoneinfo/Europe/.keep (100%) rename core/linux/test/time-zone-native-test-resources/{incorrect-timezone => missing-timezone-when-localtime-is-not-symlink}/etc/localtime (100%) rename core/linux/test/time-zone-native-test-resources/{missing-timezone => non-existent-timezone-in-timezone-file}/etc/localtime (100%) rename core/linux/test/time-zone-native-test-resources/{incorrect-timezone => non-existent-timezone-in-timezone-file}/etc/timezone (100%) rename core/linux/test/time-zone-native-test-resources/{correct-localtime-copy => timezone-file-agrees-with-localtime-contents}/etc/localtime (100%) rename core/linux/test/time-zone-native-test-resources/{correct-localtime-copy => timezone-file-agrees-with-localtime-contents}/etc/timezone (100%) rename core/linux/test/time-zone-native-test-resources/{correct-localtime-copy => timezone-file-agrees-with-localtime-contents}/usr/share/zoneinfo/Europe/Oslo (100%) rename core/linux/test/time-zone-native-test-resources/{different-timezones => timezone-file-disagrees-with-localtime-contents}/etc/localtime (100%) rename core/linux/test/time-zone-native-test-resources/{different-timezones => timezone-file-disagrees-with-localtime-contents}/etc/timezone (100%) rename core/linux/test/time-zone-native-test-resources/{different-timezones => timezone-file-disagrees-with-localtime-contents}/usr/share/zoneinfo/Europe/Berlin (100%) rename core/linux/test/time-zone-native-test-resources/{different-timezones => timezone-file-disagrees-with-localtime-contents}/usr/share/zoneinfo/Europe/Oslo (100%) diff --git a/core/linux/test/TimeZoneNativeTest.kt b/core/linux/test/TimeZoneNativeTest.kt index b8e01235a..0c9d65a67 100644 --- a/core/linux/test/TimeZoneNativeTest.kt +++ b/core/linux/test/TimeZoneNativeTest.kt @@ -22,33 +22,33 @@ class TimeZoneNativeTest { } @Test - fun timezoneFileAgreesWithLocaltimeContents() = withFakeRoot("${RESOURCES}correct-localtime-copy/") { + fun timezoneFileAgreesWithLocaltimeContentsTest() = withFakeRoot("${RESOURCES}timezone-file-agrees-with-localtime-contents/") { val tz = TimeZone.currentSystemDefault() assertEquals(TimeZone.of("Europe/Oslo"), tz) } @Test - fun fallbackToUTCWhenNoLocaltime() = withFakeRoot("${RESOURCES}missing-localtime/") { + fun fallbackToUTCWhenNoLocaltimeTest() = withFakeRoot("${RESOURCES}fallback-to-utc-when-no-localtime/") { val tz = TimeZone.currentSystemDefault() assertEquals(TimeZone.UTC, tz) } @Test - fun missingTimezoneWhenLocaltimeIsNotSymlinkTest() = withFakeRoot("${RESOURCES}missing-timezone/") { + fun missingTimezoneWhenLocaltimeIsNotSymlinkTest() = withFakeRoot("${RESOURCES}missing-timezone-when-localtime-is-not-symlink/") { assertFailsWith { TimeZone.currentSystemDefault() } } @Test - fun nonExistentTimezoneInTimezoneFile() = withFakeRoot("${RESOURCES}incorrect-timezone/") { + fun nonExistentTimezoneInTimezoneFileTest() = withFakeRoot("${RESOURCES}non-existent-timezone-in-timezone-file/") { assertFailsWith { TimeZone.currentSystemDefault() } } @Test - fun timezoneFileDisagreesWithLocaltimeContentsTest() = withFakeRoot("${RESOURCES}different-timezones/") { + fun timezoneFileDisagreesWithLocaltimeContentsTest() = withFakeRoot("${RESOURCES}timezone-file-disagrees-with-localtime-contents/") { val exception = assertFailsWith { TimeZone.currentSystemDefault() } diff --git a/core/linux/test/time-zone-native-test-resources/missing-localtime/etc/.keep b/core/linux/test/time-zone-native-test-resources/fallback-to-utc-when-no-localtime/etc/.keep similarity index 100% rename from core/linux/test/time-zone-native-test-resources/missing-localtime/etc/.keep rename to core/linux/test/time-zone-native-test-resources/fallback-to-utc-when-no-localtime/etc/.keep diff --git a/core/linux/test/time-zone-native-test-resources/missing-localtime/usr/share/zoneinfo/Europe/.keep b/core/linux/test/time-zone-native-test-resources/fallback-to-utc-when-no-localtime/usr/share/zoneinfo/Europe/.keep similarity index 100% rename from core/linux/test/time-zone-native-test-resources/missing-localtime/usr/share/zoneinfo/Europe/.keep rename to core/linux/test/time-zone-native-test-resources/fallback-to-utc-when-no-localtime/usr/share/zoneinfo/Europe/.keep diff --git a/core/linux/test/time-zone-native-test-resources/incorrect-timezone/etc/localtime b/core/linux/test/time-zone-native-test-resources/missing-timezone-when-localtime-is-not-symlink/etc/localtime similarity index 100% rename from core/linux/test/time-zone-native-test-resources/incorrect-timezone/etc/localtime rename to core/linux/test/time-zone-native-test-resources/missing-timezone-when-localtime-is-not-symlink/etc/localtime diff --git a/core/linux/test/time-zone-native-test-resources/missing-timezone/etc/localtime b/core/linux/test/time-zone-native-test-resources/non-existent-timezone-in-timezone-file/etc/localtime similarity index 100% rename from core/linux/test/time-zone-native-test-resources/missing-timezone/etc/localtime rename to core/linux/test/time-zone-native-test-resources/non-existent-timezone-in-timezone-file/etc/localtime diff --git a/core/linux/test/time-zone-native-test-resources/incorrect-timezone/etc/timezone b/core/linux/test/time-zone-native-test-resources/non-existent-timezone-in-timezone-file/etc/timezone similarity index 100% rename from core/linux/test/time-zone-native-test-resources/incorrect-timezone/etc/timezone rename to core/linux/test/time-zone-native-test-resources/non-existent-timezone-in-timezone-file/etc/timezone diff --git a/core/linux/test/time-zone-native-test-resources/correct-localtime-copy/etc/localtime b/core/linux/test/time-zone-native-test-resources/timezone-file-agrees-with-localtime-contents/etc/localtime similarity index 100% rename from core/linux/test/time-zone-native-test-resources/correct-localtime-copy/etc/localtime rename to core/linux/test/time-zone-native-test-resources/timezone-file-agrees-with-localtime-contents/etc/localtime diff --git a/core/linux/test/time-zone-native-test-resources/correct-localtime-copy/etc/timezone b/core/linux/test/time-zone-native-test-resources/timezone-file-agrees-with-localtime-contents/etc/timezone similarity index 100% rename from core/linux/test/time-zone-native-test-resources/correct-localtime-copy/etc/timezone rename to core/linux/test/time-zone-native-test-resources/timezone-file-agrees-with-localtime-contents/etc/timezone diff --git a/core/linux/test/time-zone-native-test-resources/correct-localtime-copy/usr/share/zoneinfo/Europe/Oslo b/core/linux/test/time-zone-native-test-resources/timezone-file-agrees-with-localtime-contents/usr/share/zoneinfo/Europe/Oslo similarity index 100% rename from core/linux/test/time-zone-native-test-resources/correct-localtime-copy/usr/share/zoneinfo/Europe/Oslo rename to core/linux/test/time-zone-native-test-resources/timezone-file-agrees-with-localtime-contents/usr/share/zoneinfo/Europe/Oslo diff --git a/core/linux/test/time-zone-native-test-resources/different-timezones/etc/localtime b/core/linux/test/time-zone-native-test-resources/timezone-file-disagrees-with-localtime-contents/etc/localtime similarity index 100% rename from core/linux/test/time-zone-native-test-resources/different-timezones/etc/localtime rename to core/linux/test/time-zone-native-test-resources/timezone-file-disagrees-with-localtime-contents/etc/localtime diff --git a/core/linux/test/time-zone-native-test-resources/different-timezones/etc/timezone b/core/linux/test/time-zone-native-test-resources/timezone-file-disagrees-with-localtime-contents/etc/timezone similarity index 100% rename from core/linux/test/time-zone-native-test-resources/different-timezones/etc/timezone rename to core/linux/test/time-zone-native-test-resources/timezone-file-disagrees-with-localtime-contents/etc/timezone diff --git a/core/linux/test/time-zone-native-test-resources/different-timezones/usr/share/zoneinfo/Europe/Berlin b/core/linux/test/time-zone-native-test-resources/timezone-file-disagrees-with-localtime-contents/usr/share/zoneinfo/Europe/Berlin similarity index 100% rename from core/linux/test/time-zone-native-test-resources/different-timezones/usr/share/zoneinfo/Europe/Berlin rename to core/linux/test/time-zone-native-test-resources/timezone-file-disagrees-with-localtime-contents/usr/share/zoneinfo/Europe/Berlin diff --git a/core/linux/test/time-zone-native-test-resources/different-timezones/usr/share/zoneinfo/Europe/Oslo b/core/linux/test/time-zone-native-test-resources/timezone-file-disagrees-with-localtime-contents/usr/share/zoneinfo/Europe/Oslo similarity index 100% rename from core/linux/test/time-zone-native-test-resources/different-timezones/usr/share/zoneinfo/Europe/Oslo rename to core/linux/test/time-zone-native-test-resources/timezone-file-disagrees-with-localtime-contents/usr/share/zoneinfo/Europe/Oslo From dd3ce5d192e6aa3244b7de4c7673c5fd26694590 Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 31 Mar 2025 17:31:11 +0400 Subject: [PATCH 81/82] #430: Change exception message check --- core/linux/test/TimeZoneNativeTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/linux/test/TimeZoneNativeTest.kt b/core/linux/test/TimeZoneNativeTest.kt index 0c9d65a67..5ff2efe1f 100644 --- a/core/linux/test/TimeZoneNativeTest.kt +++ b/core/linux/test/TimeZoneNativeTest.kt @@ -54,8 +54,8 @@ class TimeZoneNativeTest { } assertTrue( - exception.message?.startsWith("Timezone mismatch") == true, - "Exception message did not start with 'Timezone mismatch'" + exception.message?.contains("/etc/timezone") == true, + "Exception message does not contain '/etc/timezone' as expected" ) } From c68adb08572f0dec3f21af000d5ab5d1f00dfebe Mon Sep 17 00:00:00 2001 From: Dmitry Nekrasov Date: Mon, 31 Mar 2025 17:54:29 +0400 Subject: [PATCH 82/82] #430: Change exception message check --- core/linux/test/TimeZoneNativeTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/linux/test/TimeZoneNativeTest.kt b/core/linux/test/TimeZoneNativeTest.kt index 5ff2efe1f..3ca78b773 100644 --- a/core/linux/test/TimeZoneNativeTest.kt +++ b/core/linux/test/TimeZoneNativeTest.kt @@ -54,8 +54,8 @@ class TimeZoneNativeTest { } assertTrue( - exception.message?.contains("/etc/timezone") == true, - "Exception message does not contain '/etc/timezone' as expected" + exception.message?.contains("Europe/Oslo") == true, + "Exception message does not contain 'Europe/Oslo' as expected" ) }