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

Accessing constant from another file #616

Open
stefan6419846 opened this issue Aug 3, 2023 · 2 comments
Open

Accessing constant from another file #616

stefan6419846 opened this issue Aug 3, 2023 · 2 comments

Comments

@stefan6419846
Copy link

stefan6419846 commented Aug 3, 2023

Describe your use-case which is not covered by existing documentation.

I am currently trying to dig through the existing docs and issues to get a grasp on how the following case should be handled correctly, but everything I tried seems to fail in the one or the other way.

Let's suppose we have the following files which are running fine in Jenkins itself (this is a very simplified example):

// vars/Constants.groovy

class Constants {
    public static final String KEY = "KEY"
}
// vars/utils.groovy

void setValue(Map data) {
    data[Constants.KEY] = params.newValue
}

Now I want to test that setting the value actually works:

// tests/groovy/vars/test_utils.groovy

package tests.groovy.vars

import org.junit.jupiter.api.Test
import org.junit.jupiter.api.BeforeEach

import com.lesfurets.jenkins.unit.BasePipelineTest

class UtilsTest extends BasePipelineTest {

    Object script = null
    Object constants = null

    @Override
    @BeforeEach
    void setUp() {
        super.setUp()

        this.script = loadScript('vars/utils.groovy')
        assert script != null

        this.constants = loadScript('vars/Constants.groovy')
        assert constants != null
        binding.setVariable('Constants', constants)
        script.constants = constants
    }

    @Test
    void testSetValue() {
        Map data = ['key': 0, 'another_key': 1]
        assert data.key == 0
        this.script.setValue(data, 42)
        assert data.key == 42
    }

But it seems like the constants are not available inside the corresponding method, as well as I could not get it working to access them from the test class as well:

UtilsTest > testSetValue() FAILED
    groovy.lang.MissingPropertyException: No such property: KEY for class: org.codehaus.groovy.runtime.InvokerHelper$2
        at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:67)
        at org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.unwrap(IndyGuardsFiltersAndSignatures.java:161)
        at org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache(IndyInterface.java:321)
        at utils.setValue(utils.groovy:7)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:343)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:328)
        at groovy.lang.MetaMethod$doMethodInvoke.call(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
        at groovy.lang.MetaMethod$doMethodInvoke.call(Unknown Source)
        at com.lesfurets.jenkins.unit.PipelineTestHelper.callMethod(PipelineTestHelper.groovy:323)
        at jdk.internal.reflect.GeneratedMethodAccessor48.invoke(Unknown Source)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:343)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:328)
        at groovy.lang.MetaClassImpl.doInvokeMethod(MetaClassImpl.java:1332)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1087)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1006)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:789)
        at com.lesfurets.jenkins.unit.PipelineTestHelper.invokeMethod(PipelineTestHelper.groovy)
        at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:70)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:203)
        at com.lesfurets.jenkins.unit.PipelineTestHelper$_closure3.doCall(PipelineTestHelper.groovy:310)
        at jdk.internal.reflect.GeneratedMethodAccessor40.invoke(Unknown Source)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:343)
        at org.codehaus.groovy.runtime.metaclass.ClosureMetaMethod.invoke(ClosureMetaMethod.java:88)
        at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1140)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1006)
        at org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache(IndyInterface.java:321)
        at tests.groovy.vars.UtilsTest.testSetValue(UtilsTest.groovy:34)

What would be the preferred way to grant both the implementation and the tests access to the constants defined inside the Constants class?

Reference any relevant documentation, other materials or issues/pull requests that can be used for inspiration.

No response

@TheFriendlyCoder
Copy link

I am having a very similar issue to the one reported here. Are there any recommendations on how to handle this use case?

@stefan6419846
Copy link
Author

If I remember correctly, this might be solved by using a proper package structure for the pipeline implementation, especially the constants class used here. As a workaround, I am currently maintaining a more or less identical copy in the tests directory and have the following snippets in my base test class:

package tests.groovy.vars

import org.junit.jupiter.api.BeforeEach

import com.lesfurets.jenkins.unit.BasePipelineTest

import tests.groovy.Constants

class UtilsBaseTest extends BasePipelineTest {

    protected Object utils
    protected Class constants = Constants

    @Override
    @BeforeEach
    void setUp() {
        super.setUp()

        this.utils = loadScript('vars/utils.groovy')
        assert utils != null

        utils.Constants = Constants
    }
}

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

No branches or pull requests

2 participants