Skip to content
Open
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Gradle plugin functional test coverage

### Changed

- Declare Gradle Plugin functional test as JVM test suite
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@
import static org.assertj.core.api.Assertions.assertThat;

import com.google.common.io.MoreFiles;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Scanner;
import lombok.NonNull;
import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.GradleRunner;
Expand All @@ -22,6 +27,28 @@ void test() {
"build.gradle.kts",
"plugins { id(\"dev.lajoscseppento.ruthless.demo.java-gradle-plugin\") }");

// TODO
// ectory.toFile(), FunctionalTestUtils::shouldCopy, false);
//
// // Set up JaCoCo coverage for Gradle TestKit tests
// String jacocoTestKitProperties;
// try (InputStream is =
// FunctionalTestUtils.class.getResourceAsStream("/testkit-gradle.properties")) {
// jacocoTestKitProperties = new Scanner(is).useDelimiter("\\A").next();
// }
//
// Path gradleProperties = targetDirectory.resolve("gradle.properties");
// try (BufferedWriter writer =
// Files.newBufferedWriter(
// gradleProperties, StandardOpenOption.CREATE, StandardOpenOption.APPEND)) {
// writer.append("\n");
// writer.append("# Coverage for Gradle TestKit tests");
// writer.append(jacocoTestKitProperties);
// }
// } catch (Exception ex) {
// throw new RuntimeException("Failed to copy demo project to " + targetDirectory, ex);
// }

// When
BuildResult result =
GradleRunner.create()
Expand Down
7 changes: 7 additions & 0 deletions ruthless-gradle-plugin-test/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
plugins {
id("dev.lajoscseppento.ruthless.java-library")
}

dependencies {
api(gradleTestKit())
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package dev.lajoscseppento.ruthless.gradle.plugin.test;

import java.io.BufferedWriter;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Properties;
import java.util.Scanner;
import lombok.experimental.UtilityClass;
import org.gradle.api.GradleException;
import org.gradle.testkit.runner.GradleRunner;

@UtilityClass
public class GradleRunnerWithCoverage {
//
// public static GradleRunner create() {
//
// Properties jacocoTestKitProperties;
// try (InputStream is =
// GradleRunnerWithCoverage.class.getResourceAsStream("/testkit-gradle.properties")) {
// jacocoTestKitProperties = new Properties();
// jacocoTestKitProperties.load(is);
// } catch (Exception ex) {
// throw new GradleException("Failed to read Gradle properties for Test Kit execution", ex);
// }
//
// GradleRunner runner = GradleRunner.create();
// jacocoTestKitProperties.forEach((key, value) -> {
// runner.withArguments()
// runner.with
// });
//
// try {
// // Set up JaCoCo coverage for Gradle TestKit tests
//
// Path gradleProperties = targetDirectory.resolve("gradle.properties");
// try (BufferedWriter writer =
// Files.newBufferedWriter(
// gradleProperties, StandardOpenOption.CREATE, StandardOpenOption.APPEND)) {
// writer.append("\n");
// writer.append("# Coverage for Gradle TestKit tests");
// writer.append(jacocoTestKitProperties);
// }
// } catch (Exception ex) {
// throw new RuntimeException("Failed to copy demo project to " + targetDirectory, ex);
// }
// }
}
7 changes: 6 additions & 1 deletion ruthless-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,15 @@ buildscript {
plugins {
id("com.gradle.plugin-publish") version "1.0.0"
id("dev.lajoscseppento.ruthless.java-gradle-plugin")
id("pl.droidsonroids.jacoco.testkit") version "1.0.9"
// id("pl.droidsonroids.jacoco.testkit") version "1.0.9"
`maven-publish`
}

repositories {
// TODO Remove when #80 is released
gradlePluginPortal()
}

dependencies {
val yamlString = project.file("src/main/resources/configuration.yml").readText()
val yaml: Map<String, Any> = Yaml().load(yamlString)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,42 @@

import dev.lajoscseppento.ruthless.plugin.impl.AbstractProjectPlugin;
import dev.lajoscseppento.ruthless.plugin.impl.RuthlessJavaBasePlugin;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import lombok.NonNull;
import org.gradle.api.GradleException;
import org.gradle.api.NamedDomainObjectProvider;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.jvm.JvmTestSuite;
import org.gradle.api.plugins.jvm.JvmTestSuiteTarget;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.api.tasks.testing.Test;
import org.gradle.language.base.plugins.LifecycleBasePlugin;
import org.gradle.plugin.devel.GradlePluginDevelopmentExtension;
import org.gradle.plugin.devel.plugins.JavaGradlePluginPlugin;
import org.gradle.testing.base.TestingExtension;
import org.gradle.testing.jacoco.plugins.JacocoTaskExtension;
import org.gradle.testing.jacoco.tasks.JacocoReport;
import pl.droidsonroids.gradle.jacoco.testkit.JaCoCoTestKitPlugin;
import pl.droidsonroids.gradle.jacoco.testkit.JacocoTestKitExtension;

public class RuthlessJavaGradlePluginPlugin extends AbstractProjectPlugin {
private GradlePluginDevelopmentExtension gradlePlugin;

@Override
protected List<Class<? extends Plugin<Project>>> requiredPlugins() {
return Arrays.asList(RuthlessJavaBasePlugin.class, JavaGradlePluginPlugin.class);
return Arrays.asList(
RuthlessJavaBasePlugin.class, JavaGradlePluginPlugin.class, JaCoCoTestKitPlugin.class);
}

@Override
protected void apply() {
repositories.gradlePluginPortal();

gradlePlugin = (GradlePluginDevelopmentExtension) extensions.getByName("gradlePlugin");
TestingExtension testing = (TestingExtension) extensions.getByName("testing");

Expand All @@ -37,17 +49,89 @@ protected void apply() {
tasks
.named(LifecycleBasePlugin.CHECK_TASK_NAME)
.configure(checkTask -> checkTask.dependsOn(functionalTestSuite));

configureTestKitCoverage();
}

private void configureFunctionalTestSuite(@NonNull JvmTestSuite functionalTest) {
gradlePlugin.testSourceSets(functionalTest.getSources());
private void configureFunctionalTestSuite(@NonNull JvmTestSuite suite) {
gradlePlugin.testSourceSets(suite.getSources());

functionalTest.getTargets().all(this::configureFunctionalTestSuiteTarget);
suite.getTargets().all(this::configureFunctionalTestSuiteTarget);
}

private void configureFunctionalTestSuiteTarget(@NonNull JvmTestSuiteTarget target) {
target
.getTestTask()
.configure(testTask -> testTask.shouldRunAfter(tasks.named(JavaPlugin.TEST_TASK_NAME)));
}

private void configureTestKitCoverage() {
TaskProvider<Test> functionalTest = tasks.named("functionalTest", Test.class);
TaskProvider<JacocoReport> jacocoTestReport =
tasks.named("jacocoTestReport", JacocoReport.class);

functionalTest.configure(
task -> {
task.finalizedBy(jacocoTestReport);

// See https://github.com/koral--/jacoco-gradle-testkit-plugin/issues/9
task.doLast(
t -> {
JacocoTaskExtension jacoco =
(JacocoTaskExtension) t.getExtensions().getByName("jacoco");
File jacocoTestExec = jacoco.getDestinationFile();

int delayMs = 1000;
int intervalMs = 200;
int maxRetries = 50;
int retries = 0;

// Linux
sleepMs(delayMs);

// Windows
while (!(jacocoTestExec.exists() && jacocoTestExec.renameTo(jacocoTestExec))) {
if (retries >= maxRetries) {
int waitTime = delayMs + intervalMs * retries;
throw new GradleException(
jacocoTestExec + " is not ready, waited at least " + waitTime + " ms");
}

retries++;
logger.info(
"Waiting {} ms for {} to be ready, try #{}...",
intervalMs,
jacocoTestExec,
retries);
sleepMs(intervalMs);
}

logger.info("{} is ready", jacocoTestExec);
});
});

jacocoTestReport.configure(
t -> {
t.dependsOn(functionalTest);
t.getExecutionData()
.from(project.getBuildDir().getAbsolutePath() + "/jacoco/functionalTest.exec");
});

tasks
.named("compileFunctionalTestJava")
.configure(t -> t.dependsOn("generateJacocoFunctionalTestKitProperties"));

// TODO cast 2nd arg
((JacocoTestKitExtension) extensions.getByName("jacocoTestKit"))
.applyTo("functionalTestImplementation", (TaskProvider) functionalTest);
}

private void sleepMs(long timeout) {
try {
TimeUnit.MILLISECONDS.sleep(timeout);
} catch (InterruptedException ex) {
logger.warn("Sleep interrupted");
Thread.currentThread().interrupt();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ private void configureTest() {
jacoco.setToolVersion(RuthlessConfiguration.INSTANCE.getJacocoVersion());

JacocoReport jacocoTestReportTask = (JacocoReport) tasks.getByName("jacocoTestReport");
jacocoTestReportTask.getReports().getHtml().getRequired().set(true);
jacocoTestReportTask.getReports().getXml().getRequired().set(true);

Task testTask = tasks.getByName(JavaPlugin.TEST_TASK_NAME);
Expand Down
3 changes: 3 additions & 0 deletions ruthless-plugin/src/main/resources/configuration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,6 @@ gradlePlugins:
- groupId: io.spring.gradle
artifactId: dependency-management-plugin
version: 1.0.11.RELEASE
- groupId: gradle.plugin.pl.droidsonroids.gradle.jacoco
artifactId: jacoco-gradle-testkit-plugin
version: 1.0.9
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ gradleEnterprise {
termsOfServiceAgree = "yes"
}
}
include("ruthless-gradle-plugin-test")