Skip to content

Commit 1c3c79a

Browse files
authored
Refactors partiql-tests-runner for multiple engines (#1289)
1 parent 7c9cc9a commit 1c3c79a

File tree

20 files changed

+489
-356
lines changed

20 files changed

+489
-356
lines changed

.github/workflows/conformance-report.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ jobs:
2727
# Run the conformance tests and save to an Ion file.
2828
- name: gradle test of the conformance tests (can fail) and save to Ion file
2929
continue-on-error: true
30-
run: gradle :test:partiql-tests-runner:test --tests "*ConformanceTestsReportRunner" -PconformanceReport
30+
run: gradle :test:partiql-tests-runner:test --tests "*ConformanceTestReport" -PconformanceReport
3131
# Upload conformance report for future viewing and comparison with future runs.
3232
- name: Upload `conformance_test_results.ion`
3333
uses: actions/upload-artifact@v3
@@ -86,7 +86,7 @@ jobs:
8686
continue-on-error: true
8787
run: |
8888
cd ${{ github.event.pull_request.base.sha }}
89-
gradle :test:partiql-tests-runner:test --tests "*ConformanceTestsReportRunner" -PconformanceReport
89+
gradle :test:partiql-tests-runner:test --tests "*ConformanceTestReport" -PconformanceReport
9090
- name: (If download of target branch conformance report fails) Move conformance test report of target branch to ./artifact directory
9191
if: ${{ steps.download-report.outcome == 'failure' }}
9292
continue-on-error: true

test/partiql-tests-runner/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,19 @@ This package enables:
1212

1313
```shell
1414
# default, test data from partiql-tests submodule will be used
15-
./gradlew :test:partiql-tests-runner:test --tests "*ConformanceTestsReportRunner" -PconformanceReport
15+
./gradlew :test:partiql-tests-runner:test --tests "*ConformanceTestReport" -PconformanceReport
1616

1717
# override test data location
1818
PARTIQL_TESTS_DATA=/path/to/partiql-tests/data \
19-
./gradlew :test:partiql-tests-runner:test --tests "*ConformanceTestsReportRunner" -PconformanceReport
19+
./gradlew :test:partiql-tests-runner:test --tests "*ConformanceTestReport" -PconformanceReport
2020
```
2121
The report is written into file `test/partiql-tests-runner/conformance_test_results.ion`.
2222

2323
## Run Conformance Tests in UI
2424

2525
The above project property `-PconformanceReport` is checked in `test/partiql-tests-runner/build.gradle.kts`,
2626
to exclude the conformance test suite from executing during a normal project-build test run.
27-
Unfortunately, this also disables running `ConformanceTestsReportRunner` in a UI runner.
27+
Unfortunately, this also disables running `ConformanceTestReport` in a UI runner.
2828
To make that possible locally, temporarily comment out the check in `test/partiql-tests-runner/build.gradle.kts`.
2929

3030
## Compare Conformance Reports locally

test/partiql-tests-runner/build.gradle.kts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ tasks.test {
4040
environment(Env.PARTIQL_EVAL, file("$tests/eval/").absolutePath)
4141
environment(Env.PARTIQL_EQUIV, file("$tests/eval-equiv/").absolutePath)
4242

43-
// To make it possible to run ConformanceTestsReportRunner in unit test UI runner, comment out this check:
43+
// To make it possible to run ConformanceTestReport in unit test UI runner, comment out this check:
4444
if (!project.hasProperty("conformanceReport")) {
45-
exclude("org/partiql/runner/TestRunner\$ConformanceTestsReportRunner.class")
45+
exclude("org/partiql/runner/ConformanceTestReport.class")
4646
}
4747

4848
// May 2023: Disabled conformance testing during regular project build, because fail lists are out of date.
49-
exclude("org/partiql/runner/TestRunner\$DefaultConformanceTestRunner.class")
49+
exclude("org/partiql/runner/ConformanceTest.class")
5050
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package org.partiql.runner
2+
3+
import org.junit.jupiter.params.ParameterizedTest
4+
import org.junit.jupiter.params.provider.ArgumentsSource
5+
import org.partiql.runner.schema.TestCase
6+
import org.partiql.runner.skip.LANG_KOTLIN_EVAL_EQUIV_FAIL_LIST
7+
import org.partiql.runner.skip.LANG_KOTLIN_EVAL_FAIL_LIST
8+
import org.partiql.runner.test.TestProvider
9+
import org.partiql.runner.test.TestRunner
10+
import org.partiql.runner.test.executor.LegacyExecutor
11+
12+
/**
13+
* Runs the conformance tests with an expected list of failing tests. Ensures that tests not in the failing list
14+
* succeed with the expected result. Ensures that tests included in the failing list fail.
15+
*
16+
* These tests are included in the normal test/building.
17+
* Update May 2023: Now excluded from the normal build, because the fail lists are out of date.
18+
* TODO: Come up with a low-burden method of maintaining fail / exclusion lists.
19+
*/
20+
class ConformanceTest {
21+
22+
private val factory = LegacyExecutor.Factory
23+
private val runner = TestRunner(factory)
24+
25+
// Tests the eval tests with the Kotlin implementation
26+
@ParameterizedTest(name = "{arguments}")
27+
@ArgumentsSource(TestProvider.Eval::class)
28+
fun validatePartiQLEvalTestData(tc: TestCase) {
29+
when (tc) {
30+
is TestCase.Eval -> runner.test(tc, LANG_KOTLIN_EVAL_FAIL_LIST)
31+
else -> error("Unsupported test case category")
32+
}
33+
}
34+
35+
// Tests the eval equivalence tests with the Kotlin implementation
36+
@ParameterizedTest(name = "{arguments}")
37+
@ArgumentsSource(TestProvider.Equiv::class)
38+
fun validatePartiQLEvalEquivTestData(tc: TestCase) {
39+
when (tc) {
40+
is TestCase.Equiv -> runner.test(tc, LANG_KOTLIN_EVAL_EQUIV_FAIL_LIST)
41+
else -> error("Unsupported test case category")
42+
}
43+
}
44+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package org.partiql.runner
2+
3+
import org.junit.jupiter.api.extension.ExtendWith
4+
import org.junit.jupiter.params.ParameterizedTest
5+
import org.junit.jupiter.params.provider.ArgumentsSource
6+
import org.partiql.runner.report.ReportGenerator
7+
import org.partiql.runner.schema.TestCase
8+
import org.partiql.runner.test.TestProvider
9+
import org.partiql.runner.test.TestRunner
10+
import org.partiql.runner.test.executor.LegacyExecutor
11+
12+
/**
13+
* Runs the conformance tests without a fail list, so we can document the passing/failing tests in the conformance
14+
* report.
15+
*
16+
* These tests are excluded from normal testing/building unless the `conformanceReport` gradle property is
17+
* specified (i.e. `gradle test ... -PconformanceReport`)
18+
*/
19+
@ExtendWith(ReportGenerator::class)
20+
class ConformanceTestReport {
21+
22+
private val factory = LegacyExecutor.Factory
23+
private val runner = TestRunner(factory)
24+
25+
// Tests the eval tests with the Kotlin implementation without a fail list
26+
@ParameterizedTest(name = "{arguments}")
27+
@ArgumentsSource(TestProvider.Eval::class)
28+
fun validatePartiQLEvalTestData(tc: TestCase) {
29+
when (tc) {
30+
is TestCase.Eval -> runner.test(tc, emptyList())
31+
else -> error("Unsupported test case category")
32+
}
33+
}
34+
35+
// Tests the eval equivalence tests with the Kotlin implementation without a fail list
36+
@ParameterizedTest(name = "{arguments}")
37+
@ArgumentsSource(TestProvider.Equiv::class)
38+
fun validatePartiQLEvalEquivTestData(tc: TestCase) {
39+
when (tc) {
40+
is TestCase.Equiv -> runner.test(tc, emptyList())
41+
else -> error("Unsupported test case category")
42+
}
43+
}
44+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.partiql.runner
2+
3+
import com.amazon.ion.system.IonSystemBuilder
4+
5+
/**
6+
* IonSystem for legacy pipelines and value comparison.
7+
*/
8+
public val ION = IonSystemBuilder.standard().build()

test/partiql-tests-runner/src/test/kotlin/org/partiql/runner/Schema.kt

Lines changed: 0 additions & 51 deletions
This file was deleted.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package org.partiql.runner.report
2+
3+
import com.amazon.ion.IonType
4+
import com.amazon.ion.system.IonTextWriterBuilder
5+
import org.junit.jupiter.api.extension.AfterAllCallback
6+
import org.junit.jupiter.api.extension.ExtensionContext
7+
import org.junit.jupiter.api.extension.TestWatcher
8+
import java.io.File
9+
10+
class ReportGenerator : TestWatcher, AfterAllCallback {
11+
var failingTests = emptySet<String>()
12+
var passingTests = emptySet<String>()
13+
var ignoredTests = emptySet<String>()
14+
override fun testFailed(context: ExtensionContext?, cause: Throwable?) {
15+
failingTests += context?.displayName ?: ""
16+
super.testFailed(context, cause)
17+
}
18+
19+
override fun testSuccessful(context: ExtensionContext?) {
20+
passingTests += context?.displayName ?: ""
21+
super.testSuccessful(context)
22+
}
23+
24+
override fun afterAll(p0: ExtensionContext?) {
25+
val file = File("./conformance_test_results.ion")
26+
val outputStream = file.outputStream()
27+
val writer = IonTextWriterBuilder.pretty().build(outputStream)
28+
writer.stepIn(IonType.STRUCT) // in: outer struct
29+
30+
// set struct field for passing
31+
writer.setFieldName("passing")
32+
writer.stepIn(IonType.LIST)
33+
passingTests.forEach { passingTest ->
34+
writer.writeString(passingTest)
35+
}
36+
writer.stepOut()
37+
// set struct field for failing
38+
writer.setFieldName("failing")
39+
writer.stepIn(IonType.LIST)
40+
failingTests.forEach { failingTest ->
41+
writer.writeString(failingTest)
42+
}
43+
writer.stepOut()
44+
45+
// set struct field for ignored
46+
writer.setFieldName("ignored")
47+
writer.stepIn(IonType.LIST)
48+
ignoredTests.forEach { ignoredTest ->
49+
writer.writeString(ignoredTest)
50+
}
51+
writer.stepOut()
52+
53+
writer.stepOut() // out: outer struct
54+
}
55+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package org.partiql.runner.schema
2+
3+
import com.amazon.ion.IonValue
4+
5+
sealed class Assertion {
6+
data class EvaluationSuccess(val expectedResult: IonValue) : Assertion()
7+
object EvaluationFailure : Assertion()
8+
// TODO: other assertion and test categories: https://github.com/partiql/partiql-tests/issues/35
9+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package org.partiql.runner.schema
2+
3+
data class EquivalenceClass(
4+
val id: String,
5+
val statements: List<String>,
6+
)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package org.partiql.runner.schema
2+
3+
import com.amazon.ion.IonStruct
4+
5+
data class Namespace(
6+
var env: IonStruct,
7+
val namespaces: MutableList<Namespace>,
8+
val testCases: MutableList<TestCase>,
9+
val equivClasses: MutableMap<String, List<String>>
10+
)

test/partiql-tests-runner/src/test/kotlin/org/partiql/runner/Parse.kt renamed to test/partiql-tests-runner/src/test/kotlin/org/partiql/runner/schema/Parse.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.partiql.runner
1+
package org.partiql.runner.schema
22

33
import com.amazon.ion.IonList
44
import com.amazon.ion.IonStruct
@@ -47,7 +47,7 @@ private fun parseTestCase(testStruct: IonStruct, curNamespace: Namespace): List<
4747

4848
when (statement.type) {
4949
// statement being an IonString indicates that this is an Eval test case
50-
IonType.STRING -> EvalTestCase(
50+
IonType.STRING -> TestCase.Eval(
5151
name = name,
5252
statement = statement.stringValue() ?: error("Expected `statement` to be a string"),
5353
env = env.asIonStruct(),
@@ -57,7 +57,7 @@ private fun parseTestCase(testStruct: IonStruct, curNamespace: Namespace): List<
5757
// statement being an IonSymbol indicates that this is an eval equivalence test case
5858
IonType.SYMBOL -> {
5959
val equivClassId = statement.stringValue() ?: error("Expected `statement` to be a symbol")
60-
EvalEquivTestCase(
60+
TestCase.Equiv(
6161
name = name,
6262
statements = curNamespace.equivClasses[equivClassId] ?: error("Equiv class $equivClassId not defined in current namespace"),
6363
env = env.asIonStruct(),
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package org.partiql.runner.schema
2+
3+
import com.amazon.ion.IonStruct
4+
import org.partiql.lang.eval.CompileOptions
5+
6+
sealed class TestCase {
7+
abstract val name: String
8+
abstract val env: IonStruct
9+
abstract val compileOptions: CompileOptions
10+
abstract val assertion: Assertion
11+
12+
data class Equiv(
13+
override val name: String,
14+
val statements: List<String>,
15+
override val env: IonStruct,
16+
override val compileOptions: CompileOptions,
17+
override val assertion: Assertion
18+
) : TestCase() {
19+
override fun toString(): String {
20+
return name + ", compileOption: " + compileOptions.typingMode
21+
}
22+
}
23+
24+
data class Eval(
25+
override val name: String,
26+
val statement: String,
27+
override val env: IonStruct,
28+
override val compileOptions: CompileOptions,
29+
override val assertion: Assertion
30+
) : TestCase() {
31+
override fun toString(): String {
32+
return name + ", compileOption: " + compileOptions.typingMode
33+
}
34+
}
35+
}

0 commit comments

Comments
 (0)