Initial commit

This commit is contained in:
Peter Niederwieser
2016-01-19 14:51:19 +01:00
committed by Dan Chao
commit ecad035dca
2972 changed files with 211653 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
res1 = "bar"
res2 = ""
res3 = 1
res4 = 2.3
res5 = true
res6 = false
res7 = null

View File

@@ -0,0 +1,25 @@
module com.foo.bar.MyModule
class Person {
firstName: String
lastName: String
age: Int
}
barnOwl: Person = new {
firstName = "Barn Owl"
lastName = "Bird"
age = 38
}
pigeon: Person = new {
firstName = "Pigeon"
lastName = "Bird"
age = 41
}
typealias MyPerson = Person
personClass = Person
personTypeAlias = MyPerson

View File

@@ -0,0 +1,11 @@
res1: DataSize = 1.b
res2: DataSize = 2.kb
res3: DataSize = 3.kib
res4: DataSize = 4.mb
res5: DataSize = 5.mib
res6: DataSize = 6.gb
res7: DataSize = 7.gib
res8: DataSize = 8.tb
res9: DataSize = 9.tib
res10: DataSize = 10.pb
res11: DataSize = 11.pib

View File

@@ -0,0 +1,7 @@
res1 = 1.ns
res2 = 2.us
res3 = 3.ms
res4 = 4.s
res5 = 5.min
res6 = 6.h
res7 = 7.d

View File

@@ -0,0 +1,2 @@
res1 = IntSeq(1, 3)
res2 = IntSeq(1, 4).step(5)

View File

@@ -0,0 +1,6 @@
res1: List<Int> = List(1, 3, 5, 7)
res2: Listing<Int> = new { 2; 4; 6; 8 }
res3: List<Int> = List()
res4: Listing<Int> = new {}
res5: List<List<Int>> = List(List(1, 2))
res6: Listing<Listing<Int>> = new { new { 1; 2 } }

View File

@@ -0,0 +1,15 @@
res1: Map = Map("foo", 1, "bar", 2)
res2: Mapping = new {
["foo"] = 1
["bar"] = 2
}
res3: Mapping = new {
["childMap"] = new Mapping {
["childFoo"] = 3
}
}
res4: Mapping = new {
[Map("foo", 1)] = new Mapping {
["bar"] = 2
}
}

View File

@@ -0,0 +1,2 @@
res1 = Pair(1, 2)
res2 = Pair("foo", "bar")

View File

@@ -0,0 +1,3 @@
res1 = Regex("abc")
res2 = Regex("")
res3 = Regex("(?m)^abc$")

View File

@@ -0,0 +1,3 @@
res1: Set<Int> = Set(1, 3, 5, 7)
res2: Set<Int> = Set()
res3: Set<Any> = Set(1, true, "", null)

View File

@@ -0,0 +1,32 @@
- 1
- basic
- file:///$snippetsDir/input/basic.pkl
-
-
- 16
- res1
- bar
-
- 16
- res2
- ''
-
- 16
- res3
- 1
-
- 16
- res4
- 2.3
-
- 16
- res5
- true
-
- 16
- res6
- false
-
- 16
- res7
- null

View File

@@ -0,0 +1,54 @@
- 1
- com.foo.bar.MyModule
- file:///$snippetsDir/input/classes.pkl
-
-
- 16
- barnOwl
-
- 1
- com.foo.bar.MyModule#Person
- file:///$snippetsDir/input/classes.pkl
-
-
- 16
- firstName
- Barn Owl
-
- 16
- lastName
- Bird
-
- 16
- age
- 38
-
- 16
- pigeon
-
- 1
- com.foo.bar.MyModule#Person
- file:///$snippetsDir/input/classes.pkl
-
-
- 16
- firstName
- Pigeon
-
- 16
- lastName
- Bird
-
- 16
- age
- 41
-
- 16
- personClass
-
- 12
-
- 16
- personTypeAlias
-
- 13

View File

@@ -0,0 +1,81 @@
- 1
- datasize
- file:///$snippetsDir/input/datasize.pkl
-
-
- 16
- res1
-
- 8
- 1.0
- b
-
- 16
- res2
-
- 8
- 2.0
- kb
-
- 16
- res3
-
- 8
- 3.0
- kib
-
- 16
- res4
-
- 8
- 4.0
- mb
-
- 16
- res5
-
- 8
- 5.0
- mib
-
- 16
- res6
-
- 8
- 6.0
- gb
-
- 16
- res7
-
- 8
- 7.0
- gib
-
- 16
- res8
-
- 8
- 8.0
- tb
-
- 16
- res9
-
- 8
- 9.0
- tib
-
- 16
- res10
-
- 8
- 10.0
- pb
-
- 16
- res11
-
- 8
- 11.0
- pib

View File

@@ -0,0 +1,53 @@
- 1
- duration
- file:///$snippetsDir/input/duration.pkl
-
-
- 16
- res1
-
- 7
- 1.0
- ns
-
- 16
- res2
-
- 7
- 2.0
- us
-
- 16
- res3
-
- 7
- 3.0
- ms
-
- 16
- res4
-
- 7
- 4.0
- s
-
- 16
- res5
-
- 7
- 5.0
- min
-
- 16
- res6
-
- 7
- 6.0
- h
-
- 16
- res7
-
- 7
- 7.0
- d

View File

@@ -0,0 +1,20 @@
- 1
- intseq
- file:///$snippetsDir/input/intseq.pkl
-
-
- 16
- res1
-
- 10
- 1
- 3
- 1
-
- 16
- res2
-
- 10
- 1
- 4
- 5

View File

@@ -0,0 +1,58 @@
- 1
- list
- file:///$snippetsDir/input/list.pkl
-
-
- 16
- res1
-
- 4
-
- 1
- 3
- 5
- 7
-
- 16
- res2
-
- 5
-
- 2
- 4
- 6
- 8
-
- 16
- res3
-
- 4
- []
-
- 16
- res4
-
- 5
- []
-
- 16
- res5
-
- 4
-
-
- 4
-
- 1
- 2
-
- 16
- res6
-
- 5
-
-
- 5
-
- 1
- 2

View File

