|
16 | 16 |
|
17 | 17 | package org.springframework.cloud.dataflow.container.registry;
|
18 | 18 |
|
19 |
| -import java.util.Arrays; |
20 | 19 | import java.util.Collections;
|
21 | 20 | import java.util.HashMap;
|
22 | 21 | import java.util.Map;
|
23 | 22 |
|
24 | 23 | import com.fasterxml.jackson.core.JsonProcessingException;
|
25 | 24 | import com.fasterxml.jackson.databind.ObjectMapper;
|
26 |
| -import org.junit.jupiter.api.BeforeAll; |
27 | 25 | import org.junit.jupiter.api.BeforeEach;
|
28 | 26 | import org.junit.jupiter.api.Test;
|
| 27 | +import org.mockito.ArgumentMatcher; |
29 | 28 | import org.mockito.Mock;
|
30 | 29 | import org.mockito.MockitoAnnotations;
|
31 | 30 |
|
|
35 | 34 | import org.springframework.http.HttpHeaders;
|
36 | 35 | import org.springframework.http.HttpMethod;
|
37 | 36 | import org.springframework.http.HttpStatus;
|
| 37 | +import org.springframework.http.MediaType; |
38 | 38 | import org.springframework.http.ResponseEntity;
|
39 | 39 | import org.springframework.util.StringUtils;
|
40 | 40 | import org.springframework.web.client.RestTemplate;
|
|
46 | 46 | import static org.mockito.ArgumentMatchers.any;
|
47 | 47 | import static org.mockito.ArgumentMatchers.anyBoolean;
|
48 | 48 | import static org.mockito.ArgumentMatchers.anyMap;
|
| 49 | +import static org.mockito.ArgumentMatchers.argThat; |
49 | 50 | import static org.mockito.ArgumentMatchers.eq;
|
50 | 51 | import static org.mockito.Mockito.mock;
|
51 | 52 | import static org.mockito.Mockito.when;
|
@@ -210,6 +211,25 @@ public void getImageLabelsWithInvalidLabels() throws JsonProcessingException {
|
210 | 211 | assertThat(labels).isEmpty();
|
211 | 212 | }
|
212 | 213 |
|
| 214 | + @Test |
| 215 | + public void getImageLabelsWithMixedOCIResponses() throws JsonProcessingException { |
| 216 | + DefaultContainerImageMetadataResolver resolver = new MockedDefaultContainerImageMetadataResolver( |
| 217 | + this.containerRegistryService); |
| 218 | + String ociInCompatible = "{\"schemaVersion\": 1,\"name\": \"test/image\"}"; |
| 219 | + String ociCompatible = "{\"schemaVersion\": 2,\"mediaType\": \"application/vnd.oci.image.manifest.v1+json\",\"config\":{\"mediaType\": \"application/vnd.oci.image.config.v1+json\",\"digest\": \"sha256:efc06d6096cc88697e477abb0b3479557e1bec688c36813383f1a8581f87d9f8\",\"size\": 34268}}"; |
| 220 | + mockManifestRestTemplateCallAccepts(ociInCompatible, "my-private-repository.com", "5000", "test/image", |
| 221 | + "latest", ContainerRegistryProperties.DOCKER_IMAGE_MANIFEST_MEDIA_TYPE); |
| 222 | + mockManifestRestTemplateCallAccepts(ociCompatible, "my-private-repository.com", "5000", "test/image", "latest", |
| 223 | + ContainerRegistryProperties.OCI_IMAGE_MANIFEST_MEDIA_TYPE); |
| 224 | + String blobResponse = "{\"config\": {\"Labels\": {\"boza\": \"koza\"}}}"; |
| 225 | + mockBlogRestTemplateCall(blobResponse, "my-private-repository.com", "5000", "test/image", |
| 226 | + "sha256:efc06d6096cc88697e477abb0b3479557e1bec688c36813383f1a8581f87d9f8"); |
| 227 | + |
| 228 | + Map<String, String> labels = resolver.getImageLabels("my-private-repository.com:5000/test/image:latest"); |
| 229 | + assertThat(labels).isNotEmpty(); |
| 230 | + assertThat(labels).containsEntry("boza", "koza"); |
| 231 | + } |
| 232 | + |
213 | 233 | private void mockManifestRestTemplateCall(Map<String, Object> mapToReturn, String registryHost,
|
214 | 234 | String registryPort, String repository, String tagOrDigest) {
|
215 | 235 |
|
@@ -246,6 +266,39 @@ private void mockBlogRestTemplateCall(String jsonResponse, String registryHost,
|
246 | 266 | .thenReturn(new ResponseEntity<>(new ObjectMapper().readValue(jsonResponse, Map.class), HttpStatus.OK));
|
247 | 267 | }
|
248 | 268 |
|
| 269 | + private void mockManifestRestTemplateCallAccepts(String jsonResponse, String registryHost, String registryPort, |
| 270 | + String repository, String tagOrDigest, String accepts) throws JsonProcessingException { |
| 271 | + |
| 272 | + UriComponents blobUriComponents = UriComponentsBuilder.newInstance() |
| 273 | + .scheme("https") |
| 274 | + .host(registryHost) |
| 275 | + .port(StringUtils.hasText(registryPort) ? registryPort : null) |
| 276 | + .path("v2/{repository}/manifests/{reference}") |
| 277 | + .build() |
| 278 | + .expand(repository, tagOrDigest); |
| 279 | + |
| 280 | + MediaType mediaType = new MediaType(org.apache.commons.lang3.StringUtils.substringBefore(accepts, "/"), |
| 281 | + org.apache.commons.lang3.StringUtils.substringAfter(accepts, "/")); |
| 282 | + when(mockRestTemplate.exchange(eq(blobUriComponents.toUri()), eq(HttpMethod.GET), |
| 283 | + argThat(new HeaderAccepts(mediaType)), eq(Map.class))) |
| 284 | + .thenReturn(new ResponseEntity<>(new ObjectMapper().readValue(jsonResponse, Map.class), HttpStatus.OK)); |
| 285 | + } |
| 286 | + |
| 287 | + static class HeaderAccepts implements ArgumentMatcher<HttpEntity<?>> { |
| 288 | + |
| 289 | + private final MediaType accepts; |
| 290 | + |
| 291 | + public HeaderAccepts(MediaType accepts) { |
| 292 | + this.accepts = accepts; |
| 293 | + } |
| 294 | + |
| 295 | + @Override |
| 296 | + public boolean matches(HttpEntity<?> argument) { |
| 297 | + return argument.getHeaders().getAccept().contains(accepts); |
| 298 | + } |
| 299 | + |
| 300 | + } |
| 301 | + |
249 | 302 | private class MockedDefaultContainerImageMetadataResolver extends DefaultContainerImageMetadataResolver {
|
250 | 303 | public MockedDefaultContainerImageMetadataResolver(ContainerRegistryService containerRegistryService) {
|
251 | 304 | super(containerRegistryService);
|
|
0 commit comments