John,

Thanks for the clear, detailed explanation.

I'm +1 on what you have proposed.
While I agree with you manually pulling in transitive test dependencies is
not ideal, in this case, I think it's worth it to get over the circular
dependency hurdle and use streams:test-utils ourselves.

-Bill

On Thu, Mar 22, 2018 at 4:09 PM, John Roesler <j...@confluent.io> wrote:

> Hey everyone,
>
> In 1.1, kafka-streams adds an artifact called 'kafka-streams-test-utils'
> (see
> https://kafka.apache.org/11/documentation/streams/
> developer-guide/testing.html
> ).
>
> The basic idea is to provide first-class support for testing Kafka Streams
> applications. Without that, users were forced to either depend on our
> internal test artifacts or develop their own test utilities, neither of
> which is ideal.
>
> I think it would be great if all our APIs offered a similar module, and it
> would all be good if we followed a similar pattern, so I'll describe the
> streams approach along with one challenge we had to overcome:
>
> =====================
> = Project Structure =
> =====================
>
> The directory structure goes:
>
> kafka/streams/             <- main module code here
>              /test-utils/  <- test utilities module here
>              /examples/    <- example usages here
>
> Likewise, the artifacts are:
>
> kafka-streams
> kafka-streams-test-utils
> kafka-streams-examples
>
> And finally, the Gradle build structure is:
>
> :streams
> :streams:test-utils
> :streams:examples
>
>
> =============================
> = Problem 1: circular build =
> =============================
>
> In eat-your-own-dogfood tradition, we wanted to depend on our own
> test-utils in our streams tests, but :streams:test-utils (obviously)
> depends on :streams already.
>
> (:streams) <-- (:streams:test-utils)
>           \--->
>
> Luckily, Filipe Agapito found a way out of the conundrum (
> https://issues.apache.org/jira/browse/KAFKA-6474?
> focusedCommentId=16402326&page=com.atlassian.jira.
> plugin.system.issuetabpanels:comment-tabpanel#comment-16402326).
> Many thanks to him for this contribution.
>
> * Add this to the ':streams' definition:
>     testCompile project(':streams:test-utils').sourceSets.main.output
>
> * And this to the ':streams:test-utils' definition:
>     compile project(':streams').sourceSets.main.output
>
> * And finally (because we also have tests for the examples), add this to
> the ':streams:examples' definition:
>     testCompile project(':streams:test-utils')
>
>
>
> By scoping the dependencies to 'sourceSets.main', we break the cyclic
> dependency:
>
> (:streams main) <-- (:streams:test-utils main)
>       ^            ^           ^
>       |           /            |
>       |          /             |
> (:streams test)     (:streams:test-utils test)
>
>
> ==============================================
> = Problem 2: missing transitive dependencies =
> ==============================================
>
> Scoping the dependency to source-only skips copying transitive library
> dependencies into the build & test environment, so we ran into the
> following error in our tests for ':streams:test-utils' :
>
> java.lang.ClassNotFoundException: org.rocksdb.RocksDBException
>
> This kind of thing is easy to resolve, once you understand why it happens.
> We just added this to the :test-utils build definition:
>     testCompile libs.rocksDBJni
>
> It's a little unfortunate to have to manually pull in transitive
> dependencies for testing, but it's really the only downside of this
> approach (so far).
>
>
>
> That's about it! This is partly to propose a similar model across other
> parts of Kafka's API and partly to collect feedback on this approach.
>
> Thoughts?
> -John
>

Reply via email to