Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to use Cube outside of Arquillian Test? #242

Open
smiklosovic opened this issue Jan 9, 2016 · 28 comments
Open

How to use Cube outside of Arquillian Test? #242

smiklosovic opened this issue Jan 9, 2016 · 28 comments

Comments

@smiklosovic
Copy link
Member

@lordofthejars @aslakknutsen

This is rather question then an "issue".

I would love to use Cube but the thing what I try to achieve is that I need to manage containers with some neat Java API and once containers are started, I have another project which just executes tests against some URL. And I get that URL after container is started so I need to separate the container creation from the test execution.

I need, more or less, to control containers from Arquillian Spacelift Gradle plugin where, e.g. in "beforeTest" / "beforeSuite" closure, I will start a container with Cube API and get some manager object and after tests are executed, I need to stop that container e.g. in "afterTest" or "afterSuite" by that manager.

Is this possible? Can I just depend on some artifact via which I would construct and start Docker container, providing some docker-compose.yml? In my usecase, I do not need to have this all stuff embedded and wired directly in some Arquillian-enabled test because my tests are already lying somewhere else and are not Arquillian-enabled and likely will never be. I do not need to use Arquillian runtime for this.

@aslakknutsen
Copy link
Member

Sounds like you want Cube- standalone.

On Sat, Jan 9, 2016, 12:23 Štefan Miklošovič notifications@github.com
wrote:

@lordofthejars https://github.com/lordofthejars @aslakknutsen
https://github.com/aslakknutsen

This is rather question then an "issue"

I would love to use Cube but the thing what I try to achieve is that I
need to manage containers with some neat Java API and once containers are
started, I have another project which just execute tests against some URL
And I get that URL after container is stared so I need to separate the
container creation from the test execution

I need, more or less, to controll containers from Arquillian Spacelift
Gradle plugin where, eg in "beforeTest" / "beforeSuite" closure, I will
start a container with Cube API and get some manager object and after tests
are executed, I need to stop that container eg in "afterTest" or
"afterSuite"

Is this possible? Can I just depend on some artifact via which I would
construct and start Docker container, providing some docker-composeyml? My
my usecase, I do not need to have this all stuff embedded and wired
directly in some Arquillian-enabled test I do not need to use Arquillian
runtime for this


Reply to this email directly or view it on GitHub
#242.

@smiklosovic
Copy link
Member Author

If you mean this (1) it uses injected CubeController to manage them. I can not obviously inject anything and it uses some events to be fired beneath and in my scenario I will never have them injected in the first place.

I think it could be possible to use DockerClientExecutor class direcly. It does not depend on anything Arquillian-specific and it looks like I can safely use it directly.

Is there another approach how I can use Cube's internals to embed its functionality into something completely different?

https://github.com/arquillian/arquillian-cube/blob/master/docker/ftest-standalone/src/test/java/org/arquillian/cube/StandaloneTestCase.java

@lordofthejars
Copy link
Member

Hi @smiklosovic for what I see I think this is a use case we are missing in Cube. I agree with you that using standalone mode would not require manual steps for starting the containers. For what I see, when starting a standalone, it should take the orchestration file (docker-compose), analyze it and start everything in the correct order. So you only need to set the Runner to be Arquillan and that's all. Something like it is done in containerless.

I think it has sense.

@aslakknutsen
Copy link
Member

It's not very hard to get it running outside of a Test..

This is based on the 'docker/ftest-standalone' classpath.

Manager manager = ManagerBuilder.from()
                       .extension(LoadableExtensionLoader.class)
                       .create();

manager.start();

String cubeId = "database";

manager.fire(new CreateCube(cubeId));
manager.fire(new StartCube(cubeId));

CubeRegistry registry = manager.resolve(CubeRegistry.class);
Cube<?> cube = registry.getCube(cubeId);

System.out.println("Cube");
System.out.println("ip:          " + cube.bindings().getIP());
System.out.println("bound ports: " + cube.bindings().getNumberOfPortBindings());

manager.fire(new StopCube(cubeId));
manager.fire(new DestroyCube(cubeId));

manager.shutdown();

In this case arquillian.xml is read. But you could provide your own ArquillianDescriptor provider or just set system properties before starting. All values in arquillian.xml can be replaced / added via properties.

@aslakknutsen
Copy link
Member

Technically you could do this as well, as far as Cube is concerned, but you might miss out on some other extensions that react to the events(tho other extensions should listen to Before|After Create|Start|Stop|Destory so maybe it doesn't matter as those are fired in both cases):

String cubeId = "database";
CubeRegistry registry = manager.resolve(CubeRegistry.class);
Cube<?> cube = registry.getCube(cubeId);

cube.create();
cube.start();

System.out.println("Cube");
System.out.println("ip:          " + cube.bindings().getIP());
System.out.println("bound ports: " + cube.bindings().getNumberOfPortBindings());

cube.stop();
cube.destroy();

@aslakknutsen
Copy link
Member

You could do mamager.resolve(CubeController.class) as well, but you'd still need the Cube to get to the binding data. So not sure CubeController would do any good in this case.

@smiklosovic
Copy link
Member Author

Awesome hint Aslak. I will look into this. I can imagine this could be wrapped in some helper class so it would be a no-brainer. I think that you could use this in test case itself but it would not be run with arquillian runner but with normal JUnit4.class ....

@aslakknutsen
Copy link
Member

Yeah, that's what I'm doing here:

public class ManualStartTest {

    @Test
    public void should() throws Exception {

        Manager manager = ManagerBuilder.from()
...

How else do you run code? ;)

@smiklosovic
Copy link
Member Author

:) This just begs for @ClassRulling it ...

@aslakknutsen
Copy link
Member

@smiklosovic so why not use the Arquillian runner? :)

