Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions tenant/api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ dependencies {
testFixturesApi(libs.viaduct.shared.viaductschema)

testFixturesImplementation(testFixtures(libs.viaduct.engine.api))
testFixturesImplementation(libs.viaduct.tenant.runtime)

testImplementation(testFixtures(libs.viaduct.engine.api))
testImplementation(libs.viaduct.tenant.runtime)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
package viaduct.api.mocks

import graphql.schema.GraphQLObjectType
import viaduct.api.context.ExecutionContext
import viaduct.api.context.FieldExecutionContext
import viaduct.api.context.MutationFieldExecutionContext
import viaduct.api.context.NodeExecutionContext
import viaduct.api.context.ResolverExecutionContext
import viaduct.api.globalid.GlobalID
import viaduct.api.globalid.GlobalIDCodec
import viaduct.api.internal.InternalContext
import viaduct.api.internal.ReflectionLoader
import viaduct.api.internal.select.SelectionSetFactory
import viaduct.api.reflect.Type
import viaduct.api.select.SelectionSet
import viaduct.api.types.Arguments
import viaduct.api.types.CompositeOutput
import viaduct.api.types.Mutation
import viaduct.api.types.NodeObject
import viaduct.api.types.Object
import viaduct.api.types.Query
import viaduct.engine.api.EngineExecutionContext
import viaduct.engine.api.NodeEngineObjectData
import viaduct.engine.api.NodeReference
import viaduct.engine.api.RawSelectionSet
import viaduct.engine.api.ViaductSchema
import viaduct.engine.api.mocks.MockSchema
import viaduct.tenant.runtime.globalid.GlobalIDImpl
import viaduct.tenant.runtime.toGRT

interface PrebakedResults<T : CompositeOutput> {
fun get(selections: SelectionSet<T>): T
}

private class EmptyPrebakedResults<T : CompositeOutput> : PrebakedResults<T> {
override fun get(selections: SelectionSet<T>): T {
throw UnsupportedOperationException("No pre-baked results were provided.")
}
}

class MockNodeEngineObjectData(
override val id: String,
override val graphQLObjectType: GraphQLObjectType,
) : NodeEngineObjectData, NodeReference {
override suspend fun fetch(selection: String): Any? = idOrThrow(selection)

override suspend fun fetchOrNull(selection: String): Any? = idOrThrow(selection)

override suspend fun fetchSelections(): Iterable<String> {
throw UnsupportedOperationException()
}

private suspend fun idOrThrow(selection: String): Any? {
if (selection == "id") {
return id
}
throw UnsupportedOperationException()
}

override suspend fun resolveData(
selections: RawSelectionSet,
context: EngineExecutionContext
) {
throw UnsupportedOperationException()
}
}

/**
* Re-project this InternalContext back to an [ExecutionContext].
* If this InternalContext was originally extracted from an ExecutionContext,
* then the original ExecutionContext will be returned. Otherwise, a minimal
* ExecutionContext will be returned.
*/
val InternalContext.executionContext: ExecutionContext
get() =
this as? ExecutionContext ?: MockExecutionContext(this)

/**
* Re-project this InternalContext back to an [ResolverExecutionContext].
* If this InternalContext was originally extracted from an ExecutionContext,
* then the original ExecutionContext will be returned. Otherwise, a minimal
* ExecutionContext will be returned.
*/
val InternalContext.resolverExecutionContext: ResolverExecutionContext
get() =
this as? ResolverExecutionContext ?: MockResolverExecutionContext(this)

class MockInternalContext(
override val schema: ViaductSchema,
override val globalIDCodec: GlobalIDCodec = MockGlobalIDCodec(),
override val reflectionLoader: ReflectionLoader = mockReflectionLoader("viaduct.api.grts")
) : InternalContext {
companion object {
fun mk(
schema: ViaductSchema,
grtPackage: String = "viaduct.api.grts"
): MockInternalContext = MockInternalContext(schema, MockGlobalIDCodec(), mockReflectionLoader(grtPackage))
}
}

open class MockExecutionContext(
internalContext: InternalContext,
override val requestContext: Any? = null
) : ExecutionContext, InternalContext by internalContext {
override fun <T : NodeObject> globalIDFor(
type: Type<T>,
internalID: String
): GlobalID<T> {
return GlobalIDImpl(type, internalID)
}

companion object {
fun mk(schema: ViaductSchema = MockSchema.minimal): MockResolverExecutionContext = MockResolverExecutionContext(MockInternalContext.mk(schema))
}
}

open class MockResolverExecutionContext(
internalContext: InternalContext,
val queryResults: PrebakedResults<Query> = EmptyPrebakedResults<Query>(),
private val selectionSetFactory: SelectionSetFactory? = null,
) : MockExecutionContext(internalContext), ResolverExecutionContext {
override fun <T : CompositeOutput> selectionsFor(
type: Type<T>,
selections: String,
variables: Map<String, Any?>
): SelectionSet<T> {
return if (selectionSetFactory != null) {
selectionSetFactory.selectionsOn(type, selections, variables)
} else {
throw UnsupportedOperationException("selectionsFor() requires a selectionSetFactory to be provided")
}
}

override suspend fun <T : Query> query(selections: SelectionSet<T>): T {
@Suppress("UNCHECKED_CAST")
return queryResults.get(selections as SelectionSet<Query>) as T
}

override fun <T : NodeObject> nodeFor(globalID: GlobalID<T>): T {
val id = globalIDCodec.serialize(globalID)
val graphqlObjectType = schema.schema.getObjectType(globalID.type.name)
return MockNodeEngineObjectData(id, graphqlObjectType).toGRT(this, globalID.type)
}

override fun <T : NodeObject> globalIDStringFor(
type: Type<T>,
internalID: String
): String {
return globalIDCodec.serialize(globalIDFor(type, internalID))
}

companion object {
fun mk(schema: ViaductSchema = MockSchema.minimal): MockResolverExecutionContext = MockResolverExecutionContext(MockInternalContext.mk(schema))
}
}

class MockFieldExecutionContext<T : Object, Q : Query, A : Arguments, O : CompositeOutput>(
override val objectValue: T,
override val queryValue: Q,
override val arguments: A,
private val selectionsValue: SelectionSet<O>,
internalContext: InternalContext,
queryResults: PrebakedResults<Query> = EmptyPrebakedResults<Query>(),
selectionSetFactory: SelectionSetFactory? = null,
) : MockResolverExecutionContext(internalContext, queryResults, selectionSetFactory),
FieldExecutionContext<T, Q, A, O> {
override fun selections() = selectionsValue
}

class MockMutationFieldExecutionContext<T : Object, Q : Query, A : Arguments, O : CompositeOutput>(
override val objectValue: T,
override val queryValue: Q,
override val arguments: A,
private val selectionsValue: SelectionSet<O>,
internalContext: InternalContext,
queryResults: PrebakedResults<Query> = EmptyPrebakedResults<Query>(),
private val mutationResults: PrebakedResults<Mutation> = EmptyPrebakedResults<Mutation>(),
selectionSetFactory: SelectionSetFactory? = null,
) : MockResolverExecutionContext(internalContext, queryResults, selectionSetFactory),
MutationFieldExecutionContext<T, Q, A, O> {
override fun selections() = selectionsValue

override suspend fun <T : Mutation> mutation(selections: SelectionSet<T>): T {
@Suppress("UNCHECKED_CAST")
return mutationResults.get(selections as SelectionSet<Mutation>) as T
}
}

class MockNodeExecutionContext<T : NodeObject>(
override val id: GlobalID<T>,
private val selectionsValue: SelectionSet<T>,
internalContext: InternalContext,
queryResults: PrebakedResults<Query> = EmptyPrebakedResults<Query>(),
selectionSetFactory: SelectionSetFactory? = null,
) : MockResolverExecutionContext(internalContext, queryResults, selectionSetFactory),
NodeExecutionContext<T> {
override fun selections() = selectionsValue
}

// Helper function to create a consistent key for SelectionSet lookup
private fun createSelectionSetKey(selectionSet: SelectionSet<*>): String {
return when (selectionSet) {
SelectionSet.NoSelections -> "NoSelections"
else -> selectionSet.toString()
}
}
84 changes: 2 additions & 82 deletions tenant/api/src/testFixtures/kotlin/viaduct/api/mocks/Mocks.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,9 @@ import graphql.schema.idl.SchemaGenerator
import graphql.schema.idl.SchemaParser
import kotlin.reflect.KClass
import viaduct.api.context.ExecutionContext
import viaduct.api.context.ResolverExecutionContext
import viaduct.api.globalid.GlobalID
import viaduct.api.globalid.GlobalIDCodec
import viaduct.api.internal.InternalContext
import viaduct.api.internal.ReflectionLoader
import viaduct.api.internal.select.SelectionSetFactory
import viaduct.api.internal.select.SelectionsLoader
import viaduct.api.reflect.Type
import viaduct.api.select.SelectionSet
Expand All @@ -21,31 +18,9 @@ import viaduct.api.types.Mutation
import viaduct.api.types.NodeCompositeOutput
import viaduct.api.types.NodeObject
import viaduct.api.types.Query
import viaduct.engine.api.ViaductSchema
import viaduct.engine.api.mocks.MockSchema
import viaduct.graphql.schema.ViaductExtendedSchema
import viaduct.graphql.schema.graphqljava.GJSchema

/**
* Re-project this InternalContext back to an [ExecutionContext].
* If this InternalContext was originally extracted from an ExecutionContext,
* then the original ExecutionContext will be returned. Otherwise, a minimal
* ExecutionContext will be returned.
*/
val InternalContext.executionContext: ExecutionContext
get() =
this as? ExecutionContext ?: MockExecutionContext(this)

/**
* Re-project this InternalContext back to an [ResolverExecutionContext].
* If this InternalContext was originally extracted from an ExecutionContext,
* then the original ExecutionContext will be returned. Otherwise, a minimal
* ExecutionContext will be returned.
*/
val InternalContext.resolverExecutionContext: ResolverExecutionContext
get() =
this as? ResolverExecutionContext ?: MockResolverExecutionContext(this)

fun mkSchema(sdl: String): GraphQLSchema {
val tdr = SchemaParser().parse(sdl)
return SchemaGenerator().makeExecutableSchema(tdr, RuntimeWiring.MOCKED_WIRING)
Expand All @@ -63,54 +38,7 @@ val GraphQLSchema.viaduct: ViaductExtendedSchema
get() =
GJSchema.fromSchema(this)

class MockInternalContext(
override val schema: ViaductSchema,
override val globalIDCodec: GlobalIDCodec = MockGlobalIDCodec(),
override val reflectionLoader: ReflectionLoader = mockReflectionLoader("viaduct.api.grts")
) : InternalContext {
companion object {
fun mk(
schema: ViaductSchema,
grtPackage: String = "viaduct.api.grts"
): MockInternalContext = MockInternalContext(schema, MockGlobalIDCodec(), mockReflectionLoader(grtPackage))
}
}

open class MockExecutionContext(
internalContext: InternalContext,
override val requestContext: Any? = null
) : ExecutionContext, InternalContext by internalContext {
override fun <T : NodeObject> globalIDFor(
type: Type<T>,
internalID: String
) = throw UnsupportedOperationException()

companion object {
fun mk(schema: ViaductSchema = MockSchema.minimal): MockResolverExecutionContext = MockResolverExecutionContext(MockInternalContext.mk(schema))
}
}

class MockResolverExecutionContext(internalContext: InternalContext) : MockExecutionContext(internalContext), ResolverExecutionContext {
override fun <T : CompositeOutput> selectionsFor(
type: Type<T>,
selections: String,
variables: Map<String, Any?>
): SelectionSet<T> = throw UnsupportedOperationException()

override suspend fun <T : Query> query(selections: SelectionSet<T>): T = throw UnsupportedOperationException()

override fun <T : NodeObject> nodeFor(id: GlobalID<T>): T = throw UnsupportedOperationException()

override fun <T : NodeObject> globalIDStringFor(
type: Type<T>,
internalID: String
): String = throw UnsupportedOperationException()

companion object {
fun mk(schema: ViaductSchema = MockSchema.minimal): MockResolverExecutionContext = MockResolverExecutionContext(MockInternalContext.mk(schema))
}
}

// TODO: remove (https://app.asana.com/1/150975571430/task/1211628405683375?focus=true)
@Suppress("UNCHECKED_CAST")
class MockGlobalIDCodec : GlobalIDCodec {
override fun <T : NodeCompositeOutput> serialize(id: GlobalID<T>): String = "${id.type.name}:${id.internalID}"
Expand All @@ -124,6 +52,7 @@ class MockGlobalIDCodec : GlobalIDCodec {
}
}

// TODO: remove (https://app.asana.com/1/150975571430/task/1211628405683375?focus=true)
class MockGlobalID<T : NodeObject>(
override val type: Type<T>,
override val internalID: String
Expand Down Expand Up @@ -161,12 +90,3 @@ data class MockSelectionsLoader<T : CompositeOutput>(val t: T) : SelectionsLoade
class MockReflectionLoader(vararg val types: Type<*>) : ReflectionLoader {
override fun reflectionFor(name: String): Type<*> = types.first { it.name == name }
}

@Suppress("UNCHECKED_CAST")
class MockSelectionSetFactory(val selectionSet: SelectionSet<*> = SelectionSet.NoSelections) : SelectionSetFactory {
override fun <T : CompositeOutput> selectionsOn(
type: Type<T>,
selections: String,
variables: Map<String, Any?>
): SelectionSet<T> = selectionSet as SelectionSet<T>
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ import viaduct.api.internal.select.SelectionSetFactory
import viaduct.api.internal.select.SelectionsLoader
import viaduct.api.mocks.MockExecutionContext
import viaduct.api.mocks.MockInternalContext
import viaduct.api.mocks.MockSelectionSetFactory
import viaduct.api.mocks.MockSelectionsLoader
import viaduct.api.reflect.Type
import viaduct.api.select.SelectionSet
import viaduct.api.types.CompositeOutput
import viaduct.engine.api.EngineExecutionContext
import viaduct.engine.api.EngineObjectData
import viaduct.engine.api.RawSelectionSet
Expand Down Expand Up @@ -131,3 +133,17 @@ class MockArgs(
arguments = arguments,
)
}

/**
* This was recently moved from projects/viaduct/oss/tenant/api/src/testFixtures/kotlin/viaduct/api/mocks/Mocks.kt
* because this was the only file using it. This is not a very good test double, and in fact in most situations
* we can directly use the actual implementation for testing. So when this context file goes away so will this mock.
*/
@Suppress("UNCHECKED_CAST")
private class MockSelectionSetFactory(val selectionSet: SelectionSet<*> = SelectionSet.NoSelections) : SelectionSetFactory {
override fun <T : CompositeOutput> selectionsOn(
type: Type<T>,
selections: String,
variables: Map<String, Any?>
): SelectionSet<T> = selectionSet as SelectionSet<T>
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import viaduct.api.types.Arguments
import viaduct.api.types.CompositeOutput
import viaduct.api.types.Query
import viaduct.engine.api.ViaductSchema
import viaduct.tenant.runtime.context.FieldExecutionContextImpl
import viaduct.tenant.testing.DefaultAbstractResolverTestBase

class SimpleResolverTest : DefaultAbstractResolverTestBase() {
Expand All @@ -32,11 +31,12 @@ class SimpleResolverTest : DefaultAbstractResolverTestBase() {
object QueryResolvers {
@ResolverFor(typeName = "Query", fieldName = "field")
abstract class Field : ResolverBase<String?> {
@JvmInline
value class Context(
private val inner: FieldExecutionContextImpl<Query, Query, Arguments.NoArguments, CompositeOutput.NotComposite>
// Context wraps MockFieldExecutionContext (the concrete mock type)
// This matches the generated pattern: value class wrapping the concrete execution context impl
class Context(
private val inner: FieldExecutionContext<Query, Query, Arguments.NoArguments, CompositeOutput.NotComposite>
) : FieldExecutionContext<Query, Query, Arguments.NoArguments, CompositeOutput.NotComposite> by inner,
InternalContext by inner
InternalContext by (inner as InternalContext)

open suspend fun resolve(ctx: Context): String? = throw NotImplementedError("Query.field.resolve not implemented")

Expand Down
Loading