arquillian / arquillian-spacelift

Arquillian process and package manager. Makes executing an external process or fetching platform depends dependencies an easier job
4 stars 7 forks source link

Await until console output #16

Closed lordofthejars closed 9 years ago

lordofthejars commented 9 years ago

Hi, I open this issue because I am not sure if it is already implemented or not. Since today I used spacelift for doing fast operations which ends quickly. Let's say move files, unzip files, and so on. But today I am trying something different. I am trying to run a MongoDD. The problem is that I don't know when the mongo will be ready to be used. If I use await() method obviously it hungs there because mongo server is started but not finished so tests are never executed. I was thinking (but currently I am not pretty sure if it can be done). The idea is that we can do some kind of method called awaitUntil which receives a functional interface that is the responsible of block until some condition is met. For example we can provide a default RegExp implementation which listens stdout until some regular expression matches.

WDYT?

smiklosovic commented 9 years ago

If you think about functional interface in terms of Java 8, that will never happen, we are running it under 1.6 (likely for ever).

For the problem you have, there is the concept of execution conditions. Look here (1) and here (2).

I explain it by that example, I want to start Android emulator (just like you are starting MongoDB), so I spawn that process (3) but I do NOT wait for it to stop so I get Execution.

That execution is passed to EmulatorStatusCheckTask (line 120) and I chain it with then() where I am constantly checking if it is started or not by doing some android command.

Now you execute it (line 124) and you call until(timeout, EXECUTION CONDITION) where you are constantly checking if it is booted or not. This basically repeats until timeout.

When execution condition returns true, it means that the whole exection is considered to be done.

Apply this logic to your problem and you are done.

(1) https://github.com/arquillian/arquillian-droidium/blob/master/droidium-container/arquillian-droidium-container/src/main/java/org/arquillian/droidium/container/impl/AndroidEmulatorStartup.java#L119-L124

(2) https://github.com/arquillian/arquillian-droidium/blob/master/droidium-container/arquillian-droidium-container/src/main/java/org/arquillian/droidium/container/task/EmulatorStatusCheckTask.java

(3) https://github.com/arquillian/arquillian-droidium/blob/master/droidium-container/arquillian-droidium-container/src/main/java/org/arquillian/droidium/container/impl/AndroidEmulatorStartup.java#L110

lordofthejars commented 9 years ago

Ok yes it can work hehehe this is just what I wanted to do, it is a bit weird in the sense that you need to implement for each one, but the truth is that it works and also can be externalized to regular expression as well.

Thanks.

smiklosovic commented 9 years ago

That is the cost of having it so flexible. You can not basically cover all possible use cases but finding the greatest common denominator for all problems and make it pretty extensible is the best approach.

lordofthejars commented 9 years ago

I think I am doing something wrong/bad usage or a bug has been discovered:

Look my code:

CountDownWatch watch = new CountDownWatch(30, TimeUnit.SECONDS);

        CommandTool commandTool = Tasks
                .prepare(DownloadTool.class)
                .from("https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.4.11.tgz")
                .to("target/mongodb-linux-x86_64-2.4.11.tgz")
                .then(UntarTool.class)
                .toDir("target")
                .then(CommandTool.class)
                .command(
                        new CommandBuilder(
                                "target/mongodb-linux-x86_64-2.4.11/bin/mongod")
                                .parameters("--dbpath", "target"))
                .interaction(new ProcessInteractionBuilder().when("^.*exception.*$").printToErr());

     Tasks.prepare(MongoDbStatus.class)
         .execution(commandTool.execute())
         .then(CommandTool.class)
         .command(
                    new CommandBuilder(
                            "target/mongodb-linux-x86_64-2.4.11/bin/mongo")
              )
         .execute().until(watch, MongoDbStatus.isBootedCondition);

Where MongoDbStatus is a copy paste of yours but changing the console line.

But next exception is thrown:

org.arquillian.spacelift.execution.ExecutionException: Execution of a task failed. Invocation of "target/mongodb-linux-x86_64-2.4.11/bin/mongo" failed with 1

Note that this is the call done in second Task execution (for checking if system is online). It seems that then task is executed in parallel of commandTool task (and because MongoDb has not been downloaded yet, the exception is thrown).

TadeasKriz commented 9 years ago

Hi,

what does the "execution(..)" do? And why don't you first .execute().await() for the first task and then run the second CommandTool?

lordofthejars commented 9 years ago

Execution only saves the process as the example provided of Android but I think you are right I need to split the command into two

El dilluns, 6 octubre de 2014, Tadeas Kriz notifications@github.com va escriure:

Hi,

what does the "execution(..)" do? And why don't you first .execute().await() for the first task and then run the second CommandTool?

— Reply to this email directly or view it on GitHub https://github.com/arquillian/arquillian-spacelift/issues/16#issuecomment-58006464 .

Enviat amb Gmail Mobile