Skip to content

test(codegen): restore real KSP runtime fixture coverage for generated GraphQL sources #420

Description

@wax911

Context

PR #419 tightened the generated-source task wiring work from #418 and added honest coverage for Android-shaped task names such as kspDebugKotlin and kaptGenerateStubsDebugKotlin.

However, the KSP coverage in that PR is intentionally not full real KSP runtime coverage. The current fixtures verify task-name wiring, but they do not prove that a real KSP processor can see generated GraphQL symbols during KSP analysis.

This distinction matters for future consumers such as anitrend-v2, where data modules use KSP and generated GraphQL sources may need to be visible to symbol processors during the actual ksp*Kotlin execution phase.

Problem

The current KSP fixtures prove that the retrofit-graphql Gradle plugin wires GraphQL generation before tasks named like:

kspKotlin
kspDebugKotlin

They do not prove that a real KSP processor can resolve generated symbols such as:

sample.generated.GeneratedGraphQLRegistry

through the KSP Resolver API.

A previous attempt at real KSP TestKit coverage failed with a classpath/runtime issue similar to:

NoClassDefFoundError: org.jetbrains.kotlin.gradle.plugin.KotlinCompilerPluginSupportPlugin

That appears to be a TestKit/KSP/Kotlin Gradle Plugin classloading problem, not direct evidence that retrofit-graphql generated-source wiring is wrong. Still, the coverage gap should be closed before relying on this path during downstream migrations.

Expected Behaviour

A repository-local fixture should prove end-to-end KSP runtime visibility:

  • generateGraphQLSources runs before real ksp*Kotlin tasks.
  • A real KSP processor is loaded by the fixture build.
  • The processor can resolve generated GraphQL source symbols through Resolver.
  • The fixture fails if generated GraphQL sources are not visible during KSP analysis.
  • The fixture does not rely only on synthetic task names or dependsOn assertions.

Recommended Implementation Direction

Prefer a published-consumer TestKit fixture rather than only withPluginClasspath().

The likely issue with the previous fixture is that withPluginClasspath() injects the plugin-under-test classpath, while KSP is an external compiler plugin that must resolve and load against the correct Kotlin Gradle Plugin APIs inside the nested fixture build.

A better fixture shape is:

  1. Publish retrofit-graphql Gradle plugin to mavenLocal().
  2. Create a synthetic consumer project in TestKit.
  3. Resolve the retrofit-graphql plugin from mavenLocal() using the Gradle plugins {} DSL.
  4. Apply the real KSP plugin.
  5. Add a real KSP processor module through the ksp(...) configuration.
  6. Assert generated symbols are visible from the processor.

Example fixture plugin setup:

pluginManagement {
    repositories {
        mavenLocal()
        google()
        mavenCentral()
        gradlePluginPortal()
    }
}

plugins {
    kotlin("jvm") version "2.4.0"
    id("com.google.devtools.ksp") version "2.3.9"
    id("co.anitrend.retrofit.graphql.codegen") version "<local-version>"
}

Example processor dependency:

dependencies {
    ksp(project(":processor"))
}

Example processor assertion:

val generatedRegistry = resolver.getClassDeclarationByName(
    resolver.getKSNameFromString("sample.generated.GeneratedGraphQLRegistry"),
)

if (generatedRegistry == null) {
    logger.error("GeneratedGraphQLRegistry was not visible to KSP")
}

Suggested Test Matrix

JVM KSP fixture

  • Apply kotlin("jvm").
  • Apply real com.google.devtools.ksp.
  • Apply published retrofit-graphql codegen plugin from mavenLocal().
  • Generate a simple operation such as GetViewer.graphql.
  • Run:
./gradlew kspKotlin

Expected result:

  • generateGraphQLSources runs successfully before kspKotlin.
  • Real KSP processor loads successfully.
  • Processor resolves GeneratedGraphQLRegistry.

Android KSP fixture

  • Apply com.android.library or com.android.application.
  • Apply real com.google.devtools.ksp.
  • Apply published retrofit-graphql codegen plugin from mavenLocal().
  • Generate a simple operation such as GetViewer.graphql.
  • Run:
./gradlew kspDebugKotlin

Expected result:

  • generateGraphQLSources runs successfully before kspDebugKotlin.
  • Real KSP processor loads successfully.
  • Processor resolves GeneratedGraphQLRegistry.

Acceptance Criteria

  • A real KSP processor fixture exists and is executed by a dedicated test task.
  • The processor is registered through:
META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
  • The processor uses Resolver.getClassDeclarationByName(...) to resolve GeneratedGraphQLRegistry.
  • The test fails if generated GraphQL symbols are not visible during KSP processing.
  • The fixture covers at least JVM kspKotlin.
  • The fixture covers Android kspDebugKotlin if Android SDK/AGP fixture support is available in the executing environment.
  • Synthetic task-name-only coverage remains allowed as a lightweight regression check, but it must not be the only KSP coverage.
  • The issue documents any remaining TestKit/KSP classpath limitation if full Android KSP coverage cannot be stabilized in one pass.

Related Work

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions