Skip to content

Commit

Permalink
test: PodUpload works with new container selection logic
Browse files Browse the repository at this point in the history
Signed-off-by: Marc Nuri <marc@marcnuri.com>
  • Loading branch information
manusa committed Nov 7, 2022
1 parent e32230e commit 4f276bc
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public static boolean upload(PodOperationsImpl operation, Path pathToUpload)
throw new IllegalArgumentException("Provided arguments are not valid (file, directory, path)");
}

private static interface UploadProcessor {
private interface UploadProcessor {

void process(OutputStream out) throws IOException;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*/
package io.fabric8.kubernetes.client.dsl.internal.uploadable;

import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.PodBuilder;
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.dsl.internal.ExecWebSocketListener;
import io.fabric8.kubernetes.client.dsl.internal.OperationContext;
Expand All @@ -25,9 +27,10 @@
import io.fabric8.kubernetes.client.impl.BaseClient;
import io.fabric8.kubernetes.client.utils.CommonThreadPool;
import io.fabric8.kubernetes.client.utils.InputStreamPumper;
import io.fabric8.kubernetes.client.utils.InputStreamPumper.Writable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.mockito.Mockito;

import java.io.ByteArrayInputStream;
Expand All @@ -40,24 +43,24 @@
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

class PodUploadTest {

private HttpClient mockClient;
private Path mockPathToUpload;
private WebSocket mockWebSocket;
private PodOperationsImpl operation;

Expand All @@ -67,39 +70,41 @@ public interface PodUploadTester<R> {
}

@BeforeEach
void setUp() throws IOException {
mockClient = Mockito.mock(HttpClient.class, Mockito.RETURNS_DEEP_STUBS);
mockPathToUpload = Mockito.mock(Path.class, Mockito.RETURNS_DEEP_STUBS);
mockWebSocket = Mockito.mock(WebSocket.class, Mockito.RETURNS_DEEP_STUBS);
Mockito.when(mockWebSocket.send(Mockito.any())).thenReturn(true);

void setUp() {
mockClient = mock(HttpClient.class, Mockito.RETURNS_DEEP_STUBS);
mockWebSocket = mock(WebSocket.class, Mockito.RETURNS_DEEP_STUBS);
when(mockWebSocket.send(any())).thenReturn(true);
when(mockClient.newBuilder().readTimeout(anyLong(), any(TimeUnit.class)).build()).thenReturn(mockClient);

BaseClient client = Mockito.mock(BaseClient.class, Mockito.RETURNS_SELF);
BaseClient client = mock(BaseClient.class, Mockito.RETURNS_SELF);
Mockito.when(client.adapt(BaseClient.class).getExecutor()).thenReturn(CommonThreadPool.get());
Config config = Mockito.mock(Config.class, Mockito.RETURNS_DEEP_STUBS);
Config config = mock(Config.class, Mockito.RETURNS_DEEP_STUBS);
when(config.getMasterUrl()).thenReturn("https://openshift.com:8443");
when(config.getNamespace()).thenReturn("default");
when(client.getConfiguration()).thenReturn(config);
when(client.getHttpClient()).thenReturn(mockClient);
this.operation = new PodOperationsImpl(new PodOperationContext(), new OperationContext().withClient(client));
final Pod item = new PodBuilder()
.withNewMetadata().withName("pod").endMetadata()
.withNewSpec().addNewContainer().withName("container").endContainer().endSpec()
.build();
this.operation = new PodOperationsImpl(
new PodOperationContext(), new OperationContext().withItem(item).withClient(client));
}

@Test
void testUploadInvalidParametersShouldThrowException() {
final IllegalArgumentException result = assertThrows(IllegalArgumentException.class,
() -> PodUpload.upload(operation, mockPathToUpload));

assertThat(result.getMessage(),
equalTo("Provided arguments are not valid (file, directory, path)"));
@DisplayName("With invalid parameters, should throw exception")
void uploadInvalidParametersShouldThrowException(@TempDir Path pathToUpload) {
final Path nonExistentPath = pathToUpload.resolve("non-existent");
assertThatIllegalArgumentException()
.isThrownBy(() -> PodUpload.upload(operation, nonExistentPath))
.withMessage("Provided arguments are not valid (file, directory, path)");
}

@Test
void upload_whenFilePathProvided_shouldUploadFile() throws IOException, InterruptedException {
when(mockPathToUpload.toFile())
.thenReturn(new File(PodUpload.class.getResource("/upload/upload-sample.txt").getFile()));
uploadFileAndVerify(() -> PodUpload.upload(operation, mockPathToUpload));
verify(mockPathToUpload, atLeast(1)).toFile();
void upload_withFile_shouldUploadFile() throws IOException, InterruptedException {
final Path toUpload = new File(PodUpload.class.getResource("/upload/upload-sample.txt").getFile())
.toPath();
uploadFileAndVerify(() -> PodUpload.upload(operation, toUpload));
}

@Test
Expand All @@ -109,97 +114,66 @@ void uploadFileData_whenByteArrayInputStreamProvided_shouldUploadFile() throws I
}

@Test
void testUploadDirectoryHappyScenarioShouldUploadDirectory() throws Exception {
uploadDirectoryAndVerify("/upload");
void upload_withDirectory_shouldUploadDirectory() throws Exception {
final Path toUpload = new File(PodUpload.class.getResource("/upload").getFile())
.toPath();
uploadDirectoryAndVerify(() -> PodUpload.upload(operation, toUpload));
}

@Test
void testUploadDirectoryLongFileNameShouldUploadDirectory() throws Exception {
uploadDirectoryAndVerify("/upload_long");
}

private void uploadDirectoryAndVerify(String resourcePath) throws IOException, InterruptedException {
this.operation = operation.dir("/mock/dir");
when(mockPathToUpload.toFile())
.thenReturn(new File(PodUpload.class.getResource(resourcePath).getFile()));
WebSocket.Builder builder = Mockito.mock(WebSocket.Builder.class, Mockito.RETURNS_SELF);
when(builder.buildAsync(any())).thenAnswer(newWebSocket -> {
final ExecWebSocketListener wsl = newWebSocket.getArgument(0, ExecWebSocketListener.class);
// Set ready status
wsl.onOpen(mockWebSocket);
wsl.onMessage(mockWebSocket, ByteBuffer.wrap(new byte[] { (byte) 0 }));
// Set complete status
Mockito.doAnswer(close -> {
wsl.onClose(mockWebSocket, close.getArgument(0), close.getArgument(1));
return null;
}).when(mockWebSocket).sendClose(anyInt(), anyString());
return CompletableFuture.completedFuture(mockWebSocket);
});
when(mockClient.newWebSocketBuilder()).thenReturn(builder);

final boolean result = PodUpload.upload(operation, mockPathToUpload);

assertThat(result, equalTo(true));
verify(mockPathToUpload, atLeast(1)).toFile();
verify(builder, times(1)).uri(argThat(request -> {
assertThat(request.toString(), equalTo(
"https://openshift.com:8443/api/v1/namespaces/default/pods/exec?command=sh&command=-c&command=mkdir%20-p%20%27%2Fmock%2Fdir%27%20%26%26%20base64%20-d%20-%20%7C%20tar%20-C%20%27%2Fmock%2Fdir%27%20-xzf%20-&stdin=true&stderr=true"));
return true;
}));
verify(mockWebSocket, atLeast(1)).send(any(ByteBuffer.class));
void upload_withDirectoryAndLongFileNames_shouldUploadDirectory() throws Exception {
final Path toUpload = new File(PodUpload.class.getResource("/upload_long").getFile())
.toPath();
uploadDirectoryAndVerify(() -> PodUpload.upload(operation, toUpload));
}

@Test
void testCopy() throws Exception {
void transferTo() throws Exception {
final ByteArrayInputStream input = new ByteArrayInputStream("I'LL BE COPIED".getBytes(Charset.defaultCharset()));
final Writable consumer = (bytes, offset, length) -> {
assertThat(length, equalTo(14));
assertThat(new String(Arrays.copyOf(bytes, 14), Charset.defaultCharset()),
equalTo("I'LL BE COPIED"));
final AtomicReference<String> copiedStream = new AtomicReference<>();
final InputStreamPumper.Writable consumer = (bytes, offset, length) -> {
assertThat(length).isEqualTo(14);
copiedStream.set(new String(Arrays.copyOf(bytes, 14), Charset.defaultCharset()));
};

InputStreamPumper.transferTo(input, consumer);
assertThat(copiedStream).hasValue("I'LL BE COPIED");
}

@Test
void createExecCommandForUpload_withFileInRootPath_shouldCreateValidExecCommandForUpload() {
// When
String result = PodUpload.createExecCommandForUpload("/cp.log");

// Then
assertThat(result, equalTo("mkdir -p '/' && base64 -d - > '/cp.log'"));
assertThat(result).isEqualTo("mkdir -p '/' && base64 -d - > '/cp.log'");
}

@Test
void createExecCommandForUpload_withNormalFile_shouldCreateValidExecCommandForUpload() {
// When
String result = PodUpload.createExecCommandForUpload("/tmp/foo/cp.log");

// Then
assertThat(result, equalTo("mkdir -p '/tmp/foo' && base64 -d - > '/tmp/foo/cp.log'"));
assertThat(result).isEqualTo("mkdir -p '/tmp/foo' && base64 -d - > '/tmp/foo/cp.log'");
}

@Test
void createExecCommandForUpload_withSingleQuoteInPath() {
// When
String result = PodUpload.createExecCommandForUpload("/tmp/fo'o/cp.log");

// Then
assertThat(result, equalTo("mkdir -p '/tmp/fo\'\\'\'o' && base64 -d - > '/tmp/fo\'\\'\'o/cp.log'"));
assertThat(result).isEqualTo("mkdir -p '/tmp/fo\'\\'\'o' && base64 -d - > '/tmp/fo\'\\'\'o/cp.log'");
}

@Test
void createExecCommandForUpload_withMultipleSingleQuotesInPath() {
// When
String result = PodUpload.createExecCommandForUpload("/tmp/f'o'o/c'p.log");

// Then
assertThat(result, equalTo("mkdir -p '/tmp/f\'\\'\'o\'\\'\'o' && base64 -d - > '/tmp/f\'\\'\'o\'\\'\'o/c\'\\'\'p.log'"));
assertThat(result).isEqualTo("mkdir -p '/tmp/f\'\\'\'o\'\\'\'o' && base64 -d - > '/tmp/f\'\\'\'o\'\\'\'o/c\'\\'\'p.log'");
}

void uploadFileAndVerify(PodUploadTester<Boolean> fileUploadMethodToTest) throws IOException, InterruptedException {
this.operation = operation.file("/mock/dir/file");
WebSocket.Builder builder = Mockito.mock(WebSocket.Builder.class, Mockito.RETURNS_SELF);
operation = operation.file("/mock/dir/file");
WebSocket.Builder builder = mock(WebSocket.Builder.class, Mockito.RETURNS_SELF);
when(builder.buildAsync(any())).thenAnswer(newWebSocket -> {
final ExecWebSocketListener wsl = newWebSocket.getArgument(0, ExecWebSocketListener.class);
// Set ready status
Expand All @@ -216,10 +190,39 @@ void uploadFileAndVerify(PodUploadTester<Boolean> fileUploadMethodToTest) throws

final boolean result = fileUploadMethodToTest.apply();

assertThat(result, equalTo(true));
assertThat(result).isTrue();
verify(builder, times(1)).uri(argThat(request -> {
assertThat(request).hasToString(
"https://openshift.com:8443/api/v1/namespaces/default/pods/exec?command=sh&command=-c&command=mkdir%20-p%20%27%2Fmock%2Fdir%27%20%26%26%20base64%20-d%20-%20%3E%20%27%2Fmock%2Fdir%2Ffile%27&container=container&stdin=true&stderr=true");
return true;
}));
verify(mockWebSocket, atLeast(1)).send(any(ByteBuffer.class));
}

private void uploadDirectoryAndVerify(PodUploadTester<Boolean> directoryUpload)
throws IOException, InterruptedException {
this.operation = operation.dir("/mock/dir");
WebSocket.Builder builder = mock(WebSocket.Builder.class, Mockito.RETURNS_SELF);
when(builder.buildAsync(any())).thenAnswer(newWebSocket -> {
final ExecWebSocketListener wsl = newWebSocket.getArgument(0, ExecWebSocketListener.class);
// Set ready status
wsl.onOpen(mockWebSocket);
wsl.onMessage(mockWebSocket, ByteBuffer.wrap(new byte[] { (byte) 0 }));
// Set complete status
Mockito.doAnswer(close -> {
wsl.onClose(mockWebSocket, close.getArgument(0), close.getArgument(1));
return null;
}).when(mockWebSocket).sendClose(anyInt(), anyString());
return CompletableFuture.completedFuture(mockWebSocket);
});
when(mockClient.newWebSocketBuilder()).thenReturn(builder);

final boolean result = directoryUpload.apply();

assertThat(result).isTrue();
verify(builder, times(1)).uri(argThat(request -> {
assertThat(request.toString(), equalTo(
"https://openshift.com:8443/api/v1/namespaces/default/pods/exec?command=sh&command=-c&command=mkdir%20-p%20%27%2Fmock%2Fdir%27%20%26%26%20base64%20-d%20-%20%3E%20%27%2Fmock%2Fdir%2Ffile%27&stdin=true&stderr=true"));
assertThat(request).hasToString(
"https://openshift.com:8443/api/v1/namespaces/default/pods/exec?command=sh&command=-c&command=mkdir%20-p%20%27%2Fmock%2Fdir%27%20%26%26%20base64%20-d%20-%20%7C%20tar%20-C%20%27%2Fmock%2Fdir%27%20-xzf%20-&container=container&stdin=true&stderr=true");
return true;
}));
verify(mockWebSocket, atLeast(1)).send(any(ByteBuffer.class));
Expand Down

0 comments on commit 4f276bc

Please sign in to comment.