mirror of
https://github.com/apple/pkl.git
synced 2026-03-21 00:29:07 +01:00
Initial commit
This commit is contained in:
7
pkl-server/src/test/files/SnippetTests/input/basic.pkl
vendored
Normal file
7
pkl-server/src/test/files/SnippetTests/input/basic.pkl
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
res1 = "bar"
|
||||
res2 = ""
|
||||
res3 = 1
|
||||
res4 = 2.3
|
||||
res5 = true
|
||||
res6 = false
|
||||
res7 = null
|
||||
25
pkl-server/src/test/files/SnippetTests/input/classes.pkl
vendored
Normal file
25
pkl-server/src/test/files/SnippetTests/input/classes.pkl
vendored
Normal 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
|
||||
11
pkl-server/src/test/files/SnippetTests/input/datasize.pkl
vendored
Normal file
11
pkl-server/src/test/files/SnippetTests/input/datasize.pkl
vendored
Normal 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
|
||||
7
pkl-server/src/test/files/SnippetTests/input/duration.pkl
vendored
Normal file
7
pkl-server/src/test/files/SnippetTests/input/duration.pkl
vendored
Normal 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
|
||||
2
pkl-server/src/test/files/SnippetTests/input/intseq.pkl
vendored
Normal file
2
pkl-server/src/test/files/SnippetTests/input/intseq.pkl
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
res1 = IntSeq(1, 3)
|
||||
res2 = IntSeq(1, 4).step(5)
|
||||
6
pkl-server/src/test/files/SnippetTests/input/list.pkl
vendored
Normal file
6
pkl-server/src/test/files/SnippetTests/input/list.pkl
vendored
Normal 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 } }
|
||||
15
pkl-server/src/test/files/SnippetTests/input/map.pkl
vendored
Normal file
15
pkl-server/src/test/files/SnippetTests/input/map.pkl
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
2
pkl-server/src/test/files/SnippetTests/input/pair.pkl
vendored
Normal file
2
pkl-server/src/test/files/SnippetTests/input/pair.pkl
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
res1 = Pair(1, 2)
|
||||
res2 = Pair("foo", "bar")
|
||||
3
pkl-server/src/test/files/SnippetTests/input/regex.pkl
vendored
Normal file
3
pkl-server/src/test/files/SnippetTests/input/regex.pkl
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
res1 = Regex("abc")
|
||||
res2 = Regex("")
|
||||
res3 = Regex("(?m)^abc$")
|
||||
3
pkl-server/src/test/files/SnippetTests/input/set.pkl
vendored
Normal file
3
pkl-server/src/test/files/SnippetTests/input/set.pkl
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
res1: Set<Int> = Set(1, 3, 5, 7)
|
||||
res2: Set<Int> = Set()
|
||||
res3: Set<Any> = Set(1, true, "", null)
|
||||
32
pkl-server/src/test/files/SnippetTests/output/basic.yaml
vendored
Normal file
32
pkl-server/src/test/files/SnippetTests/output/basic.yaml
vendored
Normal 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
|
||||
54
pkl-server/src/test/files/SnippetTests/output/classes.yaml
vendored
Normal file
54
pkl-server/src/test/files/SnippetTests/output/classes.yaml
vendored
Normal 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
|
||||
81
pkl-server/src/test/files/SnippetTests/output/datasize.yaml
vendored
Normal file
81
pkl-server/src/test/files/SnippetTests/output/datasize.yaml
vendored
Normal 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
|
||||
53
pkl-server/src/test/files/SnippetTests/output/duration.yaml
vendored
Normal file
53
pkl-server/src/test/files/SnippetTests/output/duration.yaml
vendored
Normal 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
|
||||
20
pkl-server/src/test/files/SnippetTests/output/intseq.yaml
vendored
Normal file
20
pkl-server/src/test/files/SnippetTests/output/intseq.yaml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
- 1
|
||||
- intseq
|
||||
- file:///$snippetsDir/input/intseq.pkl
|
||||
-
|
||||
-
|
||||
- 16
|
||||
- res1
|
||||
-
|
||||
- 10
|
||||
- 1
|
||||
- 3
|
||||
- 1
|
||||
-
|
||||
- 16
|
||||
- res2
|
||||
-
|
||||
- 10
|
||||
- 1
|
||||
- 4
|
||||
- 5
|
||||
58
pkl-server/src/test/files/SnippetTests/output/list.yaml
vendored
Normal file
58
pkl-server/src/test/files/SnippetTests/output/list.yaml
vendored
Normal 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
|
||||
44
pkl-server/src/test/files/SnippetTests/output/map.yaml
vendored
Normal file
44
pkl-server/src/test/files/SnippetTests/output/map.yaml
vendored
Normal 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
|
||||
18
pkl-server/src/test/files/SnippetTests/output/pair.yaml
vendored
Normal file
18
pkl-server/src/test/files/SnippetTests/output/pair.yaml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
- 1
|
||||
- pair
|
||||
- file:///$snippetsDir/input/pair.pkl
|
||||
-
|
||||
-
|
||||
- 16
|
||||
- res1
|
||||
-
|
||||
- 9
|
||||
- 1
|
||||
- 2
|
||||
-
|
||||
- 16
|
||||
- res2
|
||||
-
|
||||
- 9
|
||||
- foo
|
||||
- bar
|
||||
22
pkl-server/src/test/files/SnippetTests/output/regex.yaml
vendored
Normal file
22
pkl-server/src/test/files/SnippetTests/output/regex.yaml
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
- 1
|
||||
- regex
|
||||
- file:///$snippetsDir/input/regex.pkl
|
||||
-
|
||||
-
|
||||
- 16
|
||||
- res1
|
||||
-
|
||||
- 11
|
||||
- abc
|
||||
-
|
||||
- 16
|
||||
- res2
|
||||
-
|
||||
- 11
|
||||
- ''
|
||||
-
|
||||
- 16
|
||||
- res3
|
||||
-
|
||||
- 11
|
||||
- (?m)^abc$
|
||||
30
pkl-server/src/test/files/SnippetTests/output/set.yaml
vendored
Normal file
30
pkl-server/src/test/files/SnippetTests/output/set.yaml
vendored
Normal 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
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
150
pkl-server/src/test/kotlin/org/pkl/server/BinaryEvaluatorTest.kt
Normal file
150
pkl-server/src/test/kotlin/org/pkl/server/BinaryEvaluatorTest.kt
Normal 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`")
|
||||
}
|
||||
}
|
||||
@@ -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)")
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
994
pkl-server/src/test/kotlin/org/pkl/server/ServerTest.kt
Normal file
994
pkl-server/src/test/kotlin/org/pkl/server/ServerTest.kt
Normal 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!!
|
||||
}
|
||||
}
|
||||
50
pkl-server/src/test/kotlin/org/pkl/server/TestTransport.kt
Normal file
50
pkl-server/src/test/kotlin/org/pkl/server/TestTransport.kt
Normal 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
|
||||
}
|
||||
}
|
||||
53
pkl-server/src/test/kotlin/org/pkl/server/TestUtils.kt
Normal file
53
pkl-server/src/test/kotlin/org/pkl/server/TestUtils.kt
Normal 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")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
org.pkl.server.BinaryEvaluatorSnippetTestEngine
|
||||
BIN
pkl-server/src/test/resources/org/pkl/server/resource1.jar
Normal file
BIN
pkl-server/src/test/resources/org/pkl/server/resource1.jar
Normal file
Binary file not shown.
Reference in New Issue
Block a user