Skip to content

Commit 9e20d78

Browse files
committed
SCMSourceRetrieverTest: checkDefaultVersion_inline_allowVersionEnvvar(): play with "built-in" node envvars [JENKINS-69731]
1 parent 71c51c8 commit 9e20d78

File tree

1 file changed

+170
-10
lines changed

1 file changed

+170
-10
lines changed

src/test/java/org/jenkinsci/plugins/workflow/libs/SCMSourceRetrieverTest.java

Lines changed: 170 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,24 +31,29 @@
3131
import hudson.ExtensionList;
3232
import hudson.FilePath;
3333
import hudson.Functions;
34-
import hudson.model.BuildVariableContributor;
34+
import hudson.model.Computer;
3535
import hudson.model.EnvironmentContributingAction;
3636
import hudson.model.EnvironmentContributor;
3737
import hudson.model.Item;
3838
import hudson.model.Job;
39+
import hudson.model.Node;
3940
import hudson.model.Result;
4041
import hudson.model.Run;
4142
import hudson.model.TaskListener;
4243
import hudson.plugins.git.GitSCM;
4344
import hudson.plugins.git.BranchSpec;
45+
import hudson.remoting.VirtualChannel;
4446
import hudson.scm.ChangeLogSet;
4547
import hudson.scm.SCM;
4648
import hudson.slaves.EnvironmentVariablesNodeProperty;
4749
import hudson.slaves.NodeProperty;
4850
import hudson.slaves.NodePropertyDescriptor;
51+
import hudson.slaves.OfflineCause;
52+
import hudson.slaves.WorkspaceList;
4953
import hudson.slaves.WorkspaceList;
5054
import java.io.File;
5155
import java.io.IOException;
56+
import java.lang.reflect.Field;
5257
import java.nio.charset.StandardCharsets;
5358
import java.nio.file.Files;
5459
import java.nio.file.Path;
@@ -57,11 +62,11 @@
5762
import java.util.Collections;
5863
import java.util.Iterator;
5964
import java.util.List;
60-
import java.util.TreeMap;
6165
import hudson.util.DescribableList;
6266
import jenkins.branch.BranchProperty;
6367
import jenkins.branch.BranchSource;
6468
import jenkins.branch.DefaultBranchPropertyStrategy;
69+
import jenkins.model.Jenkins;
6570
import jenkins.plugins.git.GitSCMSource;
6671
import jenkins.plugins.git.GitSampleRepoRule;
6772
import jenkins.scm.api.SCMHead;
@@ -1020,7 +1025,7 @@ public class SCMSourceRetrieverTest {
10201025
// TEST_VAR_NAME injected into env, use its value for library checkout
10211026
// https://github.com/jenkinsci/envinject-plugin/blob/master/src/test/java/org/jenkinsci/plugins/envinject/EnvInjectPluginActionTest.java
10221027
WorkflowJob p1 = r.jenkins.createProject(WorkflowJob.class, "p1");
1023-
p1.setDefinition(new CpsFlowDefinition("@Library('branchylib@${env.TEST_VAR_NAME}') import myecho; myecho(); echo \"Groovy TEST_VAR_NAME='${TEST_VAR_NAME}'\"; echo \"env.TEST_VAR_NAME='${env.TEST_VAR_NAME}'\"", true));
1028+
p1.setDefinition(new CpsFlowDefinition("@Library('branchylib@${env.TEST_VAR_NAME}') import myecho; myecho(); try { echo \"Groovy TEST_VAR_NAME='${TEST_VAR_NAME}'\"; } catch (groovy.lang.MissingPropertyException mpe) { echo \"Groovy TEST_VAR_NAME missing: ${mpe.getMessage()}\"; } ; echo \"env.TEST_VAR_NAME='${env.TEST_VAR_NAME}'\"", true));
10241029

10251030
// Inject envvar to server global settings:
10261031
DescribableList<NodeProperty<?>, NodePropertyDescriptor> globalNodeProperties = r.jenkins.getGlobalNodeProperties();
@@ -1116,13 +1121,168 @@ public class SCMSourceRetrieverTest {
11161121
r.assertLogContains("Loading library branchylib@feature", b3);
11171122
r.assertLogContains("something very special", b3);
11181123

1119-
// TODO: similar trick with built-in agent settings
1120-
// which has lowest priority behind global and injected
1121-
// envvars (see Run::getEnvironment()). Check with the
1122-
// override above, and with ecList contents restored to
1123-
// ecOrig state only.
1124-
//p1.setAssignedNode(r.createSlave());
1125-
//p1.getEnvironment(r.jenkins.getNode("built-in"), null).put("TEST_VAR_NAME", "feature");
1124+
// Below we do a similar trick with built-in agent settings
1125+
// which (as a Computer=>Node) has lowest priority behind
1126+
// global and injected envvars (see Run::getEnvironment()).
1127+
// Check with the injected envvars (they override) like above
1128+
// first, and with ecList contents restored to ecOrig state
1129+
// only (so only Computer envvars are applied).
1130+
// Trick here is that the "jenkins.model.Jenkins" is inherited
1131+
// from Node and its toComputer() returns the "built-in" (nee
1132+
// "master"), instance of "hudson.model.Hudson$MasterComputer"
1133+
// whose String getName() is actually empty.
1134+
// Pipeline scripts are initially processed only by this node,
1135+
// further run on the controller, and then the actual work is
1136+
// distributed to agents (often via remoting proxy methods)
1137+
// if any are defined.
1138+
Computer builtInComputer = r.jenkins.toComputer();
1139+
Node builtInNode = builtInComputer.getNode();
1140+
/*
1141+
EnvironmentVariablesNodeProperty builtInEnvProp = builtInNode.getNodeProperty(EnvironmentVariablesNodeProperty.class);
1142+
1143+
if (builtInEnvProp == null) {
1144+
builtInEnvProp = new EnvironmentVariablesNodeProperty();
1145+
//builtInEnvProp.setNode(builtInNode);
1146+
builtInNode.getNodeProperties().add(builtInEnvProp);
1147+
}
1148+
EnvVars builtInEnvVars = builtInEnvProp.getEnvVars();
1149+
builtInEnvVars.put("TEST_VAR_NAME", "stable");
1150+
builtInEnvProp.buildEnvVars(new EnvVars("TEST_VAR_NAME", "stable"), null);
1151+
*/
1152+
builtInNode.getNodeProperties().add(new EnvironmentVariablesNodeProperty(new EnvironmentVariablesNodeProperty.Entry("TEST_VAR_NAME", "stable")));
1153+
r.jenkins.save();
1154+
builtInNode.save();
1155+
1156+
System.out.println("[DEBUG] Restart the 'built-in' Computer connection to clear its cachedEnvironment and recognize added envvar");
1157+
builtInComputer.setTemporarilyOffline(true, new OfflineCause.ByCLI("Restart built-in to reread envvars config"));
1158+
builtInComputer.waitUntilOffline();
1159+
builtInComputer.disconnect(new OfflineCause.ByCLI("Restart built-in to reread envvars config"));
1160+
r.waitUntilNoActivity();
1161+
Thread.sleep(3000);
1162+
builtInComputer.setTemporarilyOffline(false, null);
1163+
builtInComputer.connect(true);
1164+
builtInComputer.waitUntilOnline();
1165+
1166+
System.out.println("[DEBUG] builtIn node env: " + builtInComputer.getEnvironment());
1167+
1168+
// Both injected var and build node envvar setting present;
1169+
// injected var wins:
1170+
WorkflowRun b4 = r.buildAndAssertSuccess(p1);
1171+
System.out.println("[DEBUG:EXT:p1b4] wfJob env: " + p1.getEnvironment(null, null));
1172+
System.out.println("[DEBUG:EXT:p1b4] wfRun env: " + b4.getEnvironment());
1173+
System.out.println("[DEBUG:EXT:p1b4] wfRun envContribActions: " + b4.getActions(EnvironmentContributingAction.class));
1174+
r.assertLogContains("Loading library branchylib@feature", b4);
1175+
r.assertLogContains("something very special", b4);
1176+
r.assertLogContains("Groovy TEST_VAR_NAME='feature'", b4);
1177+
r.assertLogContains("env.TEST_VAR_NAME='feature'", b4);
1178+
1179+
// Only build agent envvars are present: drop all,
1180+
// add back original (before our mock above):
1181+
List<EnvironmentContributor> ecCurr = new ArrayList();
1182+
for (EnvironmentContributor ec : ecList) {
1183+
ecCurr.add(ec);
1184+
}
1185+
ecList.removeAll(ecCurr);
1186+
for (EnvironmentContributor ec : ecOrig) {
1187+
ecList.add(ec);
1188+
}
1189+
1190+
System.out.println("[DEBUG:EXT:p1b5] EnvironmentContributor.all(): " + EnvironmentContributor.all());
1191+
System.out.println("[DEBUG:EXT:p1b5] builtIn node env: " + builtInComputer.getEnvironment());
1192+
System.out.println("[DEBUG:EXT:p1b5] wfJob env in builtIn: " + p1.getEnvironment(builtInNode, null));
1193+
System.out.println("[DEBUG:EXT:p1b5] wfJob env (without node): " + p1.getEnvironment(null, null));
1194+
WorkflowRun b5 = r.buildAndAssertSuccess(p1);
1195+
System.out.println("[DEBUG:EXT:p1b5] wfRun env: " + b5.getEnvironment());
1196+
System.out.println("[DEBUG:EXT:p1b5] wfRun envContribActions: " + b5.getActions(EnvironmentContributingAction.class));
1197+
r.assertLogContains("Loading library branchylib@stable", b5);
1198+
r.assertLogContains("something reliable", b5);
1199+
// Why oh why is the build agent's (cached) envvar not resolved
1200+
// even after reconnect?.. Probably a burden of "built-in" until
1201+
// Jenkins restart?..
1202+
r.assertLogContains("Groovy TEST_VAR_NAME missing", b5);
1203+
r.assertLogContains("env.TEST_VAR_NAME='null'", b5);
1204+
1205+
// Let's try just that - restart Jenkins to fully reinit the
1206+
// built-in node with its config:
1207+
r.jenkins.reload();
1208+
r.waitUntilNoActivity();
1209+
1210+
WorkflowRun b6 = r.buildAndAssertSuccess(p1);
1211+
r.assertLogContains("Loading library branchylib@stable", b6);
1212+
r.assertLogContains("something reliable", b6);
1213+
r.assertLogContains("Groovy TEST_VAR_NAME missing", b6);
1214+
r.assertLogContains("env.TEST_VAR_NAME='null'", b6);
1215+
1216+
Thread.sleep(160000);
1217+
}
1218+
1219+
@Issue("JENKINS-69731")
1220+
@Test public void checkDefaultVersion_inline_allowVersionEnvvar_builtIn() throws Exception {
1221+
// Test that @Library('branchylib@${env.TEST_VAR_NAME}')
1222+
// is resolved with the TEST_VAR_NAME="feature" in the
1223+
// "built-in" node environment settings.
1224+
1225+
// Do not let caller-provided BRANCH_NAME interfere here
1226+
assumeFalse("An externally provided TEST_VAR_NAME envvar interferes with tested logic",
1227+
System.getenv("TEST_VAR_NAME") != null);
1228+
1229+
// First apply the "built-in node", then touch Jenkins jobs:
1230+
Computer builtInComputer = r.jenkins.toComputer();
1231+
Node builtInNode = builtInComputer.getNode();
1232+
builtInNode.getNodeProperties().add(new EnvironmentVariablesNodeProperty(new EnvironmentVariablesNodeProperty.Entry("TEST_VAR_NAME", "stable")));
1233+
r.jenkins.save();
1234+
builtInNode.save();
1235+
1236+
System.out.println("[DEBUG] Restart the 'built-in' Computer connection to clear its cachedEnvironment and recognize added envvar");
1237+
builtInComputer.setTemporarilyOffline(true, new OfflineCause.ByCLI("Restart built-in to reread envvars config"));
1238+
builtInComputer.disconnect(new OfflineCause.ByCLI("Restart built-in to reread envvars config"));
1239+
builtInComputer.waitUntilOffline();
1240+
r.waitUntilNoActivity();
1241+
builtInComputer.getChannel().close();
1242+
Thread.sleep(3000);
1243+
r.jenkins.reload();
1244+
builtInComputer.setTemporarilyOffline(false, null);
1245+
builtInComputer.connect(true);
1246+
builtInComputer.waitUntilOnline();
1247+
r.waitUntilNoActivity();
1248+
1249+
// Feed it to Java reflection, to clear the internal cache...
1250+
Field ccc = Computer.class.getDeclaredField("cachedEnvironment");
1251+
ccc.setAccessible(true);
1252+
ccc.set(builtInComputer, null);
1253+
1254+
System.out.println("[DEBUG] builtIn node env: " + builtInComputer.getEnvironment());
1255+
1256+
sampleRepo.init();
1257+
sampleRepo.write("vars/myecho.groovy", "def call() {echo 'something special'}");
1258+
sampleRepo.git("add", "vars");
1259+
sampleRepo.git("commit", "--message=init");
1260+
sampleRepo.git("checkout", "-b", "feature");
1261+
sampleRepo.write("vars/myecho.groovy", "def call() {echo 'something very special'}");
1262+
sampleRepo.git("add", "vars");
1263+
sampleRepo.git("commit", "--message=init");
1264+
sampleRepo.git("checkout", "-b", "stable");
1265+
sampleRepo.write("vars/myecho.groovy", "def call() {echo 'something reliable'}");
1266+
sampleRepo.git("add", "vars");
1267+
sampleRepo.git("commit", "--message=init");
1268+
SCMSourceRetriever scm = new SCMSourceRetriever(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", true));
1269+
LibraryConfiguration lc = new LibraryConfiguration("branchylib", scm);
1270+
lc.setDefaultVersion("master");
1271+
lc.setIncludeInChangesets(false);
1272+
lc.setAllowVersionOverride(true);
1273+
lc.setAllowVersionEnvvar(true);
1274+
lc.setTraceDefaultedVersion(true);
1275+
GlobalLibraries.get().setLibraries(Collections.singletonList(lc));
1276+
1277+
WorkflowJob p1 = r.jenkins.createProject(WorkflowJob.class, "p1");
1278+
p1.setDefinition(new CpsFlowDefinition("@Library('branchylib@${env.TEST_VAR_NAME}') import myecho; myecho(); try { echo \"Groovy TEST_VAR_NAME='${TEST_VAR_NAME}'\"; } catch (groovy.lang.MissingPropertyException mpe) { echo \"Groovy TEST_VAR_NAME missing: ${mpe.getMessage()}\"; } ; echo \"env.TEST_VAR_NAME='${env.TEST_VAR_NAME}'\"", true));
1279+
1280+
WorkflowRun b6 = r.buildAndAssertSuccess(p1);
1281+
r.assertLogContains("Loading library branchylib@stable", b6);
1282+
r.assertLogContains("something reliable", b6);
1283+
r.assertLogContains("Groovy TEST_VAR_NAME missing", b6);
1284+
r.assertLogContains("env.TEST_VAR_NAME='null'", b6);
1285+
11261286
}
11271287

11281288
@Issue("JENKINS-43802")

0 commit comments

Comments
 (0)