Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KT-64377 use Java Test Suites for Gradle integration tests #3427

Merged
merged 40 commits into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
c31dd23
KT-64377 - remove gradle wrapper files for integration test projects …
adam-enko Dec 19, 2023
61889af
Merge branch 'master' into KT-64377/update-integration-test-build-config
adam-enko Dec 20, 2023
74a1b20
Merge remote-tracking branch 'origin/master' into KT-64377/update-int…
adam-enko Jan 2, 2024
20e0984
refactor integration test properties to use DokkaBuildProperties util…
adam-enko Jan 12, 2024
66287db
Merge branch 'master' into KT-64377/update-integration-test-build-config
adam-enko Jan 12, 2024
28f4d7a
disable explicit API mode in non-published integration-test utilities…
adam-enko Jan 12, 2024
7af0394
Merge remote-tracking branch 'origin/master' into KT-64377/update-int…
adam-enko Jan 15, 2024
10fe4b5
Restructure Gradle Integration tests to use Java Test Suites
adam-enko Jan 15, 2024
5f35a73
revert GitHub smoke test Gradle task back to 'test'
adam-enko Jan 16, 2024
0babb2c
auto-discover and set ANDROID_SDK, and also search for local.properti…
adam-enko Jan 16, 2024
9c6c80e
add TODO link for integration tests - doNotTrackState()
adam-enko Jan 16, 2024
b1c95de
Merge branch 'master' into KT-64377/java-test-suites
adam-enko Jan 22, 2024
28a1c74
tidy up after merge
adam-enko Jan 22, 2024
8a24b4d
Merge remote-tracking branch 'origin/master' into KT-64377/java-test-…
adam-enko Jan 22, 2024
57b93cf
merge cleanup
adam-enko Jan 22, 2024
a974d9b
change plugin `test-suite-base` -> `jvm-test-suite`
adam-enko Jan 23, 2024
852fc7b
move registerTestProjectSuite() to top-level function
adam-enko Jan 23, 2024
ba0c484
move gradle-specific test utils to gradle integration test
adam-enko Jan 23, 2024
6d5ab63
move unused systemVariableProviders.kt back
adam-enko Jan 23, 2024
14364ea
move `multimodule-inter-module-links` to test-suite
adam-enko Jan 23, 2024
84255e2
register DOKKA_TEST_OUTPUT_PATH as a test task input, and the dir as …
adam-enko Jan 23, 2024
37581f2
Merge branch 'master' into KT-64377/java-test-suites
adam-enko Jan 23, 2024
f6d1cca
rm old import
adam-enko Jan 23, 2024
9fe882b
make testOutputPath optional
adam-enko Jan 23, 2024
59594dd
re-add integrationTest lifecycle task
adam-enko Jan 23, 2024
d249e64
fix `it-multimodule-inter-module-links` dir, add property name to tem…
adam-enko Jan 24, 2024
ed0365f
comment to explain test-suites are independent
adam-enko Jan 24, 2024
50a6ef4
add property names to coroutines/serialization project dirs
adam-enko Jan 24, 2024
99fc753
use jvm11 for kotlinx.serialization
adam-enko Jan 24, 2024
47b3dc8
Merge branch 'master' into KT-64377/java-test-suites
adam-enko Jan 26, 2024
cd554b0
revert MaxMetaspaceSize in Coroutines test, and add comment to explain
adam-enko Jan 26, 2024
668c661
environment workaround for https://github.com/gradle/gradle/issues/11534
adam-enko Jan 31, 2024
939d577
update CI build properties
adam-enko Jan 31, 2024
42cd06c
remove `allWarningsAsErrors = false`
adam-enko Jan 31, 2024
df52ca1
remove 'check' task dependency
adam-enko Jan 31, 2024
6eff18d
Merge branch 'master' into KT-64377/java-test-suites
adam-enko Jan 31, 2024
9ec8514
Merge remote-tracking branch 'origin/master' into KT-64377/java-test-…
adam-enko Feb 6, 2024
37a38fb
fix git-checkout task dependencies after merge, so they are more spec…
adam-enko Feb 6, 2024
b1c9a41
fix logging of uri for git-checkout task
adam-enko Feb 6, 2024
f09111e
add invariantSeparatorsPath to androidSdkDir, so it's stable across m…
adam-enko Feb 6, 2024
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
4 changes: 2 additions & 2 deletions .github/workflows/preview-publish-ga.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
uses: gradle/gradle-build-action@v2
with:
gradle-home-cache-cleanup: true
arguments: :dokka-integration-tests:gradle:integrationTest --tests org.jetbrains.dokka.it.gradle.kotlin.CoroutinesGradleIntegrationTest --stacktrace "-Dorg.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=500m"
arguments: :dokka-integration-tests:gradle:testExternalProjectKotlinxCoroutines --stacktrace "-Dorg.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=500m"
env:
DOKKA_TEST_OUTPUT_PATH: /home/runner/work/dokka/coroutines
- name: Copy files to GitHub Actions Artifacts
Expand Down Expand Up @@ -56,7 +56,7 @@ jobs:
uses: gradle/gradle-build-action@v2
with:
gradle-home-cache-cleanup: true
arguments: :dokka-integration-tests:gradle:integrationTest --tests org.jetbrains.dokka.it.gradle.kotlin.SerializationGradleIntegrationTest --stacktrace "-Dorg.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=500m"
arguments: :dokka-integration-tests:gradle:testExternalProjectKotlinxSerialization --stacktrace "-Dorg.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=500m"
env:
DOKKA_TEST_OUTPUT_PATH: /home/runner/work/dokka/serialization
- name: Copy files to GitHub Actions Artifacts
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/preview-publish-web-s3.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
uses: gradle/gradle-build-action@v2
with:
gradle-home-cache-cleanup: true
arguments: :dokka-integration-tests:gradle:integrationTest --tests org.jetbrains.dokka.it.gradle.kotlin.CoroutinesGradleIntegrationTest --stacktrace "-Dorg.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=500m"
arguments: :dokka-integration-tests:gradle:testExternalProjectKotlinxCoroutines --stacktrace "-Dorg.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=500m"
env:
DOKKA_TEST_OUTPUT_PATH: /home/runner/work/dokka/coroutines
- name: Configure AWS credentials for S3 access
Expand All @@ -38,7 +38,7 @@ jobs:
- name: Print link
run: echo https://dokka-snapshots.s3.eu-central-1.amazonaws.com/${{ env.branch-name }}/coroutines/${GITHUB_SHA::7}/index.html

