Skip to content

Commit

Permalink
FIX: Not a JSON Array: null (#1691)
Browse files Browse the repository at this point in the history
  • Loading branch information
panpengfei21 authored Jul 28, 2023
1 parent b9ffb5d commit 28c54ef
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package io.fabric8.maven.docker.access.hc;

import static java.net.HttpURLConnection.*;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
Expand Down Expand Up @@ -65,6 +63,13 @@
import io.fabric8.maven.docker.util.Logger;
import io.fabric8.maven.docker.util.TimestampFactory;

import static java.net.HttpURLConnection.HTTP_CREATED;
import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR;
import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
import static java.net.HttpURLConnection.HTTP_NOT_MODIFIED;
import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
import static java.net.HttpURLConnection.HTTP_OK;

/**
* Implementation using <a href="http://hc.apache.org/">Apache HttpComponents</a>
* for remotely accessing the docker host.
Expand Down Expand Up @@ -481,7 +486,13 @@ public List<String> getImageTags(String name) throws DockerAccessException {
return null;
}
JsonObject imageDetails = JsonFactory.newJsonObject(response.getBody());
JsonArray tagsArr = imageDetails.get("RepoTags").getAsJsonArray();

JsonElement repoTags = imageDetails.get("RepoTags");
if (repoTags == null || repoTags.isJsonNull()) {
return Collections.emptyList();
}

JsonArray tagsArr = repoTags.getAsJsonArray();
if (tagsArr.size() == 0) {
return Collections.emptyList();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.CloseableHttpClient;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
Expand Down Expand Up @@ -72,7 +71,7 @@ class DockerAccessWithHcClientTest {
@BeforeEach
public void setup() throws IOException {
Mockito.doReturn("{\"ApiVersion\":\"1.40\",\"Os\":\"linux\",\"Arch\":\"amd64\"}")
.when(mockDelegate).get(BASE_URL + "/version", HTTP_OK);
.when(mockDelegate).get(BASE_URL + "/version", HTTP_OK);

client = new DockerAccessWithHcClient(BASE_URL, null, 1, mockLogger) {
@Override
Expand Down Expand Up @@ -241,6 +240,42 @@ void serverApiVersion() {
Assertions.assertEquals("1.40", client.getServerApiVersion());
}

@Test
void testRepoTagsIsNull() throws IOException {
String imageId = "123123";
ApacheHttpClientDelegate.HttpBodyAndStatus bodyAndStatus = new ApacheHttpClientDelegate.HttpBodyAndStatus(HTTP_OK, "{\"RepoTags\": null}");

Mockito.doReturn(bodyAndStatus)
.when(mockDelegate)
.get(
Mockito.eq(BASE_URL + "/v1.40/images/" + imageId + "/json"),
Mockito.any(ApacheHttpClientDelegate.BodyAndStatusResponseHandler.class),
Mockito.eq(HTTP_OK),
Mockito.eq(HTTP_NOT_FOUND)
);

List<String> imageTags = client.getImageTags(imageId);
Assertions.assertTrue(imageTags.isEmpty());
}

@Test
void testNoRepoTagsInInspect() throws IOException {
String imageId = "123123";
ApacheHttpClientDelegate.HttpBodyAndStatus bodyAndStatus = new ApacheHttpClientDelegate.HttpBodyAndStatus(HTTP_OK, "{}");

Mockito.doReturn(bodyAndStatus)
.when(mockDelegate)
.get(
Mockito.eq(BASE_URL + "/v1.40/images/" + imageId + "/json"),
Mockito.any(ApacheHttpClientDelegate.BodyAndStatusResponseHandler.class),
Mockito.eq(HTTP_OK),
Mockito.eq(HTTP_NOT_FOUND)
);

List<String> imageTags = client.getImageTags(imageId);
Assertions.assertTrue(imageTags.isEmpty());
}

private void givenAnImageName(String imageName) {
this.imageName = imageName;
}
Expand Down Expand Up @@ -289,12 +324,12 @@ private void givenImageIdRepoTagPairs(Pair<String, String>... idRepoTagPairs) th
}

Mockito.doReturn(array.toString())
.when(mockDelegate)
.get(Mockito.anyString(), Mockito.eq(HTTP_OK));
.when(mockDelegate)
.get(Mockito.anyString(), Mockito.eq(HTTP_OK));
}

private void givenThePushWillFailAndEventuallySucceed(final int retries) throws IOException {
failPost(retries-1);
failPost(retries - 1);
}

private void givenThePushWillFail(final int failures) throws IOException {
Expand All @@ -303,49 +338,49 @@ private void givenThePushWillFail(final int failures) throws IOException {

private void failPost(int retries) throws IOException {
for (int i = 0; i < retries; ++i) {
Mockito.doThrow(new HttpResponseException(HTTP_INTERNAL_ERROR, "error-"+i))
.when(mockDelegate)
.post(Mockito.anyString(), Mockito.isNull(), Mockito.anyMap(), Mockito.any(ResponseHandler.class), Mockito.eq(HTTP_OK));
Mockito.doThrow(new HttpResponseException(HTTP_INTERNAL_ERROR, "error-" + i))
.when(mockDelegate)
.post(Mockito.anyString(), Mockito.isNull(), Mockito.anyMap(), Mockito.any(ResponseHandler.class), Mockito.eq(HTTP_OK));
}
}

private void givenThePostWillFail() throws IOException {
Mockito.doThrow(new HttpResponseException(HTTP_INTERNAL_ERROR, "error"))
.when(mockDelegate)
.post(Mockito.anyString(), Mockito.any(), Mockito.any(ResponseHandler.class), Mockito.eq(HTTP_OK));
.when(mockDelegate)
.post(Mockito.anyString(), Mockito.any(), Mockito.any(ResponseHandler.class), Mockito.eq(HTTP_OK));
}

@SuppressWarnings("unchecked")
private void givenThatGetWillSucceedWithOk() throws IOException {
Mockito.doReturn(HTTP_OK)
.when(mockDelegate)
.get(Mockito.anyString(), Mockito.any(ResponseHandler.class), Mockito.eq(HTTP_OK), Mockito.eq(HTTP_NOT_FOUND));
.when(mockDelegate)
.get(Mockito.anyString(), Mockito.any(ResponseHandler.class), Mockito.eq(HTTP_OK), Mockito.eq(HTTP_NOT_FOUND));
}

@SuppressWarnings("unchecked")
private void givenThatGetWillSucceedWithNotFound() throws IOException {
Mockito.doReturn(HTTP_NOT_FOUND)
.when(mockDelegate)
.get(Mockito.anyString(), Mockito.any(ResponseHandler.class), Mockito.eq(HTTP_OK), Mockito.eq(HTTP_NOT_FOUND));
.when(mockDelegate)
.get(Mockito.anyString(), Mockito.any(ResponseHandler.class), Mockito.eq(HTTP_OK), Mockito.eq(HTTP_NOT_FOUND));
}

private void givenTheGetWillFail() throws IOException {
Mockito.doThrow(new HttpResponseException(HTTP_INTERNAL_ERROR, "error"))
.when(mockDelegate)
.get(Mockito.anyString(), Mockito.any(ResponseHandler.class), Mockito.eq(HTTP_OK));
.when(mockDelegate)
.get(Mockito.anyString(), Mockito.any(ResponseHandler.class), Mockito.eq(HTTP_OK));
}

private void givenTheGetWithoutResponseHandlerWillFail() throws IOException {
Mockito.doThrow(new HttpResponseException(HTTP_INTERNAL_ERROR, "error"))
.when(mockDelegate)
.get(Mockito.anyString(), Mockito.eq(HTTP_OK));
.when(mockDelegate)
.get(Mockito.anyString(), Mockito.eq(HTTP_OK));
}

@SuppressWarnings("unchecked")
private void givenThatDeleteWillSucceed() throws IOException {
Mockito.doReturn(new ApacheHttpClientDelegate.HttpBodyAndStatus(HTTP_OK, "body"))
.when(mockDelegate)
.delete(Mockito.anyString(), Mockito.any(ResponseHandler.class), Mockito.eq(HTTP_OK), Mockito.eq(HTTP_NOT_FOUND));
.when(mockDelegate)
.delete(Mockito.anyString(), Mockito.any(ResponseHandler.class), Mockito.eq(HTTP_OK), Mockito.eq(HTTP_NOT_FOUND));
}

private void thenImageWasNotPushed() {
Expand All @@ -359,9 +394,9 @@ private void thenImageWasPushed() {
private void thenPushSucceeded(String imageNameWithoutTag, String tag) throws IOException {
ArgumentCaptor<String> urlCapture = ArgumentCaptor.forClass(String.class);
Mockito.verify(mockDelegate)
.post(urlCapture.capture(), Mockito.isNull(), Mockito.anyMap(), Mockito.any(ResponseHandler.class), Mockito.eq(HTTP_OK));
.post(urlCapture.capture(), Mockito.isNull(), Mockito.anyMap(), Mockito.any(ResponseHandler.class), Mockito.eq(HTTP_OK));

String expectedUrl = String.format("%s/v1.40/images/%s%%2F%s/push?force=1&tag=%s", BASE_URL, registry,
String expectedUrl = String.format("%s/v1.40/images/%s%%2F%s/push?force=1&tag=%s", BASE_URL, registry,
imageNameWithoutTag, tag);
Assertions.assertEquals(expectedUrl, urlCapture.getValue());
}
Expand All @@ -374,9 +409,9 @@ private void thenAlreadyHasImageMessageIsLogged() throws IOException {
private void thenImageWasTagged(String imageNameWithoutTag, String tag) throws IOException {
ArgumentCaptor<String> urlCapture = ArgumentCaptor.forClass(String.class);
Mockito.verify(mockDelegate)
.post(urlCapture.capture(), Mockito.eq(HTTP_CREATED));
.post(urlCapture.capture(), Mockito.eq(HTTP_CREATED));

String expectedUrl = String.format("%s/v1.40/images/%s%%3A%s/tag?force=0&repo=%s%%2F%s&tag=%s", BASE_URL,
String expectedUrl = String.format("%s/v1.40/images/%s%%3A%s/tag?force=0&repo=%s%%2F%s&tag=%s", BASE_URL,
imageNameWithoutTag, tag, registry, imageNameWithoutTag, tag);
Assertions.assertEquals(expectedUrl, urlCapture.getValue());
}
Expand Down Expand Up @@ -467,16 +502,16 @@ private String getImageNameWithRegistry() {

private void givenPostCallThrowsException() throws IOException {
Mockito.doThrow(new IOException("Problem with images/create"))
.when(mockDelegate)
.post(Mockito.anyString(), Mockito.any(), Mockito.anyMap(), Mockito.any(ResponseHandler.class), Mockito.eq(HTTP_OK));
.when(mockDelegate)
.post(Mockito.anyString(), Mockito.any(), Mockito.anyMap(), Mockito.any(ResponseHandler.class), Mockito.eq(HTTP_OK));
}

private void thenImageWasPulled() throws IOException {
ArgumentCaptor<String> urlCapture = ArgumentCaptor.forClass(String.class);
Mockito.verify(mockDelegate)
.post(urlCapture.capture(), Mockito.isNull(), Mockito.anyMap(), Mockito.any(ResponseHandler.class), Mockito.eq(HTTP_OK));
.post(urlCapture.capture(), Mockito.isNull(), Mockito.anyMap(), Mockito.any(ResponseHandler.class), Mockito.eq(HTTP_OK));

String postUrl= urlCapture.getValue();
String postUrl = urlCapture.getValue();
Assertions.assertNotNull(postUrl);
Assertions.assertEquals("tcp://1.2.3.4:2375/v1.40/images/create?tag=1.1", postUrl);
}
Expand Down

0 comments on commit 28c54ef

Please sign in to comment.