@@ -0,0 +1,44 @@
- 1
- map
- file:///$snippetsDir/input/map.pkl
-
-
- 16
- res1
-
- 2
-
foo: 1
bar: 2
-
- 16
- res2
-
- 3
-
foo: 1
bar: 2
-
- 16
- res3
-
- 3
-
childMap:
- 3
-
childFoo: 3
-
- 16
- res4
-
- 3
-
?
- 2
-
foo: 1
:
- 3
-
bar: 2

View File

@@ -0,0 +1,18 @@
- 1
- pair
- file:///$snippetsDir/input/pair.pkl
-
-
- 16
- res1
-
- 9
- 1
- 2
-
- 16
- res2
-
- 9
- foo
- bar

View File

@@ -0,0 +1,22 @@
- 1
- regex
- file:///$snippetsDir/input/regex.pkl
-
-
- 16
- res1
-
- 11
- abc
-
- 16
- res2
-
- 11
- ''
-
- 16
- res3
-
- 11
- (?m)^abc$

View File

@@ -0,0 +1,30 @@
- 1
- set
- file:///$snippetsDir/input/set.pkl
-
-
- 16
- res1
-
- 6
-
- 1
- 3
- 5
- 7
-
- 16
- res2
-
- 6
- []
-
- 16
- res3
-
- 6
-
- 1
- true
- ''
- null

View File

@@ -0,0 +1,67 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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
*
* https://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 org.pkl.server
import java.nio.file.Path
import kotlin.reflect.KClass
import org.junit.platform.commons.annotation.Testable
import org.pkl.commons.test.InputOutputTestEngine
import org.pkl.core.Loggers
import org.pkl.core.ModuleSource
import org.pkl.core.SecurityManagers
import org.pkl.core.StackFrameTransformers
import org.pkl.core.module.ModuleKeyFactories
@Testable class BinaryEvaluatorSnippetTests
class BinaryEvaluatorSnippetTestEngine : InputOutputTestEngine() {
override val testClass: KClass<*> = BinaryEvaluatorSnippetTests::class
private val snippetsDir = rootProjectDir.resolve("pkl-server/src/test/files/SnippetTests")
private val outputDir = snippetsDir.resolve("output")
override val inputDir: Path = snippetsDir.resolve("input")
override val isInputFile: (Path) -> Boolean = { true }
override fun expectedOutputFileFor(inputFile: Path): Path {
val relativePath = inputDir.relativize(inputFile).toString()
return outputDir.resolve(relativePath.dropLast(3) + "yaml")
}
private val evaluator =
BinaryEvaluator(
StackFrameTransformers.empty,
SecurityManagers.defaultManager,
Loggers.stdErr(),
listOf(ModuleKeyFactories.file),
listOf(),
mapOf(),
mapOf(),
null,
null,
null,
null
)
private fun String.stripFilePaths() = replace(snippetsDir.toString(), "/\$snippetsDir")
override fun generateOutputFor(inputFile: Path): Pair<Boolean, String> {
val bytes = evaluator.evaluate(ModuleSource.path(inputFile), null)
return true to bytes.debugRendering.stripFilePaths()
}
}

View File

@@ -0,0 +1,150 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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
*
* https://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 org.pkl.server
import java.nio.file.Path
import java.util.regex.Pattern
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.pkl.core.*
import org.pkl.core.module.ModuleKeyFactories
import org.pkl.core.resource.ResourceReaders
class BinaryEvaluatorTest {
private val evaluator =
BinaryEvaluator(
StackFrameTransformers.defaultTransformer,
SecurityManagers.standard(
listOf(Pattern.compile(".*")),
listOf(Pattern.compile(".*")),
SecurityManagers.defaultTrustLevels,
Path.of("")
),
Loggers.noop(),
listOf(ModuleKeyFactories.standardLibrary),
listOf(ResourceReaders.environmentVariable(), ResourceReaders.externalProperty()),
mapOf(),
mapOf(),
null,
null,
null,
null
)
private fun evaluate(text: String, expression: String?) =
evaluator.evaluate(ModuleSource.text(text), expression)
@Test
fun `evaluate whole module`() {
val bytes = evaluate("foo = 1", null)
assertThat(bytes.debugRendering)
.isEqualTo(
"""
- 1
- text
- repl:text
-
-
- 16
- foo
- 1
"""
.trimIndent()
)
}
@Test
fun `evaluate subpath`() {
val bytes =
evaluate(
"""
foo {
bar = 2
}
"""
.trimIndent(),
"foo.bar"
)
assertThat(bytes.asInt()).isEqualTo(2)
}
@Test
fun `evaluate output text`() {
val bytes =
evaluate(
"""
foo {
bar = 2
}
output {
renderer = new YamlRenderer {}
}
"""
.trimIndent(),
"output.text"
)
assertThat(bytes.asString())
.isEqualTo(
"""
foo:
bar: 2
"""
.trimIndent()
)
}
@Test
fun `evaluate let expression`() {
val bytes = evaluate("foo = 1", "let (bar = 2) foo + bar")
assertThat(bytes.asInt()).isEqualTo(3)
}
@Test
fun `evaluate import expression`() {
val bytes = evaluate("", """import("pkl:release").current.documentation.homepage""")
assertThat(bytes.asString()).startsWith("https://pkl-lang.org/")
}
@Test
fun `evaluate expression with invalid syntax`() {
val error = assertThrows<PklException> { evaluate("foo = 1", "<>!!!") }
assertThat(error).hasMessageContaining("Mismatched input")
assertThat(error).hasMessageContaining("<>!!!")
}
@Test
fun `evaluate non-expression`() {
val error = assertThrows<PklException> { evaluate("bar = 2", "bar = 15") }
assertThat(error).hasMessageContaining("Mismatched input")
assertThat(error).hasMessageContaining("bar = 15")
}
@Test
fun `evaluate semantically invalid expression`() {
val error = assertThrows<PklException> { evaluate("foo = 1", "foo as String") }
assertThat(error).hasMessageContaining("Expected value of type `String`, but got type `Int`")
}
}

View File

