Skip to content

Commit

Permalink
✅ Add basic tests for cache store and restore, fix invalid "always pa…
Browse files Browse the repository at this point in the history
…rtial restore" status
  • Loading branch information
vlsi committed Aug 9, 2020
1 parent ce7fa0f commit 594213e
Show file tree
Hide file tree
Showing 19 changed files with 554 additions and 17 deletions.
7 changes: 6 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,17 @@ kotlin {
}
}

configure<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension> {
nodeVersion = "12.18.3"
}

val String.v: String get() = rootProject.extra["$this.version"] as String

dependencies {
implementation(project(":lib"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:${"kotlinx-coroutines".v}")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime:${"kotlinx-serialization".v}")
implementation(project(":lib"))
implementation("org.jetbrains:kotlin-extensions:${"kotlin-wrappers".v}-kotlin-${"kotlin".v}")

testImplementation(kotlin("test-js"))
}
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ kotlin.code.style=official

kotlinx-coroutines.version=1.3.8-1.4.0-rc
kotlinx-serialization.version=1.0-M1-1.4.0-rc
kotlin-wrappers.version=1.0.1-pre.110
6 changes: 6 additions & 0 deletions src/main/kotlin/com/github/burrunan/gradle/FsExtensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ suspend fun removeFiles(files: List<String>) {
}
}

suspend fun mkdir(path: String) {
if (!exists(path)) {
fs2.promises.mkdir(path)
}
}

