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

Add RobustHTTPClient tests #176

Merged
merged 8 commits into from Sep 11, 2023

Conversation

MarkEWaite
Copy link
Contributor

@MarkEWaite MarkEWaite commented Sep 10, 2023

Add RobustHTTPClient tests

Also revises the existing test to use example.com instead of x.com since there is now a site with the x.com domain name.

Switched to hamcrest assertions because I'm more comfortable with their output.

I'd appreciate a review from either @dwnusbaum or @jglick in case there is some mistake that I've made. Not required, but would love to confirm that the technique I've used is a reasonable technique.

Testing done

Tests compile and run successfully with Java 11 on Linux. Rely on ci.jenkins.io to check Windows.

Submitter checklist

  • Make sure you are opening from a topic/feature/bugfix branch (right side) and not your main branch!
  • Ensure that the pull request title represents the desired changelog entry
  • Please describe what you did
  • Link to relevant issues in GitHub or Jira
  • Link to relevant pull requests, esp. upstream and downstream changes
  • Ensure you have provided tests - that demonstrates feature works or fixes the issue

Also revises the existing test to use example.com instead of x.com since
there is now a site with the x.com domain name.

Switched to hamcrest assertions because I'm more comfortable with
their output.
@MarkEWaite MarkEWaite requested a review from a team as a code owner September 10, 2023 12:58
@MarkEWaite MarkEWaite added the test Automated test addition or improvement label Sep 10, 2023
@MarkEWaite MarkEWaite self-assigned this Sep 11, 2023
@MarkEWaite MarkEWaite changed the title Add a RobustHTTPClient downloadFile test Add RobustHTTPClient tests Sep 11, 2023
@Test
@WithoutJenkins
Copy link
Member

Choose a reason for hiding this comment

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

I am not sure this does anything (useful) in conjunction with @ClassRule. Better to separate unit from functional tests in distinct source files.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will do that. Thanks

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in b2a588a. Thanks very much!

Comment on lines 71 to 72
final AssertionError e = assertThrows(AssertionError.class, () -> {
RobustHTTPClient.sanitize(new URL("https://example.com/ /has/space/in/url/"));
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 misleading. https://github.com/jenkinsci/apache-httpcomponents-client-4-api-plugin/blob/master/src/main/java/io/jenkins/plugins/httpclient/RobustHTTPClient.java#L261-L264 only throws an assertion error when assertions are enabled, which they would not be in production. Perhaps better to just switch this to a warning. (Unfortunately URL allows bogus strings which URI does not.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks. I've added two tests in b2a588a, one with assertions enabled and one with assertions disabled. I've confirmed that the tests pass as expected whether assertions are enabled or disabled.

@Test
public void testDownloadFile() throws Exception {
JenkinsRule.WebClient wc = j.createWebClient();
RobustHTTPClient client = wc.executeOnServer(() -> {
Copy link
Member

Choose a reason for hiding this comment

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

Why the executeOnServer?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

RobustHTTPClient client = new RobustHTTPClient() without the executeOnServer throws an exception that the object is not being constructed in the Jenkins controller JVM. This is my "cheat" to cause the constructor to think that it is being called on the controller JVM.

Copy link
Member

@jglick jglick Sep 11, 2023

Choose a reason for hiding this comment

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

Not sure what you were doing, but try it again. Unless you are using RealJenkinsRule, or running tests in e.g. JenkinsSessionRule at a time when the server is not started, code run in the Surefire test will be in the same JVM and so

public RobustHTTPClient() {
JenkinsJVM.checkJenkinsJVM();
should be fine.

package io.jenkins.plugins.httpclient;
import org.junit.ClassRule;
import org.junit.Test;
import org.jvnet.hudson.test.JenkinsRule;
public class XTest {
    @ClassRule public static JenkinsRule r = new JenkinsRule();
    @Test public void x() {
        new RobustHTTPClient();
    }
}

passes as expected.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks very much! Fixed in b2a588a

RobustHTTPClient client = wc.executeOnServer(() -> {
RobustHTTPClient internalClient = new RobustHTTPClient();
internalClient.setStopAfterAttemptNumber(1);
internalClient.setTimeout(50, TimeUnit.MICROSECONDS);
Copy link
Member

Choose a reason for hiding this comment

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

This looks flaky. Set a real timeout, and instead of downloading the Jenkins root URL, use a @TestExtension on an UnprotectedRootAction whose doIndex sleeps.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks. I like that idea much better.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I won't have time to implement that change immediately, since it will require that I learn more about @TestExtension and UnprotectedRootAction. I'll leave this pull request open until I have time to implement that.

Copy link
Member

Choose a reason for hiding this comment

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

Roughly, and from memory:

@Test public void xxx() {
  theClient.download(r.getRootURL() + "hangs/");
}
@TestExtension("xxx") public static final class Hangs extends InvisibleAction implements UnprotectedRootAction {
  @Override public String getUrl() {return "hangs";}
  HttpResponse public void doIndex() {Thread.sleep(Long.MAX_VALUE);}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Implemented in c21f9c1

Creates a new test that checks santiize() behavior if assertions are
disabled.  The test is executed if Maven is called with:

  mvn clean -DenableAssertions=false verify

Simplify the JenkinsRule based integration test thanks to feedback
from @jglick.  No need to use a WebClient to wrap the execution of
the constructor.
Comment on lines +38 to +40
assertThat(
RobustHTTPClient.sanitize(new URL("http://example.com/some/long/path")),
is("http://example.com/some/long/path"));
Copy link
Member

@jtnord jtnord Sep 11, 2023

Choose a reason for hiding this comment

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

Also revises the existing test to use example.com instead of x.com since there is now a site with the x.com domain name.

this is at odds here, if the rationale here was that x.com now exists so use something that does not exist, then we can not use example.com as that exists (and is reserved). in other words you should use a different reserved domain (or TLD) that is both reserved and should not exist.

e.g. foo.invalid

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The switch from x.com to example.com had multiple motivations. I didn't mention all the motivations in the commit message. I should have done that.

It was intended to intentionally switch to a domain name that is reserved for documentation purposes. The test is documenting that the sanitization behaves as expected.

It was intended to make the URL string longer so that all three of the assertions the tests would format the same way.

It was intended to stop using a domain that now exists and is a redirect to twitter.com.

I'm fine with switching to another domain if that makes the test clearer.

Copy link
Member

@jtnord jtnord Sep 11, 2023

Choose a reason for hiding this comment

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

It was intended to intentionally switch to a domain name that is reserved for documentation purposes. The test is documenting that the sanitization behaves as expected.

I'm not sure I would call a test documentation according to the standard :)

if we do not care that a domain could or could not exist for this, then .test is available for this purpose (it may return NXDOMAIN like .invalid, but it may also be defined locally for testing purposes)

if we need a domain to exist (ie something will fail otherwise) then there is no difference here between x.com and example.com or even jenkins.io (with the exception that we control jenkins.io).

this is more an FYI.

Copy link
Member

Choose a reason for hiding this comment

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

I think example.com is fine for this purpose.


@Test
public void sanitizeReturnsInvalidURLs() throws Exception {
Assume.assumeFalse(RobustHTTPClient.class.desiredAssertionStatus());
Copy link
Member

Choose a reason for hiding this comment

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

Fine, though again I would suggest just switching production code to not use assert here if it is tricky to test.

@MarkEWaite MarkEWaite merged commit 39b59da into jenkinsci:master Sep 11, 2023
14 checks passed
@MarkEWaite MarkEWaite deleted the add-RobustHTTPClient-test branch September 11, 2023 19:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
test Automated test addition or improvement
Projects
None yet
3 participants