@@ -0,0 +1,275 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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
*
* https://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 org.pkl.server
import java.io.PipedInputStream
import java.io.PipedOutputStream
import java.net.URI
import java.nio.file.Path
import java.time.Duration
import java.util.regex.Pattern
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.msgpack.core.MessagePack
import org.pkl.core.module.PathElement
import org.pkl.core.packages.Checksums
class MessagePackCodecTest {
private val encoder: MessageEncoder
private val decoder: MessageDecoder
init {
val inputStream = PipedInputStream()
val outputStream = PipedOutputStream(inputStream)
encoder = MessagePackEncoder(MessagePack.newDefaultPacker(outputStream))
decoder = MessagePackDecoder(MessagePack.newDefaultUnpacker(inputStream))
}
private fun roundtrip(message: Message) {
encoder.encode(message)
val decoded = decoder.decode()
assertThat(decoded).isEqualTo(message)
}
@Test
fun `round-trip CreateEvaluatorRequest`() {
val resourceReader1 =
ResourceReaderSpec(
scheme = "resourceReader1",
hasHierarchicalUris = true,
isGlobbable = true,
)
val resourceReader2 =
ResourceReaderSpec(
scheme = "resourceReader2",
hasHierarchicalUris = true,
isGlobbable = false,
)
val moduleReader1 =
ModuleReaderSpec(
scheme = "moduleReader1",
hasHierarchicalUris = true,
isGlobbable = true,
isLocal = true
)
val moduleReader2 =
ModuleReaderSpec(
scheme = "moduleReader2",
hasHierarchicalUris = true,
isGlobbable = false,
isLocal = false
)
roundtrip(
CreateEvaluatorRequest(
requestId = 123,
allowedModules = listOf("pkl", "file", "https").map(Pattern::compile),
allowedResources =
listOf("pkl", "file", "https", "resourceReader1", "resourceReader2")
.map(Pattern::compile),
clientResourceReaders = listOf(resourceReader1, resourceReader2),
clientModuleReaders = listOf(moduleReader1, moduleReader2),
modulePaths = listOf(Path.of("some/path.zip"), Path.of("other/path.zip")),
env = mapOf("KEY1" to "VALUE1", "KEY2" to "VALUE2"),
properties = mapOf("property1" to "value1", "property2" to "value2"),
timeout = Duration.ofSeconds(10),
rootDir = Path.of("root/dir"),
cacheDir = Path.of("cache/dir"),
outputFormat = "pcf",
project =
Project(
projectFileUri = URI("file:///dummy/PklProject"),
packageUri = null,
dependencies =
mapOf(
"foo" to
Project(
projectFileUri = URI("file:///foo"),
packageUri = URI("package://localhost:12110/foo@1.0.0"),
dependencies =
mapOf(
"bar" to
Project(
projectFileUri = URI("file:///bar"),
packageUri = URI("package://localhost:12110/bar@1.1.0"),
dependencies = emptyMap()
)
)
),
"baz" to
RemoteDependency(URI("package://localhost:12110/baz@1.1.0"), Checksums("abc123"))
)
)
)
)
}
@Test
fun `round-trip CreateEvaluatorResponse`() {
roundtrip(CreateEvaluatorResponse(requestId = 123, evaluatorId = 456, error = null))
}
@Test
fun `round-trip CloseEvaluator`() {
roundtrip(CloseEvaluator(evaluatorId = 123))
}
@Test
fun `round-trip EvaluateRequest`() {
roundtrip(
EvaluateRequest(
requestId = 123,
evaluatorId = 456,
moduleUri = URI("some/module.pkl"),
moduleText = null,
expr = "some + expression"
)
)
}
@Test
fun `round-trip EvaluateResponse`() {
roundtrip(
EvaluateResponse(
requestId = 123,
evaluatorId = 456,
result = byteArrayOf(1, 2, 3, 4, 5),
error = null
)
)
}
@Test
fun `round-trip LogMessage`() {
roundtrip(
LogMessage(
evaluatorId = 123,
level = 0,
message = "Hello, world!",
frameUri = "file:///some/module.pkl"
)
)
}
@Test
fun `round-trip ReadResourceRequest`() {
roundtrip(
ReadResourceRequest(requestId = 123, evaluatorId = 456, uri = URI("some/resource.json"))
)
}
@Test
fun `round-trip ReadResourceResponse`() {
roundtrip(
ReadResourceResponse(
requestId = 123,
evaluatorId = 456,
contents = byteArrayOf(1, 2, 3, 4, 5),
error = null
)
)
}
@Test
fun `round-trip ReadModuleRequest`() {
roundtrip(ReadModuleRequest(requestId = 123, evaluatorId = 456, uri = URI("some/module.pkl")))
}
@Test
fun `round-trip ReadModuleResponse`() {
roundtrip(
ReadModuleResponse(requestId = 123, evaluatorId = 456, contents = "x = 42", error = null)
)
}
@Test
fun `round-trip ListModulesRequest`() {
roundtrip(ListModulesRequest(requestId = 135, evaluatorId = 246, uri = URI("foo:/bar/baz/biz")))
}
@Test
fun `round-trip ListModulesResponse`() {
roundtrip(
ListModulesResponse(
requestId = 123,
evaluatorId = 234,
pathElements = listOf(PathElement("foo", true), PathElement("bar", false)),
error = null
)
)
roundtrip(
ListModulesResponse(
requestId = 123,
evaluatorId = 234,
pathElements = null,
error = "Something dun went wrong"
)
)
}
@Test
fun `round-trip ListResourcesRequest`() {
roundtrip(ListResourcesRequest(requestId = 987, evaluatorId = 1359, uri = URI("bar:/bazzy")))
}
@Test
fun `round-trip ListResourcesResponse`() {
roundtrip(
ListResourcesResponse(
requestId = 3851,
evaluatorId = 3019,
pathElements = listOf(PathElement("foo", true), PathElement("bar", false)),
error = null
)
)
roundtrip(
ListResourcesResponse(
requestId = 3851,
evaluatorId = 3019,
pathElements = null,
error = "something went wrong"
)
)
}
@Test
fun `decode request with missing request ID`() {
val bytes =
MessagePack.newDefaultBufferPacker()
.apply {
packArrayHeader(2)
packInt(MessageType.CREATE_EVALUATOR_REQUEST.code)
packMapHeader(1)
packString("clientResourceSchemes")
packArrayHeader(0)
}
.toByteArray()
val decoder = MessagePackDecoder(MessagePack.newDefaultUnpacker(bytes))
val exception = assertThrows<DecodeException> { decoder.decode() }
assertThat(exception.message).contains("requestId")
}
@Test
fun `decode invalid message header`() {
val bytes = MessagePack.newDefaultBufferPacker().apply { packInt(2) }.toByteArray()
val decoder = MessagePackDecoder(MessagePack.newDefaultUnpacker(bytes))
val exception = assertThrows<DecodeException> { decoder.decode() }
assertThat(exception).hasMessage("Malformed message header.")
assertThat(exception).hasRootCauseMessage("Expected Array, but got Integer (02)")
}
}

