diff --git a/src/main/groovy/com/lesfurets/jenkins/unit/BasePipelineTest.groovy b/src/main/groovy/com/lesfurets/jenkins/unit/BasePipelineTest.groovy index f6555a92..cae8f334 100644 --- a/src/main/groovy/com/lesfurets/jenkins/unit/BasePipelineTest.groovy +++ b/src/main/groovy/com/lesfurets/jenkins/unit/BasePipelineTest.groovy @@ -1,5 +1,7 @@ package com.lesfurets.jenkins.unit +import com.lesfurets.jenkins.unit.global.lib.LibraryLoader + import static java.util.stream.Collectors.joining import static org.assertj.core.api.Assertions.assertThat diff --git a/src/main/groovy/com/lesfurets/jenkins/unit/PipelineTestHelper.groovy b/src/main/groovy/com/lesfurets/jenkins/unit/PipelineTestHelper.groovy index e9a71112..a8362b05 100644 --- a/src/main/groovy/com/lesfurets/jenkins/unit/PipelineTestHelper.groovy +++ b/src/main/groovy/com/lesfurets/jenkins/unit/PipelineTestHelper.groovy @@ -238,6 +238,10 @@ class PipelineTestHelper { Map mockReadFileOutputs = [:] + private static final Map scriptClasses = [:] + + private boolean shouldCacheScriptsAndLibraries = false + /** * Get library loader object * @@ -248,6 +252,18 @@ class PipelineTestHelper { return this.libLoader } + PipelineTestHelper withShouldCacheScriptsAndLibraries(boolean shouldCacheScriptsAndLibraries) { + this.shouldCacheScriptsAndLibraries = shouldCacheScriptsAndLibraries + return this + } + + /** + * Clears the cache of loaded script classes + */ + static void clearScriptClasses() { + scriptClasses.clear() + } + /** * Method interceptor for method 'load' to load scripts via encapsulated GroovyScriptEngine */ @@ -431,6 +447,11 @@ class PipelineTestHelper { LibraryAnnotationTransformer libraryTransformer = new LibraryAnnotationTransformer(libLoader) configuration.addCompilationCustomizers(libraryTransformer) + if (!shouldCacheScriptsAndLibraries) { + clearScriptClasses() + LibraryLoader.clearLibRecords() + } + ImportCustomizer importCustomizer = new ImportCustomizer() imports.each { k, v -> importCustomizer.addImport(k, v) } configuration.addCompilationCustomizers(importCustomizer) @@ -541,7 +562,11 @@ class PipelineTestHelper { Script loadScript(String scriptName, Binding binding) { Objects.requireNonNull(binding, "Binding cannot be null.") Objects.requireNonNull(gse, "GroovyScriptEngine is not initialized: Initialize the helper by calling init().") - Class scriptClass = gse.loadScriptByName(scriptName) + Class scriptClass = scriptClasses.get(scriptName) + if (scriptClass == null) { + scriptClass = gse.loadScriptByName(scriptName) + scriptClasses.put(scriptName, scriptClass) + } setGlobalVars(binding) Script script = InvokerHelper.createScript(scriptClass, binding) InterceptingGCL.interceptClassMethods(script.metaClass, this, binding) diff --git a/src/main/groovy/com/lesfurets/jenkins/unit/global/lib/LibraryLoader.groovy b/src/main/groovy/com/lesfurets/jenkins/unit/global/lib/LibraryLoader.groovy index 7df7d718..bb037b27 100644 --- a/src/main/groovy/com/lesfurets/jenkins/unit/global/lib/LibraryLoader.groovy +++ b/src/main/groovy/com/lesfurets/jenkins/unit/global/lib/LibraryLoader.groovy @@ -35,7 +35,7 @@ class LibraryLoader { //classes want to access the binding env. Boolean preloadLibraryClasses = true - final Map libRecords = new HashMap<>() + static final Map libRecords = new HashMap<>() LibraryLoader(GroovyClassLoader groovyClassLoader, Map libraryDescriptions) { this.groovyClassLoader = groovyClassLoader @@ -66,6 +66,13 @@ class LibraryLoader { } } + /** + * Clears the cache of lib records + */ + static void clearLibRecords() { + libRecords.clear() + } + /** * Load library described by expression if it corresponds to a known library configuration * @param expression diff --git a/src/test/groovy/com/lesfurets/jenkins/TestLibraryAndScriptCaching.groovy b/src/test/groovy/com/lesfurets/jenkins/TestLibraryAndScriptCaching.groovy new file mode 100644 index 00000000..1b7cf538 --- /dev/null +++ b/src/test/groovy/com/lesfurets/jenkins/TestLibraryAndScriptCaching.groovy @@ -0,0 +1,71 @@ +package com.lesfurets.jenkins + +import com.lesfurets.jenkins.unit.BasePipelineTest +import com.lesfurets.jenkins.unit.global.lib.LibraryLoader +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test + +import static com.lesfurets.jenkins.unit.global.lib.LibraryConfiguration.library +import static com.lesfurets.jenkins.unit.global.lib.ProjectSource.projectSource +import static org.junit.jupiter.api.Assertions.assertEquals +import static org.junit.jupiter.api.Assertions.assertNotEquals + +class TestLibraryAndScriptCaching extends BasePipelineTest { + + @Override + @BeforeEach + void setUp() throws Exception { + scriptRoots += 'src/test/jenkins' + super.setUp() + } + + private final library = library().name('commons') + .defaultVersion('') + .allowOverride(false) + .implicit(false) + .targetPath('') + .retriever(projectSource(this.class.getResource('/libs/commons@master').getFile())) + .build() + + @Test + void scriptCacheDisabled() { + def script1 = loadScript('job/exampleJob.jenkins') + helper.init() + def script2 = loadScript('job/exampleJob.jenkins') + assertNotEquals(script1.metaClass.theClass, script2.metaClass.theClass) + } + + @Test + void scriptCacheEnabledDisabled() { + helper.withShouldCacheScriptsAndLibraries(true) + def script1 = loadScript('job/exampleJob.jenkins') + helper.init() + def script2 = loadScript('job/exampleJob.jenkins') + assertEquals(script1.metaClass.theClass, script2.metaClass.theClass) + } + + @Test + void libraryCacheDisabled() { + helper.registerSharedLibrary(library) + helper.libLoader.loadLibrary(library.name) + def lib1 = LibraryLoader.libRecords.get("commons@") + helper.init() + helper.registerSharedLibrary(library) + helper.libLoader.loadLibrary(library.name) + def lib2 = LibraryLoader.libRecords.get("commons@") + assertNotEquals(lib1, lib2) + } + + @Test + void libraryCacheEnabled() { + helper.withShouldCacheScriptsAndLibraries(true) + helper.registerSharedLibrary(library) + helper.libLoader.loadLibrary(library.name) + def lib1 = LibraryLoader.libRecords.get("commons@") + helper.init() + helper.registerSharedLibrary(library) + helper.libLoader.loadLibrary(library.name) + def lib2 = LibraryLoader.libRecords.get("commons@") + assertEquals(lib1, lib2) + } +}