From d7eefa8066b8e2ac70e0a4080c52bce20da24a23 Mon Sep 17 00:00:00 2001 From: Joel Klinghed Date: Thu, 22 Aug 2024 00:10:26 +0200 Subject: samba: Add docker server run by tests Current user needs to be in docker group (or in some other way have access to the docker.socket) for this to work. Two current problems: * listRoot() fails, no directories are found. * gradle hangs after running the samba tests --- libs/samba/build.gradle.kts | 25 ++++- .../the_jk/cleversync/io/samba/SambaConnection.kt | 1 + .../org/the_jk/cleversync/io/samba/SambaTree.kt | 7 +- libs/samba/src/test/docker/docker-compose.yml | 22 +++++ .../org/the_jk/cleversync/samba/SambaTreeTest.kt | 108 ++++++++++++++++++--- 5 files changed, 146 insertions(+), 17 deletions(-) create mode 100644 libs/samba/src/test/docker/docker-compose.yml (limited to 'libs/samba') diff --git a/libs/samba/build.gradle.kts b/libs/samba/build.gradle.kts index 2fc5007..b7816c4 100644 --- a/libs/samba/build.gradle.kts +++ b/libs/samba/build.gradle.kts @@ -1,7 +1,12 @@ +import org.gradle.api.tasks.testing.logging.TestExceptionFormat + plugins { alias(libs.plugins.android.library) } +val shareDir = layout.buildDirectory.dir("test-share") +val dockerDir = layout.projectDirectory.dir("src/test/docker") + android { namespace = "org.the_jk.cleversync.samba" @@ -19,6 +24,24 @@ android { externalNativeBuild { cmake { cFlags += listOf("-O3") } } } } + + testOptions { + unitTests { + all { test -> + test.doFirst { + shareDir.get().asFile.mkdirs() + } + + test.systemProperty("dockerDir", dockerDir.toString()) + test.systemProperty("shareDir", shareDir.get().toString()) + + test.testLogging { + showStandardStreams = true + exceptionFormat = TestExceptionFormat.FULL + } + } + } + } } dependencies { @@ -26,7 +49,7 @@ dependencies { } listOf("Debug", "Release").forEach { buildType -> - val buildDir = project.layout.buildDirectory.dir("test/debug/build") + val buildDir = project.layout.buildDirectory.dir("test-cpp/debug/build") val configure by tasks.register( "configureLibsFor${buildType}UnitTest", diff --git a/libs/samba/src/main/java/org/the_jk/cleversync/io/samba/SambaConnection.kt b/libs/samba/src/main/java/org/the_jk/cleversync/io/samba/SambaConnection.kt index 0b62b61..d7302cd 100644 --- a/libs/samba/src/main/java/org/the_jk/cleversync/io/samba/SambaConnection.kt +++ b/libs/samba/src/main/java/org/the_jk/cleversync/io/samba/SambaConnection.kt @@ -1,6 +1,7 @@ package org.the_jk.cleversync.io.samba internal class SambaConnection(uri: String, credentials: SambaCredentials) { + val description = uri private val context = NativeSamba.newContext() private val url = context.parseUrl(uri) private var destroyed = false diff --git a/libs/samba/src/main/java/org/the_jk/cleversync/io/samba/SambaTree.kt b/libs/samba/src/main/java/org/the_jk/cleversync/io/samba/SambaTree.kt index 3667a74..91dee56 100644 --- a/libs/samba/src/main/java/org/the_jk/cleversync/io/samba/SambaTree.kt +++ b/libs/samba/src/main/java/org/the_jk/cleversync/io/samba/SambaTree.kt @@ -3,9 +3,12 @@ package org.the_jk.cleversync.io.samba import android.content.res.Resources import org.the_jk.cleversync.io.ModifiableTree -internal class SambaTree(conn: SambaConnection, root: String) : SambaDirectory(conn, root, ""), ModifiableTree { +internal class SambaTree( + private val conn: SambaConnection, + root: String, +) : SambaDirectory(conn, root, ""), ModifiableTree { override fun description(resources: Resources): CharSequence { - TODO("Not yet implemented") + return conn.description } override fun close() { diff --git a/libs/samba/src/test/docker/docker-compose.yml b/libs/samba/src/test/docker/docker-compose.yml new file mode 100644 index 0000000..c7af330 --- /dev/null +++ b/libs/samba/src/test/docker/docker-compose.yml @@ -0,0 +1,22 @@ +services: + samba: + image: ghcr.io/servercontainers/samba:smbd-only-a3.20.2-s4.19.6-r0 + restart: always + environment: + WSDD2_DISABLE: 1 + AVAHI_DISABLE: 1 + NETBIOS_DISABLE: 1 + + GROUP_family: 1050 + + ACCOUNT_test: notverysecret + UID_test: 1000 + GROUPS_test: family + + SAMBA_VOLUME_CONFIG_test: "[Share]; path=/shares/test; valid users = test; guest ok = no; read only = no; browseable = yes" + + volumes: + - ../../../build/test-share:/shares/test + + ports: + - "127.0.0.1:10445:445" diff --git a/libs/samba/src/test/java/org/the_jk/cleversync/samba/SambaTreeTest.kt b/libs/samba/src/test/java/org/the_jk/cleversync/samba/SambaTreeTest.kt index 3f1fa04..b581df9 100644 --- a/libs/samba/src/test/java/org/the_jk/cleversync/samba/SambaTreeTest.kt +++ b/libs/samba/src/test/java/org/the_jk/cleversync/samba/SambaTreeTest.kt @@ -1,39 +1,119 @@ package org.the_jk.cleversync.samba +import android.content.Context +import androidx.test.core.app.ApplicationProvider import com.google.common.truth.Truth.assertThat import org.junit.After +import org.junit.AfterClass import org.junit.Before +import org.junit.BeforeClass import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config +import org.the_jk.cleversync.io.Link import org.the_jk.cleversync.io.samba.SambaCredentials +import java.io.File +import kotlin.io.path.createSymbolicLinkPointingTo @Config(manifest=Config.NONE) @RunWith(RobolectricTestRunner::class) class SambaTreeTest { - private lateinit var uri: String - private lateinit var credentials: SambaCredentials - @Before - fun setUp() { - uri = "smb://127.0.0.1:10445/" - credentials = SambaCredentials("test", "notverysecret") + fun setUpTest() { + assertThat(shareDir.listFiles()).isEmpty() } @After - fun tearDown() { + fun tearDownTest() { + for (file in shareDir.listFiles()!!) { + if (file.isDirectory) { + file.deleteRecursively() + } else { + file.delete() + } + } + } + + @Test + fun description() { + val resources = ApplicationProvider.getApplicationContext().resources + SambaTreeFactory.tree(uri, credentials).getOrThrow().use { tree -> + assertThat(tree.description(resources).toString()).contains(uri) + } + } + @Test + fun listEmptyRoot() { + SambaTreeFactory.tree(uri, credentials).getOrThrow().use { root -> + val content = root.list() + assertThat(content.directories).isEmpty() + assertThat(content.files).isEmpty() + assertThat(content.links).isEmpty() + } } @Test fun listRoot() { - val result = SambaTreeFactory.tree(uri, credentials) - assertThat(result.isSuccess).isTrue() - val root = result.getOrThrow() - val content = root.list() - assertThat(content.directories).hasSize(1) - assertThat(content.files).isEmpty() - assertThat(content.links).isEmpty() + val dir = File(shareDir, "dir") + val file = File(shareDir, "file") + val link = File(shareDir, "link") + dir.mkdir() + file.writeText("foo") + link.toPath().createSymbolicLinkPointingTo(file.toPath()) + + SambaTreeFactory.tree(uri, credentials).getOrThrow().use { root -> + val content = root.list() + assertThat(content.directories).hasSize(1) + assertThat(content.directories[0].name).isEqualTo("dir") + assertThat(content.files).hasSize(1) + assertThat(content.files[0].name).isEqualTo("file") + assertThat(content.files[0].size).isEqualTo(3U) + assertThat(content.links).hasSize(1) + assertThat(content.links[0].name).isEqualTo("link") + val target = content.links[0].resolve() + if (target is Link.FileTarget) { + assertThat(target.file.name).isEqualTo("file") + } else { + assertThat(target).isInstanceOf(Link.FileTarget::class.java) + } + } + } + + companion object { + private lateinit var uri: String + private lateinit var credentials: SambaCredentials + private lateinit var dockerDir: File + private lateinit var shareDir: File + private var dockerRunning = false + + @BeforeClass + @JvmStatic + fun setUpClass() { + uri = "smb://127.0.0.1:10445/Share" + credentials = SambaCredentials("test", "notverysecret") + dockerDir = File(System.getProperty("dockerDir")!!) + shareDir = File(System.getProperty("shareDir")!!) + shareDir.deleteRecursively() + shareDir.mkdirs() + + val pb = ProcessBuilder("docker", "compose", "up", "--wait", "--wait-timeout", "60") + pb.directory(dockerDir) + val exitCode = pb.start().waitFor() + assertThat(exitCode).isEqualTo(0) + dockerRunning = true + } + + @AfterClass + @JvmStatic + fun tearDownClass() { + if (dockerRunning) { + val pb = ProcessBuilder("docker", "compose", "down") + pb.directory(dockerDir) + pb.start().waitFor() + dockerRunning = false + } + shareDir.deleteRecursively() + } } } -- cgit v1.2.3-70-g09d2