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 match-all addShMock invocation #657

Merged
merged 1 commit into from
May 6, 2024

Conversation

rmartine-ias
Copy link
Contributor

@rmartine-ias rmartine-ias commented Apr 22, 2024

The existing configuration for a match-everything sh mock uses null as the argument, which causes this error:

groovy.lang.GroovyRuntimeException: Ambiguous method overloading for method com.lesfurets.jenkins.unit.PipelineTestHelper#addShMock.
Cannot resolve which method to invoke for [null, class TestIsDatabricksRepo$_testNoDbxFolder_closure5] due to overlapping prototypes between:
	[class java.lang.String, class groovy.lang.Closure]
	[class java.util.regex.Pattern, class groovy.lang.Closure]

This can be resolved by using a pattern that matches everything (~/(?s).*/). We need the embedded DOTALL0 flag, because otherwise multiline scripts like the following are not caught:

    def status = sh(script: '''\
    echo hi
    ls -d .dbx
    '''.stripIndent(), returnStatus: true)

If there is a better way to do this, let me know! But for now, this fixes the docs bug of the docs suggesting an incorrect configuration.

Testing done

Submitter checklist

Preview Give feedback

@rmartine-ias
Copy link
Contributor Author

rmartine-ias commented Apr 22, 2024

If tests or more thorough reproduction steps for this change are needed, let me know.

@nre-ableton
Copy link
Contributor

nre-ableton commented Apr 22, 2024

Great find! 👍 I guess we never had a test case for this behavior, and there should have been one, it seems. 😅 So I tried to add such a test:

    @Test()
    void runShWithNull() {
        // given:
        def helper = new PipelineTestHelper()
        helper.addShMock(null) { script ->
            return [stdout: '', exitValue: 2]
        }

        // when:
        def status = helper.runSh(returnStatus: true, script: 'echo foo')

        // then:
        assertThat(status).isEqualTo(2)
    }

...and I ran into the same GroovyRuntimeException for ambiguous method overloading as you did. So it's definitely broken.

However, I don't think that the best solution here is to fix the documentation, but rather we should change the API to better handle catch-all cases. I appreciate that you may have wanted to avoid such a breaking change in your PR, but I do believe it would be the better solution (also considering that the method documentation for all addShMock and addBatMock overrides claim that passing null for the first argument is allowed, when this will fail).

What would you think about adding an override like this?

void addShMock(Closure callback) {
    mockShHandlers << new MockScriptHandler(~/(?s).*/, callback)
}

Which means that users would call helper.addShMock(null) { /* whatever */ }. I realize that this is a big ask for what was initially a rather small PR, so just let me know if you'd rather that I take care of it (when I have some time, that is). Otherwise if you are keen to do so then feel free to rework this PR.

@rmartine-ias
Copy link
Contributor Author

Taking a crack at this! I have two solutions for you, will push code in a sec.

Your suggested fix still fails, if I'm running it right, because no first param != null first param. So we can either:

  1. make the suggested match-all call addShMock() {} with no args
  2. import javax.lang.model.type.NullType and define a method that takes NullType and Closure, which is more specific than String or Pattern, so we're good to keep addShMock(null) {}

I'm not sure which is more idiomatic Java, I will ask around. Let me know if you have thoughts.

@rmartine-ias
Copy link
Contributor Author

rmartine-ias commented Apr 26, 2024

Alright, I've pushed two commits, one for each option. The first seems "cleaner" to me, but diverges from the existing API, so people would have to change their test code to update. The second feels a bit more like a hack, but keeps the API the same as it used to be.

Both also don't use a regex to match, but just match all, which I think is a little less error prone.

@nre-ableton
Copy link
Contributor

@rmartine-ias thanks for taking the time to look into this! I agree with you that the first approach (the one in 84c149a) looks nicer, so let's go with it. I'll deal with documenting the breaking change in the release notes etc.

Would you mind reworking your branch to drop the other commits? 🙏 Thanks also for adding tests; once this branch is cleaned up, it should basically be good to go.

The existing configuration for a match-everything sh mock uses `null` as the argument, which causes this error:

```console
groovy.lang.GroovyRuntimeException: Ambiguous method overloading for method com.lesfurets.jenkins.unit.PipelineTestHelper#addShMock.
Cannot resolve which method to invoke for [null, class TestIsDatabricksRepo$_testNoDbxFolder_closure5] due to overlapping prototypes between:
	[class java.lang.String, class groovy.lang.Closure]
	[class java.util.regex.Pattern, class groovy.lang.Closure]
```

This adds a new method signature (no args) to match everything, instead.
@rmartine-ias
Copy link
Contributor Author

Done & done, that's why I kept the commits separate. Thank you so much!

@nre-ableton nre-ableton changed the title Update addShMock docs in README.md Add match-all addShMock invocation May 3, 2024
Copy link
Contributor

@nre-ableton nre-ableton left a comment

Choose a reason for hiding this comment

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

Thanks @rmartine-ias for putting in the work on this PR! 👍 I'll merge it on Monday and make a release directly afterwards.

@nre-ableton nre-ableton merged commit 18b3054 into jenkinsci:master May 6, 2024
10 checks passed
@nre-ableton
Copy link
Contributor

I just released https://github.com/jenkinsci/JenkinsPipelineUnit/releases/tag/v1.20 and documented this change in the release notes. Thanks again for your contribution! 👍

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

Successfully merging this pull request may close these issues.

2 participants