Cannot load resources from the plugin's classpath when running unit tests

I’m running into an error where if I try to run a plugin under an integration test the part of my plugin that tries to load a resource from the classpath fails to find that resource. However, if I run that same code as a unit test the resource is found without any issue. I’ve checked the classpath it is configured with and I see the resource directory incuded in the list of directories provided to the classpath. But when I check the classloader of my class (println( this.classloader )) all I get is null which means the system classloader. I’d expect it to be a classloader with my plugin’s classpath. Here is the code I’m using:

String build = """           
        plugins {
            id "com.myplugin.datadensity"
        }

        datadensity {
            exampleColumns = [
                "id"
            ]
            separator = ","
            src = files( "\${projectDir}/pii-test.csv" )
            output = file("\${buildDir}/datadensity" )
        }
        """
buildFile.withPrintWriter { it.write( build ) }

BuildResult result = GradleRunner.create()
        .withProjectDir( projectDir.getRoot() )
        .withPluginClasspath()
        .withArguments( "datadensity")
        .build()

When I debug the withPluginClasspath() method I can see my resource directory being added so that appears to work. This is under gradle 5.6.4

What is wrong?

How are the integration tests being configured in the build?

If you are using the java-gradle-plugin plugin, have you told the java-gradle-plugin about the integration test sourceset? I suspect you have since you’re seeing the plugin get applied and then fail. eg:

gradlePlugin {
    testSourceSet project.sourceSets.integrationTest
}

Just to clarify, what is this.classloader? Did you mean this.class.classLoader? What class is this, the plugin class?

Correct. It is this.class.classloader In this case the class in question isn’t the plugin but it’s apart of that jar file. It’s a supporting class. It’s the following class:

class Resources {
    static Set<String> loadData( String pathname ) {
        InputStream lastStream = this.class.getResourceAsStream(pathname)  // this fails when executed inside gradle
        BufferedReader br =new BufferedReader(new InputStreamReader(lastStream))
        Set<String> cache=[] as HashSet
        try {
            String line
            while( (line = br.readLine() ) != null ) {
                cache.add( line.trim().toLowerCase() )
            }
        }
        finally {
            br.close()
        }
        return cache
    }
}

As far as configuring the sourceSets it’s just part of the default test directory. I didn’t separate it out, and I am running the test as you state.

Did you check what pathname your utility class is getting?
From your configuration it looks like you are not addressing a file that is part of your jar file but from the filesystem instead. And if that absolute filesystem path is going to be smth else than you’d expect, it has nothing to do with the classpath.

So pathname is something like “/firstnames.csv” which is a file in the resources directory. The filenames passed to it are hardcoded in the plugin files. Its data that would be included with the plugin jar file. The paths you see in the gradle.build file are not passed to Resources.loadData() method. I mainly included the build file and code so you can see how I configured the GradleRunner. I also included the Resources file so it was clear how I was loading the files in question. But I see that I may have caused more confusion in doing so.

So I finally got back to working on this, and I figured out my problem. I had code like this:

class Resources {
    static Set<String> loadData( String pathname ) {
        InputStream lastStream = this.class.getResourceAsStream(pathname)  // this fails when executed inside gradle
       ....
   }
}

So the problem was the use of this inside a static method. This is a difference in Java and Groovy I was unaware of, but in Groovy this is valid and points to the class the static method is defined within. By me doing this.class I was retrieving the java.lang.Class object which was loaded by the primordial class loader which didn’t have the classpath from the plugin. Changing it to this worked:

class Resources {
    static Set<String> loadData( String pathname ) {
        InputStream lastStream = Resources.getResourceAsStream(pathname)  // this fails when executed inside gradle
       ....
   }
}