From 2be9f7511da52c2143c76693989bd09ed1e05c56 Mon Sep 17 00:00:00 2001
From: Peter Darton
Date: Wed, 10 Mar 2021 22:53:36 +0000
Subject: [PATCH 1/3] Add Delegating DockerClient code.
---
pom.xml | 14 +
.../client/DelegatingDockerClient.java | 437 ++++++++++++++++++
.../client/DelegatingDockerClientTest.java | 157 +++++++
3 files changed, 608 insertions(+)
create mode 100644 src/main/java/io/jenkins/dockerjavaapi/client/DelegatingDockerClient.java
create mode 100644 src/test/java/io/jenkins/dockerjavaapi/client/DelegatingDockerClientTest.java
diff --git a/pom.xml b/pom.xml
index f0a41b0..5371602 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,6 +28,7 @@
-SNAPSHOT1.609.18
+ UTF-83.1
@@ -126,5 +127,18 @@
jackson2-api2.6.4
+
+
+ org.hamcrest
+ hamcrest-core
+ 2.2
+ test
+
+
+ org.mockito
+ mockito-core
+ 2.10.0
+ test
+
diff --git a/src/main/java/io/jenkins/dockerjavaapi/client/DelegatingDockerClient.java b/src/main/java/io/jenkins/dockerjavaapi/client/DelegatingDockerClient.java
new file mode 100644
index 0000000..4eb5aa3
--- /dev/null
+++ b/src/main/java/io/jenkins/dockerjavaapi/client/DelegatingDockerClient.java
@@ -0,0 +1,437 @@
+// Copyright 2011 Peter Darton
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+package io.jenkins.dockerjavaapi.client;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import javax.annotation.Nonnull;
+
+import com.github.dockerjava.api.DockerClient;
+import com.github.dockerjava.api.command.*;
+import com.github.dockerjava.api.exception.DockerException;
+import com.github.dockerjava.api.model.*;
+
+// MAINTENANCE NOTE:
+// The DockerClient API varies depending on the version of the docker-java
+// library that this plugin provides.
+// It may be necessary to add/remove methods from this class when changing
+// the version of docker-java.
+// ...but, by having this here, it allows all other Jenkins plugins to be much
+// less affected by changes to the version of docker-java, meaning that this
+// plugin can be upgraded without breaking every other docker-using plugin.
+
+/**
+ * Simple delegate class for the {@link DockerClient} interface.
+ *
+ * This makes it easy for other classes to override specific methods without
+ * having to implement all of them.
+ *
+ * If you are writing a Jenkins plugin that needs a class to implement/wrap
+ * {@link DockerClient}, you'd be best advised to extend this one, otherwise
+ * your code could fail whenever the version of this plugin changes.
+ */
+@SuppressWarnings("deprecation")
+public class DelegatingDockerClient implements DockerClient {
+
+ private final DockerClient delegate;
+
+ /**
+ * Constructs a new instance that delegates all API calls to the specified
+ * {@link DockerClient}.
+ *
+ * @param delegate The {@link DockerClient} to delegate to.
+ */
+ public DelegatingDockerClient(@Nonnull DockerClient delegate) {
+ this.delegate = delegate;
+ }
+
+ /**
+ * Obtains the underlying {@link DockerClient} interface. Subclasses can
+ * override this if they need to hook into every call.
+ *
+ * @return the {@link DockerClient} to be delegated to.
+ */
+ @Nonnull
+ protected DockerClient getDelegate() {
+ return delegate;
+ }
+
+ @Override
+ public AttachContainerCmd attachContainerCmd(String arg0) {
+ return getDelegate().attachContainerCmd(arg0);
+ }
+
+ @Override
+ public AuthCmd authCmd() {
+ return getDelegate().authCmd();
+ }
+
+ @Override
+ public AuthConfig authConfig() throws DockerException {
+ return getDelegate().authConfig();
+ }
+
+ @Override
+ public BuildImageCmd buildImageCmd() {
+ return getDelegate().buildImageCmd();
+ }
+
+ @Override
+ public BuildImageCmd buildImageCmd(File arg0) {
+ return getDelegate().buildImageCmd(arg0);
+ }
+
+ @Override
+ public BuildImageCmd buildImageCmd(InputStream arg0) {
+ return getDelegate().buildImageCmd(arg0);
+ }
+
+ @Override
+ public void close() throws IOException {
+ getDelegate().close();
+ }
+
+ @Override
+ public CommitCmd commitCmd(String arg0) {
+ return getDelegate().commitCmd(arg0);
+ }
+
+ @Override
+ public ConnectToNetworkCmd connectToNetworkCmd() {
+ return getDelegate().connectToNetworkCmd();
+ }
+
+ @Override
+ public ContainerDiffCmd containerDiffCmd(String arg0) {
+ return getDelegate().containerDiffCmd(arg0);
+ }
+
+ @Override
+ public CopyArchiveFromContainerCmd copyArchiveFromContainerCmd(String arg0, String arg1) {
+ return getDelegate().copyArchiveFromContainerCmd(arg0, arg1);
+ }
+
+ @Override
+ public CopyArchiveToContainerCmd copyArchiveToContainerCmd(String arg0) {
+ return getDelegate().copyArchiveToContainerCmd(arg0);
+ }
+
+ @Override
+ public CopyFileFromContainerCmd copyFileFromContainerCmd(String arg0, String arg1) {
+ return getDelegate().copyFileFromContainerCmd(arg0, arg1);
+ }
+
+ @Override
+ public CreateContainerCmd createContainerCmd(String arg0) {
+ return getDelegate().createContainerCmd(arg0);
+ }
+
+ @Override
+ public CreateImageCmd createImageCmd(String arg0, InputStream arg1) {
+ return getDelegate().createImageCmd(arg0, arg1);
+ }
+
+ @Override
+ public CreateNetworkCmd createNetworkCmd() {
+ return getDelegate().createNetworkCmd();
+ }
+
+ @Override
+ public CreateVolumeCmd createVolumeCmd() {
+ return getDelegate().createVolumeCmd();
+ }
+
+ @Override
+ public DisconnectFromNetworkCmd disconnectFromNetworkCmd() {
+ return getDelegate().disconnectFromNetworkCmd();
+ }
+
+ @Override
+ public EventsCmd eventsCmd() {
+ return getDelegate().eventsCmd();
+ }
+
+ @Override
+ public ExecCreateCmd execCreateCmd(String arg0) {
+ return getDelegate().execCreateCmd(arg0);
+ }
+
+ @Override
+ public ExecStartCmd execStartCmd(String arg0) {
+ return getDelegate().execStartCmd(arg0);
+ }
+
+ @Override
+ public InfoCmd infoCmd() {
+ return getDelegate().infoCmd();
+ }
+
+ @Override
+ public InspectContainerCmd inspectContainerCmd(String arg0) {
+ return getDelegate().inspectContainerCmd(arg0);
+ }
+
+ @Override
+ public InspectExecCmd inspectExecCmd(String arg0) {
+ return getDelegate().inspectExecCmd(arg0);
+ }
+
+ @Override
+ public InspectImageCmd inspectImageCmd(String arg0) {
+ return getDelegate().inspectImageCmd(arg0);
+ }
+
+ @Override
+ public InspectNetworkCmd inspectNetworkCmd() {
+ return getDelegate().inspectNetworkCmd();
+ }
+
+ @Override
+ public InspectVolumeCmd inspectVolumeCmd(String arg0) {
+ return getDelegate().inspectVolumeCmd(arg0);
+ }
+
+ @Override
+ public KillContainerCmd killContainerCmd(String arg0) {
+ return getDelegate().killContainerCmd(arg0);
+ }
+
+ @Override
+ public ListContainersCmd listContainersCmd() {
+ return getDelegate().listContainersCmd();
+ }
+
+ @Override
+ public ListImagesCmd listImagesCmd() {
+ return getDelegate().listImagesCmd();
+ }
+
+ @Override
+ public ListNetworksCmd listNetworksCmd() {
+ return getDelegate().listNetworksCmd();
+ }
+
+ @Override
+ public ListVolumesCmd listVolumesCmd() {
+ return getDelegate().listVolumesCmd();
+ }
+
+ @Override
+ public LoadImageCmd loadImageCmd(InputStream arg0) {
+ return getDelegate().loadImageCmd(arg0);
+ }
+
+ @Override
+ public LogContainerCmd logContainerCmd(String arg0) {
+ return getDelegate().logContainerCmd(arg0);
+ }
+
+ @Override
+ public PauseContainerCmd pauseContainerCmd(String arg0) {
+ return getDelegate().pauseContainerCmd(arg0);
+ }
+
+ @Override
+ public PingCmd pingCmd() {
+ return getDelegate().pingCmd();
+ }
+
+ @Override
+ public PullImageCmd pullImageCmd(String arg0) {
+ return getDelegate().pullImageCmd(arg0);
+ }
+
+ @Override
+ public PushImageCmd pushImageCmd(String arg0) {
+ return getDelegate().pushImageCmd(arg0);
+ }
+
+ @Override
+ public PushImageCmd pushImageCmd(Identifier arg0) {
+ return getDelegate().pushImageCmd(arg0);
+ }
+
+ @Override
+ public RemoveContainerCmd removeContainerCmd(String arg0) {
+ return getDelegate().removeContainerCmd(arg0);
+ }
+
+ @Override
+ public RemoveImageCmd removeImageCmd(String arg0) {
+ return getDelegate().removeImageCmd(arg0);
+ }
+
+ @Override
+ public RemoveNetworkCmd removeNetworkCmd(String arg0) {
+ return getDelegate().removeNetworkCmd(arg0);
+ }
+
+ @Override
+ public RemoveVolumeCmd removeVolumeCmd(String arg0) {
+ return getDelegate().removeVolumeCmd(arg0);
+ }
+
+ @Override
+ public RenameContainerCmd renameContainerCmd(String arg0) {
+ return getDelegate().renameContainerCmd(arg0);
+ }
+
+ @Override
+ public RestartContainerCmd restartContainerCmd(String arg0) {
+ return getDelegate().restartContainerCmd(arg0);
+ }
+
+ @Override
+ public SaveImageCmd saveImageCmd(String arg0) {
+ return getDelegate().saveImageCmd(arg0);
+ }
+
+ @Override
+ public SearchImagesCmd searchImagesCmd(String arg0) {
+ return getDelegate().searchImagesCmd(arg0);
+ }
+
+ @Override
+ public StartContainerCmd startContainerCmd(String arg0) {
+ return getDelegate().startContainerCmd(arg0);
+ }
+
+ @Override
+ public StatsCmd statsCmd(String arg0) {
+ return getDelegate().statsCmd(arg0);
+ }
+
+ @Override
+ public StopContainerCmd stopContainerCmd(String arg0) {
+ return getDelegate().stopContainerCmd(arg0);
+ }
+
+ @Override
+ public TagImageCmd tagImageCmd(String arg0, String arg1, String arg2) {
+ return getDelegate().tagImageCmd(arg0, arg1, arg2);
+ }
+
+ @Override
+ public TopContainerCmd topContainerCmd(String arg0) {
+ return getDelegate().topContainerCmd(arg0);
+ }
+
+ @Override
+ public UnpauseContainerCmd unpauseContainerCmd(String arg0) {
+ return getDelegate().unpauseContainerCmd(arg0);
+ }
+
+ @Override
+ public UpdateContainerCmd updateContainerCmd(String arg0) {
+ return getDelegate().updateContainerCmd(arg0);
+ }
+
+ @Override
+ public VersionCmd versionCmd() {
+ return getDelegate().versionCmd();
+ }
+
+ @Override
+ public WaitContainerCmd waitContainerCmd(String arg0) {
+ return getDelegate().waitContainerCmd(arg0);
+ }
+
+ @Override
+ public InitializeSwarmCmd initializeSwarmCmd(SwarmSpec swarmSpec) {
+ return getDelegate().initializeSwarmCmd(swarmSpec);
+ }
+
+ @Override
+ public InspectSwarmCmd inspectSwarmCmd() {
+ return getDelegate().inspectSwarmCmd();
+ }
+
+ @Override
+ public JoinSwarmCmd joinSwarmCmd() {
+ return getDelegate().joinSwarmCmd();
+ }
+
+ @Override
+ public LeaveSwarmCmd leaveSwarmCmd() {
+ return getDelegate().leaveSwarmCmd();
+ }
+
+ @Override
+ public UpdateSwarmCmd updateSwarmCmd(SwarmSpec swarmSpec) {
+ return getDelegate().updateSwarmCmd(swarmSpec);
+ }
+
+ @Override
+ public UpdateSwarmNodeCmd updateSwarmNodeCmd() {
+ return getDelegate().updateSwarmNodeCmd();
+ }
+
+ @Override
+ public ListSwarmNodesCmd listSwarmNodesCmd() {
+ return getDelegate().listSwarmNodesCmd();
+ }
+
+ @Override
+ public ListServicesCmd listServicesCmd() {
+ return getDelegate().listServicesCmd();
+ }
+
+ @Override
+ public CreateServiceCmd createServiceCmd(ServiceSpec serviceSpec) {
+ return getDelegate().createServiceCmd(serviceSpec);
+ }
+
+ @Override
+ public InspectServiceCmd inspectServiceCmd(String serviceId) {
+ return getDelegate().inspectServiceCmd(serviceId);
+ }
+
+ @Override
+ public UpdateServiceCmd updateServiceCmd(String serviceId, ServiceSpec serviceSpec) {
+ return getDelegate().updateServiceCmd(serviceId, serviceSpec);
+ }
+
+ @Override
+ public RemoveServiceCmd removeServiceCmd(String serviceId) {
+ return getDelegate().removeServiceCmd(serviceId);
+ }
+
+ @Override
+ public ListTasksCmd listTasksCmd() {
+ return getDelegate().listTasksCmd();
+ }
+
+ @Override
+ public LogSwarmObjectCmd logServiceCmd(String serviceId) {
+ return getDelegate().logServiceCmd(serviceId);
+ }
+
+ @Override
+ public LogSwarmObjectCmd logTaskCmd(String taskId) {
+ return getDelegate().logTaskCmd(taskId);
+ }
+
+ @Override
+ public PruneCmd pruneCmd(PruneType pruneType) {
+ return getDelegate().pruneCmd(pruneType);
+ }
+}
diff --git a/src/test/java/io/jenkins/dockerjavaapi/client/DelegatingDockerClientTest.java b/src/test/java/io/jenkins/dockerjavaapi/client/DelegatingDockerClientTest.java
new file mode 100644
index 0000000..a9505d1
--- /dev/null
+++ b/src/test/java/io/jenkins/dockerjavaapi/client/DelegatingDockerClientTest.java
@@ -0,0 +1,157 @@
+// Copyright 2011 Peter Darton
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+package io.jenkins.dockerjavaapi.client;
+
+import static org.hamcrest.CoreMatchers.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.mockito.exceptions.base.MockitoException;
+
+import com.github.dockerjava.api.DockerClient;
+
+/**
+ * Ensures that every method in DelegatingDockerClient delegates to the matching
+ * method in the instance it delegates to. Uses reflection/introspection to
+ * ensure that this class doesn't need updating if new methods are added.
+ */
+@RunWith(Parameterized.class)
+public class DelegatingDockerClientTest {
+
+ /**
+ * Defines the set of data that all test methods (in this test class) will be
+ * run with - in this case, it's all the methods of {@link DockerClient}.
+ *
+ * Each element in the returned {@link Iterable} is an Object[] whose contents
+ * matches the arguments taken by this class's constructor.
+ *
+ * The annotation name = "{0}" says that the name of each set of
+ * data should be first element of the array.
+ *
+ * @return {@link Iterable} of [ {@link String}, {@link Method} ].
+ */
+ @Parameterized.Parameters(name = "{0}")
+ public static Iterable
* If you are writing a Jenkins plugin that needs a class to implement/wrap
* {@link DockerClient}, you'd be best advised to extend this one, otherwise
@@ -75,363 +84,382 @@ protected DockerClient getDelegate() {
return delegate;
}
+ /**
+ * Called just before the result is returned. Allows a subclass to act just
+ * before the method returns and/or to alter the result.
+ *
+ * @param originalAnswer The result from the delegate.
+ * @return The result to be returned instead.
+ */
+ protected T interceptAnswer(T originalAnswer) {
+ return originalAnswer;
+ }
+
+ /**
+ * Called just before the method returns void. Allows a subclass to act just
+ * before the method returns.
+ */
+ protected void interceptVoid() {
+ }
+
@Override
public AttachContainerCmd attachContainerCmd(String arg0) {
- return getDelegate().attachContainerCmd(arg0);
+ return interceptAnswer(getDelegate().attachContainerCmd(arg0));
}
@Override
public AuthCmd authCmd() {
- return getDelegate().authCmd();
+ return interceptAnswer(getDelegate().authCmd());
}
@Override
public AuthConfig authConfig() throws DockerException {
- return getDelegate().authConfig();
+ return interceptAnswer(getDelegate().authConfig());
}
@Override
public BuildImageCmd buildImageCmd() {
- return getDelegate().buildImageCmd();
+ return interceptAnswer(getDelegate().buildImageCmd());
}
@Override
public BuildImageCmd buildImageCmd(File arg0) {
- return getDelegate().buildImageCmd(arg0);
+ return interceptAnswer(getDelegate().buildImageCmd(arg0));
}
@Override
public BuildImageCmd buildImageCmd(InputStream arg0) {
- return getDelegate().buildImageCmd(arg0);
+ return interceptAnswer(getDelegate().buildImageCmd(arg0));
}
@Override
public void close() throws IOException {
getDelegate().close();
+ interceptVoid();
}
@Override
public CommitCmd commitCmd(String arg0) {
- return getDelegate().commitCmd(arg0);
+ return interceptAnswer(getDelegate().commitCmd(arg0));
}
@Override
public ConnectToNetworkCmd connectToNetworkCmd() {
- return getDelegate().connectToNetworkCmd();
+ return interceptAnswer(getDelegate().connectToNetworkCmd());
}
@Override
public ContainerDiffCmd containerDiffCmd(String arg0) {
- return getDelegate().containerDiffCmd(arg0);
+ return interceptAnswer(getDelegate().containerDiffCmd(arg0));
}
@Override
public CopyArchiveFromContainerCmd copyArchiveFromContainerCmd(String arg0, String arg1) {
- return getDelegate().copyArchiveFromContainerCmd(arg0, arg1);
+ return interceptAnswer(getDelegate().copyArchiveFromContainerCmd(arg0, arg1));
}
@Override
public CopyArchiveToContainerCmd copyArchiveToContainerCmd(String arg0) {
- return getDelegate().copyArchiveToContainerCmd(arg0);
+ return interceptAnswer(getDelegate().copyArchiveToContainerCmd(arg0));
}
@Override
public CopyFileFromContainerCmd copyFileFromContainerCmd(String arg0, String arg1) {
- return getDelegate().copyFileFromContainerCmd(arg0, arg1);
+ return interceptAnswer(getDelegate().copyFileFromContainerCmd(arg0, arg1));
}
@Override
public CreateContainerCmd createContainerCmd(String arg0) {
- return getDelegate().createContainerCmd(arg0);
+ return interceptAnswer(getDelegate().createContainerCmd(arg0));
}
@Override
public CreateImageCmd createImageCmd(String arg0, InputStream arg1) {
- return getDelegate().createImageCmd(arg0, arg1);
+ return interceptAnswer(getDelegate().createImageCmd(arg0, arg1));
}
@Override
public CreateNetworkCmd createNetworkCmd() {
- return getDelegate().createNetworkCmd();
+ return interceptAnswer(getDelegate().createNetworkCmd());
}
@Override
public CreateVolumeCmd createVolumeCmd() {
- return getDelegate().createVolumeCmd();
+ return interceptAnswer(getDelegate().createVolumeCmd());
}
@Override
public DisconnectFromNetworkCmd disconnectFromNetworkCmd() {
- return getDelegate().disconnectFromNetworkCmd();
+ return interceptAnswer(getDelegate().disconnectFromNetworkCmd());
}
@Override
public EventsCmd eventsCmd() {
- return getDelegate().eventsCmd();
+ return interceptAnswer(getDelegate().eventsCmd());
}
@Override
public ExecCreateCmd execCreateCmd(String arg0) {
- return getDelegate().execCreateCmd(arg0);
+ return interceptAnswer(getDelegate().execCreateCmd(arg0));
}
@Override
public ExecStartCmd execStartCmd(String arg0) {
- return getDelegate().execStartCmd(arg0);
+ return interceptAnswer(getDelegate().execStartCmd(arg0));
}
@Override
public InfoCmd infoCmd() {
- return getDelegate().infoCmd();
+ return interceptAnswer(getDelegate().infoCmd());
}
@Override
public InspectContainerCmd inspectContainerCmd(String arg0) {
- return getDelegate().inspectContainerCmd(arg0);
+ return interceptAnswer(getDelegate().inspectContainerCmd(arg0));
}
@Override
public InspectExecCmd inspectExecCmd(String arg0) {
- return getDelegate().inspectExecCmd(arg0);
+ return interceptAnswer(getDelegate().inspectExecCmd(arg0));
}
@Override
public InspectImageCmd inspectImageCmd(String arg0) {
- return getDelegate().inspectImageCmd(arg0);
+ return interceptAnswer(getDelegate().inspectImageCmd(arg0));
}
@Override
public InspectNetworkCmd inspectNetworkCmd() {
- return getDelegate().inspectNetworkCmd();
+ return interceptAnswer(getDelegate().inspectNetworkCmd());
}
@Override
public InspectVolumeCmd inspectVolumeCmd(String arg0) {
- return getDelegate().inspectVolumeCmd(arg0);
+ return interceptAnswer(getDelegate().inspectVolumeCmd(arg0));
}
@Override
public KillContainerCmd killContainerCmd(String arg0) {
- return getDelegate().killContainerCmd(arg0);
+ return interceptAnswer(getDelegate().killContainerCmd(arg0));
}
@Override
public ListContainersCmd listContainersCmd() {
- return getDelegate().listContainersCmd();
+ return interceptAnswer(getDelegate().listContainersCmd());
}
@Override
public ListImagesCmd listImagesCmd() {
- return getDelegate().listImagesCmd();
+ return interceptAnswer(getDelegate().listImagesCmd());
}
@Override
public ListNetworksCmd listNetworksCmd() {
- return getDelegate().listNetworksCmd();
+ return interceptAnswer(getDelegate().listNetworksCmd());
}
@Override
public ListVolumesCmd listVolumesCmd() {
- return getDelegate().listVolumesCmd();
+ return interceptAnswer(getDelegate().listVolumesCmd());
}
@Override
public LoadImageCmd loadImageCmd(InputStream arg0) {
- return getDelegate().loadImageCmd(arg0);
+ return interceptAnswer(getDelegate().loadImageCmd(arg0));
}
@Override
public LogContainerCmd logContainerCmd(String arg0) {
- return getDelegate().logContainerCmd(arg0);
+ return interceptAnswer(getDelegate().logContainerCmd(arg0));
}
@Override
public PauseContainerCmd pauseContainerCmd(String arg0) {
- return getDelegate().pauseContainerCmd(arg0);
+ return interceptAnswer(getDelegate().pauseContainerCmd(arg0));
}
@Override
public PingCmd pingCmd() {
- return getDelegate().pingCmd();
+ return interceptAnswer(getDelegate().pingCmd());
}
@Override
public PullImageCmd pullImageCmd(String arg0) {
- return getDelegate().pullImageCmd(arg0);
+ return interceptAnswer(getDelegate().pullImageCmd(arg0));
}
@Override
public PushImageCmd pushImageCmd(String arg0) {
- return getDelegate().pushImageCmd(arg0);
+ return interceptAnswer(getDelegate().pushImageCmd(arg0));
}
@Override
public PushImageCmd pushImageCmd(Identifier arg0) {
- return getDelegate().pushImageCmd(arg0);
+ return interceptAnswer(getDelegate().pushImageCmd(arg0));
}
@Override
public RemoveContainerCmd removeContainerCmd(String arg0) {
- return getDelegate().removeContainerCmd(arg0);
+ return interceptAnswer(getDelegate().removeContainerCmd(arg0));
}
@Override
public RemoveImageCmd removeImageCmd(String arg0) {
- return getDelegate().removeImageCmd(arg0);
+ return interceptAnswer(getDelegate().removeImageCmd(arg0));
}
@Override
public RemoveNetworkCmd removeNetworkCmd(String arg0) {
- return getDelegate().removeNetworkCmd(arg0);
+ return interceptAnswer(getDelegate().removeNetworkCmd(arg0));
}
@Override
public RemoveVolumeCmd removeVolumeCmd(String arg0) {
- return getDelegate().removeVolumeCmd(arg0);
+ return interceptAnswer(getDelegate().removeVolumeCmd(arg0));
}
@Override
public RenameContainerCmd renameContainerCmd(String arg0) {
- return getDelegate().renameContainerCmd(arg0);
+ return interceptAnswer(getDelegate().renameContainerCmd(arg0));
}
@Override
public RestartContainerCmd restartContainerCmd(String arg0) {
- return getDelegate().restartContainerCmd(arg0);
+ return interceptAnswer(getDelegate().restartContainerCmd(arg0));
}
@Override
public SaveImageCmd saveImageCmd(String arg0) {
- return getDelegate().saveImageCmd(arg0);
+ return interceptAnswer(getDelegate().saveImageCmd(arg0));
}
@Override
public SearchImagesCmd searchImagesCmd(String arg0) {
- return getDelegate().searchImagesCmd(arg0);
+ return interceptAnswer(getDelegate().searchImagesCmd(arg0));
}
@Override
public StartContainerCmd startContainerCmd(String arg0) {
- return getDelegate().startContainerCmd(arg0);
+ return interceptAnswer(getDelegate().startContainerCmd(arg0));
}
@Override
public StatsCmd statsCmd(String arg0) {
- return getDelegate().statsCmd(arg0);
+ return interceptAnswer(getDelegate().statsCmd(arg0));
}
@Override
public StopContainerCmd stopContainerCmd(String arg0) {
- return getDelegate().stopContainerCmd(arg0);
+ return interceptAnswer(getDelegate().stopContainerCmd(arg0));
}
@Override
public TagImageCmd tagImageCmd(String arg0, String arg1, String arg2) {
- return getDelegate().tagImageCmd(arg0, arg1, arg2);
+ return interceptAnswer(getDelegate().tagImageCmd(arg0, arg1, arg2));
}
@Override
public TopContainerCmd topContainerCmd(String arg0) {
- return getDelegate().topContainerCmd(arg0);
+ return interceptAnswer(getDelegate().topContainerCmd(arg0));
}
@Override
public UnpauseContainerCmd unpauseContainerCmd(String arg0) {
- return getDelegate().unpauseContainerCmd(arg0);
+ return interceptAnswer(getDelegate().unpauseContainerCmd(arg0));
}
@Override
public UpdateContainerCmd updateContainerCmd(String arg0) {
- return getDelegate().updateContainerCmd(arg0);
+ return interceptAnswer(getDelegate().updateContainerCmd(arg0));
}
@Override
public VersionCmd versionCmd() {
- return getDelegate().versionCmd();
+ return interceptAnswer(getDelegate().versionCmd());
}
@Override
public WaitContainerCmd waitContainerCmd(String arg0) {
- return getDelegate().waitContainerCmd(arg0);
+ return interceptAnswer(getDelegate().waitContainerCmd(arg0));
}
@Override
public InitializeSwarmCmd initializeSwarmCmd(SwarmSpec swarmSpec) {
- return getDelegate().initializeSwarmCmd(swarmSpec);
+ return interceptAnswer(getDelegate().initializeSwarmCmd(swarmSpec));
}
@Override
public InspectSwarmCmd inspectSwarmCmd() {
- return getDelegate().inspectSwarmCmd();
+ return interceptAnswer(getDelegate().inspectSwarmCmd());
}
@Override
public JoinSwarmCmd joinSwarmCmd() {
- return getDelegate().joinSwarmCmd();
+ return interceptAnswer(getDelegate().joinSwarmCmd());
}
@Override
public LeaveSwarmCmd leaveSwarmCmd() {
- return getDelegate().leaveSwarmCmd();
+ return interceptAnswer(getDelegate().leaveSwarmCmd());
}
@Override
public UpdateSwarmCmd updateSwarmCmd(SwarmSpec swarmSpec) {
- return getDelegate().updateSwarmCmd(swarmSpec);
+ return interceptAnswer(getDelegate().updateSwarmCmd(swarmSpec));
}
@Override
public UpdateSwarmNodeCmd updateSwarmNodeCmd() {
- return getDelegate().updateSwarmNodeCmd();
+ return interceptAnswer(getDelegate().updateSwarmNodeCmd());
}
@Override
public ListSwarmNodesCmd listSwarmNodesCmd() {
- return getDelegate().listSwarmNodesCmd();
+ return interceptAnswer(getDelegate().listSwarmNodesCmd());
}
@Override
public ListServicesCmd listServicesCmd() {
- return getDelegate().listServicesCmd();
+ return interceptAnswer(getDelegate().listServicesCmd());
}
@Override
public CreateServiceCmd createServiceCmd(ServiceSpec serviceSpec) {
- return getDelegate().createServiceCmd(serviceSpec);
+ return interceptAnswer(getDelegate().createServiceCmd(serviceSpec));
}
@Override
public InspectServiceCmd inspectServiceCmd(String serviceId) {
- return getDelegate().inspectServiceCmd(serviceId);
+ return interceptAnswer(getDelegate().inspectServiceCmd(serviceId));
}
@Override
public UpdateServiceCmd updateServiceCmd(String serviceId, ServiceSpec serviceSpec) {
- return getDelegate().updateServiceCmd(serviceId, serviceSpec);
+ return interceptAnswer(getDelegate().updateServiceCmd(serviceId, serviceSpec));
}
@Override
public RemoveServiceCmd removeServiceCmd(String serviceId) {
- return getDelegate().removeServiceCmd(serviceId);
+ return interceptAnswer(getDelegate().removeServiceCmd(serviceId));
}
@Override
public ListTasksCmd listTasksCmd() {
- return getDelegate().listTasksCmd();
+ return interceptAnswer(getDelegate().listTasksCmd());
}
@Override
public LogSwarmObjectCmd logServiceCmd(String serviceId) {
- return getDelegate().logServiceCmd(serviceId);
+ return interceptAnswer(getDelegate().logServiceCmd(serviceId));
}
@Override
public LogSwarmObjectCmd logTaskCmd(String taskId) {
- return getDelegate().logTaskCmd(taskId);
+ return interceptAnswer(getDelegate().logTaskCmd(taskId));
}
@Override
public PruneCmd pruneCmd(PruneType pruneType) {
- return getDelegate().pruneCmd(pruneType);
+ return interceptAnswer(getDelegate().pruneCmd(pruneType));
}
}
diff --git a/src/test/java/io/jenkins/dockerjavaapi/client/DelegatingDockerClientTest.java b/src/test/java/io/jenkins/dockerjavaapi/client/DelegatingDockerClientTest.java
index a9505d1..1746ac9 100644
--- a/src/test/java/io/jenkins/dockerjavaapi/client/DelegatingDockerClientTest.java
+++ b/src/test/java/io/jenkins/dockerjavaapi/client/DelegatingDockerClientTest.java
@@ -22,10 +22,9 @@
import static org.hamcrest.CoreMatchers.sameInstance;
import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import java.lang.reflect.Constructor;
@@ -38,6 +37,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
+import org.mockito.InOrder;
import org.mockito.exceptions.base.MockitoException;
import com.github.dockerjava.api.DockerClient;
@@ -57,7 +57,7 @@ public class DelegatingDockerClientTest {
* Each element in the returned {@link Iterable} is an Object[] whose contents
* matches the arguments taken by this class's constructor.
*
- * The annotation name = "{0}" says that the name of each set of
+ * Note: The annotation name = "{0}" says that the name of each set of
* data should be first element of the array.
*
* @return {@link Iterable} of [ {@link String}, {@link Method} ].
@@ -99,6 +99,32 @@ public DelegatingDockerClientTest(String methodName, Method dockerClientMethod)
this.dockerClientMethod = dockerClientMethod;
}
+ private interface HookPoints {
+ void interceptAnswerCalled(Object originalAnswer);
+
+ void interceptVoidCalled();
+ }
+
+ private static class DelegatingDockerClientUnderTest extends DelegatingDockerClient {
+ final HookPoints hooks = mock(HookPoints.class);
+
+ protected DelegatingDockerClientUnderTest(DockerClient delegate) {
+ super(delegate);
+ }
+
+ @Override
+ protected T interceptAnswer(T originalAnswer) {
+ hooks.interceptAnswerCalled(originalAnswer);
+ return super.interceptAnswer(originalAnswer);
+ }
+
+ @Override
+ protected void interceptVoid() {
+ hooks.interceptVoidCalled();
+ super.interceptVoid();
+ }
+ }
+
@Test
public void methodIsDelegatedCorrectly() throws Exception {
// Given
@@ -111,7 +137,7 @@ public void methodIsDelegatedCorrectly() throws Exception {
if (mockReturnValue != null) {
when(dockerClientMethod.invoke(mockDelegate, mockParameters)).thenReturn(mockReturnValue);
}
- final DelegatingDockerClient instanceUnderTest = new DelegatingDockerClient(mockDelegate);
+ final DelegatingDockerClientUnderTest instanceUnderTest = new DelegatingDockerClientUnderTest(mockDelegate);
// When
final Object actualReturnValue = dockerClientMethod.invoke(instanceUnderTest, mockParameters);
@@ -120,8 +146,14 @@ public void methodIsDelegatedCorrectly() throws Exception {
if (mockReturnValue != null) {
assertThat("Returned value is what delegate returned", actualReturnValue, sameInstance(mockReturnValue));
}
- dockerClientMethod.invoke(verify(mockDelegate, times(1)), mockParameters);
- verifyNoMoreInteractions(mockDelegate);
+ final InOrder inOrder = inOrder(mockDelegate, instanceUnderTest.hooks);
+ dockerClientMethod.invoke(inOrder.verify(mockDelegate, times(1)), mockParameters);
+ if (mockReturnValue != null) {
+ inOrder.verify(instanceUnderTest.hooks).interceptAnswerCalled(actualReturnValue);
+ } else {
+ inOrder.verify(instanceUnderTest.hooks).interceptVoidCalled();
+ }
+ inOrder.verifyNoMoreInteractions();
}
private static Object[] createFakeArgumentValues(final Parameter[] methodParameters) throws Exception {
From 1295d3de79069cb834977302d8257e23bdbe2a29 Mon Sep 17 00:00:00 2001
From: Peter Darton
Date: Fri, 23 Apr 2021 17:36:19 +0100
Subject: [PATCH 3/3] Improved javadocs.
---
.../client/DelegatingDockerClient.java | 26 +++++++++++++++----
1 file changed, 21 insertions(+), 5 deletions(-)
diff --git a/src/main/java/io/jenkins/dockerjavaapi/client/DelegatingDockerClient.java b/src/main/java/io/jenkins/dockerjavaapi/client/DelegatingDockerClient.java
index 4168262..d8ee197 100644
--- a/src/main/java/io/jenkins/dockerjavaapi/client/DelegatingDockerClient.java
+++ b/src/main/java/io/jenkins/dockerjavaapi/client/DelegatingDockerClient.java
@@ -53,10 +53,11 @@
* delegate method's answer and returns whatever
* {@link #interceptAnswer(Object)} returned.
*
- *
+ *
* If you are writing a Jenkins plugin that needs a class to implement/wrap
* {@link DockerClient}, you'd be best advised to extend this one, otherwise
- * your code could fail whenever the version of this plugin changes.
+ * your code could fail whenever the version of this plugin changes and the
+ * {@link DockerClient} gains additional methods.
*/
@SuppressWarnings("deprecation")
public class DelegatingDockerClient implements DockerClient {
@@ -75,7 +76,8 @@ public DelegatingDockerClient(@Nonnull DockerClient delegate) {
/**
* Obtains the underlying {@link DockerClient} interface. Subclasses can
- * override this if they need to hook into every call.
+ * override this if they need to hook into every call before anything else
+ * happens.
*
* @return the {@link DockerClient} to be delegated to.
*/
@@ -85,10 +87,18 @@ protected DockerClient getDelegate() {
}
/**
- * Called just before the result is returned. Allows a subclass to act just
- * before the method returns and/or to alter the result.
+ * Called just before the result is returned. Subclasses can override this if
+ * they need to hook into every call just before the method returns and/or to
+ * alter the result.
+ *
+ * Note: If a subclass only wishes to act upon certain specific
+ * {@link DockerClient} calls then it may be clearer to override those specific
+ * methods instead. This hook is intended for use by subclasses that need to act
+ * upon "all methods" or need to act on methods that were not part of the
+ * {@link DockerClient} API at the time they were implemented.
*
* @param originalAnswer The result from the delegate.
+ * @param The type of the originalAnswer.
* @return The result to be returned instead.
*/
protected T interceptAnswer(T originalAnswer) {
@@ -98,6 +108,12 @@ protected T interceptAnswer(T originalAnswer) {
/**
* Called just before the method returns void. Allows a subclass to act just
* before the method returns.
+ *
+ * Note: If a subclass only wishes to act upon certain specific
+ * {@link DockerClient} calls then it may be clearer to override those specific
+ * methods instead. This hook is intended for use by subclasses that need to act
+ * upon "all methods" or need to act on methods that were not part of the
+ * {@link DockerClient} API at the time they were implemented.
*/
protected void interceptVoid() {
}