-
Notifications
You must be signed in to change notification settings - Fork 395
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
Testing Shared Libraries that use Jenkins commands #51
Comments
Hey, you forgot some lines in the pipeline
Take a look on this one https://github.com/headcrabmeat/pipeline-sharedlib-testharness |
Hi, I read it again =). so it should look like
|
I think @vle-tom was trying to access steps outside of the scope of an enclosing class, i.e. the first example ( i.e. // src/com/company/Util.groovy
package com/company;
def getBuildProperties(){
return script.readFile('file.properties')
} this works for me in Jenkins but in the test environment I got the same error. |
I'm having the exact same problem. Did you ever find a solution`? |
We face the same issue. We have shared libaries were we combine a number of Jenkins default commands for example. We like to unit tests our own shared libraries. |
I may have a work around. I havent tried it out with JenkinsPipelineUnit:
Do
then have a factory
which can override the Util class given:
Then when running a test, you can
But that means that you have to override all pipeline methods the util class calls. |
I think I am experiencing this too. I am able (sort-of) to load and run a
It looks like a bug because |
But, I've seen this done in https://github.com/SAP/jenkins-library not sure what magic is necessary. |
If this helps anyone, I just spent an afternoon trying to figure this out, and what it boiled down for me was that including the This works: sourceSets {
main {
groovy {
srcDirs = ['src']
}
}
test {
groovy {
srcDirs = ['test']
}
}
} This doesn't: sourceSets {
main {
groovy {
srcDirs = ['src', 'vars']
}
}
test {
groovy {
srcDirs = ['test']
}
}
} I guess it is because the library scripts in |
P.S. And I just now found the same solution mentioned here: #25 (comment) Oh well. Now we know. 😃 |
I'm seeing what appears to be the same issue, but I actually don't have sourceSets defined in my build.gradle... I'm not sure what I'm doing wrong, but my shared library functions can't call steps like echo. Is there some other way that the groovy library code could be pulled into the class path? |
I think my issue is because I'm trying to run steps inside of the src/* functions of my library. Is there a way to make that work? |
@jacob-keller Hi, I am facing issues on the similar lines, I am using steps() and node() under src/* is that the reason? Official docs say this: "Only entire pipelines can be defined in shared libraries as of this time. This can only be done in vars/*.groovy, and only in a call method. Only one Declarative Pipeline can be executed in a single build, and if you attempt to execute a second one, your build will fail as a result" Should I move the steps, stages, etc. sections to vars/* ? |
@giorgiosironi @luispollo @jacob-keller Hi! I am facing similar issues as folks in this thread. I am using declarative pipelines and debugged my issues to pipeline basic steps not being able to be recognized from src/ . |
@skatlapa Hmm. I don't remember if I got this resolved or simply worked around it. I think the way I got something like this working, is that I created a pipeline script which pulls the steps and then I forward those into the src/* class via a class variable. This way, the pipeline in the test framework starts, gets the current steps, and assigns them to the class. Finally, all of my src/* code references full steps via "steps.", i.e. "steps.sh" or "steps.echo" or "steps.stage". I believe that's how I got everything working, but I could be wrong. I'll try to double check if I can find any more details on this tomorrow. |
@jacob-keller Thanks a lot for the response, I assume you did something like this: https://github.com/zowe/jenkins-library/blob/master/src/org/zowe/jenkins_shared_library/pipelines/base/Pipeline.groovy I think that works too, but my current use case is pretty convoluted/complex. I could switch to using scripted pipelines to workaround but I am more inclined towards maintaining/get it working with declarative pipelines. Also, could you let me know if you've used declarative pipelines as well? You can get back when you get a moment, thanks again! |
To clarify, you can do the "steps" setup from within a vars/* step itself, so then it could work within a declarative pipeline as well. I haven't really used declarative pipelines myself, as most of the pipelines I wrote are from before the declarative style existed. |
@jacob-keller Thanks for the clarification, I am aware of that. I have previously defined large(entire) parts of declarative pipelines under vars and called the scripts into the Jenkinsfiles and I had no problems at all. I am trying to do something around the lines of this: https://gist.github.com/skatlapa/cd96b98bda9806cf134c03b6c30737d9 Notice the pipeline steps https://gist.github.com/skatlapa/cd96b98bda9806cf134c03b6c30737d9#file-srcmethod-groovy-L8 , node {..} here is not being recognized and get the error similar to the error(s) in the thread. I get the same error for steps {..}, retry(){}, etc. I wanted to know a way to keep that method in src/ and make it work, also any other tips related or otherwise are appreciated. Please note I am using declarative style of Jenkinsfile. |
See https://jenkins.io/doc/book/pipeline/shared-libraries/#accessing-steps for some example of how to access steps in the src/* classes: in the vars/* code: In the src/* classes: Hope that helps. Basically you ultimately need to pass "this" or "this.steps" into the method somehow from the vars/* code, but the vast majority including actually calling steps can be done in src/* code. |
@jacob-keller Thanks! That seems to make sense. I will give it a go and update here. |
Update - That did not work for me, I may be calling/using scripts step incorrectly, I haven't gotten chance to dive deep. I'll get back to this the next week and keep you posted. Thanks! |
@luispollo Removing the "vars" directory for the "srcDir", does work, but it breaks IntelliJ autocompletion for code inside the vars directory, do you know what else can be done? |
I am trying to test the methods of a class without needing to create an entry in I have a class:
Which I am trying to test like so:
This seems to follow what @jacob-keller said above (passing the pipeline into the class and store it, then the pipeline methods through that).
Am I doing something wrong, or is this expected not to work? |
@timbrown5, def exampleClass = new ExampleClass(this) But I'm not sure if it will work. If you're testing a shared library please see README for demo projects. |
@stchar This allowed me to write some unit tests for a portion of my code. Then I started trying to test a groovy class in
My plan was to use Groovy classes which contain common pipeline actions to help abstract away OS differences. Not sure this it's possible to write tests for this with the current implementation. I will try writing wrappers scripts, in |
To test this kind of classes I do this way: In my resources test I create a file def version = '1.0'
return this And my tests class: class TestExampleClass extends BasePipelineTest {
Script steps = null
@Override
@Before
void setUp() throws Exception {
this.scriptRoots += "test/resources"
this.scriptRoots += "src"
super.setUp()
LibraryConfiguration library = LibraryConfiguration.library().name("jenkins-ci")
.retriever(new ProjectSourceRetreiver())
.targetPath("N/A")
.defaultVersion("master")
.allowOverride(true)
.implicit(true)
.build();
helper.registerSharedLibrary(library);
helper.registerAllowedMethod("echo", [String.class]) { String message ->
println(message)
}
steps = loadScript('foo.groovy')
}
@Test
void testExampleClassSayHelloTo() {
ExampleClass exampleClass = new ExampleClass(steps)
exampleClass.sayHelloTo('Stéphane')
}
} The output of my test:
In my opinion the use of the foo script is a trick but it's the aonly way I found to test util method in a sharedlib that use jenkins methods (echo in the example). If there is a best way to do that tell me ! |
@philippart-s Wow, that is a neat trick. I've need scratching my head for a while so thanks for the help 👍. I had a little problem checking that it fixed my issue, so am adding my source below incase it helps anyone:
Further to the other issue I found a way to get my use case above to work... use maven 🤢. I have ported my gradle project to maven and have the same test passing when using |
@timbrown5, could you please also share your |
|
@timbrown5, cool, this is a great starting point to a create wiki. |
I was planning to offer documentation if my approach was the right one, so if you want, I would like to participate in writing an article if that helps. |
That's fine by me 👍. |
example_jenkins_shared_library_tests.tar.gz |
What is this community's current best guideline as of today, May 2021, for testing Declarative pipelines that use a shared library? I've built a shared library that is being adopted across my dev org. Each app's repo includes the library and passes in a few specific params, and the rest is done by the shared lib: // github.mycompany.com/some-app-repo/Jenkinsfile
library 'shared-pipeline-library-repo'
servicePipeline {
someParam = 'value'
} // github.mycompany.com/shared-pipeline-library-repo
|-Jenkinsfile
├───jenkins-workflow
│ application.xml
│ unitTest.ps1
│
├───resources
│ pipelineHelpers.ps1
│ pipelineHelpers.Tests.ps1
│
└───vars
addAllErrorsToInfoMessages.groovy
addStageResultToInfoMessages.groovy
addToInfoMessages.groovy
deploy.groovy
deployApproved.groovy
doIntegrationTests.groovy
doRestore.groovy
servicePipeline.groovy I've trimmed the list of files in def call(body) {
// this is a jenkins-provided pattern to take in the pipeline params
def pipelineParams = [:]
body.resolveStrategy = Closure.DELEGATE_FIRST
body.delegate = pipelineParams
body()
pipeline {
// the pipeline
} The My main question is, how can I test the groovy files and the pipeline itself? Is it possible in this current structure, or will I have to port everything into I've been able to set up the Pester tests for the powershell scripts fairly easily. In fact I've considered moving as much functionality out of the groovy files as I can, just so I can test it; but then the tradeoff is the loss of object permanence going in and out of powershell (since env vars can only be strings. Happy to explain this more if I'm not being clear). Is there a way to use inline assertions in the .groovy files in UPDATE May-20-2021I've landed on a combination of methods to get to a functional state. I'm still having trouble with mocking |
I have been trying to test a shared library and went the route of wrapping it in a test pipeline and using this framework to exercise it. The library has a method that looks like
def getBuildProperties(){ return readFile('file.properties')}
where readFile is a Jenkins command.My test case is set up to register the method like so,
The pipeline looks like
The error I get is,
Is there something I'm missing here or is this not supported?
Is there a mechanism for testing a shared library in a standard unit test with the ability to have the Jenkins commands available, mocked or otherwise?
The text was updated successfully, but these errors were encountered: