I have a working build of a custom Gradle plugin. I have a couple of unit tests, and now I'm trying to get integration tests going, using nebula-test.
I'm getting a confusing test error in the integration test. I must be doing something wrong in how I'm using nebula-test.
I'll show full code, but I'll describe the essentials first.
The plugin defines an extension block which contains a handful of properties, one of which is a file path where particular files can be found. For context, that property name is called "yangFilesRootDir".
The plugin creates an instance of a custom task called "YangGenerate". The task has an instance variable called "yangFilesRootDir" of type File, and this instance variable has a @InputDirectory annotation on it. The task has other instance variables, some with "@Input..." annotations on them.
The task has an "init" method that is called from the plugin after project evaluation. This initializes the task instance variables from the values in the extension block. In the "init" method, if the "yangFilesRootDir" property isn't set in the extension block, I use a default value of "src/main/yang".
Before working on this integration test, I set up a standalone project referencing the plugin. The "build.gradle" for this project specifies the extension block, and I've tested it both with the property setting and without (I'm storing the files in that the default location), and it's working fine.
This is what my spec looks like right now:
class YangPluginIntegSpec extends IntegrationSpec {
def 'simple'() {
createFile("src/main/yang/dummy")
writeHelloWorld("com.example")
buildFile << applyPlugin(YangPlugin)
buildFile << '''
yang {
yangFilesRootDir 'src/main/yang'
}
'''.stripIndent()
when:
ExecutionResult result = runTasksSuccessfully('build')
then:
println result
}
}
I've tried this both with and without the "yang" block, and the test is failing with this stacktrace:
org.gradle.api.GradleException: Build aborted because of an internal error.
at nebula.test.functional.internal.DefaultExecutionResult.rethrowFailure(DefaultExecutionResult.groovy:95)
at nebula.test.IntegrationSpec.runTasksSuccessfully(IntegrationSpec.groovy:234)
at com.att.opnfv.yang.gradle.YangPluginIntegSpec.simple(YangPluginIntegSpec.groovy:18)
Caused by: org.gradle.internal.exceptions.LocationAwareException: A problem was found with the configuration of task ':yangGenerate'.
at org.gradle.initialization.DefaultExceptionAnalyser.transform(DefaultExceptionAnalyser.java:77)
at org.gradle.initialization.MultipleBuildFailuresExceptionAnalyser.transform(MultipleBuildFailuresExceptionAnalyser.java:47)
at org.gradle.initialization.StackTraceSanitizingExceptionAnalyser.transform(StackTraceSanitizingExceptionAnalyser.java:30)
at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:108)
at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:86)
at org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:80)
at org.gradle.tooling.internal.provider.BuildModelAction.run(BuildModelAction.java:43)
at org.gradle.tooling.internal.provider.BuildModelAction.run(BuildModelAction.java:30)
at org.gradle.tooling.internal.provider.ConfiguringBuildAction.run(ConfiguringBuildAction.java:119)
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:36)
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:26)
at org.gradle.tooling.internal.provider.DaemonBuildActionExecuter.execute(DaemonBuildActionExecuter.java:42)
at org.gradle.tooling.internal.provider.DaemonBuildActionExecuter.execute(DaemonBuildActionExecuter.java:29)
at org.gradle.tooling.internal.provider.LoggingBridgingBuildActionExecuter.execute(LoggingBridgingBuildActionExecuter.java:62)
at org.gradle.tooling.internal.provider.LoggingBridgingBuildActionExecuter.execute(LoggingBridgingBuildActionExecuter.java:34)
at org.gradle.tooling.internal.provider.ProviderConnection.run(ProviderConnection.java:107)
at org.gradle.tooling.internal.provider.ProviderConnection.run(ProviderConnection.java:94)
at org.gradle.tooling.internal.provider.DefaultConnection.getModel(DefaultConnection.java:149)
at org.gradle.tooling.internal.consumer.connection.CancellableModelBuilderBackedModelProducer.produceModel(CancellableModelBuilderBackedModelProducer.java:58)
at org.gradle.tooling.internal.consumer.connection.AbstractConsumerConnection.run(AbstractConsumerConnection.java:56)
at org.gradle.tooling.internal.consumer.DefaultBuildLauncher$1.run(DefaultBuildLauncher.java:82)
at org.gradle.tooling.internal.consumer.DefaultBuildLauncher$1.run(DefaultBuildLauncher.java:76)
at org.gradle.tooling.internal.consumer.connection.LazyConsumerActionExecutor.run(LazyConsumerActionExecutor.java:83)
at org.gradle.tooling.internal.consumer.connection.ProgressLoggingConsumerActionExecutor.run(ProgressLoggingConsumerActionExecutor.java:58)
at org.gradle.tooling.internal.consumer.async.DefaultAsyncConsumerActionExecutor$1$1.run(DefaultAsyncConsumerActionExecutor.java:55)
at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:64)
Caused by: org.gradle.api.tasks.TaskValidationException: A problem was found with the configuration of task ':yangGenerate'.
at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:55)
at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:42)
at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:53)
at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
at org.gradle.api.internal.AbstractTask.executeWithoutThrowingTaskFailure(AbstractTask.java:306)
at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.executeTask(AbstractTaskPlanExecutor.java:79)
at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:63)
at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:51)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:23)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:88)
at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:29)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:62)
at org.gradle.execution.DefaultBuildExecuter.access$200(DefaultBuildExecuter.java:23)
at org.gradle.execution.DefaultBuildExecuter$2.proceed(DefaultBuildExecuter.java:68)
at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:62)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:55)
at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:149)
at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:106)
... 22 more
Caused by: org.gradle.api.InvalidUserDataException: Directory 'src\main\yang' specified for property 'yangFilesRootDir' does not exist.
at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:47)
... 41 more
I also ran this with "-i" so I can get more info, and it showed me the path to the temporary build directory for the test, and after the test failed I verified that "src/main/yang/dummy" exists in the test project directory.
Here's the relevant code for the plugin class:
class YangPlugin implements Plugin<Project> {
public void apply(Project project) {
YangExtension yang = project.extensions.create(YANG_EXT, YangExtension, project)
YangGenerateTask task = project.task(YANG_GENERATE_TASK, type: YangGenerateTask)
project.afterEvaluate {
task.init(project, yang)
project.compileJava.dependsOn task
if (task.yangFilesRootDir && task.yangFilesRootDir.exists()) {
Jar jarTask = project.jar
if (task.yangFilesRootDir.getPath().startsWith(FilenameUtils.normalize(SRC_MAIN_RESOURCES))) {
jarTask.exclude(task.yangFilesRootDir.getPath() - FilenameUtils.normalize(SRC_MAIN_RESOURCES))
}
jarTask.from(task.yangFilesRootDir) { into(META_INF_YANG) }
}
}
}
}
And the relevant portion of the YangGenerate task:
class YangGenerateTask extends DefaultTask {
private static final String DEFAULT_YANG_FILES_ROOT_DIR = "src/main/yang"
Project project
Collection<CodeGeneratorConfig> generators
boolean inspectDependencies
Collection<String> excludeFiles
String yangFilesConfiguration
String generatorsConfiguration
Pattern yangFilePattern = Pattern.compile("META-INF/yang/.*\\.yang\$")
@InputDirectory
File yangFilesRootDir
@Input
def getGeneratorClasses() {
...
}
@InputFiles
def getOptionalYangClasspath() {
...
}
@OutputDirectories
def getOutputDirectories() {
...
}
@TaskAction
void generate() {
...
}
public void init(Project project, YangExtension yang) {
this.yangFilesRootDir = new File(yang.yangFilesRootDir ?: DEFAULT_YANG_FILES_ROOT_DIR)
...
}
}
Update:
I finally thought to run this test in the debugger, and I discovered that the reason the path isn't found is that the "current directory" is not the base directory of the test project, but the base directory of the main plugin project, which definitely doesn't have a "src/main/yang" directory.
Someone on #gradle pointed me to how to open files in the plugin code relative to the project basedir (project.file(...)), and after I changed my plugin code to do this, this error went away.