Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit e499c21

Browse filesBrowse files
committed
Improve unit testing.
1 parent 52f847c commit e499c21
Copy full SHA for e499c21

File tree

Expand file treeCollapse file tree

9 files changed

+571
-23
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

9 files changed

+571
-23
lines changed
Open diff view settings
Collapse file

‎util/src/main/java/io/kubernetes/client/Copy.java‎

Copy file name to clipboardExpand all lines: util/src/main/java/io/kubernetes/client/Copy.java
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ public void copyDirectoryFromPod(
116116
false,
117117
false);
118118
InputStream is = new Base64InputStream(new BufferedInputStream(proc.getInputStream()));
119-
try (ArchiveInputStream archive =
120-
new TarArchiveInputStream(is)) { // new GzipCompressorInputStream(is))) {
119+
try (ArchiveInputStream archive = new TarArchiveInputStream(is)) {
120+
// TODO Use new GzipCompressorInputStream(is))) here {
121121
for (ArchiveEntry entry = archive.getNextEntry();
122122
entry != null;
123123
entry = archive.getNextEntry()) {
Collapse file

‎util/src/main/java/io/kubernetes/client/Exec.java‎

Copy file name to clipboardExpand all lines: util/src/main/java/io/kubernetes/client/Exec.java
+3-3Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ public Process exec(
199199
throws ApiException, IOException {
200200
String path = makePath(namespace, name, command, container, stdin, tty);
201201

202-
ExecProcess exec = new ExecProcess();
202+
ExecProcess exec = new ExecProcess(apiClient);
203203
WebSocketStreamHandler handler = exec.getHandler();
204204
WebSockets.stream(path, "GET", apiClient, handler);
205205

@@ -245,13 +245,13 @@ static int parseExitCode(ApiClient client, InputStream inputStream) {
245245
return -1;
246246
}
247247

248-
private class ExecProcess extends Process {
248+
protected static class ExecProcess extends Process {
249249
private final WebSocketStreamHandler streamHandler;
250250
private int statusCode = -1;
251251
private boolean isAlive = true;
252252
private final Map<Integer, InputStream> input = new HashMap<>();
253253

254-
public ExecProcess() throws IOException {
254+
public ExecProcess(final ApiClient apiClient) throws IOException {
255255
this.streamHandler =
256256
new WebSocketStreamHandler() {
257257
@Override
Collapse file

‎util/src/main/java/io/kubernetes/client/PodLogs.java‎

Copy file name to clipboardExpand all lines: util/src/main/java/io/kubernetes/client/PodLogs.java
+7-1Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ public ApiClient getApiClient() {
4949
}
5050

5151
public InputStream streamNamespacedPodLog(V1Pod pod) throws ApiException, IOException {
52+
if (pod.getSpec() == null) {
53+
throw new ApiException("pod.spec is null and container isn't specified.");
54+
}
55+
if (pod.getSpec().getContainers() == null || pod.getSpec().getContainers().size() < 1) {
56+
throw new ApiException("pod.spec.containers has no containers");
57+
}
5258
return streamNamespacedPodLog(
5359
pod.getMetadata().getNamespace(),
5460
pod.getMetadata().getName(),
@@ -86,7 +92,7 @@ public InputStream streamNamespacedPodLog(
8692
null);
8793
Response response = call.execute();
8894
if (!response.isSuccessful()) {
89-
throw new ApiException("Logs request failed: " + response.code());
95+
throw new ApiException(response.code(), "Logs request failed: " + response.code());
9096
}
9197
return response.body().byteStream();
9298
}
Collapse file
+86Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
Copyright 2018 The Kubernetes Authors.
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
package io.kubernetes.client;
14+
15+
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
16+
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
17+
import static com.github.tomakehurst.wiremock.client.WireMock.get;
18+
import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
19+
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
20+
import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
21+
import static com.github.tomakehurst.wiremock.client.WireMock.verify;
22+
23+
import com.github.tomakehurst.wiremock.junit.WireMockRule;
24+
import io.kubernetes.client.Attach.AttachResult;
25+
import io.kubernetes.client.util.ClientBuilder;
26+
import java.io.IOException;
27+
import org.junit.Before;
28+
import org.junit.Rule;
29+
import org.junit.Test;
30+
31+
/** Tests for the Attach helper class */
32+
public class AttachTest {
33+
private String namespace;
34+
private String podName;
35+
private String container;
36+
37+
private ApiClient client;
38+
39+
private static final int PORT = 8089;
40+
@Rule public WireMockRule wireMockRule = new WireMockRule(PORT);
41+
42+
@Before
43+
public void setup() throws IOException {
44+
client = new ClientBuilder().setBasePath("http://localhost:" + PORT).build();
45+
46+
namespace = "default";
47+
podName = "apod";
48+
container = "acontainer";
49+
}
50+
51+
@Test
52+
public void testUrl() throws IOException, ApiException, InterruptedException {
53+
Attach attach = new Attach(client);
54+
55+
stubFor(
56+
get(urlPathEqualTo("/api/v1/namespaces/" + namespace + "/pods/" + podName + "/attach"))
57+
.willReturn(
58+
aResponse()
59+
.withStatus(404)
60+
.withHeader("Content-Type", "application/json")
61+
.withBody("{}")));
62+
63+
AttachResult res1 = attach.attach(namespace, podName, container, false, false);
64+
AttachResult res2 = attach.attach(namespace, podName, true);
65+
66+
// TODO: Kill this sleep, the trouble is that the test tries to validate before the connection
67+
// event has happened
68+
Thread.sleep(2000);
69+
70+
res1.close();
71+
res2.close();
72+
73+
verify(
74+
getRequestedFor(
75+
urlPathEqualTo("/api/v1/namespaces/" + namespace + "/pods/" + podName + "/attach"))
76+
.withQueryParam("stdin", equalTo("false"))
77+
.withQueryParam("tty", equalTo("false"))
78+
.withQueryParam("container", equalTo(container)));
79+
80+
verify(
81+
getRequestedFor(
82+
urlPathEqualTo("/api/v1/namespaces/" + namespace + "/pods/" + podName + "/attach"))
83+
.withQueryParam("stdin", equalTo("true"))
84+
.withQueryParam("tty", equalTo("false")));
85+
}
86+
}
Collapse file
+75Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
Copyright 2018 The Kubernetes Authors.
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
package io.kubernetes.client;
14+
15+
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
16+
import static com.github.tomakehurst.wiremock.client.WireMock.get;
17+
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
18+
import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
19+
20+
import com.github.tomakehurst.wiremock.junit.WireMockRule;
21+
import io.kubernetes.client.models.V1ObjectMeta;
22+
import io.kubernetes.client.models.V1Pod;
23+
import io.kubernetes.client.util.ClientBuilder;
24+
import java.io.IOException;
25+
import java.io.InputStream;
26+
import org.junit.Before;
27+
import org.junit.Rule;
28+
import org.junit.Test;
29+
30+
/** Tests for the Copy helper class */
31+
public class CopyTest {
32+
private String namespace;
33+
private String podName;
34+
private String[] cmd;
35+
36+
private ApiClient client;
37+
38+
private static final int PORT = 8089;
39+
@Rule public WireMockRule wireMockRule = new WireMockRule(PORT);
40+
41+
@Before
42+
public void setup() throws IOException {
43+
client = new ClientBuilder().setBasePath("http://localhost:" + PORT).build();
44+
45+
namespace = "default";
46+
podName = "apod";
47+
}
48+
49+
@Test
50+
public void testUrl() throws IOException, ApiException, InterruptedException {
51+
Copy copy = new Copy(client);
52+
53+
V1Pod pod = new V1Pod().metadata(new V1ObjectMeta().name(podName).namespace(namespace));
54+
55+
stubFor(
56+
get(urlPathEqualTo("/api/v1/namespaces/" + namespace + "/pods/" + podName + "/exec"))
57+
.willReturn(
58+
aResponse()
59+
.withStatus(404)
60+
.withHeader("Content-Type", "application/json")
61+
.withBody("{}")));
62+
63+
InputStream is = copy.copyFileFromPod(pod, "/some/path/to/file");
64+
65+
// verify(
66+
// getRequestedFor(
67+
// urlPathEqualTo("/api/v1/namespaces/" + namespace + "/pods/" + podName +
68+
// "/exec"))
69+
// .withQueryParam("stdin", equalTo("false"))
70+
// .withQueryParam("stdout", equalTo("true"))
71+
// .withQueryParam("stderr", equalTo("true"))
72+
// .withQueryParam("tty", equalTo("false"))
73+
// .withQueryParam("command", new AnythingPattern()));
74+
}
75+
}
Collapse file

‎util/src/test/java/io/kubernetes/client/ExecTest.java‎

Copy file name to clipboardExpand all lines: util/src/test/java/io/kubernetes/client/ExecTest.java
+89-17Lines changed: 89 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,21 @@
1717
import static com.github.tomakehurst.wiremock.client.WireMock.get;
1818
import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
1919
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
20-
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
2120
import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
2221
import static com.github.tomakehurst.wiremock.client.WireMock.verify;
2322
import static org.junit.Assert.assertEquals;
2423

2524
import com.github.tomakehurst.wiremock.junit.WireMockRule;
26-
27-
import io.kubernetes.client.ApiException;
25+
import com.google.common.io.ByteStreams;
26+
import io.kubernetes.client.Exec.ExecProcess;
27+
import io.kubernetes.client.models.V1ObjectMeta;
28+
import io.kubernetes.client.models.V1Pod;
2829
import io.kubernetes.client.util.ClientBuilder;
29-
3030
import java.io.ByteArrayInputStream;
31+
import java.io.ByteArrayOutputStream;
3132
import java.io.IOException;
3233
import java.io.InputStream;
34+
import java.io.OutputStream;
3335
import java.nio.charset.StandardCharsets;
3436
import org.junit.Before;
3537
import org.junit.Rule;
@@ -45,6 +47,8 @@ public class ExecTest {
4547
"{\"metadata\":{},\"status\":\"Failure\",\"message\":\"command terminated with non-zero exit code: Error executing in Docker Container: 126\",\"reason\":\"NonZeroExitCode\",\"details\":{\"causes\":[{\"reason\":\"ExitCode\",\"message\":\"126\"}]}}";
4648
private static final String BAD_OUTPUT_INCOMPLETE_MSG1 =
4749
"{\"metadata\":{},\"status\":\"Failure\",\"message\":\"command terminated with non-zero exit code: Error executing in Docker Container: 1\",\"reas";
50+
private static final String OUTPUT_EXIT_BAD_INT =
51+
"{\"metadata\":{},\"status\":\"Failure\",\"message\":\"command terminated with non-zero exit code: Error executing in Docker Container: 126\",\"reason\":\"NonZeroExitCode\",\"details\":{\"causes\":[{\"reason\":\"ExitCode\",\"message\":\"not a number\"}]}}";
4852

4953
private String namespace;
5054
private String podName;
@@ -58,37 +62,97 @@ public class ExecTest {
5862
@Before
5963
public void setup() throws IOException {
6064
client = new ClientBuilder().setBasePath("http://localhost:" + PORT).build();
61-
65+
6266
namespace = "default";
6367
podName = "apod";
64-
// TODO: When WireMock supports multiple query params with the same name expand this
68+
// TODO: When WireMock supports multiple query params with the same name expand
69+
// this
6570
// See: https://github.com/tomakehurst/wiremock/issues/398
6671
cmd = new String[] {"cmd"};
6772
}
6873

74+
public static InputStream makeStream(int streamNum, byte[] data) {
75+
return makeStream(new byte[] {(byte) streamNum}, data);
76+
}
77+
78+
public static InputStream makeStream(byte[] prefix, byte[] data) {
79+
byte[] out = new byte[prefix.length + data.length];
80+
System.arraycopy(prefix, 0, out, 0, prefix.length);
81+
System.arraycopy(data, 0, out, prefix.length, data.length);
82+
return new ByteArrayInputStream(out);
83+
}
84+
85+
public static Thread asyncCopy(final InputStream is, final OutputStream os) {
86+
Thread t =
87+
new Thread(
88+
new Runnable() {
89+
public void run() {
90+
try {
91+
ByteStreams.copy(is, os);
92+
} catch (IOException ex) {
93+
ex.printStackTrace();
94+
}
95+
}
96+
});
97+
t.start();
98+
return t;
99+
}
100+
101+
@Test
102+
public void testExecProcess() throws IOException, InterruptedException {
103+
final ExecProcess process = new ExecProcess(client);
104+
process.getHandler().open("wss", null);
105+
String msgData = "This is the stdout message";
106+
String errData = "This is the stderr message";
107+
108+
process.getHandler().bytesMessage(makeStream(1, msgData.getBytes(StandardCharsets.UTF_8)));
109+
process.getHandler().bytesMessage(makeStream(2, errData.getBytes(StandardCharsets.UTF_8)));
110+
process.getHandler().bytesMessage(makeStream(3, OUTPUT_EXIT0.getBytes(StandardCharsets.UTF_8)));
111+
112+
final ByteArrayOutputStream stdout = new ByteArrayOutputStream();
113+
final ByteArrayOutputStream stderr = new ByteArrayOutputStream();
114+
115+
Thread t1 = asyncCopy(process.getInputStream(), stdout);
116+
Thread t2 = asyncCopy(process.getErrorStream(), stderr);
117+
118+
// TODO: Fix this asap!
119+
Thread.sleep(1000);
120+
121+
process.destroy();
122+
123+
assertEquals(msgData, stdout.toString());
124+
assertEquals(errData, stderr.toString());
125+
assertEquals(false, process.isAlive());
126+
assertEquals(0, process.exitValue());
127+
}
128+
69129
@Test
70130
public void testUrl() throws IOException, ApiException, InterruptedException {
71-
Exec exec = new Exec(client);
131+
Exec exec = new Exec(client);
132+
133+
V1Pod pod = new V1Pod().metadata(new V1ObjectMeta().name(podName).namespace(namespace));
72134

73-
stubFor(
135+
stubFor(
74136
get(urlPathEqualTo("/api/v1/namespaces/" + namespace + "/pods/" + podName + "/exec"))
75137
.willReturn(
76138
aResponse()
77139
.withStatus(404)
78140
.withHeader("Content-Type", "application/json")
79141
.withBody("{}")));
80142

81-
Process p = exec.exec(namespace, podName, cmd, false);
82-
p.waitFor();
143+
Process p = exec.exec(pod, cmd, true, false);
144+
p.waitFor();
83145

84-
verify(getRequestedFor(urlPathEqualTo("/api/v1/namespaces/" + namespace + "/pods/" + podName + "/exec"))
85-
.withQueryParam("stdin", equalTo("false"))
86-
.withQueryParam("stdout", equalTo("true"))
87-
.withQueryParam("stderr", equalTo("true"))
88-
.withQueryParam("tty", equalTo("false"))
89-
.withQueryParam("command", equalTo("cmd")));
146+
verify(
147+
getRequestedFor(
148+
urlPathEqualTo("/api/v1/namespaces/" + namespace + "/pods/" + podName + "/exec"))
149+
.withQueryParam("stdin", equalTo("true"))
150+
.withQueryParam("stdout", equalTo("true"))
151+
.withQueryParam("stderr", equalTo("true"))
152+
.withQueryParam("tty", equalTo("false"))
153+
.withQueryParam("command", equalTo("cmd")));
90154

91-
assertEquals(-1, p.exitValue());
155+
assertEquals(-1, p.exitValue());
92156
}
93157

94158
@Test
@@ -122,4 +186,12 @@ public void testIncompleteData1() {
122186
int exitCode = Exec.parseExitCode(client, inputStream);
123187
assertEquals(-1, exitCode);
124188
}
189+
190+
@Test
191+
public void testNonZeroBadIntExit() {
192+
InputStream inputStream =
193+
new ByteArrayInputStream(OUTPUT_EXIT_BAD_INT.getBytes(StandardCharsets.UTF_8));
194+
int exitCode = Exec.parseExitCode(client, inputStream);
195+
assertEquals(-1, exitCode);
196+
}
125197
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.