Skip to content

Commit 09fb03b

Browse files
committed
Integration test
1 parent 142e6f6 commit 09fb03b

File tree

11 files changed

+819
-0
lines changed

11 files changed

+819
-0
lines changed
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
/*
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for
4+
* license information.
5+
*/
6+
7+
package com.microsoft.jenkins.kubernetes.integration;
8+
9+
import com.fasterxml.jackson.databind.JsonNode;
10+
import com.fasterxml.jackson.databind.ObjectMapper;
11+
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
12+
import com.microsoft.jenkins.azurecommons.remote.SSHClient;
13+
import com.microsoft.jenkins.kubernetes.KubernetesClientWrapper;
14+
import hudson.EnvVars;
15+
import hudson.FilePath;
16+
import hudson.Launcher;
17+
import hudson.model.Run;
18+
import hudson.model.TaskListener;
19+
import hudson.security.ACL;
20+
import io.fabric8.kubernetes.api.model.extensions.Deployment;
21+
import io.fabric8.kubernetes.client.KubernetesClient;
22+
import io.fabric8.kubernetes.client.KubernetesClientException;
23+
import io.fabric8.kubernetes.client.Watch;
24+
import io.fabric8.kubernetes.client.Watcher;
25+
import org.acegisecurity.context.SecurityContextHolder;
26+
import org.apache.commons.io.FileUtils;
27+
import org.apache.commons.lang.StringUtils;
28+
import org.junit.Assert;
29+
import org.junit.Before;
30+
import org.junit.ClassRule;
31+
import org.junit.Rule;
32+
import org.junit.rules.TemporaryFolder;
33+
import org.junit.rules.Timeout;
34+
import org.jvnet.hudson.test.JenkinsRule;
35+
import org.mockito.invocation.InvocationOnMock;
36+
import org.mockito.stubbing.Answer;
37+
38+
import java.io.File;
39+
import java.io.FileOutputStream;
40+
import java.io.OutputStream;
41+
import java.io.PrintWriter;
42+
import java.util.concurrent.CountDownLatch;
43+
import java.util.concurrent.TimeUnit;
44+
import java.util.logging.Level;
45+
import java.util.logging.Logger;
46+
47+
import static com.microsoft.jenkins.kubernetes.integration.TestHelpers.loadProperty;
48+
import static org.mockito.ArgumentMatchers.any;
49+
import static org.mockito.Mockito.doAnswer;
50+
import static org.mockito.Mockito.mock;
51+
import static org.mockito.Mockito.when;
52+
53+
public abstract class IntegrationTest {
54+
private static final Logger LOGGER = Logger.getLogger(IntegrationTest.class.getName());
55+
56+
private static final ObjectMapper JSON = new ObjectMapper();
57+
private static final ObjectMapper YAML = new ObjectMapper(new YAMLFactory());
58+
59+
@ClassRule
60+
public static JenkinsRule j = new JenkinsRule() {{
61+
// disable the default 180s timeout
62+
timeout = -1;
63+
}};
64+
65+
@Rule
66+
public TemporaryFolder tmpFolder = new TemporaryFolder();
67+
68+
@Rule
69+
public Timeout globalTimeout = new Timeout(30, TimeUnit.MINUTES);
70+
71+
public final String masterHost;
72+
public final int port;
73+
public final String adminUser;
74+
public final String privateKeyPath;
75+
76+
public final String dockerRegistry;
77+
public final String dockerUsername;
78+
public final String dockerPassword;
79+
public final String dockerRepository;
80+
81+
public File workspaceKubeConfig;
82+
83+
public JsonNode config;
84+
85+
public String serverUrl;
86+
public String certificateAuthorityData;
87+
public String clientCertificateData;
88+
public String clientKeyData;
89+
90+
protected Run run;
91+
protected FilePath workspace;
92+
protected Launcher launcher;
93+
protected TaskListener taskListener;
94+
95+
protected EnvVars envVars = new EnvVars();
96+
97+
public IntegrationTest() {
98+
String host = loadProperty("KUBERNETES_CD_MASTER_HOST");
99+
String[] parts = host.split(",", 2);
100+
masterHost = StringUtils.trimToNull(parts[0]);
101+
port = parts.length == 2 ? Integer.parseInt(StringUtils.trimToNull(parts[1])) : 22;
102+
adminUser = loadProperty("KUBERNETES_CD_ADMIN_USER", "azureuser");
103+
privateKeyPath = loadProperty("KUBERNETES_CD_KEY_PATH", new File(System.getProperty("user.home"), ".ssh/id_rsa").getAbsolutePath());
104+
105+
dockerRegistry = loadProperty("KUBERNETES_CD_DOCKER_REGISTRY");
106+
dockerUsername = loadProperty("KUBERNETES_CD_DOCKER_USERNAME");
107+
dockerPassword = loadProperty("KUBERNETES_CD_DOCKER_PASSWORD");
108+
dockerRepository = loadProperty("KUBERNETES_CD_DOCKER_REPOSITORY");
109+
110+
Assert.assertTrue("Master host is not configured in environment", StringUtils.isNotEmpty(masterHost));
111+
}
112+
113+
@Before
114+
public void setup() throws Exception {
115+
SecurityContextHolder.getContext().setAuthentication(ACL.SYSTEM);
116+
117+
SSHClient client = new SSHClient(masterHost, port, adminUser, null, FileUtils.readFileToString(new File(privateKeyPath)));
118+
workspaceKubeConfig = tmpFolder.newFile();
119+
try (SSHClient connected = client.connect()) {
120+
try (OutputStream os = new FileOutputStream(workspaceKubeConfig)) {
121+
connected.copyFrom(".kube/config", os);
122+
}
123+
}
124+
try {
125+
config = YAML.readTree(workspaceKubeConfig);
126+
} catch (Exception e) {
127+
config = JSON.readTree(workspaceKubeConfig);
128+
}
129+
130+
serverUrl = config.at("/clusters/0/cluster/server").asText();
131+
certificateAuthorityData = config.at("/clusters/0/cluster/certificate-authority-data").asText();
132+
clientCertificateData = config.at("/users/0/user/client-certificate-data").asText();
133+
clientKeyData = config.at("/users/0/user/client-key-data").asText();
134+
135+
workspace = new FilePath(tmpFolder.getRoot());
136+
137+
run = mock(Run.class);
138+
launcher = mock(Launcher.class);
139+
140+
taskListener = mock(TaskListener.class);
141+
when(taskListener.getLogger()).thenReturn(System.err);
142+
doAnswer(new Answer<PrintWriter>() {
143+
@Override
144+
public PrintWriter answer(InvocationOnMock invocationOnMock) throws Throwable {
145+
String msg = invocationOnMock.getArgument(0);
146+
System.err.print(msg);
147+
return new PrintWriter(System.err);
148+
}
149+
}).when(taskListener).error(any(String.class));
150+
when(run.getDisplayName()).thenReturn("acs-test-run");
151+
when(run.getEnvironment(any(TaskListener.class))).thenReturn(envVars);
152+
}
153+
154+
protected class DeploymentWatcher implements AutoCloseable {
155+
final String name;
156+
final Watch deploymentWatch;
157+
final CountDownLatch latch;
158+
159+
public DeploymentWatcher(String namespace, String name) {
160+
this.name = name;
161+
latch = new CountDownLatch(1);
162+
KubernetesClient client = new KubernetesClientWrapper(workspaceKubeConfig.getAbsolutePath()).getClient();
163+
deploymentWatch =
164+
client.extensions()
165+
.deployments()
166+
.inNamespace(namespace)
167+
.withName(name)
168+
.watch(new Watcher<Deployment>() {
169+
@Override
170+
public void eventReceived(Action action, Deployment deployment) {
171+
Integer availableReplica = deployment.getStatus().getAvailableReplicas();
172+
if (availableReplica != null && availableReplica > 0) {
173+
latch.countDown();
174+
}
175+
}
176+
177+
@Override
178+
public void onClose(KubernetesClientException e) {
179+
if (e != null) {
180+
LOGGER.log(Level.SEVERE, null, e);
181+
throw e;
182+
}
183+
}
184+
});
185+
}
186+
187+
public void waitReady(long timeout, TimeUnit tu) throws InterruptedException {
188+
if (!latch.await(timeout, tu)) {
189+
Assert.fail("Timeout while waiting for the deployment " + name + " to become ready");
190+
}
191+
}
192+
193+
@Override
194+
public void close() {
195+
if (deploymentWatch != null) {
196+
deploymentWatch.close();
197+
}
198+
}
199+
}
200+
}

0 commit comments

Comments
 (0)