suspend fun exists(path: String) =
suspendCoroutine<Boolean> { cont ->
fs.exists(path.normalizedPath) {
Expand Down
3 changes: 0 additions & 3 deletions src/main/kotlin/com/github/burrunan/gradle/JsExtensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine

inline fun <T : Any> jsObject(builder: T.() -> Unit = {}): T =
(js("({})") as T).apply(builder)

suspend inline fun suspendWithCallback(crossinline block: ((Error?) -> Unit) -> Unit) =
suspendCoroutine<Nothing?> { cont ->
block.invoke { error ->
Expand Down
1 change: 1 addition & 0 deletions src/main/kotlin/com/github/burrunan/gradle/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package com.github.burrunan.gradle
import com.github.burrunan.gradle.github.env.ActionsEnvironment
import com.github.burrunan.gradle.github.event.currentTrigger
import github.actions.core.info
import kotlinext.js.jsObject
import process

internal fun getInput(name: String, required: Boolean = false): String =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package com.github.burrunan.gradle

import NodeJS.ReadableStream
import NodeJS.WritableStream
import kotlinext.js.jsObject
import stream.Duplex
import stream.internal

Expand Down
8 changes: 6 additions & 2 deletions src/main/kotlin/com/github/burrunan/gradle/cache/Cache.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ interface Cache {
sealed class RestoreType {
data class Exact(val path: String) : RestoreType()
data class Partial(val path: String) : RestoreType()
object None : RestoreType()
object Unknown : RestoreType()
object None : RestoreType() {
override fun toString() = "None"
}
object Unknown : RestoreType() {
override fun toString() = "Unknown"
}
}
5 changes: 3 additions & 2 deletions src/main/kotlin/github/actions/cache/CacheExtensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package github.actions.cache
import com.github.burrunan.gradle.cache.RestoreType
import github.actions.core.info
import github.actions.core.warning
import kotlinext.js.jsObject
import kotlinx.coroutines.await

suspend fun restoreAndLog(
Expand All @@ -44,8 +45,8 @@ suspend fun restoreAndLog(
}
}
}
if (result != null) {
return if (result == primaryKey) RestoreType.Exact(result) else RestoreType.Partial(result)
result?.removePrefix(version)?.let {
return if (it.endsWith(primaryKey)) RestoreType.Exact(it) else RestoreType.Partial(it)
}
info("Cache was not found for $primaryKey, restore keys: ${restoreKeys.joinToString(", ")}")
return RestoreType.None
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/github/actions/exec/functions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*/
package github.actions.exec

import com.github.burrunan.gradle.jsObject
import kotlinext.js.jsObject
import kotlinx.coroutines.await

class ExecResult(
Expand Down
81 changes: 81 additions & 0 deletions src/test/kotlin/com/github/burrunan/gradle/CacheServerTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright 2020 Vladimir Sitnikov <sitnikov.vladimir@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.github.burrunan.gradle

import com.github.burrunan.gradle.cache.CacheService
import com.github.burrunan.gradle.cache.RestoreType
import github.actions.cache.restoreAndLog
import github.actions.cache.saveAndLog
import kotlinx.coroutines.await
import kotlin.test.Test
import kotlin.test.assertEquals

class CacheServerTest {
val cacheService = CacheService()

@Test
fun saveCache() = runTest {
val dir = "saveCache"
mkdir(dir)
val file = "$dir/cached.txt"
val contents = "hello, world"
fs2.promises.writeFile(file, contents, "utf8").await()
val patterns = listOf("$dir/**")

val primaryKey = "linux-gradle-123123"

cacheService {
saveAndLog(patterns, primaryKey, "1-")

fs2.promises.unlink(file)

assertEquals(
RestoreType.Exact(primaryKey),
restoreAndLog(
patterns,
primaryKey,
restoreKeys = listOf("linux-gradle-", "linux-"),
version = "1-",
),
"Cache restored from exact match",
)

assertEquals(
fs2.promises.readFile(file, "utf8").await(),
contents,
"Contents after restore should match",
)

assertEquals(
RestoreType.Partial(primaryKey),
restoreAndLog(
patterns,
"asdf$primaryKey",
restoreKeys = listOf("linux-gradle-", "linux-"),
version = "1-",
),
"PK not found => restored from restoreKeys",
)

assertEquals(
fs2.promises.readFile(file, "utf8").await(),
contents,
"Contents after restore should match",
)
}
}
}
27 changes: 19 additions & 8 deletions src/test/kotlin/com/github/burrunan/gradle/GlobTest.kt
Original file line number Diff line number Diff line change
@@ -1,27 +1,38 @@
/*
* Copyright 2020 Vladimir Sitnikov <sitnikov.vladimir@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.github.burrunan.gradle

import com.github.burrunan.gradle.github.formatBytes
import com.github.burrunan.gradle.hashing.hashFilesDetailed
import kotlinx.coroutines.await
import runTest
import kotlin.test.Test
import kotlin.test.assertEquals

class GlobTest {
@Test
fun glob() = runTest {
val dirName = "globTest"
if (!exists(dirName)) {
fs2.promises.mkdir(dirName).await()
}
mkdir(dirName)
fs2.promises.writeFile("$dirName/good.txt", "a", "utf8")
fs2.promises.writeFile("$dirName/bad.txt", "a", "utf8")

val hash = hashFilesDetailed(
"**/*.txt",
"!**/*bad**",
"$dirName/**/*.txt",
"!$dirName/**/*bad**",
)
println("${hash.info.totalBytes.formatBytes()} ${hash.info.totalFiles} files")
val actual = hash.contents.files.entries.joinToString { (file, details) ->
"${details.fileSize.formatBytes()} ${details.hash} $file"
}
Expand Down
32 changes: 32 additions & 0 deletions src/test/kotlin/com/github/burrunan/gradle/StreamExtensions.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright 2020 Vladimir Sitnikov <sitnikov.vladimir@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.github.burrunan.gradle

import Buffer
import NodeJS.ReadableStream

suspend fun <T> ReadableStream.readJson(): T = JSON.parse<T>(readToBuffer().toString("utf8"))

suspend fun ReadableStream.readToBuffer(): Buffer {
val data = mutableListOf<Buffer>()
use {
it.on("data") { chunk: Any ->
data += chunk as Buffer
}
}
return Buffer.concat(data.toTypedArray())
}
55 changes: 55 additions & 0 deletions src/test/kotlin/com/github/burrunan/gradle/cache/CacheContract.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright 2020 Vladimir Sitnikov <sitnikov.vladimir@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.github.burrunan.gradle.cache

external interface GetCacheParams {
val keys: String
val version: String
}

external interface ReserveCacheRequest {
val key: String
val version: String?
}

external interface ReserveCacheResponse {
var cacheId: Number
}

external interface ArtifactCacheEntry {
var cacheKey: String?
var scope: String?
var creationTime: String?
var archiveLocation: String?
}

external interface CommitCacheRequest {
val size: Number
}

external interface InternalCacheOptions {
val compressionMethod: CompressionMethod?
}

external enum class CompressionMethod {
Gzip,

// Long range mode was added to zstd in v1.3.2.
// This enum is for earlier version of zstd that does not have --long support
ZstdWithoutLong,
Zstd
}
Loading

0 comments on commit 594213e

Please sign in to comment.