Skip to content

fix errors in tests#938

Merged
KostyaSha merged 10 commits intodocker-java:masterfrom
Baqend:test-fixes
Oct 31, 2017
Merged

fix errors in tests#938
KostyaSha merged 10 commits intodocker-java:masterfrom
Baqend:test-fixes

Conversation

@fbuecklers
Copy link
Copy Markdown
Contributor

@fbuecklers fbuecklers commented Oct 24, 2017

Try to fix some outstanding test failures


This change is Reviewable

} else {
exception.expect(NotFoundException.class);
}
}*/
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you will have different errors for different api versions, i spent a lot of time in this place

Copy link
Copy Markdown
Contributor Author

@fbuecklers fbuecklers Oct 25, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes true, but it seems that only swarm behaves differently here compared to docker. The main error here was that awaitCompletion and not awaitSuccess was called.
The error handling for the pull command was only in awaitSuccess. I have moved that to awaitCompletion since you will expect correct error handling there.

@fbuecklers
Copy link
Copy Markdown
Contributor Author

Hm..., I really don't like it that all test cases leave there containers and resources there.
It will be really more clean if all test classes cleanups there created resources like images/containers/networks/volumes etc.
Currently, the potential is relatively high that one test conflicts with a previously executed test. Because a name/port/volume etc. already existst.

@codecov-io
Copy link
Copy Markdown

codecov-io commented Oct 25, 2017

Codecov Report

Merging #938 into master will increase coverage by 0.29%.
The diff coverage is 78.84%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #938      +/-   ##
==========================================
+ Coverage   61.29%   61.58%   +0.29%     
==========================================
  Files         411      411              
  Lines        8134     8172      +38     
  Branches      526      530       +4     
==========================================
+ Hits         4986     5033      +47     
+ Misses       2846     2838       -8     
+ Partials      302      301       -1
Impacted Files Coverage Δ
...b/dockerjava/api/command/InspectImageResponse.java 100% <ø> (ø) ⬆️
...com/github/dockerjava/netty/InvocationBuilder.java 90.86% <100%> (ø) ⬆️
...ckerjava/core/command/PushImageResultCallback.java 76.47% <66.66%> (+16.47%) ⬆️
.../dockerjava/core/async/ResultCallbackTemplate.java 76.74% <66.66%> (ø) ⬆️
...ckerjava/core/command/PullImageResultCallback.java 80.76% <80.95%> (+24.51%) ⬆️
...ava/netty/handler/FramedResponseStreamHandler.java 84.48% <0%> (ø) ⬆️
...hub/dockerjava/core/async/JsonStreamProcessor.java 80% <0%> (+3.33%) ⬆️
...com/github/dockerjava/api/model/ContainerPort.java 6.25% <0%> (+6.25%) ⬆️
.../dockerjava/core/command/CreateNetworkCmdImpl.java 74.19% <0%> (+6.45%) ⬆️
.../github/dockerjava/api/model/PullResponseItem.java 62.5% <0%> (+12.5%) ⬆️
... and 1 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update fce9df9...7e24a13. Read the comment docs.

# Conflicts:
#	src/main/java/com/github/dockerjava/api/model/PullResponseItem.java
#	src/main/java/com/github/dockerjava/core/command/PullImageResultCallback.java
"--name=swarm_join" \
"swarm:${SWARM_VERSION}" \
join --advertise="${HOST_IP}:${HOST_PORT}" --delay="0s" --heartbeat "5s" "nodes://${HOST_IP}:${HOST_PORT}"
# join engine to swarm, is not required if fixed ip addresses are used
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because then you will have huge default delays

LOG.info("Committing container: {}", container.toString());
String imageId = dockerRule.getClient().commitCmd(container.getId()).exec();

//swarm needs some time to refelct new images
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo

String imageId = dockerRule.getClient().commitCmd(container.getId()).exec();

//swarm needs some time to refelct new images
wait(5000);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use awaitility with query to what needed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you exactly mean?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean that awaitility with client query for some good to go criteria is right way. https://github.com/awaitility/awaitility