@smiklosovic
Copy link
Member Author

There are some cucumber + serenity tests and it has some crazy runner and even I know there is some Cuke + Arquillian integration, it would mean that the structure of the tests would have to change significantly to "Arquillianify it" and nobody aint got time for that. Plus there is not Serenity support in that extension...

It seems to me that better approach would be just to extract the functionality of what I need when it comes to Docker and set it up in some scenario / steps fixtures.

Extracting into separate artifact would enable reusability e.g. in that arquillian-spacelift-gradle plugin as well where I could use it in before / after test closures. Having the possibility to use Rule would be just a nice addon where you could eventually run tests against your local setup or against docker if you want to without Arquillian runner but with Arquillian internals from Arquillian-Docker core.

@aslakknutsen
Copy link
Member

It's only 3 lines of code to get Arquillian created/started/stopped. The rest is Cube already. Not sure what you would gain by 'extract the functionality of what I need when it comes to Docker' .

@smiklosovic
Copy link
Member Author

Yes, maybe I am overengineering here little bit. I think that, looking at your code you have posted while ago, it would be sufficient to not wrap it into anything and use it directly as-is.

@smiklosovic
Copy link
Member Author

@aslakknutsen it works and it is awesome :)

@aslakknutsen
Copy link
Member

@smiklosovic excellent! 👍

@aslakknutsen
Copy link
Member

So technically possible to do, I think we still need to document it to show how. So we can leave this open as a doc issue. wdyt?

@aslakknutsen aslakknutsen changed the title How to use Cube out of Arquillian? How to use Cube out of Arquillian Test? Jan 15, 2016
@aslakknutsen aslakknutsen changed the title How to use Cube out of Arquillian Test? How to use Cube outside of Arquillian Test? Jan 15, 2016
@smiklosovic
Copy link
Member Author

@aslakknutsen
Copy link
Member

@smiklosovic
Copy link
Member Author

If I recall correctly, without that, ArquillianDescriptor was not resolved nor fired further to the Cube extension,.

@smiklosovic
Copy link
Member Author

Huh ... it is working without that line as well, even better, that was some kind of fuzz ... However config-imp-base still has to be there

@aslakknutsen
Copy link
Member

yeah, I assume it came in before you added config-impl to cp :) Shouldn't need the custom reg of CubeDockerExtension either. It's not a @observer in the scense of Core anyway so it won't do anything :)

@smiklosovic
Copy link
Member Author

confirmed, thanks

I am wondering what about Docker compose scenario. I have docker-compose.yml with custom images deployed in private Docker registry. docker-compose up works ok. I am just starting one container of them in the test right now but having them all started would be cool as well.

I had to specify cubeId which was equal to name in dockerContainers property. However when I set dockerContainersFile to compose file, what cubeId should I use?

Should I just start them one by one using name of container as cubeId? Once container is linked to other three, is not it sufficient to start just that one and all linked containers would be started as well?

@smiklosovic
Copy link
Member Author

I do not know who wrote that Cube readme but I bet on Alex and I have to say that it reads like a wine. Every now and then I "hmmm" for myself getting know something new. Kudos to @lordofthejars !

@aslakknutsen
Copy link
Member

You could try to set autoStartContainers to regexp:.* or something.. that should start all containers.

@smiklosovic
Copy link
Member Author

@aslakknutsen

It is possible to use this in a suite?

My problem is that I have JUnit Categories tests and I gather all Docker-like tests together. Every test case class interacts with Docker somehow.

I have Manager static and the funny thing is that when Manager is shutted down (as a result of the test case itself, I am shutting down Manager after all containers are stopped), it throws NPE on the run of the other test class, contexts array is clean so ApplicationScoped context is null so it can not fire events and so on ...

Any hint?

@smiklosovic
Copy link
Member Author

I slightly rewrote that class in a way that it constructs Manager (= loads the extension) everytime it detects that it is stopped so it effectively activates application context.

@aslakknutsen
Copy link
Member

@smiklosovic If you can find the correct hooks sure. @before / @after in a @runner(Suite.class) executes before and after the suite if I remember correctly.

@aslakknutsen
Copy link
Member

But you'll need to enforce the Junit4.7 Maven Surefire runner to support it, and I believe exclude the 'Suite children' from running in Maven. And you'll need to ru the Suite for any of them to work, as a Child doesn't know of the Suite but it requires it.. I guess you could workaround that with some Base class the Docker ones and the Suite extend and store Manager in a static or something to only initiate it once (on second thought, you'l still have the After / Manager closed issue with the Base class idea)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants