From 533391f05fdcf568404e9857270e68a7996b55b6 Mon Sep 17 00:00:00 2001 From: Marc Nuri Date: Mon, 7 Nov 2022 15:57:22 +0100 Subject: [PATCH] test: PodUpload works with new container selection logic Signed-off-by: Marc Nuri --- .../dsl/internal/uploadable/PodUpload.java | 2 +- .../internal/uploadable/PodUploadTest.java | 161 +++++++++--------- 2 files changed, 83 insertions(+), 80 deletions(-) diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/uploadable/PodUpload.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/uploadable/PodUpload.java index 5ad38ee4f92..285b67fad5a 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/uploadable/PodUpload.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/uploadable/PodUpload.java @@ -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; diff --git a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/internal/uploadable/PodUploadTest.java b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/internal/uploadable/PodUploadTest.java index 3a7d347954e..0f40128fd95 100644 --- a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/internal/uploadable/PodUploadTest.java +++ b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/internal/uploadable/PodUploadTest.java @@ -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; @@ -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; @@ -40,16 +43,17 @@ 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; @@ -57,7 +61,6 @@ class PodUploadTest { private HttpClient mockClient; - private Path mockPathToUpload; private WebSocket mockWebSocket; private PodOperationsImpl operation; @@ -67,39 +70,41 @@ public interface PodUploadTester { } @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 @@ -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 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 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 @@ -216,10 +190,39 @@ void uploadFileAndVerify(PodUploadTester fileUploadMethodToTest) throws final boolean result = fileUploadMethodToTest.apply(); - assertThat(result, equalTo(true)); + assertThat(result).isTrue(); + verify(builder, times(1)).uri(argThat(request -> { + assertThat(request.toString()).isEqualTo( + "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 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.toString()).isEqualTo( + "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));