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

test(JenkinsClient): add tests for exceptional cases on JenkinsClient #629

Merged
merged 5 commits into from
Feb 17, 2021

Conversation

skaldarnar
Copy link
Member

@skaldarnar skaldarnar commented Feb 17, 2021

The JenkinsClient introduced in #624 is not tested. This PR adds two tests for exceptional cases to ensure that the launcher handles these gracefully. One of the tests reveiled that the launcher would crash.

@skaldarnar skaldarnar added the Topic: Tests/QA Testing and quality assurance topics. label Feb 17, 2021
final Gson gson = new Gson();
final JenkinsClient client = new JenkinsClient(gson);

InputStream invalidPayload = new ByteArrayInputStream("{ this is ] no json |[!".getBytes());
Copy link
Member Author

@skaldarnar skaldarnar Feb 17, 2021

Choose a reason for hiding this comment

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

I'm not sure, maybe it would be better to stub the resoponse of gson.fromJson(...) here to force throwing an exception... 🤔 that might, however, lead to succeeding tests but breaking code in production (assume the parser throws a different exception after an update).

Copy link
Member

Choose a reason for hiding this comment

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

As long as it's a few objects that are easy to create (e.g. not something like MTE with a ton of start-up time and interconnected state), it is nice to be able to use real objects instead of mockito mocks.

Partly for the reason you mentioned: it can be hard to know when your mockito-defined behavior is no longer realistic.

and partly for some Java-specific worries I caught when working on old Mockito tests with warnings about illegal reflective access. Maybe they've fixed that? because Mockito is clearly still going strong and hasn't been destroyed by new releases of Java.

Copy link
Member

@keturn keturn left a comment

Choose a reason for hiding this comment

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

A test that catches a bug is a good test!

final Gson gson = new Gson();
final JenkinsClient client = new JenkinsClient(gson);

InputStream invalidPayload = new ByteArrayInputStream("{ this is ] no json |[!".getBytes());
Copy link
Member

Choose a reason for hiding this comment

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

As long as it's a few objects that are easy to create (e.g. not something like MTE with a ton of start-up time and interconnected state), it is nice to be able to use real objects instead of mockito mocks.

Partly for the reason you mentioned: it can be hard to know when your mockito-defined behavior is no longer realistic.

and partly for some Java-specific worries I caught when working on old Mockito tests with warnings about illegal reflective access. Maybe they've fixed that? because Mockito is clearly still going strong and hasn't been destroyed by new releases of Java.

Comment on lines +39 to 44
} catch (JsonSyntaxException | JsonIOException e) {
logger.warn("Failed to read JSON from '{}'", url.toExternalForm(), e);
} catch (IOException e) {
e.printStackTrace();
logger.warn("Failed to read from URL: {}", url.toExternalForm(), e);
}
return null;
Copy link
Member

Choose a reason for hiding this comment

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

This is the sort of thing where I'd be happy to let errors throw exceptions instead of returning nullable. Sure, it could help to catch gson's exception here and wrap it in something defined in our API, so the caller doesn't have to worry if it's a gson.JsonSyntaxException vs some other implementation, but having to do null-checking isn't better for our caller than having to catch an exception.

Not required for this PR though.

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'd like to go more in the direction of monadic error handling, so instead of catch-and-log-to-nullable I'd like to wrap the error/message in a better error type and use that in further processing. This may be combined with new features such as pattern matching on instanceof.

Not sure how to proceed on that front, though. You can find a very simple Result class, or go for more full-fledged libraries such as https://www.vavr.io/ or jOOλ. 🤓

How much of that would we get "for free" when using Kotlin? ... or maybe exceptions aren't that bad at all, and I should befriend them a little more? 🧐

Copy link
Member

Choose a reason for hiding this comment

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

Kotlin doesn't have Result built-in. If you want to go the full functional programming route with Kotlin, I think the thing to use is Λrrow.

I don't think exceptions are such a bad thing. The feeling I get is that most people don't think Java's checked exceptions are a feature worth keeping — e.g. Kotlin omits that idea entirely — but in general, throwing an exception when the method can't continue as planned, allowing that exception to bubble up through the stack, and having dedicated syntax for error-handling blocks (try/catch) seems okay to me.

(Clearly some language designers feel otherwise, as neither Go nor Rust have exceptions.)

Anyway, it sounds like neither of us are really fans of having null represent an error case. I haven't been won over by the idea of using Result in Java yet; it feels like it adds more noise to the happy-path (.getOrElse, etc) than try/catch does, but if we had a fully functional framework for use with JavaFX I could go along with that.

As this is a network operation, I also would want this to be an asynchronous function and would use something like ListenableFuture for that. But I hear programming languages have support for coroutines these days so maybe that's the cool thing to do?

@keturn keturn merged commit f4db71d into master Feb 17, 2021
@keturn keturn deleted the test/JenkinsClient branch February 17, 2021 19:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Topic: Tests/QA Testing and quality assurance topics.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants