From 8f26cfceb2d800ba83636d15e907c53456f53afc Mon Sep 17 00:00:00 2001 From: Carl-Gustaf Harroch Date: Thu, 22 Sep 2011 13:35:30 +0100 Subject: [PATCH 1/5] started working on integration test logic --- build.sbt | 2 +- project/plugins/build.sbt | 2 +- src/main/scala/AndroidInstall.scala | 2 + src/main/scala/AndroidTest.scala | 78 +++++++++++++++++++++++++---- 4 files changed, 71 insertions(+), 13 deletions(-) diff --git a/build.sbt b/build.sbt index bb2763f..9afe4a0 100644 --- a/build.sbt +++ b/build.sbt @@ -2,7 +2,7 @@ organization := "org.scala-tools.sbt" name := "sbt-android-plugin" -version := "0.6.0-SNAPSHOT" +version := "0.6.1-SNAPSHOT" scalacOptions += "-deprecation" diff --git a/project/plugins/build.sbt b/project/plugins/build.sbt index 7703cdd..ce69736 100644 --- a/project/plugins/build.sbt +++ b/project/plugins/build.sbt @@ -1 +1 @@ -libraryDependencies += "com.tristanhunt" %% "knockoff" % "0.8.0-16" +//libraryDependencies += "com.tristanhunt" %% "knockoff" % "0.8.0-16" diff --git a/src/main/scala/AndroidInstall.scala b/src/main/scala/AndroidInstall.scala index a0b8a1e..1c22a5e 100644 --- a/src/main/scala/AndroidInstall.scala +++ b/src/main/scala/AndroidInstall.scala @@ -80,6 +80,8 @@ object AndroidInstall { "-keep public class * extends android.content.ContentProvider" :: "-keep public class * extends android.view.View" :: "-keep public class * extends android.app.Application" :: + "-keep public class * extends android.app.Instrumentation" :: + "-keep public class * extends android.test.InstrumentationTestRunner" :: "-keep public class "+manifestPackage+".** { public protected *; }" :: "-keep public class * implements junit.framework.Test { public void test*(); }" :: proguardOption :: Nil diff --git a/src/main/scala/AndroidTest.scala b/src/main/scala/AndroidTest.scala index b6f8565..6ae8288 100644 --- a/src/main/scala/AndroidTest.scala +++ b/src/main/scala/AndroidTest.scala @@ -1,30 +1,86 @@ import sbt._ import Keys._ - import AndroidKeys._ import AndroidHelpers._ object AndroidTest { def instrumentationTestAction(emulator: Boolean) = (dbPath, manifestPackage) map { (dbPath, manifestPackage) => - val action = "shell am instrument -w "+ manifestPackage + - "/android.test.InstrumentationTestRunner" + val action = "shell am instrument -w " + manifestPackage + + "/android.test.InstrumentationTestRunner" adbTask(dbPath.absolutePath, emulator, action) - } + } - /** AndroidTestProject */ - lazy val androidSettings = settings ++ Seq ( + /**AndroidTestProject */ + lazy val androidSettings = settings ++ Seq( proguardInJars in Android := Nil ) lazy val settings: Seq[Setting[_]] = AndroidBase.settings ++ - AndroidInstall.settings ++ - inConfig(Android) (Seq ( - testEmulator <<= instrumentationTestAction(true), - testDevice <<= instrumentationTestAction(false) - )) ++ Seq ( + AndroidInstall.settings ++ + inConfig(Android)(Seq( + testEmulator <<= instrumentationTestAction(true), + testDevice <<= instrumentationTestAction(false) + )) ++ Seq( testEmulator <<= (testEmulator in Android).identity, testDevice <<= (testDevice in Android).identity ) + + lazy val Instrumentation = config("inst") extend (Android) + + val tasks: Seq[Setting[_]] = Seq( + helloTask + ) + + lazy val instSettings: Seq[Setting[_]] = + inConfig(Instrumentation)(Defaults.defaultSettings ++ Defaults.testSettings ++ AndroidBase.settings ++ AndroidProject.androidSettings ++ + Seq( + manifestName <<= (manifestName in Android).identity, + resDirectoryName <<= (resDirectoryName in Android).identity, + assetsDirectoryName <<= (assetsDirectoryName in Android).identity, + name <<= (name)("%s-test" format _), + dbPath <<= (dbPath in Android).identity, + manifestPath <<= (sourceDirectory, manifestName)(_ / _), + mainAssetsPath <<= (sourceDirectory, assetsDirectoryName)(_ / _), + mainResPath <<= (sourceDirectory, resDirectoryName)(_ / _), + uninstallEmulator <<= (uninstallEmulator in Android).identity, + packageDebug <<= (packageDebug in Android).identity, + uninstallDevice <<= (uninstallDevice in Android).identity, + + packageConfig <<= + (toolsPath in Android, packageApkPath in Instrumentation, resourcesApkPath in Instrumentation, classesDexPath in Instrumentation, + nativeLibrariesPath in Instrumentation, classesMinJarPath in Instrumentation, resourceDirectory in Instrumentation) + (ApkConfig(_, _, _, _, _, _, _)) + )) ++ inConfig(Android)(Seq(hello := helloTask)) + // + // makeAssetPath <<= directory(mainAssetsPath), + // + // aaptPackage <<= aaptPackageTask, + // aaptPackage <<= aaptPackage dependsOn (makeAssetPath, dx), + // dx <<= dxTask, + // dx <<= dx dependsOn proguard, + // + // cleanApk <<= (packageApkPath) map (IO.delete(_)), + // + // proguard <<= proguardTask, + // proguard <<= proguard dependsOn (compile in Compile), + // + // packageConfig <<= + // (toolsPath, packageApkPath, resourcesApkPath, classesDexPath, + // nativeLibrariesPath, classesMinJarPath, resourceDirectory) + // (ApkConfig(_, _, _, _, _, _, _)), + // + // packageDebug <<= packageTask(true), + // packageRelease <<= packageTask(false) + // ) ++ Seq(packageDebug, packageRelease).map { + // t => t <<= t dependsOn (cleanApk, aaptPackage) + // }) + + val hello = TaskKey[Unit]("hello", "Prints 'Hello World'") + + val helloTask = hello := { + println("Hello World") + } + } From f206d1ddfd59f106b229fdec64e4950e80a10850 Mon Sep 17 00:00:00 2001 From: Carl Harroch Date: Sun, 12 Feb 2012 14:36:48 +0000 Subject: [PATCH 2/5] inst info --- build.sbt | 2 +- src/main/scala/AndroidDefault.scala | 3 +++ src/main/scala/AndroidKeys.scala | 1 + src/main/scala/AndroidTest.scala | 31 ++++++++++++++++------------- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/build.sbt b/build.sbt index 294acc2..ec5ffb5 100644 --- a/build.sbt +++ b/build.sbt @@ -2,7 +2,7 @@ name := "sbt-android-plugin" organization := "org.scala-tools.sbt" -version := "0.6.1-SNAPSHOT" +version := "0.6.3-SNAPSHOT" scalacOptions += "-deprecation" diff --git a/src/main/scala/AndroidDefault.scala b/src/main/scala/AndroidDefault.scala index 5f2169e..0acc9d3 100644 --- a/src/main/scala/AndroidDefault.scala +++ b/src/main/scala/AndroidDefault.scala @@ -18,6 +18,7 @@ object AndroidDefaults { val DefaultDxJavaOpts = "-JXmx512m" val DefaultManifestSchema = "http://schemas.android.com/apk/res/android" val DefaultEnvs = List("ANDROID_SDK_HOME", "ANDROID_SDK_ROOT", "ANDROID_HOME") + val DefaultInstrumentationRunner = "android.test.InstrumentationTestRunner" lazy val settings: Seq[Setting[_]] = Seq ( aaptName := DefaultAaaptName, @@ -34,6 +35,8 @@ object AndroidDefaults { dxJavaOpts := DefaultDxJavaOpts, manifestSchema := DefaultManifestSchema, envs := DefaultEnvs, + instrumentationRunner := DefaultInstrumentationRunner, + // a list of modules which are already included in Android preinstalledModules := Seq[ModuleID]( ModuleID("org.apache.httpcomponents", "httpcore", null), diff --git a/src/main/scala/AndroidKeys.scala b/src/main/scala/AndroidKeys.scala index 98c3387..6123d04 100644 --- a/src/main/scala/AndroidKeys.scala +++ b/src/main/scala/AndroidKeys.scala @@ -174,6 +174,7 @@ object AndroidKeys { /** Test Project Tasks */ val testEmulator = TaskKey[Unit]("test-emulator", "runs tests in emulator") val testDevice = TaskKey[Unit]("test-device", "runs tests on device") + val instrumentationRunner = SettingKey[String] ("test-runner", "instrumentation test runner e.g. android.test.InstrumentationTestRunner") /** Github tasks & keys */ val uploadGithub = TaskKey[Option[String]]("github-upload", "Upload file to github") diff --git a/src/main/scala/AndroidTest.scala b/src/main/scala/AndroidTest.scala index fe416da..e35856b 100644 --- a/src/main/scala/AndroidTest.scala +++ b/src/main/scala/AndroidTest.scala @@ -5,30 +5,33 @@ import AndroidKeys._ import AndroidHelpers._ object AndroidTest { - def instrumentationTestAction(emulator: Boolean) = (dbPath, manifestPackage, streams) map { - (dbPath, manifestPackage, s) => + + def instrumentationTestAction(emulator: Boolean) = (dbPath, manifestPackage, instrumentationRunner , streams) map { + (dbPath, manifestPackage, inst, s) => val action = Seq("shell", "am", "instrument", "-w", - manifestPackage+"/android.test.InstrumentationTestRunner") - adbTask(dbPath.absolutePath, emulator, s, action:_*) - } + manifestPackage + "/" + inst) + adbTask(dbPath.absolutePath, emulator, s, action: _*) + } + - /** AndroidTestProject */ + /**AndroidTestProject */ lazy val androidSettings = settings ++ - inConfig(Android)( Seq( + inConfig(Android)(Seq( proguardInJars <<= (scalaInstance) map { (scalaInstance) => - Seq(scalaInstance.libraryJar) + Seq(scalaInstance.libraryJar) } ) - ) + ) + lazy val settings: Seq[Setting[_]] = AndroidBase.settings ++ - AndroidInstall.settings ++ - inConfig(Android) (Seq ( - testEmulator <<= instrumentationTestAction(true), - testDevice <<= instrumentationTestAction(false) - )) ++ Seq ( + AndroidInstall.settings ++ + inConfig(Android)(Seq( + testEmulator <<= instrumentationTestAction(true), + testDevice <<= instrumentationTestAction(false) + )) ++ Seq( testEmulator <<= (testEmulator in Android), testDevice <<= (testDevice in Android) ) From 8e0d43d5fa3c8b0684890e790f8981038ada9de6 Mon Sep 17 00:00:00 2001 From: Carl-Gustaf Harroch Date: Sun, 12 Feb 2012 23:14:34 +0000 Subject: [PATCH 3/5] adding per project instrumentation logic --- src/main/scala/AndroidDefault.scala | 2 -- src/main/scala/AndroidKeys.scala | 2 +- src/main/scala/AndroidTest.scala | 5 ++++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/scala/AndroidDefault.scala b/src/main/scala/AndroidDefault.scala index 0acc9d3..4467644 100644 --- a/src/main/scala/AndroidDefault.scala +++ b/src/main/scala/AndroidDefault.scala @@ -18,7 +18,6 @@ object AndroidDefaults { val DefaultDxJavaOpts = "-JXmx512m" val DefaultManifestSchema = "http://schemas.android.com/apk/res/android" val DefaultEnvs = List("ANDROID_SDK_HOME", "ANDROID_SDK_ROOT", "ANDROID_HOME") - val DefaultInstrumentationRunner = "android.test.InstrumentationTestRunner" lazy val settings: Seq[Setting[_]] = Seq ( aaptName := DefaultAaaptName, @@ -35,7 +34,6 @@ object AndroidDefaults { dxJavaOpts := DefaultDxJavaOpts, manifestSchema := DefaultManifestSchema, envs := DefaultEnvs, - instrumentationRunner := DefaultInstrumentationRunner, // a list of modules which are already included in Android preinstalledModules := Seq[ModuleID]( diff --git a/src/main/scala/AndroidKeys.scala b/src/main/scala/AndroidKeys.scala index 6123d04..b2189b5 100644 --- a/src/main/scala/AndroidKeys.scala +++ b/src/main/scala/AndroidKeys.scala @@ -174,7 +174,7 @@ object AndroidKeys { /** Test Project Tasks */ val testEmulator = TaskKey[Unit]("test-emulator", "runs tests in emulator") val testDevice = TaskKey[Unit]("test-device", "runs tests on device") - val instrumentationRunner = SettingKey[String] ("test-runner", "instrumentation test runner e.g. android.test.InstrumentationTestRunner") + val instrumentationRunner = SettingKey[String] ("instrumentation-runner", "instrumentation test runner e.g. android.test.InstrumentationTestRunner") /** Github tasks & keys */ val uploadGithub = TaskKey[Option[String]]("github-upload", "Upload file to github") diff --git a/src/main/scala/AndroidTest.scala b/src/main/scala/AndroidTest.scala index e35856b..62cf354 100644 --- a/src/main/scala/AndroidTest.scala +++ b/src/main/scala/AndroidTest.scala @@ -6,7 +6,9 @@ import AndroidHelpers._ object AndroidTest { - def instrumentationTestAction(emulator: Boolean) = (dbPath, manifestPackage, instrumentationRunner , streams) map { + val DefaultInstrumentationRunner = "android.test.InstrumentationTestRunner" + + def instrumentationTestAction(emulator: Boolean) = (dbPath, manifestPackage, instrumentationRunner, streams) map { (dbPath, manifestPackage, inst, s) => val action = Seq("shell", "am", "instrument", "-w", manifestPackage + "/" + inst) @@ -29,6 +31,7 @@ object AndroidTest { AndroidBase.settings ++ AndroidInstall.settings ++ inConfig(Android)(Seq( + instrumentationRunner := DefaultInstrumentationRunner, testEmulator <<= instrumentationTestAction(true), testDevice <<= instrumentationTestAction(false) )) ++ Seq( From 9713f1d81029ba9a71e2d2e5c418a58ce49970de Mon Sep 17 00:00:00 2001 From: Carl-Gustaf Harroch Date: Tue, 17 Apr 2012 09:16:28 +0100 Subject: [PATCH 4/5] added single instrumentation specific instrumentation runner --- src/main/scala/AndroidTest.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/AndroidTest.scala b/src/main/scala/AndroidTest.scala index c3e2781..c63cded 100644 --- a/src/main/scala/AndroidTest.scala +++ b/src/main/scala/AndroidTest.scala @@ -19,8 +19,9 @@ object AndroidTest { adbTask(dbPath.absolutePath, emulator, s, action: _*) } - def runSingleTest(emulator: Boolean) = (test: TaskKey[String]) => (test, dbPath, manifestPackage, streams) map { (test, dbPath, manifestPackage, s) => - val action = Seq("shell", "am", "instrument", "-w", "-e", "class", test, manifestPackage+"/android.test.InstrumentationTestRunner") + def runSingleTest(emulator: Boolean) = (test: TaskKey[String]) => (test, dbPath, manifestPackage, instrumentationRunner, streams) map { + (test, dbPath, manifestPackage, inst, s) => + val action = Seq("shell", "am", "instrument", "-w", "-e", "class", test, manifestPackage+"/" + inst) adbTask(dbPath.absolutePath, emulator, s, action:_*) } From 5dcd6ab0cd1344611836f40cb4d5a049632c428e Mon Sep 17 00:00:00 2001 From: Carl-Gustaf Harroch Date: Tue, 1 May 2012 19:16:23 +0100 Subject: [PATCH 5/5] adding parser key --- src/main/scala/AndroidHelpers.scala | 11 ++++++----- src/main/scala/AndroidKeys.scala | 1 + src/main/scala/AndroidTest.scala | 24 +++++++++++++++--------- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/main/scala/AndroidHelpers.scala b/src/main/scala/AndroidHelpers.scala index c2f1cc9..8e11ea7 100644 --- a/src/main/scala/AndroidHelpers.scala +++ b/src/main/scala/AndroidHelpers.scala @@ -1,3 +1,4 @@ +import java.io.InputStream import sbt._ import Keys._ @@ -25,7 +26,8 @@ object AndroidHelpers { (manifest(mpath) \ "uses-sdk").head.attribute(schema, key).map(_.text.toInt) def adbTask(dPath: String, emulator: Boolean, s: TaskStreams, action: String*) { - val (exit, out) = adbTaskWithOutput(dPath, emulator, s, action:_*) + val out = new StringBuffer + val exit = adbTaskWithOutput(dPath, emulator, s, action:_*) { i => out.append(IO.readStream(i)) } if (exit != 0 || // adb doesn't bother returning a non-zero exit code on failure out.toString.contains("Failure")) { @@ -34,15 +36,14 @@ object AndroidHelpers { } else s.log.info(out.toString) } - def adbTaskWithOutput(dPath: String, emulator: Boolean, s: TaskStreams, action: String*) = { + def adbTaskWithOutput(dPath: String, emulator: Boolean, s: TaskStreams, action: String*) (parser:InputStream => Unit) = { val adb = Seq(dPath, if (emulator) "-e" else "-d") ++ action s.log.debug(adb.mkString(" ")) val out = new StringBuffer - val exit = adb.run(new ProcessIO(input => (), - output => out.append(IO.readStream(output)), + adb.run(new ProcessIO(input => (), + output => parser(output), error => out.append(IO.readStream(error))) ).exitValue() - (exit, out.toString) } def startTask(emulator: Boolean) = diff --git a/src/main/scala/AndroidKeys.scala b/src/main/scala/AndroidKeys.scala index 3b22fa7..91141f3 100644 --- a/src/main/scala/AndroidKeys.scala +++ b/src/main/scala/AndroidKeys.scala @@ -179,6 +179,7 @@ object AndroidKeys { val testOnlyEmulator = InputKey[Unit]("test-only-emulator", "run a single test on emulator") val testOnlyDevice = InputKey[Unit]("test-only-device", "run a single test on device") val instrumentationRunner = SettingKey[String] ("instrumentation-runner", "instrumentation test runner e.g. android.test.InstrumentationTestRunner") + val testOutputParser = TaskKey[Option[AndroidTest.TestParser]] ("test-output-parser", "Optional test parser") /** Github tasks & keys */ val uploadGithub = TaskKey[Option[String]]("github-upload", "Upload file to github") diff --git a/src/main/scala/AndroidTest.scala b/src/main/scala/AndroidTest.scala index dee6a3a..e8b8761 100644 --- a/src/main/scala/AndroidTest.scala +++ b/src/main/scala/AndroidTest.scala @@ -1,3 +1,4 @@ +import java.io.InputStream import sbt._ import Keys._ @@ -11,22 +12,26 @@ import com.android.ddmlib.testrunner.{InstrumentationResultParser,ITestRunListen object AndroidTest { + type TestParser = (InputStream => Unit) + val DefaultInstrumentationRunner = "android.test.InstrumentationTestRunner" - def instrumentationTestAction(emulator: Boolean) = (dbPath, manifestPackage, instrumentationRunner, streams) map { - (dbPath, manifestPackage, inst, s) => - val action = Seq("shell", "am", "instrument", "-r", "-w", - manifestPackage+"/" + inst) - val (exit, out) = adbTaskWithOutput(dbPath.absolutePath, emulator, s, action:_*) - if (exit == 0) parseTests(out, manifestPackage, s.log) + def instrumentationTestAction(emulator: Boolean) = (dbPath, manifestPackage, instrumentationRunner, testOutputParser, streams) map { + (dbPath, manifestPackage, inst, parser, s) => + val action = Seq("shell", "am", "instrument", "-r", "-w", manifestPackage+"/" + inst) + val out = new StringBuffer + val exit = adbTaskWithOutput(dbPath.absolutePath, emulator, s, action:_*) {i => parser.map(_.apply(i)).getOrElse(out.append(IO.readStream(i))) } + if (exit == 0) parseTests(out.toString, manifestPackage, s.log) else sys.error("am instrument returned error %d\n\n%s".format(exit, out)) () } - def runSingleTest(emulator: Boolean) = (test: TaskKey[String]) => (test, dbPath, manifestPackage, instrumentationRunner, streams) map { (test, dbPath, manifestPackage, inst, s) => + def runSingleTest(emulator: Boolean) = (test: TaskKey[String]) => (test, dbPath, manifestPackage, instrumentationRunner, testOutputParser,streams) map { + (test, dbPath, manifestPackage, inst,parser, s) => val action = Seq("shell", "am", "instrument", "-r", "-w", "-e", "class", test, manifestPackage+"/" + inst) - val (exit, out) = adbTaskWithOutput(dbPath.absolutePath, emulator, s, action:_*) - if (exit == 0) parseTests(out, manifestPackage, s.log) + val out = new StringBuffer + val exit = adbTaskWithOutput(dbPath.absolutePath, emulator, s, action:_*) {i => parser.map(_.apply(i)).getOrElse(out.append(IO.readStream(i))) } + if (exit == 0) parseTests(out.toString, manifestPackage, s.log) else sys.error("am instrument returned error %d\n\n%s".format(exit, out)) () } @@ -62,6 +67,7 @@ object AndroidTest { AndroidInstall.settings ++ inConfig(Android) (Seq ( instrumentationRunner := DefaultInstrumentationRunner, + testOutputParser := None, testEmulator <<= instrumentationTestAction(true), testDevice <<= instrumentationTestAction(false), testOnlyEmulator <<= InputTask(loadForParser(definedTestNames in Test)( (s, i) => testParser(s, i getOrElse Nil))) { test =>