View File

@@ -0,0 +1,110 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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
*
* https://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 org.pkl.server
import java.lang.IllegalStateException
import org.msgpack.core.MessagePack
import org.msgpack.core.MessageUnpacker
import org.msgpack.value.ValueType
import org.pkl.core.util.yaml.YamlEmitter
/** Renders MessagePack structures in YAML. */
class MessagePackDebugRenderer(bytes: ByteArray) {
private val unpacker: MessageUnpacker = MessagePack.newDefaultUnpacker(bytes)
private val currIndent = StringBuilder("")
private val sb = StringBuilder()
private val indent = " "
private val yamlEmitter = YamlEmitter.create(sb, "1.2", indent)
private fun incIndent() {
currIndent.append(indent)
}
private fun decIndent() {
currIndent.setLength(currIndent.length - indent.length)
}
private fun newline() {
sb.append("\n")
sb.append(currIndent)
}
private fun renderKey() {
val mf = unpacker.nextFormat
when (mf.valueType!!) {
ValueType.STRING -> yamlEmitter.emit(unpacker.unpackString(), currIndent, true)
ValueType.MAP,
ValueType.ARRAY -> {
sb.append("? ")
incIndent()
renderValue()
decIndent()
newline()
}
else -> renderValue()
}
sb.append(": ")
}
private fun renderValue() {
val mf = unpacker.nextFormat
when (mf.valueType!!) {
ValueType.INTEGER,
ValueType.FLOAT,
ValueType.BOOLEAN,
ValueType.NIL -> sb.append(unpacker.unpackValue().toJson())
ValueType.STRING -> yamlEmitter.emit(unpacker.unpackString(), currIndent, false)
ValueType.ARRAY -> {
val size = unpacker.unpackArrayHeader()
if (size == 0) {
sb.append("[]")
return
}
for (i in 0 until size) {
newline()
sb.append("- ")
incIndent()
renderValue()
decIndent()
}
}
ValueType.MAP -> {
val size = unpacker.unpackMapHeader()
if (size == 0) {
sb.append("{}")
return
}
for (i in 0 until size) {
newline()
renderKey()
incIndent()
renderValue()
decIndent()
}
}
ValueType.BINARY,
ValueType.EXTENSION -> throw IllegalStateException("Unexpected value type ${mf.valueType}")
}
}
val output by lazy {
renderValue()
sb.toString().removePrefix("\n")
}
}
val ByteArray.debugRendering
get() = MessagePackDebugRenderer(this).output

View File