kotilnx-serialization:
kotlinx-serialization:
runs-on: ubuntu-latest
if: github.repository == 'Kotlin/dokka'
steps:
Expand All @@ -55,7 +55,7 @@ jobs:
uses: gradle/gradle-build-action@v2
with:
gradle-home-cache-cleanup: true
arguments: :dokka-integration-tests:gradle:integrationTest --tests org.jetbrains.dokka.it.gradle.kotlin.SerializationGradleIntegrationTest --stacktrace "-Dorg.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=500m"
arguments: :dokka-integration-tests:gradle:testExternalProjectKotlinxSerialization --stacktrace "-Dorg.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=500m"
env:
DOKKA_TEST_OUTPUT_PATH: /home/runner/work/dokka/serialization
- name: Configure AWS credentials for S3 access
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/tests-thorough.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ jobs:
# Running tests with the Gradle daemon on windows agents leads to some very strange
# JVM crashes for some reason. Most likely a problem of Gradle/GitHub/Windows server
run: >
./gradlew test --stacktrace --no-daemon --no-parallel
./gradlew test --stacktrace --no-daemon --no-parallel --continue
adam-enko marked this conversation as resolved.
Show resolved Hide resolved
"-Dorg.gradle.jvmargs=-Xmx1g -XX:MaxMetaspaceSize=500m"
"-Porg.jetbrains.dokka.javaToolchain.testLauncher=${{ matrix.javaVersion }}"
- name: Run tests under Ubuntu/Macos
if: matrix.os != 'windows-latest'
run: >
./gradlew test --stacktrace
./gradlew test --stacktrace --continue
"-Porg.jetbrains.dokka.javaToolchain.testLauncher=${{ matrix.javaVersion }}"
1 change: 0 additions & 1 deletion build-logic/src/main/kotlin/dokkabuild.base.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/*
* Copyright 2014-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

import dokkabuild.DokkaBuildProperties
import org.gradle.language.base.plugins.LifecycleBasePlugin.VERIFICATION_GROUP

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ val installMavenBinary by tasks.registering(Sync::class) {
val archives = serviceOf<ArchiveOperations>()
from(
mavenBinary.flatMap { conf ->
@Suppress("UnstableApiUsage")
val resolvedArtifacts = conf.incoming.artifacts.resolvedArtifacts

resolvedArtifacts.map { artifacts ->
Expand Down
20 changes: 20 additions & 0 deletions build-logic/src/main/kotlin/dokkabuild/DokkaBuildProperties.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@

package dokkabuild

import org.gradle.api.file.ProjectLayout
import org.gradle.api.provider.Provider
import org.gradle.api.provider.ProviderFactory
import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
import java.io.File
import javax.inject.Inject

/**
Expand All @@ -20,8 +22,12 @@ import javax.inject.Inject
*/
abstract class DokkaBuildProperties @Inject constructor(
private val providers: ProviderFactory,
private val layout: ProjectLayout,
) {

val isCI: Provider<Boolean> =
providers.environmentVariable("CI").map(String::toBoolean).orElse(false)
adam-enko marked this conversation as resolved.
Show resolved Hide resolved

/**
* The main version of Java that should be used to build Dokka source code.
*
Expand Down Expand Up @@ -62,6 +68,20 @@ abstract class DokkaBuildProperties @Inject constructor(
dokkaProperty("integration_test.useK2", String::toBoolean)
.orElse(false)

val androidSdkDir: Provider<File> =
providers
// first try finding a local.properties file in any parent directory
.provider {
generateSequence(layout.projectDirectory.asFile, File::getParentFile)
.mapNotNull { dir -> dir.resolve("local.properties").takeIf(File::exists) }
.flatMap { file -> file.readLines().filter { it.startsWith("sdk.dir=") } }
.firstOrNull()
?.substringAfter("sdk.dir=")
}
// else try getting pre-installed SDK (e.g. via GitHub step setup-android)
.orElse(providers.environmentVariable("ANDROID_SDK_ROOT"))
.orElse(providers.environmentVariable("ANDROID_HOME"))
.map(::File)

private fun <T : Any> dokkaProperty(name: String, convert: (String) -> T) =
providers.gradleProperty("org.jetbrains.dokka.$name").map(convert)
Expand Down
4 changes: 4 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ plugins {
id("dokkabuild.base")
}

tasks.check {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK we already have this dependency below: addDependencyOnSameTasksOfIncludedBuilds

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, in this root build script we have integrationTest aggregate task, which, as far as I understand, will now run only maven and cli tests and not Gradle. Are we planning to migrate maven/cli tests to test suites soon? If no, I think it will be better to somehow align this.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: before, when running check (gradle check) integration tests were not executed, but now they are. It's not convenient as integration tests are long :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK we already have this dependency below: addDependencyOnSameTasksOfIncludedBuilds

Unfortunately addDependencyOnSameTasksOfIncludedBuilds adds a dependency on :dokka-integration-tests:check, not :dokka-integration-tests:gradle:check.

TBH I found the logic about setting up task dependencies a bit confusing in this file, so there's probably a better way of using the functions, but I found being explicit easier to understand :).

I get that it's a workaround for a Gradle flaw gradle/gradle#22335 - I think using a task rule might be help https://stackoverflow.com/a/69179714/4161471

Are we planning to migrate maven/cli tests to test suites soon?

Yes, for sure. I wanted to do it one subproject at a time, to minimize PR size, and then it will be easier to determine what functionality can be extracted into conventions & build-logic utils.

Note: before, when running check (gradle check) integration tests were not executed, but now they are. It's not convenient as integration tests are long :)

Yes, that's intentional :) 'check' is the defacto standard lifecycle task for all verification.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's start from the end:)

Yes, that's intentional :) 'check' is the defacto standard lifecycle task for all verification.

  1. Yes, but in day-to-day workflow I would like to run just test + apiCheck (so old check) to test if my changes didn't broke anything. Sometimes it's fine to run only one module/test, but not all the time. At my side running check now will take 1-2 minute I think. If we will put running integration tests into check - it will become much more, so I will start to use test and apiCheck tasks separately. Or I will just run check for some subproject(s). External contributors also could just run check (as it's defacto standard lifecycle task for all verification.) and Im not sure, that all of them will want to wait for all tests or some of the tests could even fail, f.e. android, if there is no setup, and they will spend more time to fix the issue or will just ignore running test, or even finishing the feature. This is a little inconvenient.
  2. as far as I understand, test suites created by Gradle test-suite plugin doesn't run when running check - and I think for a reason. check is day-to-day task for fast versification - integration tests are not fast.

So I think, that running check should not run integration tests - they should run by default on CI (in same/separate workflow), it should be enough for most cases. If needed, they can be easily run locally, all of them (rarely) or specific one (more frequently).

I wanted to do it one subproject at a time, to minimize PR size

Agree, though, I've just mentioned inconsistency in behaviour of different integration tests after merging this PR - not a blocker, but just something to be aware of.

TBH I found the logic about setting up task dependencies a bit confusing in this file, so there's probably a better way of using the functions, but I found being explicit easier to understand :).

yeah, still, it's very convenient to have such aggregated tasks in root project. If you have ideas on how to improve this, I will be glad to review separate PR :)
I've never used task rules before, so I don't know will it be possible/simpler/complex, so up to you.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for explaining, it definitely makes sense to make the UX of the Gradle tasks more comprehensible. Anyone should be able to run suitable tests with a single Gradle task.

I see there are some good options for this, proposed at the bottom, but first I want to clarify about the check task.

Check task

Personally, I find the current behaviour (check doesn't run all tests) confusing because in all other projects it's a lifecycle task that runs all verifications.

That's because the check task is provided by the Gradle Base Plugin, which all other plugins use, and it's supposed to run all verifications.

image

Of course, Gradle is very flexible so Dokka doesn't have to follow this convention, but it would be unusual. It's important to align the conventions within Kotlin projects - so while "check runs all tests" might not meet your understanding at the moment, I hope it will make more sense in the future.

Proposal

I see two options

  1. Update the test task so that it will also run the apiCheck task.

    Update the README instructions:

    • ./gradlew check - run all verifications (which might be slow):
      • ./gradlew test - run unit tests (and also apiCheck)
      • ./gradlew apiCheck - BCV check
      • ./gradlew integrationTest - run all integration tests (Slow! Requires Prep!)
  2. Add a custom quickCheck (or checkFast - whatever name you want) lifecycle task that will run unit tests + apiCheck (and any other future 'fast' checks).

    Update the README instructions:

    • ./gradlew check - run all verification (which might be slow):
      • ./gradlew quickCheck - runs quicker checks (test and apiCheck)
      • ./gradlew test - run unit tests
      • ./gradlew apiCheck - BCV check
      • ./gradlew integrationTest - run all integration tests (Slow! Requires Prep!)

I have a slight preference towards 1, because currently there's not many verification tasks apart from test and apiCheck that would justify a new task.

Which do you prefer?

I can also split out these changes to the test-task dependencies into a separate PR to keep this PR focused.

Copy link
Member

@IgnatBeresnev IgnatBeresnev Jan 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's supposed to run all verifications.

Can you try to define "all" here? :)

I think it's very important to draw the line somewhere, otherwise it's easy to fall into unproductive malicious compliance and make the check task perform literally all verifications:

  • Running tests on different platforms and not only on the user's one (i.e start docker containers for missing OSes like MacOS/Linux/Windows)
  • Publishing verification checks (not done now)
  • UI tests that might reside in a different repo (we'll have them soon, Infrastructure to run UI tests #3469)
  • Run first with K1, then with K2 (even if not needed by default)
  • Tests that run Dokka with the latest/arbitrary commit of kotlin-compiler / KGP / etc (also planned)
  • Stress tests / Performance tests / Benchmarks

I would draw the line somewhere close to "Runs all embedded verifications that don't require special knowledge or setup, and that are reasonably expected to be run locally by developers". By that definition, Dokka's "integration tests" (which are really completely separate e2e tests) are not it for several reasons


About the proposals - I would first try to understand why we need the check task to run Dokka's "integration tests" specifically. It's taken for granted, but I don't think it should be :)

Who or what is going to be using it if check also runs Dokka's "integration tests"? How is it going to be useful? (other than abiding by Gradle's "all checks", which can be taken to extremes)


I can also split out these changes to the test-task dependencies into a separate PR to keep this PR focused.

Certainly wouldn't hurt, if you have the time 👍

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, Im totally agree with Ignat.
Still I will add some additional points:

  1. AGP doesn't make check dependsOn instrumented tests (which are executed on emulator/real device) - they are slow and environment dependent
  2. even Gradle by default doesn't do this for test suites - this means, that it's not strictly true, that we need to run all kind of tests by default when we run check
  3. If we will make test dependOn apiCheck or any other check task (f.e. if we will add detekt) - if we will run tests from IDEA via gutter (just one test or test class), we will execute apiCheck - not sure it's expected. May be it's possible to workaround it, but not sure that by doing this we will simplify both build setup and user expectations.

So I believe integrationTests for Dokka should be executed in separate task. Additionally, we could created lifecycle task checkAll/checkLong if we really do want to execute it.

Another possibility: make global check run all tests except integration tests. make dokka-integration-tests check run all tests there, even integration.
It can cause confusion, in this case we will have some split between check tasks. But IMO, it will be still better then running all integration tests by calling global check

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say it would be more conventional to have the check task that tests as much as possible within the current environment and thus you just need to invoke a single task and wait; also I agree with Adam that something like quickCheck or smokeCheck could be used here for smoke testing. It's about making the build conventional and thus easing the build discoverability. But, also I agree that we shouldn't always blindly follow the conventions, especially if it harms locally established use cases. Anyway, the final word is on your side 🙂
After a round of thinking, I don't see anything criminal in breaking that convention a bit. We are not the first, we are not the last here. I would just suggest to reflect this in the project docs

Copy link
Member Author

@adam-enko adam-enko Jan 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed the check task dependency.

it's supposed to run all verifications.

Can you try to define "all" here? :)

See https://docs.gradle.org/current/userguide/base_plugin.html

Plugins and build authors should attach their verification tasks, such as ones that run tests, to this lifecycle task using check.dependsOn(task).

  • Running tests on different platforms and not only on the user's one (i.e start docker containers for missing OSes like MacOS/Linux/Windows)
  • Publishing verification checks (not done now)

There are no Gradle tasks for this, so check can't depend on them.

check can't depend on tasks in other repos.

  • Run first with K1, then with K2 (even if not needed by default)

This is a good idea. It would help prevent the problem we saw recently where the K2 tests weren't running on TeamCity.

  • Tests that run Dokka with the latest/arbitrary commit of kotlin-compiler / KGP / etc (also planned)

If this is achieved with a Gradle task then yes, check should depend on that task.

  • Stress tests / Performance tests / Benchmarks

This depends:

  • If the task has checks, then yes, check should depend on it

    For example, the existing SequentialTasksExecutionStressTest

  • If the tasks are measuring performance and reporting on it, but not verifying it, then that's not a verification task so check shouldn't depend on it.

    For example: if JMH tests were added

I would draw the line somewhere close to "Runs all embedded verifications that don't require special knowledge or setup, and that are reasonably expected to be run locally by developers". By that definition, Dokka's "integration tests" (which are really completely separate e2e tests) are not it for several reasons

I agree, there's a good need for such lifecycle task, and the meaning you explain is clear.

It's confusing to overload an existing task with a different meaning. It would make more sense to create a new lifecycle task that meets this definition.

It would also help prevent issues on CI where verifications have been skipped. E.g. K2 tests not being run, and up until recently apiCheck wasn't run on TeamCity.

Using check to run all test tasks aligns how check works both within JetBrains, but also within the Gradle ecosystem. Many other plugins use check to run all verifications.

dependsOn(gradle.includedBuild("dokka-integration-tests").task(":gradle:check"))
}

val publishedIncludedBuilds = listOf("runner-cli", "runner-gradle-plugin-classic", "runner-maven-plugin")
val gradlePluginIncludedBuilds = listOf("runner-gradle-plugin-classic")

Expand Down
4 changes: 2 additions & 2 deletions dokka-integration-tests/gradle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Integration tests have fixed git revision number, with the diff patch applied fr

In order to update:

* Checkout the project with the requered revision
* Checkout the project with the required revision
- It's some state of the `master`
* Manually write the diff (or apply the existing one and tweak) to have the project buildable against locally published Dokka of version `for-integration-tests-SNAPSHOT`
* `git diff > $pathToProjectInDokka/project.diff`
Expand All @@ -26,4 +26,4 @@ In order to update:
### Run integration tests with K2 (symbols)

To run integration tests with K2, the property `org.jetbrains.dokka.integration_test.useK2` should be set to `true`.
By default, the task `integrationTest` is run with K1 (descriptors).
By default, the integration tests are run with K1 (descriptors).
Loading
Loading