<?xml version="1.0"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>The Flowers Are Still Standing</title>
        <link>http://www.jonathanpearlin.com/</link>
        <atom:link href="http://www.jonathanpearlin.com//feed.xml" rel="self" type="application/rss+xml" />
        <description>Jonathan Pearlin's Blog</description>
        <language>en-us</language>
        <pubDate>Fri, 26 Jun 2026 17:42:06 +0000</pubDate>
        <lastBuildDate>Fri, 26 Jun 2026 17:42:06 +0000</lastBuildDate>
        <image>
            <url>http://www.jonathanpearlin.com//img/robot_devil.png</url>
            <title>Jonathan Pearlin's Blog</title>
            <link>http://www.jonathanpearlin.com/</link>
        </image>
        <item>
            <title>Using Rolling Deployments to Limit Service Disruptions</title>
            <link>http://www.jonathanpearlin.com/2018/04/02/blog_post.html</link>
            <pubDate>Mon, 2 Apr 2018 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">2018/04/02/blog_post.html</guid>
            <description>
                    &lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Please check out my latest &lt;a href=&quot;https://blog.newrelic.com/2018/04/02/rolling-deployments/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;blog post&lt;/a&gt; for &lt;a href=&quot;https://www.newrelic.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;New Relic&lt;/a&gt; where I discuss how we deploy our high throughput, backend microservices. Please give it a read and am interested in your thoughts on the subject!&lt;/p&gt;
&lt;/div&gt;
            </description>
        </item>
        <item>
            <title>A Gradle Plugin That Applies Itself</title>
            <link>http://www.jonathanpearlin.com/2018/03/29/gradle_plugin_include_itself.html</link>
            <pubDate>Thu, 29 Mar 2018 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">2018/03/29/gradle_plugin_include_itself.html</guid>
            <description>
                    &lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The plugin feature of &lt;a href=&quot;https://gradle.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle&lt;/a&gt; makes it very easy to codify functionality for re-use between different projects.  I personally like to use this functionality to provide common build and deploy
functionality to many of my projects.  Recently, I found myself creating a plugin that will generate a &lt;a href=&quot;https://daringfireball.net/projects/markdown/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Markdown&lt;/a&gt; file containing all of the changes committed to &lt;a href=&quot;https://git-scm.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Git&lt;/a&gt;, organized by release.
When I finished creating the plugin, I realized that I also wanted to use the plugin in the plugin project itself so that I could keep a log of changes to the plugin (so meta!).  However, releasing the plugin and including it as a dependency so it could be applied to itself seemed like a bad idea:  it would forever be one release behind, assuming that I remembered to update the
dependency version each time.  That obviously is not a very maintainable solution.  The answer?  Apply the plugin to itself programmatically by taking advantage of some &lt;a href=&quot;http://groovy-lang.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Groovy&lt;/a&gt; magic:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;// Apply the changelog plugin to itself!
def classpath = [file(&apos;src/main/groovy&apos;).absolutePath, file(&apos;src/main/resources&apos;).absolutePath] as String[]
def pluginDescriptor = new Properties()
pluginDescriptor.load(new InputStreamReader(new FileInputStream(file(&apos;src/main/resources/META-INF/gradle-plugins/changelog.properties&apos;).absolutePath)))
apply plugin: new GroovyScriptEngine(classpath, this.getClass().getClassLoader()).loadScriptByName(&quot;${pluginDescriptor.getProperty(&apos;implementation-class&apos;).replaceAll(&apos;\\.&apos;, &apos;/&apos;)}.groovy&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So, what is this code snippet doing exactly?  The first line ensures that the source folders of the plugin project are part of the classpath that will be used to find and load the plugin.  The
second line simply creates a new Java &lt;code&gt;Properties&lt;/code&gt; object, which will be used to hold the plugin&amp;#8217;s descriptor file.  The third line loads the &lt;a href=&quot;https://gradle.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle&lt;/a&gt; plugin descriptor file so that we can determine the main class of the plugin.  Finally, the last line uses the &lt;a href=&quot;http://groovy-lang.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Groovy&lt;/a&gt; &lt;code&gt;GroovyScriptEngine&lt;/code&gt; class to load the class referenced the plugin descriptor so that it can be applied by &lt;a href=&quot;https://gradle.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle&lt;/a&gt; as a plugin.  After placing this code in the plugin&amp;#8217;s &lt;code&gt;build.gradle&lt;/code&gt; file, we are now assured that the latest source in the plugin is applied to the plugin itself so that it can be used to generate the changelog for that project.&lt;/p&gt;
&lt;/div&gt;
            </description>
        </item>
        <item>
            <title>Choosing an Application Framework for Microservices</title>
            <link>http://www.jonathanpearlin.com/2017/08/08/blog_post.html</link>
            <pubDate>Tue, 8 Aug 2017 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">2017/08/08/blog_post.html</guid>
            <description>
                    &lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Earlier this year, I authored a &lt;a href=&quot;https://blog.newrelic.com/2017/05/18/alerts-microservices-environment-spring-boot/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;blog post&lt;/a&gt; for &lt;a href=&quot;https://www.newrelic.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;New Relic&lt;/a&gt; where I discussed how my team decided to use &lt;a href=&quot;https://projects.spring.io/spring-boot/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Spring Boot&lt;/a&gt; to build microservices.  Recently, the post has been picked up by a bunch of other outlets and has been making the rounds on the interwebs.  Please give it a read and am interested in your thoughts on the subject!&lt;/p&gt;
&lt;/div&gt;
            </description>
        </item>
        <item>
            <title>The Peculiar Case of the Kafka ConsumerIterator</title>
            <link>http://www.jonathanpearlin.com/2016/12/20/kafka_iterator.html</link>
            <pubDate>Tue, 20 Dec 2016 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">2016/12/20/kafka_iterator.html</guid>
            <description>
                    &lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;em&gt;This post is written using &lt;a href=&quot;https://kafka.apache.org/082/documentation.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Apache Kafka 0.8.2&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Creating a &lt;a href=&quot;https://kafka.apache.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Apache Kafka&lt;/a&gt; client is a pretty straight-forward and prescriptive endeavor.  What is not straight-forward or even expected is the behavior of the &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Iterator&lt;/a&gt; that is
used to poll a &lt;a href=&quot;https://kafka.apache.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Apache Kafka&lt;/a&gt; topic/partition for messages.  More on this in a moment.  First, let&amp;#8217;s look at the typical setup to consume data from a &lt;a href=&quot;https://kafka.apache.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Apache Kafka&lt;/a&gt; stream
(for the sake of keeping this post brief, I am going to skip the details around creating and configuring a &lt;a href=&quot;https://github.com/apache/kafka/blob/0.8.2/core/src/main/scala/kafka/consumer/ConsumerConnector.scala&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ConsumerConnector&lt;/a&gt;):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;final Map&amp;lt;String, List&amp;lt;KafkaStream&amp;lt;byte[], byte[]&amp;gt;&amp;gt;&amp;gt; consumerMap =
    consumerConnector.createMessageStreams(Collections.singletonMap(&quot;topic&quot;,1));
final List&amp;lt;KafkaStream&amp;lt;byte[], byte[]&amp;gt;&amp;gt; streams = consumerMap.get(&quot;topic&quot;);
final ConsumerIterator&amp;lt;byte[],byte[]&amp;gt; = streams.get(0).iterator();‍‍‍‍‍‍‍‍&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With the &lt;a href=&quot;https://github.com/apache/kafka/blob/0.8.2/core/src/main/scala/kafka/consumer/ConsumerIterator.scala&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ConsumerIterator&lt;/a&gt; in hand, the next step is to poll the &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Iterator&lt;/a&gt; for incoming messages:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;while(iterator.hasNext()) {
    MessageAndMetadata&amp;lt;byte[], byte[]&amp;gt; message = iterator.next();
    ...
}‍‍‍‍&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;‍
‍This all seems pretty simple.  Now, back to the issue with this code:  the expectation is that this would check the &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Iterator&lt;/a&gt; for a message and if not present loop immediately and check
again (standard &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Iterator&lt;/a&gt; behavior).  However, this is not the case.  The behavior of the &lt;a href=&quot;https://github.com/apache/kafka/blob/0.8.2/core/src/main/scala/kafka/consumer/ConsumerIterator.scala&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ConsumerIterator&lt;/a&gt; is actually controlled by the &lt;a href=&quot;https://kafka.apache.org/082/documentation.html#consumerconfigs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;consumer.timeout.ms&lt;/a&gt; configuration setting.  This
setting controls whether or not the &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Iterator&lt;/a&gt; &amp;#8220;throw(s) a timeout exception to the consumer if no message is available for consumption after the specified interval&amp;#8221;.  By default, this
value is set to -1, which means that the call to &lt;code&gt;hasNext()&lt;/code&gt; will block indefinitely until a message is available on the topic/partition assigned to the consumer.  The &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Java documentation&lt;/a&gt;
for the &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Iterator&lt;/a&gt; interface does not specify whether or not the &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html#hasNext--&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;hasNext()&lt;/a&gt; method is allowed to block indefinitely, so its hard to say that the &lt;a href=&quot;https://github.com/apache/kafka/blob/0.8.2/core/src/main/scala/kafka/consumer/ConsumerIterator.scala&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ConsumerIterator&lt;/a&gt; is violating the contract.
However, this is certainly not the behavior anyone use to using the &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Iterator&lt;/a&gt; pattern in Java would expect, as collections typically don&amp;#8217;t block until data is available in the data structure.
If the &lt;a href=&quot;https://kafka.apache.org/082/documentation.html#consumerconfigs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;consumer.timeout.ms&lt;/a&gt; configuration setting is set to a positive value, the consumption code would need to be modified to handle a &lt;a href=&quot;https://github.com/apache/kafka/blob/0.8.2/core/src/main/scala/kafka/consumer/ConsumerIterator.scala#L114&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ConsumerTimeoutException&lt;/a&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;while(active) {
    try {
        if(iterator.hasNext()) {
            MessageAndMetadata&amp;lt;byte[],byte[]&amp;gt; message = iterator.next();
            ...
        }
    } catch(ConsumerTimeoutException e) {
        // Do nothing -- this means no data is available on the topic/partition
    }
}‍‍‍‍‍‍‍‍‍‍&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;‍
Now, the call to &lt;code&gt;hasNext()&lt;/code&gt; will behave more like an &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Iterator&lt;/a&gt; retrieved from a collection, which is to say it will not block indefinitely.  It is recommended that you do some testing to determine
an acceptable timeout value to avoid looping too frequently, as this will cause an increase in CPU utilization by the loop.  It is also worth noting that the &lt;a href=&quot;https://kafka.apache.org/082/documentation.html#consumerconfigs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Kafka documentation&lt;/a&gt; does not directly
link the configuration setting and the &lt;a href=&quot;https://github.com/apache/kafka/blob/0.8.2/core/src/main/scala/kafka/consumer/ConsumerIterator.scala&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ConsumerIterator&lt;/a&gt; and this issue would most likely go unnoticed in scenarios where data is consistently available to the client.  In any case, this issue
highlights the need to take a deeper look at any API or library you include in your application in order to ensure that you understand exactly how it works and what performance impacts it may have
on the execution of your code.&lt;/p&gt;
&lt;/div&gt;
            </description>
        </item>
        <item>
            <title>Testing a custom Gradle plugin with Gradle Test Kit</title>
            <link>http://www.jonathanpearlin.com/2016/03/29/gradle_test_kit.html</link>
            <pubDate>Tue, 29 Mar 2016 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">2016/03/29/gradle_test_kit.html</guid>
            <description>
                    &lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With the release of &lt;a href=&quot;https://gradle.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle&lt;/a&gt; 2.10, the &lt;a href=&quot;https://docs.gradle.org/current/userguide/test_kit.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle Test Kit&lt;/a&gt; was included as an &quot;incubating&quot; feature to &quot;[aid] in testing  Gradle plugins and build logic generally.&quot;  Prior
to the creation of the &lt;a href=&quot;https://docs.gradle.org/current/userguide/test_kit.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle Test Kit&lt;/a&gt;, it had been fairly cumbersome to test custom &lt;a href=&quot;https://gradle.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle&lt;/a&gt; plugins.  Tests often involved using the &lt;a href=&quot;https://docs.gradle.org/current/javadoc/org/gradle/testfixtures/ProjectBuilder.html&quot;&gt;ProductBuilder&lt;/a&gt;
to create a dummy instance of a &lt;code&gt;Project&lt;/code&gt; and retrieving a declared &lt;code&gt;Task&lt;/code&gt; and executing it manually.  While this would test the task logic directly, it did not test the execution of the task as part of a
normal &lt;a href=&quot;https://gradle.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle&lt;/a&gt; execution.  Furthermore, it would not exercise task-based caching, making it hard to verify that any configured inputs/outputs are being honored.  This is where the &lt;a href=&quot;https://docs.gradle.org/current/userguide/test_kit.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle Test Kit&lt;/a&gt; can help.
It is focused on functional testing, which means that it emulates what a user will see when attempting to run tasks via the command line or &lt;a href=&quot;https://gradle.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle&lt;/a&gt; wrapper.  Being an &quot;incubating&quot; feature, however, some of
the documentation is lacking, especially when it comes to testing a custom &lt;a href=&quot;https://gradle.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle&lt;/a&gt; plugin within the project that contains the plugin definition and source.  In this post, we will explore how to set up
your custom plugin&amp;#8217;s project to use the &lt;a href=&quot;https://docs.gradle.org/current/userguide/test_kit.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle Test Kit&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_using_the_gradle_test_kit&quot;&gt;Using the Gradle Test Kit&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The first step is to include the &lt;a href=&quot;https://docs.gradle.org/current/userguide/test_kit.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle Test Kit&lt;/a&gt; as a &lt;code&gt;test&lt;/code&gt; scoped dependency in your project&amp;#8217;s &lt;code&gt;build.gradle&lt;/code&gt; file:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;dependencies {
  ...

  testCompile gradleTestKit()
  testCompile &apos;org.spockframework:spock-core:1.0-groovy-2.4&apos;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This will pull in the &lt;a href=&quot;https://docs.gradle.org/current/userguide/test_kit.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle Test Kit&lt;/a&gt; libraries for use during the &lt;code&gt;test&lt;/code&gt; phase of your project.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_creating_the_plugin_classpath&quot;&gt;Creating the Plugin Classpath&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The next step, which is hard to determine from the documentation, is to make sure that custom plugin and its descriptor are on the classpath path when using the &lt;a href=&quot;https://docs.gradle.org/current/userguide/test_kit.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle Test Kit&lt;/a&gt;.  In its current form,
there is no easy way to pass/build this classpath as part of a &lt;a href=&quot;https://github.com/spockframework/spock&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Spock Framework&lt;/a&gt; test at runtime.  The trick is to follow what is outlined in section 43.2.1 of the &lt;a href=&quot;https://docs.gradle.org/current/userguide/test_kit.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle Test Kit&lt;/a&gt; documentation, which outlines
how to create a text file containing the classpath to be used by the &lt;a href=&quot;https://docs.gradle.org/current/userguide/test_kit.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle Test Kit&lt;/a&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;task createPluginClasspath {
    def outputDir = file(&quot;${buildDir}/resources/test&quot;)

    inputs.files sourceSets.test.runtimeClasspath
    outputs.dir outputDir

    doLast {
        outputDir.mkdirs()
        file(&quot;${outputDir}/plugin-classpath.txt&quot;).text = sourceSets.test.runtimeClasspath.join(&apos;\n&apos;,)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the example above, we use the &lt;code&gt;runtime&lt;/code&gt; classpath of the &lt;code&gt;test&lt;/code&gt; configuration to generate the classpath list to be passed to the &lt;a href=&quot;https://docs.gradle.org/current/userguide/test_kit.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle Test Kit&lt;/a&gt; runner.  The example in the &lt;a href=&quot;https://docs.gradle.org/current/userguide/test_kit.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle Test Kit&lt;/a&gt; documentation
uses the &lt;code&gt;main&lt;/code&gt; configuration, which is fine if you don&amp;#8217;t need to provide any additional libraries for testing.  In my case, I needed to have some other custom plugins available for the functional test, but
did not want those dependencies to be on my main &lt;code&gt;compile&lt;/code&gt; or &lt;code&gt;runtime&lt;/code&gt; classpath.  If you don&amp;#8217;t want to have to manually call this task each time you test your project, you can add the following your
&lt;code&gt;build.gradle&lt;/code&gt; script to tie its execution to the &lt;code&gt;test&lt;/code&gt; task:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;test.dependsOn([&apos;createPluginClasspath&apos;])&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now that we have a task to generate the plugin classpath text file, we need to use it as part of our test.  In the example below, the contents of the &lt;code&gt;plugin-classpath.txt&lt;/code&gt; file read, collected,
converted into &lt;code&gt;File&lt;/code&gt; objects and stored into a list:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;class MyPluginFunctionalSpec extends Specification {

    @Rule
    TemporaryFolder testProjectDir = new TemporaryFolder()

    File buildFile

    File propertiesFile

    List pluginClasspath

    def setup() {
        buildFile = testProjectDir.newFile(&apos;build.gradle&apos;)
        propertiesFile = testProjectDir.newFile(&apos;gradle.properties&apos;)
        pluginClasspath = getClass().classLoader.findResource(&apos;plugin-classpath.txt&apos;).readLines().collect { new File(it) }
    }

    ...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The &lt;code&gt;pluginClasspath&lt;/code&gt; list will be passed to the &lt;a href=&quot;https://docs.gradle.org/current/userguide/test_kit.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle Test Kit&lt;/a&gt; runner via the &lt;code&gt;withPluginClasspath&lt;/code&gt; method of the builder, which we will see in a bit.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_building_the_functional_test&quot;&gt;Building the Functional Test&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now that we have our classpath sorted out, the next step is to build test(s) to execute your custom plugin and task(s):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;def &quot;test that when the custom plugin is applied to a project and the customTask is executed, the customTask completes successfully&quot;() {
    setup:
        buildFile &amp;lt;&amp;lt; &apos;&apos;&apos;
            plugins {
                id &apos;my-custom-plugin
            }

            dependencies {
                compile &apos;com.google.guava:guava:19.0&apos;
                compile &apos;joda-time:joda-time:2.9.2&apos;
                compile &apos;org.slf4j:slf4j-api:1.7.13&apos;

                runtime &apos;org.slf4j:log4j-over-slf4j:1.7.13&apos;

                testCompile &apos;org.spockframework:spock-core:1.0-groovy-2.4&apos;
            }

            repositories {
                mavenLocal()
                mavenCentral()
            }
        &apos;&apos;&apos;
    when:
        GradleRunner runner = GradleRunner.create()
            .withProjectDir(testProjectDir.getRoot())
            .withArguments(&apos;customTask&apos;, &apos;--stacktrace&apos;, &apos;--refresh-dependencies&apos;)
            .withPluginClasspath(pluginClasspath)
        BuildResult result =  runner.build()
    then:
        result.task(&apos;:customTask&apos;).getOutcome() == TaskOutcome.SUCCESS
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the example above, notice that we build a full build script, which includes the application of our custom &lt;a href=&quot;https://gradle.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle&lt;/a&gt; plugin, and output it to &lt;code&gt;buildFile&lt;/code&gt; created in the setup seen
previously.  This can be anything that you would do in a project&amp;#8217;s &lt;code&gt;build.gradle&lt;/code&gt; file.  You could even store these files in &lt;code&gt;src/test/resources&lt;/code&gt; and load and copy the contents of
these files from the classpath and write it out to the file to be provided to the &lt;a href=&quot;https://docs.gradle.org/current/userguide/test_kit.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle Test Kit&lt;/a&gt; runner.  In the &lt;code&gt;when&lt;/code&gt; block, we see the &lt;a href=&quot;https://docs.gradle.org/current/userguide/test_kit.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle Test Kit&lt;/a&gt; in action.  Here, we set
the project directory to the &lt;code&gt;TemporaryFolder&lt;/code&gt; that will contain the &lt;code&gt;build.gradle&lt;/code&gt; file, the arguments to be passed to &lt;a href=&quot;https://gradle.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle&lt;/a&gt; (e.g. the task(s) and switches), and the plugin
classpath we generated in the setup.  Without the plugin classpath, you will see errors related to &lt;a href=&quot;https://gradle.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle&lt;/a&gt; being unable to locate any plugins that match your custom plugin&amp;#8217;s
ID.  Finally, in the &lt;code&gt;then&lt;/code&gt; block, we see that we test to make sure the status of the task execution is the one we expected.  You can also inspect the output of the build by
inspecting the &lt;code&gt;output&lt;/code&gt; field of the &lt;code&gt;BuildResult&lt;/code&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;result.output.contains(&apos;some text&apos;) == true&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is also useful for debugging, as you can print out the contents of the result output to see the full output of the &lt;a href=&quot;https://gradle.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle&lt;/a&gt; execution.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_test_failures_and_xerces&quot;&gt;Test Failures and Xerces&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Depending on what is on your plugin classpath, you may have tests fail due to issues related to the Xerces library.  This is often due to multiple versions of Xerces being present
on the classpath when the runner is executed and can be remedied by excluding Xerces from the generated classpath:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;pluginClasspath = getClass().classLoader.findResource(&apos;plugin-classpath.txt&apos;).readLines().collect { new File(it) }.findAll { !it.name.contains(&apos;xercesImpl&apos;) }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Notice that we added a step to find all the classpath entries that do not contain the string &lt;code&gt;xercesImpl&lt;/code&gt; to ensure that we do not end up with duplicate Xerces
implementations on the classpath provided to the test kit runner.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_summary&quot;&gt;Summary&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The &lt;a href=&quot;https://docs.gradle.org/current/userguide/test_kit.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle Test Kit&lt;/a&gt; provides an excellent way to functionally test your custom &lt;a href=&quot;https://gradle.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle&lt;/a&gt; plugins.  Because it uses actual build scripts, it is easy to build up a library of configurations
that you want to continually test as changes are made to the custom plugin.  Furthermore, the &lt;a href=&quot;https://docs.gradle.org/current/userguide/test_kit.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle Test Kit&lt;/a&gt; drastically reduces the amount of test code that you need to write,
allowing you to more efficiently test your plugin.  All of these are great reasons to convert your plugin tests to use the &lt;a href=&quot;https://docs.gradle.org/current/userguide/test_kit.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gradle Test Kit&lt;/a&gt; or to write tests for the first time
if you don&amp;#8217;t currently have test coverage for your code.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
            </description>
        </item>
    </channel>
</rss>
