Gradle in Android Studio and finalizedBy

Hi,

In parallel of trying to make SimpleHttpServer work ( see discussion Using SimpleHttpFileServer), I’m trying to do it another way, by calling python -m SimpleHttpServer.

It works not bad, as I can run the python http server, and run my tests. The problem is that I want to kill the server once the tests are all finished (successfully or not).

I tried to play with finalizedBy, but I don’t see on what task to put it. I don’t understand what is the test task that Android Studio is running.

I tried with gradle.buildFinished, but it is called after the build / compilation phase, and then right before running the tests.

Is there something that I’m missing?

Thanks

You’ll want the task that stops the server to finalize the connectedCheck task. However, Android builds are a little tricky since there can be any number of those tasks (at least two, for debug and release build types) so you’ll have to do something like this:

android {
  testVariants.all { variant ->
    variant.connectedInstrumentTest.finalizedBy stopHttpServer
  }
}

Ok, now I’m confused, I have 2 build.gradle files, one global, the other one in the app folder, so probably the file to only build the app that is running the tests. I don’t know how these files are connected, or what are their dependencies. Anyway, the global build.gradle doesn’t know “android” , and when I use the app build.gradle, the stopHttpServer is well called, but…at the beginning.
I feel like I’m too much a beginner in Gradle to ask questions about that :slight_smile:

Yes, this configuration should go in the one in the app folder. That is the build script for the app project itself. Since Android projects are by default multi-project builds, the other build.gradle file exists to contain configuration applicable to all projects.

Can you share the bit of your build script that is defining the ‘stopHttpServer’ task?

Ok, I moved things in the app project.

Here is my gradle file

apply plugin: 'com.android.application'
 
android { 
   compileSdkVersion 17
   buildToolsVersion '22.0.1'
   defaultConfig {
      applicationId "com.a2ia.qafeatj"
      minSdkVersion 17
      targetSdkVersion 17
      versionCode 1
      versionName "1.0"
      testApplicationId "com.a2ia.qafeatj.test"
   }
   buildTypes {
      release {
         minifyEnabled false
         proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
      }
   }
   productFlavors {
   }
}

dependencies {
   compile fileTree(include: ['*.jar'], dir: 'libs')
   compile files('libs/junit-4.11.jar')
   compile files('libs/libImageHttpLoader.jar')
   compile files('libs/A2iA.Mobility.jar')
}

task stopHttpServer {
   println "stop Http Server"
}

task prepareFiles {
   println 'Preparing files'
   ant.importBuild '../../../ant-copy.xml'
}

task startHttpServer(type: ExecWait) {
   println 'start Http Server'
}

task adbConnect(type: Exec, dependsOn: [prepareFiles, startHttpServer]) {
   commandLine 'adb', 'connect', '192.168.200.92'
}

android {
   testVariants.all { variant ->
      variant.connectedInstrumentTest.finalizedBy stopHttpServer
   }
}

class ExecWait extends DefaultTask
{
   HttpFileServer server = null

   @TaskAction
   def spawnProcess()
   {
      println 'Starting server'
      File root = project.buildscript.sourceFile.getParentFile().getParentFile().getParentFile().getParentFile()

      int port = 8001
      SimpleHttpFileServerFactory factory = new SimpleHttpFileServerFactory()
      server = factory.start(root, port)

      println "Server started in directory " + server.getContentRoot()+", port "+server.getPort()
   }
}

I’m not sure in Android Studio a task connectedCheck is called, I see nothing in output about that :

Executing tasks: [adbConnect]

Configuration on demand is an incubating feature.
stop Http Server
Preparing files
start Http Server
:app:prepareFiles UP-TO-DATE
:app:startHttpServer
Starting server
Server started in directory D:\src\64bits\products, port 8001
:app:adbConnect
already connected to 192.168.200.92:5555

BUILD SUCCESSFUL

Total time: 2.292 secs

The first issue is the configuration vs execution ordering issue that nearly everyone new to Gradle gets messed up on. Your println statements are executing during project configuration not necessarily when the particular task is run, which is why the output you are getting is not in the order you would expect. Instead, that logic should go in a task action.

task stopHttpServer {
    doLast {
        println "stop Http Server"
    }
}

Second, it’s unclear to me what task is responsible for actually running your tests. The code snippet I shared before is for the tests that would live under ‘src/androidTest’. In this case you are running the ‘adbConnect’ task, which from what I can tell won’t actually run any tests.

Ok, I get it now, I’ll try with doLast.

And it’s also unclear for me. In Android Studio, I’ve just made an Android Tests configuration, it runs Gradle-aware Make, then I added the adbConnect task, and then tests are launched I don’t know how.

Otherwise, in TeamCity, or in command line, I call connectedCheck task. Which make me think I could try in a command line :flushed:

Android Studio is likely running the ‘connectedCheck’ task or one of the ‘connectAndroidTest’ tasks. You should probably using the same tasks when running from the command line.

I’ve seen an assembleDebugTest or something like that.

I’ve runned in command line, with connectedCheck, the stopServer is called ! Great!

I’ve done something like that to get a reference on the server, I don’t know if there is something smarter or simplier?

task startHttpServer(type: ExecWait) {
   doLast {
      println 'start Http Server'
      File root = project.buildscript.sourceFile.getParentFile().getParentFile().getParentFile().getParentFile()

      int port = 8001
      SimpleHttpFileServerFactory factory = new SimpleHttpFileServerFactory()
      server = factory.start(root, port)

      println "Server started in directory " + server.getContentRoot()+", port "+server.getPort()
   }
}

task stopHttpServer(type: ExecWait) {
   doLast {
      println "stop Http Server"
      if (server==null)
      {
         println 'server is null'
      }
      else
      {
         server.stop()
      }
   }
}

class ExecWait extends DefaultTask
{
   static HttpFileServer server = null
}

You probably don’t want to use static variables to store this stuff. It could be something as simple as def server in the root of your build script. The reason for this is the Gradle Daemon reuses classloaders in version 2.4 and newer, so you’ll run into problems with static stuff persisting across multiple build invocations.

I see. Ok, with a def in the root, it works well.
Thank you very much for your help, I’ll keep working on that to have something fully working, but I already have a server starting and stopping, that’s a big step :smile: