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

JUnit 5 support - A new junitlauncher task #60

Closed
wants to merge 9 commits into from

Conversation

jaikiran
Copy link
Member

@jaikiran jaikiran commented Feb 15, 2018

This is the initial working version of a new junitlauncher task that support using JUnit 5 framework for testing, within Ant build files. The commit in this PR is the initial set of goals that I had in mind for the first release of this task.

The manual for this task can be (temporarily) found at https://home.apache.org/~jaikiran/temp_workspace/manual/Tasks/junitlauncher.html

The dev list discussion about this PR can be found at https://www.mail-archive.com/dev@ant.apache.org/msg46656.html

@asfgit
Copy link

asfgit commented Feb 15, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ant%20Github-PR-Windows/40/

@asfgit
Copy link

asfgit commented Feb 15, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ant%20Github-PR-Linux/34/

@jaikiran
Copy link
Member Author

Please ignore the Jenkins failures on this PR. I'll sort out that part in a separate discussion.

@jaikiran
Copy link
Member Author

retest this please

@asfgit
Copy link

asfgit commented Feb 16, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ant%20Github-PR-Linux/35/

@asfgit
Copy link

asfgit commented Feb 16, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ant%20Github-PR-Windows/41/

@asfgit
Copy link

asfgit commented Feb 18, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ant%20Github-PR-Linux/38/

@asfgit
Copy link

asfgit commented Feb 18, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ant%20Github-PR-Windows/44/

try {
this.sysErrFilePath = Files.createTempFile(null, "syserr");
this.sysErrFilePath.toFile().deleteOnExit();
this.sysErrStream = Files.newOutputStream(this.sysOutFilePath);
Copy link
Member

Choose a reason for hiding this comment

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

copy-paste error, you want that to be sysErrFilePath :-)

Copy link
Member Author

Choose a reason for hiding this comment

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

Indeed :) Fixed.

try (final InputStream is = Files.newInputStream(path)) {
while ((numBytes = is.read(content)) != -1) {
writer.write(new String(content, 0, numBytes));
}
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this is going to work reliably. The read may have split a multi-byte sequence at the end of content and then creating a string from it is going to break. Is there any reason you want to use a stream when reading the temporary file rather than a reader?

Copy link
Member Author

Choose a reason for hiding this comment

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

You are right, good catch! I hadn't considered that scenario. I have now switched to using a reader instead.

} catch (Exception e) {
// ignore
}
}
Copy link
Member

Choose a reason for hiding this comment

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

FileUtils.close?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, make sense. Fixed.

@jaikiran
Copy link
Member Author

@bodewig, Thank you very much for the review. Based on the review comments, I have updated the PR with additional separate commits (for easier reference). I'll be squashing all these commits together during merge.

@asfgit
Copy link

asfgit commented Feb 19, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ant%20Github-PR-Windows/45/

@asfgit
Copy link

asfgit commented Feb 19, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ant%20Github-PR-Linux/39/