@@ -0,0 +1,994 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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
*
* https://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 org.pkl.server
import java.io.PipedInputStream
import java.io.PipedOutputStream
import java.net.URI
import java.nio.file.Path
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.regex.Pattern
import kotlin.io.path.createDirectories
import kotlin.io.path.outputStream
import kotlin.io.path.writeText
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir
import org.msgpack.core.MessagePack
import org.pkl.commons.test.PackageServer
import org.pkl.core.module.PathElement
class ServerTest {
companion object {
private const val useDirectTransport = false
private val executor: ExecutorService =
if (useDirectTransport) {
createDirectExecutor()
} else {
Executors.newCachedThreadPool()
}
@AfterAll
@JvmStatic
@Suppress("unused")
fun afterAll() {
executor.shutdown()
}
}
private val transports: Pair<MessageTransport, MessageTransport> = run {
if (useDirectTransport) {
MessageTransports.direct()
} else {
val in1 = PipedInputStream()
val out1 = PipedOutputStream(in1)
val in2 = PipedInputStream()
val out2 = PipedOutputStream(in2)
MessageTransports.stream(in1, out2) to MessageTransports.stream(in2, out1)
}
}
private val client: TestTransport = TestTransport(transports.first)
private val server: Server = Server(transports.second)
@BeforeEach
fun before() {
executor.execute { server.start() }
executor.execute { client.start() }
}
@AfterEach
fun after() {
client.close()
server.close()
}
@Test
fun `create and close evaluator`() {
val evaluatorId = client.sendCreateEvaluatorRequest(requestId = 123)
client.send(CloseEvaluator(evaluatorId = evaluatorId))
}
@Test
fun `evaluate module`() {
val evaluatorId = client.sendCreateEvaluatorRequest()
val requestId = 234L
client.send(
EvaluateRequest(
requestId = requestId,
evaluatorId = evaluatorId,
moduleUri = URI("repl:text"),
moduleText =
"""
foo {
bar = "bar"
}
"""
.trimIndent(),
expr = null
)
)
val response = client.receive<EvaluateResponse>()
assertThat(response.error).isNull()
assertThat(response.result).isNotNull
assertThat(response.requestId).isEqualTo(requestId)
val unpacker = MessagePack.newDefaultUnpacker(response.result)
val value = unpacker.unpackValue()
assertThat(value.isArrayValue)
}
@Test
fun `trace logs`() {
val evaluatorId = client.sendCreateEvaluatorRequest()
client.send(
EvaluateRequest(
requestId = 1,
evaluatorId = evaluatorId,
moduleUri = URI("repl:text"),
moduleText =
"""
foo = trace(1 + 2 + 3)
"""
.trimIndent(),
expr = null
)
)
val response = client.receive<LogMessage>()
assertThat(response.level).isEqualTo(0)
assertThat(response.message).isEqualTo("1 + 2 + 3 = 6")
client.receive<EvaluateResponse>()
}
@Test
fun `warn logs`() {
val evaluatorId = client.sendCreateEvaluatorRequest()
client.send(
EvaluateRequest(
requestId = 1,
evaluatorId = evaluatorId,
moduleUri = URI("repl:text"),
moduleText =
"""
@Deprecated { message = "use bar instead" }
function foo() = 5
result = foo()
"""
.trimIndent(),
expr = null
)
)
val response = client.receive<LogMessage>()
assertThat(response.level).isEqualTo(1)
assertThat(response.message).contains("use bar instead")
client.receive<EvaluateResponse>()
}
@Test
fun `read resource`() {
val reader =
ResourceReaderSpec(scheme = "bahumbug", hasHierarchicalUris = true, isGlobbable = false)
val evaluatorId = client.sendCreateEvaluatorRequest(resourceReaders = listOf(reader))
client.send(
EvaluateRequest(
requestId = 1,
evaluatorId = evaluatorId,
moduleUri = URI("repl:text"),
moduleText = """res = read("bahumbug:/foo.pkl").text""",
expr = "res"
)
)
val readResourceMsg = client.receive<ReadResourceRequest>()
assertThat(readResourceMsg.uri.toString()).isEqualTo("bahumbug:/foo.pkl")
assertThat(readResourceMsg.evaluatorId).isEqualTo(evaluatorId)
client.send(
ReadResourceResponse(
requestId = readResourceMsg.requestId,
evaluatorId = evaluatorId,
contents = "my bahumbug".toByteArray(),
error = null
)
)
val evaluateResponse = client.receive<EvaluateResponse>()
assertThat(evaluateResponse.error).isNull()
val unpacker = MessagePack.newDefaultUnpacker(evaluateResponse.result)
val value = unpacker.unpackValue()
assertThat(value.asStringValue().asString()).isEqualTo("my bahumbug")
}
@Test
fun `read resource error`() {
val reader =
ResourceReaderSpec(scheme = "bahumbug", hasHierarchicalUris = true, isGlobbable = false)
val evaluatorId = client.sendCreateEvaluatorRequest(resourceReaders = listOf(reader))
client.send(
EvaluateRequest(
requestId = 1,
evaluatorId = evaluatorId,
moduleUri = URI("repl:text"),
moduleText = """res = read("bahumbug:/foo.txt").text""",
expr = "res"
)
)
val readResourceMsg = client.receive<ReadResourceRequest>()
client.send(
ReadResourceResponse(
requestId = readResourceMsg.requestId,
evaluatorId = evaluatorId,
contents = null,
error = "cannot read my bahumbug"
)
)
val evaluateResponse = client.receive<EvaluateResponse>()
assertThat(evaluateResponse.error).contains("bahumbug:/foo.txt")
assertThat(evaluateResponse.error).doesNotContain("org.pkl.core.PklBugException")
}
@Test
fun `glob resource`() {
val reader = ResourceReaderSpec(scheme = "bird", hasHierarchicalUris = true, isGlobbable = true)
val evaluatorId = client.sendCreateEvaluatorRequest(resourceReaders = listOf(reader))
client.send(
EvaluateRequest(
requestId = 1,
evaluatorId = evaluatorId,
moduleUri = URI("repl:text"),
moduleText =
"""
res = read*("bird:/**.txt").keys
"""
.trimIndent(),
expr = "res"
)
)
val listResourcesRequest = client.receive<ListResourcesRequest>()
assertThat(listResourcesRequest.uri.toString()).isEqualTo("bird:/")
client.send(
ListResourcesResponse(
requestId = listResourcesRequest.requestId,
evaluatorId = listResourcesRequest.evaluatorId,
pathElements = listOf(PathElement("foo.txt", false), PathElement("subdir", true)),
error = null
)
)
val listResourcesRequest2 = client.receive<ListResourcesRequest>()
assertThat(listResourcesRequest2.uri.toString()).isEqualTo("bird:/subdir/")
client.send(
ListResourcesResponse(
requestId = listResourcesRequest2.requestId,
evaluatorId = listResourcesRequest2.evaluatorId,
pathElements =
listOf(
PathElement("bar.txt", false),
),
error = null
)
)
val evaluateResponse = client.receive<EvaluateResponse>()
assertThat(evaluateResponse.result!!.debugYaml)
.isEqualTo(
"""
- 6
-
- bird:/foo.txt
- bird:/subdir/bar.txt
"""
.trimIndent()
)
}
@Test
fun `glob resource error`() {
val reader = ResourceReaderSpec(scheme = "bird", hasHierarchicalUris = true, isGlobbable = true)
val evaluatorId = client.sendCreateEvaluatorRequest(resourceReaders = listOf(reader))
client.send(
EvaluateRequest(
requestId = 1,
evaluatorId = evaluatorId,
moduleUri = URI("repl:text"),
moduleText =
"""
res = read*("bird:/**.txt").keys
"""
.trimIndent(),
expr = "res"
)
)
val listResourcesRequest = client.receive<ListResourcesRequest>()
assertThat(listResourcesRequest.uri.toString()).isEqualTo("bird:/")
client.send(
ListResourcesResponse(
requestId = listResourcesRequest.requestId,
evaluatorId = listResourcesRequest.evaluatorId,
pathElements = null,
error = "didnt work"
)
)
val evaluateResponse = client.receive<EvaluateResponse>()
assertThat(evaluateResponse.error)
.isEqualTo(
"""
Pkl Error
I/O error resolving glob pattern `bird:/**.txt`.
IOException: didnt work
1 | res = read*("bird:/**.txt").keys
^^^^^^^^^^^^^^^^^^^^^
at text#res (repl:text)
1 | res
^^^
at (repl:text)
"""
.trimIndent()
)
}
@Test
fun `read module`() {
val reader =
ModuleReaderSpec(
scheme = "bird",
hasHierarchicalUris = true,
isLocal = true,
isGlobbable = false
)
val evaluatorId = client.sendCreateEvaluatorRequest(moduleReaders = listOf(reader))
client.send(
EvaluateRequest(
requestId = 1,
evaluatorId = evaluatorId,
moduleUri = URI("repl:text"),
moduleText = """res = import("bird:/pigeon.pkl").value""",
expr = "res"
)
)
val readModuleMsg = client.receive<ReadModuleRequest>()
assertThat(readModuleMsg.uri.toString()).isEqualTo("bird:/pigeon.pkl")
assertThat(readModuleMsg.evaluatorId).isEqualTo(evaluatorId)
client.send(
ReadModuleResponse(
requestId = readModuleMsg.requestId,
evaluatorId = evaluatorId,
contents = "value = 5",
error = null
)
)
val evaluateResponse = client.receive<EvaluateResponse>()
assertThat(evaluateResponse.error).isNull()
val unpacker = MessagePack.newDefaultUnpacker(evaluateResponse.result)
val value = unpacker.unpackValue()
assertThat(value.asIntegerValue().asInt()).isEqualTo(5)
}
@Test
fun `read module error`() {
val reader =
ModuleReaderSpec(
scheme = "bird",
hasHierarchicalUris = true,
isLocal = true,
isGlobbable = false
)
val evaluatorId = client.sendCreateEvaluatorRequest(moduleReaders = listOf(reader))
client.send(
EvaluateRequest(
requestId = 1,
evaluatorId = evaluatorId,
moduleUri = URI("repl:text"),
moduleText = """res = import("bird:/pigeon.pkl").value""",
expr = "res"
)
)
val readModuleMsg = client.receive<ReadModuleRequest>()
assertThat(readModuleMsg.uri.toString()).isEqualTo("bird:/pigeon.pkl")
assertThat(readModuleMsg.evaluatorId).isEqualTo(evaluatorId)
client.send(
ReadModuleResponse(
requestId = readModuleMsg.requestId,
evaluatorId = evaluatorId,
contents = null,
error = "Don't know where Pigeon is"
)
)
val evaluateResponse = client.receive<EvaluateResponse>()
assertThat(evaluateResponse.error).contains("Don't know where Pigeon is")
}
@Test
fun `glob module`() {
val reader =
ModuleReaderSpec(
scheme = "bird",
hasHierarchicalUris = true,
isLocal = true,
isGlobbable = true
)
val evaluatorId = client.sendCreateEvaluatorRequest(moduleReaders = listOf(reader))
client.send(
EvaluateRequest(
requestId = 1,
evaluatorId = evaluatorId,
moduleUri = URI("repl:text"),
moduleText = """res = import*("bird:/**.pkl").keys""",
expr = "res"
)
)
val listModulesMsg = client.receive<ListModulesRequest>()
assertThat(listModulesMsg.uri.scheme).isEqualTo("bird")
assertThat(listModulesMsg.uri.path).isEqualTo("/")
client.send(
ListModulesResponse(
requestId = listModulesMsg.requestId,
evaluatorId = evaluatorId,
pathElements =
listOf(
PathElement("birds", true),
PathElement("majesticBirds", true),
PathElement("Person.pkl", false)
),
error = null
)
)
val listModulesMsg2 = client.receive<ListModulesRequest>()
assertThat(listModulesMsg2.uri.scheme).isEqualTo("bird")
assertThat(listModulesMsg2.uri.path).isEqualTo("/birds/")
client.send(
ListModulesResponse(
requestId = listModulesMsg2.requestId,
evaluatorId = listModulesMsg2.evaluatorId,
pathElements =
listOf(
PathElement("pigeon.pkl", false),
PathElement("parrot.pkl", false),
),
error = null
)
)
val listModulesMsg3 = client.receive<ListModulesRequest>()
assertThat(listModulesMsg3.uri.scheme).isEqualTo("bird")
assertThat(listModulesMsg3.uri.path).isEqualTo("/majesticBirds/")
client.send(
ListModulesResponse(
requestId = listModulesMsg3.requestId,
evaluatorId = listModulesMsg3.evaluatorId,
pathElements =
listOf(
PathElement("barnOwl.pkl", false),
PathElement("elfOwl.pkl", false),
),
error = null
)
)
val evaluateResponse = client.receive<EvaluateResponse>()
assertThat(evaluateResponse.result!!.debugRendering)
.isEqualTo(
"""
- 6
-
- bird:/Person.pkl
- bird:/birds/parrot.pkl
- bird:/birds/pigeon.pkl
- bird:/majesticBirds/barnOwl.pkl
- bird:/majesticBirds/elfOwl.pkl
"""
.trimIndent()
)
}
@Test
fun `glob module error`() {
val reader =
ModuleReaderSpec(
scheme = "bird",
hasHierarchicalUris = true,
isLocal = true,
isGlobbable = true
)
val evaluatorId = client.sendCreateEvaluatorRequest(moduleReaders = listOf(reader))
client.send(
EvaluateRequest(
requestId = 1,
evaluatorId = evaluatorId,
moduleUri = URI("repl:text"),
moduleText = """res = import*("bird:/**.pkl").keys""",
expr = "res"
)
)
val listModulesMsg = client.receive<ListModulesRequest>()
assertThat(listModulesMsg.uri.scheme).isEqualTo("bird")
assertThat(listModulesMsg.uri.path).isEqualTo("/")
client.send(
ListModulesResponse(
requestId = listModulesMsg.requestId,
evaluatorId = evaluatorId,
pathElements = null,
error = "nope"
)
)
val evaluateResponse = client.receive<EvaluateResponse>()
assertThat(evaluateResponse.error)
.isEqualTo(
"""
Pkl Error
I/O error resolving glob pattern `bird:/**.pkl`.
IOException: nope
1 | res = import*("bird:/**.pkl").keys
^^^^^^^^^^^^^^^^^^^^^^^
at text#res (repl:text)
1 | res
^^^
at (repl:text)
"""
.trimIndent()
)
}
@Test
fun `read and evaluate module path from jar`(@TempDir tempDir: Path) {
val jarFile = tempDir.resolve("resource1.jar")
jarFile.outputStream().use { outStream ->
javaClass.getResourceAsStream("resource1.jar")!!.use { inStream ->
inStream.copyTo(outStream)
}
}
val evaluatorId = client.sendCreateEvaluatorRequest(modulePaths = listOf(jarFile))
client.send(
EvaluateRequest(
requestId = 1,
evaluatorId = evaluatorId,
moduleUri = URI("modulepath:/dir1/module.pkl"),
moduleText = null,
expr = "output.text"
)
)
val response = client.receive<EvaluateResponse>()
assertThat(response.error).isNull()
val tripleQuote = "\"\"\""
assertThat(response.result!!.debugYaml)
.isEqualTo(
"""
|
res1 {
uri = "modulepath:/dir1/resource1.txt"
text = $tripleQuote
content
$tripleQuote
base64 = "Y29udGVudAo="
}
res2 {
uri = "modulepath:/dir1/resource1.txt"
text = $tripleQuote
content
$tripleQuote
base64 = "Y29udGVudAo="
}
res3 {
ressy = "the module2 output"
}
"""
.trimIndent()
)
}
@Test
fun `import triple-dot path`() {
val reader =
ModuleReaderSpec(
scheme = "bird",
hasHierarchicalUris = true,
isLocal = true,
isGlobbable = true
)
val evaluatorId = client.sendCreateEvaluatorRequest(moduleReaders = listOf(reader))
client.send(
EvaluateRequest(
requestId = 1,
evaluatorId = evaluatorId,
moduleUri = URI("bird:/foo/bar/baz.pkl"),
moduleText =
"""
import ".../buz.pkl"
res = buz.res
"""
.trimIndent(),
expr = "res"
)
)
val readModuleRequest = client.receive<ReadModuleRequest>()
assertThat(readModuleRequest.uri).isEqualTo(URI("bird:/foo/buz.pkl"))
client.send(
ReadModuleResponse(
requestId = readModuleRequest.requestId,
evaluatorId = readModuleRequest.evaluatorId,
contents = null,
error = "not here"
)
)
val readModuleRequest2 = client.receive<ReadModuleRequest>()
assertThat(readModuleRequest2.uri).isEqualTo(URI("bird:/buz.pkl"))
client.send(
ReadModuleResponse(
requestId = readModuleRequest2.requestId,
evaluatorId = readModuleRequest2.evaluatorId,
contents = "res = 1",
error = null
)
)
val evaluatorResponse = client.receive<EvaluateResponse>()
assertThat(evaluatorResponse.result!!.debugYaml).isEqualTo("1")
}
@Test
fun `evaluate error`() {
val evaluatorId = client.sendCreateEvaluatorRequest()
client.send(
EvaluateRequest(
requestId = 1,
evaluatorId = evaluatorId,
moduleUri = URI("repl:text"),
moduleText = """foo = 1""",
expr = "foo as String"
)
)
val evaluateResponse = client.receive<EvaluateResponse>()
assertThat(evaluateResponse.requestId).isEqualTo(1)
assertThat(evaluateResponse.error).contains("Expected value of type")
}
@Test
fun `evaluate client-provided module reader`() {
val reader =
ModuleReaderSpec(
scheme = "bird",
hasHierarchicalUris = true,
isLocal = false,
isGlobbable = false
)
val evaluatorId = client.sendCreateEvaluatorRequest(moduleReaders = listOf(reader))
client.send(
EvaluateRequest(
requestId = 1,
evaluatorId = evaluatorId,
moduleUri = URI("bird:/pigeon.pkl"),
moduleText = null,
expr = "output.text",
)
)
val readModuleRequest = client.receive<ReadModuleRequest>()
assertThat(readModuleRequest.uri.toString()).isEqualTo("bird:/pigeon.pkl")
client.send(
ReadModuleResponse(
requestId = readModuleRequest.requestId,
evaluatorId = evaluatorId,
contents =
"""
firstName = "Pigeon"
lastName = "Bird"
fullName = firstName + " " + lastName
"""
.trimIndent(),
error = null
)
)
val evaluateResponse = client.receive<EvaluateResponse>()
assertThat(evaluateResponse.result).isNotNull
assertThat(evaluateResponse.result!!.debugYaml)
.isEqualTo(
"""
|
firstName = "Pigeon"
lastName = "Bird"
fullName = "Pigeon Bird"
"""
.trimIndent()
)
}
@Test
fun `concurrent evaluations`() {
val reader =
ModuleReaderSpec(
scheme = "bird",
hasHierarchicalUris = true,
isLocal = false,
isGlobbable = false
)
val evaluatorId = client.sendCreateEvaluatorRequest(moduleReaders = listOf(reader))
client.send(
EvaluateRequest(
requestId = 1,
evaluatorId = evaluatorId,
moduleUri = URI("bird:/pigeon.pkl"),
moduleText = null,
expr = "output.text",
)
)
client.send(
EvaluateRequest(
requestId = 2,
evaluatorId = evaluatorId,
moduleUri = URI("bird:/parrot.pkl"),
moduleText = null,
expr = "output.text"
)
)
// evaluation is single-threaded; `parrot.pkl` gets evaluated after `pigeon.pkl` completes.
val response11 = client.receive<ReadModuleRequest>()
assertThat(response11.uri.toString()).isEqualTo("bird:/pigeon.pkl")
client.send(
ReadModuleResponse(
response11.requestId,
evaluatorId,
contents =
"""
firstName = "Pigeon"
lastName = "Bird"
fullName = firstName + " " + lastName
"""
.trimIndent(),
error = null
)
)
val response12 = client.receive<EvaluateResponse>()
assertThat(response12.result).isNotNull
assertThat(response12.result!!.debugYaml)
.isEqualTo(
"""
|
firstName = "Pigeon"
lastName = "Bird"
fullName = "Pigeon Bird"
"""
.trimIndent()
)
val response21 = client.receive<ReadModuleRequest>()
assertThat(response21.uri.toString()).isEqualTo("bird:/parrot.pkl")
client.send(
ReadModuleResponse(
response21.requestId,
evaluatorId,
contents =
"""
firstName = "Parrot"
lastName = "Bird"
fullName = firstName + " " + lastName
"""
.trimIndent(),
error = null
)
)
val response22 = client.receive<EvaluateResponse>()
assertThat(response22.result).isNotNull
assertThat(response22.result!!.debugYaml)
.isEqualTo(
"""
|
firstName = "Parrot"
lastName = "Bird"
fullName = "Parrot Bird"
"""
.trimIndent()
)
}
@Test
fun `evaluate with project dependencies`(@TempDir tempDir: Path) {
val cacheDir = tempDir.resolve("cache").createDirectories()
PackageServer.populateCacheDir(cacheDir)
val libDir = tempDir.resolve("lib/").createDirectories()
libDir
.resolve("lib.pkl")
.writeText(
"""
text = "This is from lib"
"""
.trimIndent()
)
libDir
.resolve("PklProject")
.writeText(
"""
amends "pkl:Project"
package {
name = "lib"
baseUri = "package://localhost:12110/lib"
version = "5.0.0"
packageZipUrl = "https://localhost:12110/lib.zip"
}
"""
.trimIndent()
)
val projectDir = tempDir.resolve("proj/").createDirectories()
val module = projectDir.resolve("mod.pkl")
module.writeText(
"""
import "@birds/Bird.pkl"
import "@lib/lib.pkl"
res: Bird = new {
name = "Birdie"
favoriteFruit { name = "dragonfruit" }
}
libContents = lib
"""
.trimIndent()
)
val dollar = '$'
projectDir
.resolve("PklProject.deps.json")
.writeText(
"""
{
"schemaVersion": 1,
"resolvedDependencies": {
"package://localhost:12110/birds@0": {
"type": "remote",
"uri": "projectpackage://localhost:12110/birds@0.5.0",
"checksums": {
"sha256": "${dollar}skipChecksumVerification"
}
},
"package://localhost:12110/fruit@1": {
"type": "remote",
"uri": "projectpackage://localhost:12110/fruit@1.0.5",
"checksums": {
"sha256": "${dollar}skipChecksumVerification"
}
},
"package://localhost:12110/lib@5": {
"type": "local",
"uri": "projectpackage://localhost:12110/lib@5.0.0",
"path": "../lib"
}
}
}
"""
.trimIndent()
)
val evaluatorId =
client.sendCreateEvaluatorRequest(
cacheDir = cacheDir,
project =
Project(
projectFileUri = projectDir.resolve("PklProject").toUri(),
packageUri = null,
dependencies =
mapOf(
"birds" to
RemoteDependency(packageUri = URI("package://localhost:12110/birds@0.5.0"), null),
"lib" to
Project(
projectFileUri = libDir.toUri().resolve("PklProject"),
packageUri = URI("package://localhost:12110/lib@5.0.0"),
dependencies = emptyMap()
)
)
)
)
client.send(
EvaluateRequest(
requestId = 1,
evaluatorId = evaluatorId,
moduleUri = module.toUri(),
moduleText = null,
expr = "output.text",
)
)
val resp2 = client.receive<EvaluateResponse>()
assertThat(resp2.error).isNull()
assertThat(resp2.result).isNotNull()
assertThat(resp2.result!!.debugRendering.trim())
.isEqualTo(
"""
|
res {
name = "Birdie"
favoriteFruit {
name = "dragonfruit"
}
}
libContents {
text = "This is from lib"
}
"""
.trimIndent()
)
}
private val ByteArray.debugYaml
get() = MessagePackDebugRenderer(this).output.trimIndent()
private fun TestTransport.sendCreateEvaluatorRequest(
requestId: Long = 123,
resourceReaders: List<ResourceReaderSpec> = listOf(),
moduleReaders: List<ModuleReaderSpec> = listOf(),
modulePaths: List<Path> = listOf(),
project: Project? = null,
cacheDir: Path? = null
): Long {
val message =
CreateEvaluatorRequest(
requestId = 123,
allowedResources = listOf(Pattern.compile(".*")),
allowedModules = listOf(Pattern.compile(".*")),
clientResourceReaders = resourceReaders,
clientModuleReaders = moduleReaders,
modulePaths = modulePaths,
env = mapOf(),
properties = mapOf(),
timeout = null,
rootDir = null,
cacheDir = cacheDir,
outputFormat = null,
project = project
)
send(message)
val response = receive<CreateEvaluatorResponse>()
assertThat(response.requestId).isEqualTo(requestId)
assertThat(response.evaluatorId).isNotNull
assertThat(response.error).isNull()
return response.evaluatorId!!
}
}