@Test
public void createContainerWithPortBindings() throws DockerException {
int baseport = dockerRule.getKind().equals("jersey")? 11000: 12000;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getKind() is string value, test itself is parametrized with enum, so you can do it easy with getFactoryType() == JERSEY


// we have to block until image is pushed
dockerRule.getClient().pushImageCmd(username + "/busybox").exec(new PushImageResultCallback()).awaitSuccess();
dockerRule.getClient().pushImageCmd(username + "/busybox").exec(new PushImageResultCallback()).awaitCompletion();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it may complete with not pushed r tests needs awaitSuccess() everywhere as clear success of operation.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that it is not a good choice to have an awaitComplete and an awaitSuccess. Since awaitComplete does not validate all error cases on pull and push

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then it will hide bugs in .awaitSuccess logic. In any case success should be success for test even the next code do single checks of success criteria.

dockerRule.getClient().pushImageCmd(username + "/xxx")
.exec(new PushImageResultCallback())
.awaitCompletion(20, TimeUnit.SECONDS); // exclude infinite await sleep
.awaitCompletion(); // exclude infinite await sleep
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. comment is wrong
  2. without timeout test may stuck forever, test needs some timeout.

exception.expect(DockerClientException.class);
} else {
//swarms throws a different error here
if (TestUtils.isSwarm(dockerRule.getClient())) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it not related to swarm. Run locally 2 DINDs with different version and run test against - you will see different behaviour

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Problem was that sometimes awaitSuccess and sometimes awaitComplete was used. And they behaves inconsistent while handling the error.
Therefore i propose that awaitComplete does the correct error handling and we deprecate awaitSuccess.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i not sure at all why we parse messages because http response code should indicate success or failure... But it could be changed in future, now i want end swarm & tests scope of changes and make major release.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really since docker send always an success status code and will later then indicate the error status in the body. That is not so unknown pattern for long running asynchronous operations, since a http request will otherwise be timeout by clients or intermediate proxies.

@fbuecklers
Copy link
Copy Markdown
Contributor Author

Yeah all seems to be green
What dou you think about the changes?

dockerRule.getClient().startContainerCmd(container.getId()).exec();

Integer status = dockerRule.getClient().waitContainerCmd(container.getId())
.exec(new WaitContainerResultCallback()).awaitStatusCode();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on one line client.command()
on other lines fluent calls .exec()
.await()
That's for eyes redability


//swarm needs some time to refelct new images
synchronized (this) {
wait(5000);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the criteria that it swarm is ready?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know but we use the same trick in our production swarm cluster. I guess that swarm manager keeps an image cache in memory or something like that.
And this cache is lazy reinitialized after a new image is in place.

.exec(new PushImageResultCallback())
.awaitCompletion(30, TimeUnit.SECONDS);

Assert.fail("An exception is expected.");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assert.fail() is not junit Expected Rule style

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes sure is there a different easy way to define two different expectations?

Copy link
Copy Markdown
Member

@KostyaSha KostyaSha Oct 25, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fast lookup shows that ExpectedException.expect(Class) uses org.hamcrest.CoreMatchers#instanceOf and there is org.junit.rules.ExpectedException#expect(org.hamcrest.Matcher<?>)
so i guess you can construct org.hamcrest.CoreMatchers#anyOf(java.lang.Iterable<org.hamcrest.Matcher<? super T>>) + instanceOf()

But again, you are changing the existing behaviour of the test. Test was about success + different api versions, so you shouldn't combine and hide this errors.
This tests not only about green status, they like documentation examples. Usually when i have questions i go to tests and this conditionals will show what may be wrong.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That will make only sense for me if I can always expect the same exception for the same error. But that is not the case. If I upgrade my docker version, for example, I will get no a different Exception. Thats not a really cool behavior. And since docker behaves like that, it should be more straightforward to throw an exception that I can always handle. For instance a common DockerException base class for all Exception which the docker client will throw.

.awaitCompletion(30, TimeUnit.SECONDS);

fail("An exception is expected.");
} catch (NotFoundException | DockerClientException e) {
Copy link
Copy Markdown
Member

@KostyaSha KostyaSha Oct 25, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that seems a wrong junit exception usage. test shouldn't suppress exceptions, it need only configure exception (that is Rule).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But thats an or exception condition
maybe we let DockerClientException extend DockerException?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no idea, how it influence on this test case? Different docker versions return different error codes so client returns different exceptions. That's why Exception Rule was conditionally configured before call that should throw error.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will change that each method will at least throw a DockerException. So you can always expect a DockerException regardless which docker version you exactly use.
Currently you must expect a DockerException or a DockerClientException.

exception.expect(DockerClientException.class);
}
//different docker version throws different errors here
exception.expect(anyOf(instanceOf(NotFoundException.class), instanceOf(DockerClientException.class)));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please restore original logic, original code tests for expected exceptions, not or.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was a bug, in the error handling logic it will always throw an error now. But in my tests docker behaves different also on same versions by just switching to swarm. And again I do not like that, that you must handle different exception types depending on the used docker/swarm version.
If we at least let DockerClientException extend DockerException we can say it will always throw an DockerException independent of the used docker / swarm version.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

library is transparent to docker api/daemon bugs. We don't do magic, NotFoundException is handled in different way by library users because it means that image not found and user may be wanting to switch to other image, all other errors - 500, 501 etc are not recoverable for application usage. And if swarm and docker behaves differently then it should be library user problem. In fact i don't see a problem, in library you can catch it with oneEx | secondEx and tests catches exactly like it is.

Copy link
Copy Markdown
Contributor Author

@fbuecklers fbuecklers Oct 31, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The case why I do not like this behavior is, that the docker daemon indicates an error asynchronously and we make a docker client exception out of it.
My expectation was that the DockerClientException is only thrown if a client-side error occurred, not a remote one.

.exec(new PushImageResultCallback())
.awaitCompletion(20, TimeUnit.SECONDS); // exclude infinite await sleep

.awaitCompletion(30, TimeUnit.SECONDS);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

restore comment

//swarm will attach additional labels here
assertThat(responseLabels.size(), greaterThanOrEqualTo(2));
assertThat(responseLabels.get("label1"), equalTo("abc"));
assertThat(responseLabels.get("label2"), equalTo("123"));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but why it work before?

Copy link
Copy Markdown
Contributor Author

@fbuecklers fbuecklers Oct 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It works before because, on some docker versions, the labels were copied to the containerConfig. That was the reason why this test fails on some test configurations. We can only expect the labels on the config object since the container was not started with any labels.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

@KostyaSha KostyaSha merged commit 8902e32 into docker-java:master Oct 31, 2017
@KostyaSha KostyaSha added this to the 3.1.0 milestone Oct 31, 2017
@KostyaSha
Copy link
Copy Markdown
Member

Thanks!

@fbuecklers fbuecklers deleted the test-fixes branch November 21, 2017 11:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants