I have a Java+Kotlin application, building with Gradle.
Some of its low-level functionality is provided by a separate C++ application.
The two applications communicate via a socket or pipe, using Protocol Buffers and gRPC.
Initially, I'd hoped to build all three (ProtoBuf generated code, Java application, C++ application) in one project, however the cpp-application and java conflict over certain tasks (compile/implementation/test?).
I've since split this into three projects:
/
build.gradle
settings.gradle
cpp-app/
build.gradle
settings.gradle
...
java-app/
build.gradle
settings.gradle
...
protocol/
build.gradle
settings.gradle
build/generated/source/proto/main/java/... <-- Java generated code
build/generated/source/proto/main/cpp/... <-- C++ generated code
...
I have the protocol project successfully generating C++ and Java implementations.
How do I get the C++ and Java application projects to resolve and to use these outputs in their builds?
I solved this while I was writing the question.
The gradle configuration files are shown below. There are a couple redundant blocks which are not needed for this example (or needed at all), however they achieve the objective.
/build.gradle
subprojects {
group = 'com.whatever.your.group'
version = '0.0.0'
repositories {
mavenCentral()
}
}
/settings.gradle
rootProject.name = 'my-project'
include 'java-app'
include 'cpp-app'
include 'protocol'
/java-app/build.gradle
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.20"
}
}
plugins {
// Java
id 'maven'
id 'idea'
id 'application'
id 'java'
id 'org.jetbrains.kotlin.jvm' version '1.3.20'
// ProtoBuf
id 'com.google.protobuf' version '0.8.8'
}
description = """"""
sourceCompatibility = 8
targetCompatibility = 8
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
mainClassName = 'my.main.Class'
dependencies {
protobuf project(':protocol') // <-- name of protobuf project
compile project(':protocol') // <-- name of protobuf project
// We have "protobuf" and "compile", as "compile" brings in transitive dependencies
testCompile 'junit:junit:4.12'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.20"
testImplementation "org.jetbrains.kotlin:kotlin-test:1.3.20"
testImplementation "org.jetbrains.kotlin:kotlin-test-junit:1.3.20"
}
sourceSets {
main {
java {
srcDir "src/main/java"
}
kotlin {
srcDir "src/main/kotlin"
}
}
}
/java-app/settings.gradle
rootProject.name = 'java-app'
/cpp-app/build.gradle
plugins {
id 'maven'
id 'cpp'
}
description = """"""
project.tasks.build.dependsOn 'protocol' // <-- name of protobuf project
model {
components {
main(NativeExecutableSpec) {
...
}
}
...
}
/cpp-app/settings.gradle
rootProject.name = 'cpp-app'
/protocol/build.gradle
plugins {
id 'maven'
id 'java'
id 'com.google.protobuf' version '0.8.8'
}
repositories {
mavenCentral()
}
description = """"""
sourceCompatibility = 8
targetCompatibility = 8
dependencies {
compile 'com.google.protobuf:protobuf-java:3.7.0'
compile 'io.grpc:grpc-stub:1.19.0'
compile 'io.grpc:grpc-protobuf:1.19.0'
}
sourceSets {
main {
proto {
srcDir "src/main/proto"
}
}
}
protobuf {
protoc {
artifact = "com.google.protobuf:protoc:3.7.0"
}
plugins {
grpc_java {
artifact = 'io.grpc:protoc-gen-grpc-java:1.19.0'
}
grpc_cpp {
path = getPluginPath('cpp')
}
grpc_python {
path = getPluginPath('python')
}
}
generateProtoTasks {
generatedFilesBaseDir = "${buildDir}/build/generated/src"
all()*.builtins {
java { }
cpp { }
python { }
}
all()*.plugins {
grpc_java {
outputSubDir = 'java'
}
grpc_cpp {
outputSubDir = 'cpp'
}
grpc_python {
outputSubDir = 'python'
}
}
}
}
clean {
delete protobuf.generatedFilesBaseDir
}
// Used to find executables for generating C++ and Java gRPC
static def getPluginPath(name) {
def path = "which grpc_${name}_plugin".execute()
path.waitFor()
path = path.in.text.trim()
if (!path) {
println "Failed to locate GRPC plugin for ${name}"
} else {
println "Found GRPC plugin for ${name} at ${path}"
}
return path
}
/protocol/settings.gradle
rootProject.name = 'protocol'
Then in the project root, I can run gradle assemble, and:
$ gradle assemble
> Configure project :protocol
Found GRPC plugin for cpp at /usr/bin/grpc_cpp_plugin
Found GRPC plugin for python at /usr/bin/grpc_python_plugin
> Task :cpp-app:linkMainExecutable NO-SOURCE
> Task :cpp-app:mainExecutable UP-TO-DATE
> Task :cpp-app:assemble UP-TO-DATE
> Task :protocol:extractIncludeProto
> Task :protocol:extractProto
> Task :protocol:generateProto
> Task :protocol:compileJava
> Task :protocol:processResources
> Task :protocol:classes
> Task :protocol:jar
> Task :protocol:assemble
> Task :java-app:extractIncludeProto
> Task :java-app:extractProto
> Task :java-app:generateProto
> Task :java-app:compileKotlin
> Task :java-app:compileJava
> Task :java-app:processResources
> Task :java-app:classes
> Task :java-app:inspectClassesForKotlinIC
> Task :java-app:jar
> Task :java-app:startScripts
> Task :java-app:distTar
> Task :java-app:distZip
> Task :java-app:assemble
BUILD SUCCESSFUL in 10s
17 actionable tasks: 17 executed
Related
I am trying to test a Kotlin class in my common library for my Kotlin Multiplatform project in Android Studio.
I have had to reconfigure the build.gradle file several times and managed to fix most of the unresolved references, but Gradle still can't find the reference for the #Test annotation, while the editor recognizes that it is from the kotlin.test library.
Here is my test class:
import kotlin.test.*
import kotlinx.serialization.json.*
import Recipe
class RecipeTest {
#Test
fun serializeTest() {
val keys = arrayOf("Dessert", "Cookies", "Cute")
val ingredients = arrayOf("12 cups sugar", "2 cups flour", "1 bottle warm love")
val instructions = arrayOf("Sift together in bowl", "Cook however else you see fit!")
val recipe = Recipe(
"Macaroons",
"Morgan",
"Today",
"small cookies",
"1 hour",
keys,
"1 dozen macaroons",
"Dessert",
"French",
false,
ingredients,
instructions,
true
)
val jsonString = JSON.stringify(Recipe.serializer(), recipe)
val obj = JSON.parse(Recipe.serializer(), jsonString)
assertEquals(Recipe.toString(), jsonString)
assertEquals(Recipe.toString(), obj.toString())
}
}
And my module build.gradle file:
plugins {
id("com.android.library")
}
apply plugin: 'kotlin-multiplatform'
apply plugin: 'kotlinx-serialization'
android {
compileSdkVersion = 28
buildToolsVersion = '28.0.3'
defaultConfig {
minSdkVersion 21
targetSdkVersion 28
versionCode 1
versionName "1.0"
}
sourceSets {
main {
manifest.srcFile 'src/androidMain/AndroidManifest.xml'
}
}
}
kotlin {
android {
}
iosArm64 {
binaries {
executable()
}
}
iosX64 {
binaries {
executable()
}
}
sourceSets {
commonMain {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib-common'
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.9.1'
}
}
commonTest {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib-common'
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.9.1'
implementation kotlin('test')
implementation kotlin('test-common')
implementation kotlin('test-annotations-common')
}
}
androidMain {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib'
implementation kotlin('test-common')
implementation kotlin('test-annotations-common')
}
}
iosMain {
}
}
}
configurations {
compileClasspath
}
When the test in run from command line, the build fails with an exception, saying
Unresolved reference: test
at the line with the #Test annotation.
EDIT: I changed the accepted answer to the one that appears to be most helpful to others, but I'm leaving my old one just in case.
I had a similar issue and found that I needed to explicitly add the platform specific Kotlin test dependencies:
kotlin {
// ...
sourceSets {
commonTest {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-test-annotations-common"
implementation "org.jetbrains.kotlin:kotlin-test-common"
}
}
jvmTest {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-test-junit"
}
}
jsTest {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-test-js"
}
}
}
}
With only the commonTest dependencies I received the "Unresolved reference: test" error. Once I added the jvmTest and jsTest blocks it fixed the error.
As it turns out, I had some conflicting dependencies in my commonTest source set after all. The 'test' dependency was conflicting with the 'test-common', which led to problems that were buried in some build logs. After deleting the extra dependencies, the build succeeded and the test ran. (and passed!)
sourceSets {
...
commonTest {
dependencies {
//only these are needed
implementation kotlin('test-common')
implementation kotlin('test-annotations-common')
}
}
...
}
I'm trying to follow https://selimober.com/gradle_unit_integration/
Using a slightly different file structure:
src/test/integration/groovy
src/test/unit/groovy
src/test/resources
Running "gradle integration" - the compile runs OK and class files appear in:
build/classes/integration
build/classes/main/
But the tests themselves are never run. I think I'm missing a section in dependencies or a linking of integration to running tests but can't figure out what I'm missing. Unless its that I have to change the file structure and have Test in the taskname like "integrationTest"
I've tried adding:
check.dependsOn integration
and
integrationCompile sourceSets.main.output
integrationCompile configurations.testCompile
integrationCompile sourceSets.test.output
integrationRuntime configurations.testRuntime
and
task integ(type: Test) {
testClassesDir = sourceSets.integ.output.classesDir
classpath = sourceSets.integ.runtimeClasspath
}
But that either hasn't changed anything or given me errors like:
Could not find method integrationCompile() for arguments [main classes] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.
Thanks for any help.
My build.gradle file:
apply plugin: 'groovy'
repositories {
maven {
url repository_url
credentials {
username = artifactory_user
password = artifactory_password
}
}
}
dependencies {
compile(
'com.oracle:ojdbc6:11.2.0.1.0',
'javax.xml.bind:jsr173_api:1.0',
'org.apache.directory:groovy-ldap:1.0',
'org.codehaus.groovy:groovy-all:2.4.5',
'weblogic:wlfullclient:10.3.6',
'javax.jms:jms:1.1'
)
testCompile(
'junit:junit:4.12',
'org.spockframework:spock-core:1.0-groovy-2.4'
)
}
sourceSets {
unit {
groovy {
srcDir file('src/test/unit/groovy')
exclude '**/integration/**'
}
resources {
srcDir file('src/test/resources')
}
compileClasspath += sourceSets.main.output + sourceSets.test.output + configurations.testRuntime
runtimeClasspath += sourceSets.main.output + sourceSets.test.output + configurations.testRuntime
}
integration {
groovy {
srcDir 'src/test/integration/groovy'
exclude '**/unit/**'
}
resources {
srcDir 'src/test/resources'
}
compileClasspath += sourceSets.main.output + sourceSets.test.output + configurations.testRuntime
runtimeClasspath += sourceSets.main.output + sourceSets.test.output + configurations.testRuntime
}
}
configurations {
unitCompile.extendsFrom testCompile
unitRuntime.extendsFrom testRuntime
integrationCompile.extendsFrom testCompile
integrationRuntime.extendsFrom testRuntime
}
task unit(type: Test) {
include '**/unit/**'
testClassesDir = sourceSets.unit.output.classesDir
classpath = sourceSets.unit.runtimeClasspath
}
task integration(type: Test) {
include '**/integration/**'
testClassesDir = sourceSets.integration.output.classesDir
classpath = sourceSets.integration.runtimeClasspath
outputs.upToDateWhen { false }
}
The problem is in your includes in the tasks:
task unit(type: Test) {
include '**/unit/**'
}
task integration(type: Test) {
include '**/integration/**'
}
You don't need that, the folders are defined by the source sets. The includes cause the tests to be limited to classes whose package includes "unit" resp. "integration".
Delete that and your tests should run.
BTW you don't need these excludes neither:
sourceSets {
unit {
groovy {
exclude '**/integration/**'
}
}
}
Put your dependencies after source sets and configurations. Worked for me.
I'm trying to use Gradle to build the google-test example included in the samples folder with the download. On OS X and Linux it compiles correctly, but on Windows I get the error Plugin with id "google-test" not found.
My build.gradle file looks like this:
apply plugin: "cpp"
apply plugin: "google-test"
model {
flavors {
passing
failing
}
platforms {
x86 {
architecture "x86"
}
}
repositories {
libs(PrebuiltLibraries) {
googleTest {
headers.srcDir "libs/googleTest/1.7.0/include"
binaries.withType(StaticLibraryBinary) {
staticLibraryFile =
file("libs/googleTest/1.7.0/lib/" +
findGoogleTestCoreLibForPlatform(targetPlatform))
}
}
}
}
components {
operators(NativeLibrarySpec) {
targetPlatform "x86"
}
}
}
binaries.withType(GoogleTestTestSuiteBinarySpec) {
lib library: "googleTest", linkage: "static"
if (flavor == flavors.failing) {
cppCompiler.define "PLUS_BROKEN"
}
}
tasks.withType(RunTestExecutable) {
args "--gtest_output=xml:test_detail.xml"
}
def findGoogleTestCoreLibForPlatform(Platform platform) {
if (platform.operatingSystem.windows) {
return "vs2013/gtest.lib"
// return "vs2013/gtest-core.lib"
// return "cygwin/gtest-core.lib"
// return "mingw/gtest-core.lib"
} else if (platform.operatingSystem.macOsX) {
return "osx/libgtest.a"
} else {
return "linux/libgtest.a"
}
}
Any ideas on what could cause this?
Check the gradle version that you installed on windows/macosx. I'm not sure but I think the google-test plugin comes with version 2.5 rc
https://docs.gradle.org/release-candidate/release-notes#google-test-support
I have a Gradle project configured with jacoco plugin to report the test code coverage. My unit tests are written in Spock framework.
Though the Jacoco plugin generates the HTML report, it reports the code coverage as 0% on all classes.
I googled a lot and couldn't find what I'm missing. Has anyone got the Spock code coverage working with Gradle + Jacoco?
apply plugin: "jacoco"
apply plugin: "groovy"
sourceSets {
main {
java { srcDirs = ['src/main/java'] }
groovy {srcDirs = ['src/main/groovy'] }
resources { srcDir 'src/main/resources' }
}
test {
java { srcDirs = ['src/test/java'] }
groovy { srcDirs = ['src/test/groovy'] }
resources { srcDir 'src/test/resources' }
}
}
test {
jvmArgs '-Xms64m', '-Xmx2G', '-XX:MaxPermSize=128m'
}
jacocoTestReport {
reports {
xml.enabled false
csv.enabled false
html.destination "${buildDir}/jacocoHtml"
}
}
dependencies {
testCompile "org.spockframework:spock-core:0.7-groovy-2.0"
testCompile "org.spockframework:spock-spring:0.7-groovy-2.0"
}
Suggestion from #PeterNiederwieser worked perfectly. Here is the final result:
apply plugin: "groovy"
apply plugin: "jacoco"
repositories { mavenCentral() }
dependencies {
compile "org.codehaus.groovy:groovy-all:2.2.2"
testCompile "org.spockframework:spock-core:0.7-groovy-2.0"
}
jacocoTestReport {
reports {
xml.enabled false
csv.enabled false
html.destination "${buildDir}/jacocoHtml"
}
}
I want to make test of some clases in my project.
I'm project is all android, but the new clases are pure Java (I'm trying to make a little sdk for the app)
But I don't know how to configure correctly
Gradle file:
apply plugin: 'android'
android {
compileSdkVersion "Google Inc.:Google APIs:19"
buildToolsVersion "19.0.1"
lintOptions{
checkReleaseBuilds false
}
defaultConfig {
minSdkVersion 8
targetSdkVersion 19
versionCode 28
versionName "4.0.5"
}
signingConfigs {
debug {
..........
}
release {
..........
}
}
buildTypes {
debug{
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
debuggable true
buildConfigField "boolean", "LOG_ENABLED", "true"
signingConfig signingConfigs.debug
}
release {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
debuggable false
buildConfigField "boolean", "LOG_ENABLED", "false"
signingConfig signingConfigs.release
}
}
productFlavors{
develFlavor{
}
testFlavor{
..........
}
trainingFlavor{
..........
}
preFlavor{
..........
}
proFlavor{
.........
}
}
}
if (project.hasProperty('storePassword')) {
android.signingConfigs.release.storePassword = storePassword
}
if (project.hasProperty('keyAlias')) {
android.signingConfigs.release.keyAlias = keyAlias
}
if (project.hasProperty('keyPassword')) {
android.signingConfigs.release.keyPassword = keyPassword
}
repositories {
mavenCentral()
}
sourceSets {
test {
java.srcDir file(''src/main/java/es/tempos/gas/sdk/test'')
}
}
dependencies {
unitTestCompile 'junit:junit:4.11'
compile 'com.google.code.gson:gson:1.7.1'
compile 'com.android.support:appcompat-v7:+'
compile files('libs/libGoogleAnalyticsServices.jar')
compile files('libs/sbc_mapslib.jar')
compile files('libs/t21c2dm-lib-v1.0.jar')
}
I want to put the test cases in the folfer Test>SDK
Estructure of the app:
+SmartPhoneGreatApp
----.idea
----app
-----build
-----libs
-----src
-----develFlavor
-----main
----sdk
-----preFlavor
----- .........
........
-----test
------sdk
and the testing class(for the moment do nothing)
package es.tempos21.gas.sdk.test;
import org.junit.Test;
public class AuthenticateTest {
#Test
public void testAuthenticate() throws Exception {
}
}
And the error I'm getting:
Gradle 'SmartPhoneGreatApp' project refresh failed:
Could not find property 'unitTest' on SourceSet container.
Gradle settings
In the Android plugin, sourceSets are configured differently from how the Java plugin does it, so you should read the docs at http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Sourcesets-and-Dependencies
For testing you'll want to do something like this:
android {
sourceSets {
androidTest.setRoot('tests')
}
}
A shortcut would be to do this instead:
android.sourceSets.androidTest.setRoot('tests')
Note that you're supplying a new top-level directory for where the tests go (and the Java classes will be in a directory structure underneath that corresponds to their package path); in your example you're trying to point it at a package already inside src/main/java/path/to/package, which isn't going to work.