* task. This classpath will then be used for execution of the tests
*/
public Path createClassPath() {
this.classPath = new Path(getProject());
Copy link
Member

Choose a reason for hiding this comment

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

if users specify multiple nested classpath elements, only the last one will be used. You may want to return an already created this.classpath or move on to an add method and collect the paths inside of a wrapper Path.

Copy link
Member Author

Choose a reason for hiding this comment

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

You are right. I hadn't taken that into account. I have updated the PR to change this part of the code.

*/
public SingleTestClass createTest() {
final SingleTestClass test = new SingleTestClass();
this.preConfigure(test);
Copy link
Member

Choose a reason for hiding this comment

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

create* is called before the attribute setters, If you call preconfigure here the test won't see the actual values set at the task level.

addConfigured would get called after the attribute setters, alternatively you need to defer pre-configuration until execute is called. With both approaches you need to ensure you don't overwrite the test's explicit configuration with values from the task, of course.

Same for createTestClasses.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thank you, for catching this. I went back and read the Ant manual about writing custom tasks (which I had skipped the first time around) and now understand this logic of execution better. I have updated the PR to fix this and use the addConfiguredXXX construct and also made sure my preConfigure implementation doesn't overwrite values that might have been specified on the nested elements.


private static void safeClose(final Closeable... closeables) {
for (final Closeable closeable : closeables) {
try {
Copy link
Member

Choose a reason for hiding this comment

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

FileUtils.close?

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed.

final byte[] data = new byte[1024];
try {
while ((numRead = this.sourceStream.read(data)) != -1) {
final byte[] copy = new byte[numRead];
Copy link
Member

Choose a reason for hiding this comment

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

Arrays.copyOf?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

@Override
public void run() {
if (this.resultFormatters.isEmpty()) {
// no one to feed the stream content to
Copy link
Member

Choose a reason for hiding this comment

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

I believe this may cause the PipedOutputStream to consider the PipedInputStream "broken" soon and throw on any write operation.

Copy link
Member Author

Choose a reason for hiding this comment

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

This check is actually "dead code", in the sense that this will never be true. I wanted to avoid running these threads when there's no result formatter interested in the sysout/syserr content. But that check obviously needs to happen before the thread is even created and in fact, there's already such a check in the trySwitchSysOut and trySwitchSysErr methods (the place where this thread gets created).

So I've now updated the PR to remove this check.

@asfgit
Copy link

asfgit commented Feb 21, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ant%20Github-PR-Windows/46/

@asfgit
Copy link

asfgit commented Feb 21, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ant%20Github-PR-Linux/40/

@asfgit
Copy link

asfgit commented Feb 21, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ant%20Github-PR-Windows/47/

@asfgit
Copy link

asfgit commented Feb 21, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ant%20Github-PR-Linux/41/

@asfgit
Copy link

asfgit commented Feb 21, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ant%20Github-PR-Windows/48/

@asfgit
Copy link

asfgit commented Feb 21, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ant%20Github-PR-Linux/42/

@asfgit
Copy link

asfgit commented Feb 23, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ant%20Github-PR-Linux/43/

@asfgit
Copy link

asfgit commented Feb 23, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ant%20Github-PR-Windows/49/

…ized limited buffer, before switching to a file based store, if the size limit is exceeded
@asfgit
Copy link

asfgit commented Feb 23, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ant%20Github-PR-Linux/44/

@asfgit
Copy link

asfgit commented Feb 23, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ant%20Github-PR-Linux/45/

@asfgit
Copy link

asfgit commented Feb 23, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ant%20Github-PR-Windows/50/

@asfgit
Copy link

asfgit commented Feb 23, 2018

Refer to this link for build results (access rights to CI server needed):
https://builds.apache.org/job/Ant%20Github-PR-Windows/51/

// the buffer capacity can't hold this incoming data, so this
// incoming data hasn't been transferred to the buffer. let's
// now fall back to a file store
this.usingFileStore = true;
Copy link
Member

Choose a reason for hiding this comment

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

maybe defer setting the flag until storeToFile below succeeds?

Also, is there any chance this method could be invoked concurrently? I haven't fully checked every execution path so maybe you are synchronizing somewhere. Tests could spawn new threads you are not aware of and these threads could be writing to syserr/out concurrently.

Copy link
Member Author

Choose a reason for hiding this comment

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

maybe defer setting the flag until storeToFile below succeeds?
I did actually think of it while coding this part. The reason I decided to go this way, was to make sure that as soon as the memory size limit is reached, I prefered it to be better to no more use the in memory store even if the file store cannot be created/used.

That would imply that the subsequent syserr/sysout message will be lost but at least that won't lead to the in memory store going past the limit that's set.

The alternate approach would be to let the in-memory store be used even past its limit (and not lose any sysout/syserr content) if the file store cannot be created for whatever reason. If that feels more better approach to take, I can switch this logic in here.

Copy link
Member Author

Choose a reason for hiding this comment

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

Also, is there any chance this method could be invoked concurrently? I haven't fully checked every execution path so maybe you are synchronizing somewhere. Tests could spawn new threads you are not aware of and these threads could be writing to syserr/out concurrently.

One thing I didn't note in the implementation comments is that the sysOutAvailable and sysErrAvailable on these result formatter implementations will always be invoked by a single thread - the thread that we create and control SysOutErrContentDeliverer. Multiple threads write out to our redirected sysout/syserr stream which then gets read by the SysOutErrStreamReader thread which then hands off that read data to the SysOutErrContentDeliverer thread to have it delivered to these result formatters.


private FileOutputStream createFileStore() throws IOException {
this.filePath = Files.createTempFile(null, this.tmpFileSuffix);
this.filePath.toFile().deleteOnExit();
Copy link
Member

Choose a reason for hiding this comment

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

FileUtils.createTempFile? Probably not worth it.

Copy link
Member Author

Choose a reason for hiding this comment

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

I hadn't noticed that API. I think it makes sense to use it for consistency.

sysErrStreamer.start();
return Optional.of(new SwitchedStreamHandle(pipedOutputStream, streamer));
}

Copy link
Member

Choose a reason for hiding this comment

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

you could probably DRY up the two methods a little by extracting the common logic.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes makes sense, I'll clean up this part a bit.

@bodewig
Copy link
Member

bodewig commented Mar 4, 2018

Nice work!

I don't see any reason not to merge this PR.

@jaikiran
Copy link
Member Author

jaikiran commented Mar 4, 2018

Thank you Stefan for the thorough review. I'll clean up the commits to squash them into one and do these minor final changes before merging.

@jaikiran
Copy link
Member Author

This is now merged upstream. Closing this PR. Thanks Stefan for the extensive review.

@jaikiran jaikiran closed this Mar 17, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants