Skip to content

Commit 752b582

Browse files
committed
support loading dependenices, and transpilation
1 parent 6e67c69 commit 752b582

File tree

8 files changed

+225
-62
lines changed

8 files changed

+225
-62
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"click-events-topic-name" : "click-clack"
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import com.orbitalhq.preflight.dsl.OrbitalSpec
2+
import io.kotest.matchers.shouldBe
3+
4+
class OverridingGlobalEnvVariablesSpec : OrbitalSpec({
5+
6+
env("click-events-topic-name", "clickstream")
7+
describe("overriding global env config variables") {
8+
it("should compile using the overridden env variable") {
9+
schema.service("com.foo.PersonEventsKafkaService")
10+
.streamOperations
11+
.single()
12+
.firstMetadata("com.orbitalhq.kafka.KafkaOperation")
13+
.params["topic"]
14+
.shouldBe("clickstream")
15+
}
16+
}
17+
})
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import app.cash.turbine.test
2+
import com.orbitalhq.preflight.dsl.OrbitalSpec
3+
import kotlin.time.Duration.Companion.seconds
4+
import com.orbitalhq.expectMap
5+
import io.kotest.matchers.nulls.shouldNotBeNull
6+
import io.kotest.matchers.shouldBe
7+
8+
class StreamingQuerySpec : OrbitalSpec({
9+
describe("Project with Orbital dependencies") {
10+
it("can unit test a streaming query") {
11+
runNamedQueryForStream("com.foo.StreamPersonEventsToMongo") { stubService ->
12+
stubService.addResponseEmitter("clickEvents")
13+
.next(
14+
"""{
15+
| "id" : "jimmy"
16+
|}
17+
""".trimMargin()
18+
)
19+
stubService.addResponseReturningInputs("upsertPerson")
20+
}
21+
.test(5.seconds) {
22+
val next = expectMap()
23+
next.shouldNotBeNull()
24+
next.shouldBe(mapOf("personId" to "jimmy"))
25+
}
26+
}
27+
it("resolves the env variables from env.conf") {
28+
schema.service("com.foo.PersonEventsKafkaService")
29+
.streamOperations
30+
.single()
31+
.firstMetadata("com.orbitalhq.kafka.KafkaOperation")
32+
.params["topic"]
33+
.shouldBe("click-clack")
34+
35+
}
36+
}
37+
})

preflight-core/preflight-gradle-plugin/src/main/kotlin/com/orbitalhq/preflight/gradle/PreflightPlugin.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class PreflightPlugin : Plugin<Project> {
3333
val mainSourceSet = sourceSets.getByName("main")
3434

3535
val testSourceSet = sourceSets.maybeCreate("test")
36+
testSourceSet.resources.srcDir("test-resources")
3637
testSourceSet.java.srcDir("test") // top-level test directory
3738
testSourceSet.compileClasspath += mainSourceSet.output + mainSourceSet.compileClasspath
3839
testSourceSet.runtimeClasspath += mainSourceSet.output + mainSourceSet.runtimeClasspath

preflight-core/preflight-runtime/build.gradle.kts

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ plugins {
33
`maven-publish`
44
}
55

6-
val taxiVersion = "1.65.0"
7-
val orbitalVersion = "0.36.0-M4"
6+
val taxiVersion = "1.66.0-SNAPSHOT"
7+
val orbitalVersion = "0.36.0-M9"
88

99
dependencies {
1010
testImplementation(platform("org.junit:junit-bom:5.10.0"))
@@ -24,18 +24,25 @@ dependencies {
2424
exclude(group = "org.jooq.pro")
2525
exclude(group = "org.pac4j")
2626
}
27-
api("org.opentest4j:opentest4j:1.3.0")
28-
api("com.orbitalhq:taxi-playground-core:$orbitalVersion") {
29-
exclude(group = "io.confluent")
30-
exclude(group = "org.jooq.pro")
31-
exclude(group = "org.pac4j")
32-
}
3327
api("com.orbitalhq:taxiql-query-engine:$orbitalVersion") {
3428
artifact { classifier = "tests" }
3529
// Not published to maven central, and not needed for testing
3630
// as it relates to saml auth
3731
exclude(group = "org.pac4j")
32+
33+
// This might need adding (and shading), but later...
34+
// Can we avoid by just using the OSS version in Preflight?
35+
exclude(group = "org.jooq.pro")
36+
exclude(group = "org.pac4j")
3837
}
38+
api("org.opentest4j:opentest4j:1.3.0")
39+
api("com.orbitalhq:taxi-playground-core:$orbitalVersion") {
40+
exclude(group = "io.confluent")
41+
exclude(group = "org.jooq.pro")
42+
exclude(group = "org.pac4j")
43+
}
44+
45+
api("app.cash.turbine:turbine-jvm:0.12.1")
3946
implementation("com.orbitalhq:schema-server-core:$orbitalVersion") {
4047
// This could become an issue - but this isn't published to maven central
4148
// If we end up needing this, we'll need to configure
@@ -60,6 +67,7 @@ dependencies {
6067
implementation("io.kotest:kotest-framework-datatest")
6168
implementation("io.kotest:kotest-framework-discovery")
6269
implementation("io.kotest:kotest-assertions-core")
70+
testImplementation("io.kotest:kotest-runner-junit5")
6371

6472

6573
testImplementation(platform("org.junit:junit-bom:5.10.0"))
@@ -68,6 +76,7 @@ dependencies {
6876

6977
tasks.test {
7078
useJUnitPlatform()
79+
systemProperty("kotest.framework.classpath.scanning.config.disable", "false")
7180
}
7281

7382
publishing {

preflight-core/preflight-runtime/src/main/kotlin/com/orbitalhq/preflight/dsl/OrbitalSpec.kt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package com.orbitalhq.preflight.dsl
22

3+
import com.orbitalhq.Vyne
4+
import com.orbitalhq.models.TypedInstance
35
import com.orbitalhq.schemas.taxi.TaxiSchema
46
import com.orbitalhq.stubbing.StubService
57
import io.kotest.core.spec.style.DescribeSpec
8+
import kotlinx.coroutines.flow.Flow
69
import lang.taxi.TaxiDocument
710
import lang.taxi.packages.TaxiPackageProject
811

@@ -15,10 +18,10 @@ import lang.taxi.packages.TaxiPackageProject
1518
*
1619
* @param body The test specification body that defines the test structure
1720
*/
18-
abstract class OrbitalSpec(body: OrbitalSpec.() -> Unit) : DescribeSpec() {
21+
abstract class OrbitalSpec(body: OrbitalSpec.() -> Unit, sourceConfig: PreflightSourceConfig = FilePathSourceConfig(), ) : DescribeSpec() {
1922

2023
@Suppress("MemberVisibilityCanBePrivate")
21-
val preflight = PreflightExtension()
24+
val preflight = PreflightExtension(sourceConfig)
2225

2326
init {
2427
extension(preflight)
@@ -47,14 +50,11 @@ abstract class OrbitalSpec(body: OrbitalSpec.() -> Unit) : DescribeSpec() {
4750
return preflight.schema
4851
}
4952

50-
/**
51-
* Provides access to the Taxi Package Project - taxi's taxi.conf file,
52-
* and source roots etc.
53-
*/
54-
val taxiProject: TaxiPackageProject
55-
get() {
56-
return preflight.taxiProject
57-
}
53+
suspend fun runNamedQueryForStream(queryName: String, stubCustomizer: (StubService) -> Unit = {}):Flow<TypedInstance> =
54+
preflight.runNamedQueryForStream(queryName, stubCustomizer)
55+
suspend fun runNamedQueryForObject(queryName: String, stubCustomizer: (StubService) -> Unit = {}) =
56+
preflight.runNamedQueryForObject(queryName, stubCustomizer)
57+
5858
/**
5959
* Executes the query, and returns a raw scalar value (Int, String, Boolean, etc).
6060
* Optionally accepts a callback for customizing the Stub service, which allows for

preflight-core/preflight-runtime/src/main/kotlin/com/orbitalhq/preflight/dsl/PreflightExtension.kt

Lines changed: 97 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -10,35 +10,94 @@ import com.orbitalhq.query.QueryResult
1010
import com.orbitalhq.rawObjects
1111
import com.orbitalhq.schemaServer.core.adaptors.taxi.TaxiSchemaSourcesAdaptor
1212
import com.orbitalhq.schemaServer.core.file.FileProjectSpec
13+
import com.orbitalhq.schemaServer.core.file.packages.FileSystemPackageLoader
1314
import com.orbitalhq.schemas.taxi.TaxiSchema
1415
import com.orbitalhq.stubbing.StubService
1516
import com.orbitalhq.testVyne
17+
import com.orbitalhq.utils.files.ReactivePollingFileSystemMonitor
18+
import io.kotest.assertions.AssertionFailedError
1619
import io.kotest.assertions.fail
1720
import io.kotest.assertions.withClue
21+
import io.kotest.core.extensions.TestCaseExtension
22+
import io.kotest.core.listeners.AfterTestListener
1823
import io.kotest.core.listeners.BeforeSpecListener
1924
import io.kotest.core.spec.Spec
25+
import io.kotest.core.test.TestCase
26+
import io.kotest.core.test.TestResult
27+
import kotlinx.coroutines.withContext
2028
import lang.taxi.CompilationException
2129
import lang.taxi.TaxiDocument
2230
import lang.taxi.packages.TaxiPackageLoader
23-
import lang.taxi.packages.TaxiPackageProject
31+
import lang.taxi.query.TaxiQLQueryString
32+
import org.taxilang.packagemanager.DefaultDependencyFetcherProvider
33+
import org.taxilang.packagemanager.DependencyFetcherProvider
2434
import java.nio.file.Path
2535
import java.nio.file.Paths
26-
import kotlin.io.path.absolute
27-
import com.orbitalhq.schemaServer.core.file.packages.FileSystemPackageLoader
28-
import com.orbitalhq.utils.files.ReactivePollingFileSystemMonitor
29-
import io.kotest.assertions.AssertionFailedError
30-
import io.kotest.core.extensions.TestCaseExtension
31-
import io.kotest.core.listeners.AfterTestListener
32-
import io.kotest.core.test.TestCase
33-
import io.kotest.core.test.TestResult
34-
import kotlinx.coroutines.withContext
35-
import lang.taxi.query.TaxiQLQueryString
3636
import java.time.Duration
3737
import kotlin.coroutines.CoroutineContext
3838
import kotlin.coroutines.coroutineContext
39+
import kotlin.io.path.absolute
40+
41+
sealed interface PreflightSourceConfig {
42+
fun loadSchema(environmentVariables: Map<String,String> = emptyMap()): TaxiSchema
43+
}
3944

40-
class PreflightExtension(val projectRoot: Path = Paths.get("./")) : BeforeSpecListener, AfterTestListener,
41-
TestCaseExtension {
45+
class FilePathSourceConfig(
46+
private val projectRoot: Path = Paths.get("./"),
47+
private val dependencyFetcherProvider: DependencyFetcherProvider = DefaultDependencyFetcherProvider
48+
) : PreflightSourceConfig {
49+
override fun loadSchema(environmentVariables: Map<String, String>): TaxiSchema {
50+
val loader = TaxiPackageLoader.forDirectoryContainingTaxiFile(projectRoot.absolute().normalize())
51+
val taxiProject = loader.load()
52+
val sourcePackage = loadSourcePackage(taxiProject.packageRootPath!!)
53+
54+
return withClue("Taxi project should compile without errors") {
55+
val taxiSchema = try {
56+
TaxiSchema.from(
57+
sourcePackage,
58+
environmentVariables = environmentVariables,
59+
onErrorBehaviour = TaxiSchema.Companion.TaxiSchemaErrorBehaviour.THROW_EXCEPTION
60+
)
61+
} catch (e: CompilationException) {
62+
fail("Taxi project has errors: \n${e.message}")
63+
}
64+
taxiSchema
65+
}
66+
}
67+
68+
/**
69+
* Loads a source path into a SourcePackage
70+
* Uses the orbital approach of loading (using a FileSystemPackageLoader)
71+
* rather than a simple TaxiPackageLoader, as we need to support transpilation of non-taxi sources
72+
*/
73+
private fun loadSourcePackage(packageRootPath: Path): SourcePackage {
74+
val spec = FileProjectSpec(path = packageRootPath)
75+
val fileMonitor = ReactivePollingFileSystemMonitor(packageRootPath, Duration.ofHours(9999))
76+
val converter = TaxiSchemaSourcesAdaptor(
77+
dependencyFetcherProvider = dependencyFetcherProvider
78+
)
79+
val packageLoader = FileSystemPackageLoader(spec, converter, fileMonitor)
80+
val packageMetadata = converter.buildMetadata(packageLoader)
81+
.block()!!
82+
val sourcePackage = converter.convert(packageMetadata, packageLoader).block()!!
83+
return sourcePackage
84+
}
85+
}
86+
87+
class StringSourceConfig(private val source: String) : PreflightSourceConfig {
88+
override fun loadSchema(environmentVariables: Map<String, String>): TaxiSchema {
89+
return TaxiSchema.from(source, environmentVariables = environmentVariables)
90+
}
91+
}
92+
93+
fun forSchema(source: String) = StringSourceConfig(source)
94+
95+
class PreflightExtension(private val sourceConfig: PreflightSourceConfig = FilePathSourceConfig(),
96+
private val envVariableContainer: EnvVariableContainer = SpecEnvVariables.newInstance()
97+
) : BeforeSpecListener,
98+
AfterTestListener,
99+
TestCaseExtension,
100+
EnvVariableContainer by envVariableContainer {
42101

43102
companion object {
44103
val PreflightTestCaseKey = object : CoroutineContext.Key<PreflightTestCaseContext> {}
@@ -54,14 +113,7 @@ class PreflightExtension(val projectRoot: Path = Paths.get("./")) : BeforeSpecLi
54113
lateinit var schema: TaxiSchema
55114
private set
56115

57-
lateinit var sourcePackage: SourcePackage
58-
private set
59-
60-
/**
61-
* Provides access to the actual Taxi project (the equivalent of the
62-
* taxi.conf file)
63-
*/
64-
lateinit var taxiProject: TaxiPackageProject
116+
private lateinit var sourcePackage: SourcePackage
65117
private set
66118

67119
private val capturedScenarios = mutableMapOf<TestCase, CapturedQuery>()
@@ -71,10 +123,7 @@ class PreflightExtension(val projectRoot: Path = Paths.get("./")) : BeforeSpecLi
71123
envVariableContainer.markImmutable()
72124
withClue("Taxi project should compile without errors") {
73125
val taxiSchema = try {
74-
TaxiSchema.from(
75-
sourcePackage,
76-
onErrorBehaviour = TaxiSchema.Companion.TaxiSchemaErrorBehaviour.THROW_EXCEPTION
77-
)
126+
sourceConfig.loadSchema(environmentVariables = envVariableContainer.envVariables)
78127
} catch (e: CompilationException) {
79128
fail("Taxi project has errors: \n${e.message}")
80129
}
@@ -84,23 +133,8 @@ class PreflightExtension(val projectRoot: Path = Paths.get("./")) : BeforeSpecLi
84133
}
85134
}
86135

87-
/**
88-
* Loads a source path into a SourcePackage
89-
* Uses the orbital approach of loading (using a FileSystemPackageLoader)
90-
* rather than a simple TaxiPackageLoader, as we need to support transpilation of non-taxi sources
91-
*/
92-
private fun loadSourcePackage(packageRootPath: Path): SourcePackage {
93-
val spec = FileProjectSpec(path = packageRootPath)
94-
val fileMonitor = ReactivePollingFileSystemMonitor(packageRootPath, Duration.ofHours(9999))
95-
val packageLoader = FileSystemPackageLoader(spec, TaxiSchemaSourcesAdaptor(), fileMonitor)
96-
val converter = TaxiSchemaSourcesAdaptor()
97-
val packageMetadata = converter.buildMetadata(packageLoader)
98-
.block()!!
99-
val sourcePackage = converter.convert(packageMetadata, packageLoader).block()!!
100-
return sourcePackage
101-
}
102136

103-
fun orbital(): Pair<Orbital, StubService> {
137+
private fun orbital(): Pair<Orbital, StubService> {
104138
return testVyne(this.schema)
105139
}
106140

@@ -148,7 +182,26 @@ class PreflightExtension(val projectRoot: Path = Paths.get("./")) : BeforeSpecLi
148182
.firstTypedInstace()
149183
}
150184

151-
suspend fun query(taxiQl: String, stubCustomizer: (StubService) -> Unit = {}): QueryResult {
185+
suspend fun runNamedQueryForObject(queryName: String, stubCustomizer: (StubService) -> Unit = {}) =
186+
runNamedQuery(queryName, stubCustomizer)
187+
.firstTypedInstace()
188+
189+
suspend fun runNamedQueryForStream(queryName: String, stubCustomizer: (StubService) -> Unit = {}) =
190+
runNamedQuery(queryName, stubCustomizer).results
191+
192+
private suspend fun runNamedQuery(queryName: String, stubCustomizer: (StubService) -> Unit = {}): QueryResult {
193+
val (orbital) = orbital()
194+
val savedQuery = orbital.schema.queries.singleOrNull {
195+
it.name.parameterizedName == queryName || it.name.name == queryName
196+
}
197+
if (savedQuery == null) {
198+
fail("No query named $queryName was found")
199+
}
200+
val taxiQl = savedQuery.sources.joinToString("\n") { it.content }
201+
return query(taxiQl, stubCustomizer)
202+
}
203+
204+
private suspend fun query(taxiQl: String, stubCustomizer: (StubService) -> Unit = {}): QueryResult {
152205
val (orbital, stub) = orbital()
153206
stubCustomizer(stub)
154207
val testContext = coroutineContext[PreflightTestCaseKey]
@@ -165,7 +218,7 @@ class PreflightExtension(val projectRoot: Path = Paths.get("./")) : BeforeSpecLi
165218
return withContext(context) {
166219
val testResult = execute(testCase)
167220
val capturedScenario = capturedScenarios[testCase]
168-
if (testResult.isErrorOrFailure && capturedScenario != null) {
221+
if (testResult.isFailure && capturedScenario != null) {
169222

170223
val failure = testResult as TestResult.Failure
171224
val originalError = failure.cause as AssertionFailedError
@@ -204,4 +257,4 @@ data class CapturedQuery(
204257

205258
data class PreflightTestCaseContext(val testCase: TestCase) : CoroutineContext.Element {
206259
override val key = PreflightTestCaseKey
207-
}
260+
}

0 commit comments

Comments
 (0)