View File

@@ -0,0 +1,50 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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
*
* https://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 org.pkl.server
import java.util.concurrent.ArrayBlockingQueue
import java.util.concurrent.BlockingQueue
import org.assertj.core.api.Assertions.assertThat
internal class TestTransport(private val delegate: MessageTransport) : AutoCloseable {
private val incomingMessages: BlockingQueue<Message> = ArrayBlockingQueue(10)
fun start() {
delegate.start({ incomingMessages.put(it) }, { incomingMessages.put(it) })
}
override fun close() {
delegate.close()
}
fun send(message: ClientOneWayMessage) {
delegate.send(message)
}
fun send(message: ClientRequestMessage) {
delegate.send(message) { incomingMessages.put(it) }
}
fun send(message: ClientResponseMessage) {
delegate.send(message)
}
inline fun <reified T : Message> receive(): T {
val message = incomingMessages.take()
assertThat(message).isInstanceOf(T::class.java)
return message as T
}
}

View File

@@ -0,0 +1,53 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* 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
*
* https://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 org.pkl.server
import java.util.concurrent.AbstractExecutorService
import java.util.concurrent.ExecutorService
import java.util.concurrent.TimeUnit
import org.msgpack.core.MessagePack
import org.msgpack.value.ImmutableValue
fun ByteArray.unpack(): ImmutableValue = MessagePack.newDefaultUnpacker(this).unpackValue()
fun ByteArray.asInt(): Int = unpack().asIntegerValue().asInt()
fun ByteArray.asString(): String = unpack().asStringValue().asString()
fun createDirectExecutor(): ExecutorService =
object : AbstractExecutorService() {
override fun execute(command: Runnable) {
command.run()
}
override fun shutdown() {}
override fun shutdownNow(): MutableList<Runnable> {
throw UnsupportedOperationException("shutdownNow")
}
override fun isShutdown(): Boolean {
throw UnsupportedOperationException("isShutdown")
}
override fun isTerminated(): Boolean {
throw UnsupportedOperationException("isTerminated")
}
override fun awaitTermination(timeout: Long, unit: TimeUnit): Boolean {
throw UnsupportedOperationException("awaitTermination")
}
}

View File

@@ -0,0 +1 @@
org.pkl.server.BinaryEvaluatorSnippetTestEngine