From 339bf5c6945821d647734dc03c6e29f0c6459f09 Mon Sep 17 00:00:00 2001 From: Tuan Nguyen Date: Tue, 9 Jan 2024 04:22:36 +0700 Subject: [PATCH] Test index aggregation (#131) --------- Co-authored-by: oluiscabral --- lib/build.gradle | 2 + .../arklib/data/index/IndexAggregationTest.kt | 171 ++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 lib/src/test/java/space/taran/arklib/data/index/IndexAggregationTest.kt diff --git a/lib/build.gradle b/lib/build.gradle index 14e2fc1d..e013c401 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -82,6 +82,8 @@ dependencies { testImplementation "junit:junit:4.13.2" testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3' + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4" + testImplementation "io.mockk:mockk:1.13.7" } diff --git a/lib/src/test/java/space/taran/arklib/data/index/IndexAggregationTest.kt b/lib/src/test/java/space/taran/arklib/data/index/IndexAggregationTest.kt new file mode 100644 index 00000000..039e9c9e --- /dev/null +++ b/lib/src/test/java/space/taran/arklib/data/index/IndexAggregationTest.kt @@ -0,0 +1,171 @@ +package space.taran.arklib.data.index + +import dev.arkbuilders.arklib.ResourceId +import dev.arkbuilders.arklib.data.index.IndexAggregation +import dev.arkbuilders.arklib.data.index.Resource +import dev.arkbuilders.arklib.data.index.ResourceUpdates +import dev.arkbuilders.arklib.data.index.RootIndex +import io.mockk.* +import io.mockk.InternalPlatformDsl.toStr +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.runBlocking +import org.junit.After +import org.junit.Assert.* +import org.junit.Before +import org.junit.Test +import java.nio.file.Path +import java.nio.file.attribute.FileTime +import java.time.Instant +import java.util.* +import kotlin.io.path.Path +import kotlin.random.Random + +class IndexAggregationTest { + + private var updatedShards: Int = 0 + private lateinit var shards: Set + private lateinit var indexAggregation: IndexAggregation + + @Before + fun beforeEach() { + updatedShards = 0 + shards = createShards(3) + indexAggregation = IndexAggregation(shards) + } + + @After + fun afterEach() { + unmockkAll() + } + + private fun createShards(amount: Int): Set { + val shards = HashSet(amount) + for (i in 1..amount) { + val rootIndex = createRootIndex() + shards.add(rootIndex) + } + return shards + } + + private fun createRootIndex(): RootIndex { + val rootIndex = mockk() + val resources = createRandomResources(3) + val resourceIdSlot = CapturingSlot() + val resourcePaths = createResourceRandomPaths(resources) + every { rootIndex.allPaths() } returns resourcePaths + every { rootIndex.allIds() } returns resources.map { it.id }.toSet() + every { rootIndex.updates } returns MutableSharedFlow() + every { rootIndex.allResources() } returns resources.associateBy({ it.id }, { it }) + every { rootIndex.getResource(capture(resourceIdSlot)) } answers { + val resourceId = resourceIdSlot.captured + resources.firstOrNull { resource -> resource.id == resourceId } + } + every { rootIndex.getPath(capture(resourceIdSlot)) } answers { + val resourceId = resourceIdSlot.captured + resourcePaths[resourceId] + } + coEvery { rootIndex.updateAll() } answers { + updatedShards += 1 + } + return rootIndex; + } + + private fun createRandomResources(amount: Int): Set { + return (1..amount).map { + val resourceId = createRandomResourceId() + Resource(resourceId, UUID.randomUUID().toString(), "txt", FileTime.from(Instant.now())) + }.toSet() + } + + private fun createRandomResourceId(): ResourceId { + val crc32 = generateRandomLong(18) + val size = Random.nextLong(0, 16364) + return ResourceId(size, crc32) + } + + private fun generateRandomLong(length: Int): Long { + require(length > 0) { "Length must be greater than 0" } + val stringBuilder = StringBuilder(length) + repeat(length) { + val digit = Random.nextInt(1, 10) + stringBuilder.append(digit.toStr()) + } + return stringBuilder.toString().toLong() + } + + private fun createResourceRandomPaths(resources: Set): Map { + return resources.map { resource -> + val path = Path(UUID.randomUUID().toString()) + resource.id to path + }.associateBy({ it.first }, { it.second }) + } + + @Test + fun testAllResources() = runBlocking { + val expected = shards.map { it.allResources() }.toList().reduce { acc, map -> acc + map } + val allResources = indexAggregation.allResources() + assertEquals(9, allResources.size) // 3 resources per shard, so 3 shards * 3 resources + assertEquals(expected, allResources) + } + + @Test + fun testAllResourcesEmpty() = runBlocking { + val indexAggregation = IndexAggregation(setOf()) + val allResources = indexAggregation.allResources() + assertEquals(0, allResources.size) + assertEquals(mapOf(), allResources) + } + + @Test + fun testGetResource() = runBlocking { + val shard = shards.random() + val resource = shard.allResources().values.random() + val result = indexAggregation.getResource(resource.id) + assertEquals(resource, result) + } + + @Test + fun testGetResourceNotFound() = runBlocking { + val indexAggregation = IndexAggregation(setOf()) + val result = indexAggregation.getResource(ResourceId(0, 123456789)) + assertNull(result) + } + + @Test + fun testGetAllPaths() = runBlocking { + val expected = shards.map { it.allPaths() }.toList().reduce { acc, map -> acc + map } + val result = indexAggregation.allPaths() + assertEquals(9, result.size) // 3 shards * 3 resource per shard + assertEquals(expected, result) + } + + @Test + fun testGetAllPathsEmpty() = runBlocking { + val indexAggregation = IndexAggregation(listOf()) + val result = indexAggregation.allPaths() + assertEquals(0, result.size) + assertEquals(mapOf(), result) + } + + @Test + fun testGetPath() = runBlocking { + val shard = shards.random() + val resource = shard.allResources().values.random() + val result = indexAggregation.getPath(resource.id) + assertTrue(result is Path) + } + + @Test + fun getPathNotFound() = runBlocking { + val indexAggregation = IndexAggregation(setOf()) + val result = indexAggregation.getResource(ResourceId(0, 123456789)) + assertNull(result) + } + + @Test + fun testUpdateAll() = runBlocking { + indexAggregation.updateAll() + assertEquals(3, updatedShards) + } + +}