Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #2687: RawCustomResourceOperationsImpl ignores provided Config #2721

Merged
merged 2 commits into from Jan 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -3,6 +3,7 @@
### 5.1-SNAPSHOT

#### Bugs
* Fix #2687: RawCustomResourceOperationsImpl ignores config

#### Improvements

Expand Down
Expand Up @@ -60,16 +60,13 @@ public class RawCustomResourceOperationsImpl extends OperationSupport {

private static final String METADATA = "metadata";
private static final String RESOURCE_VERSION = "resourceVersion";
private OkHttpClient client;
private Config config;
private CustomResourceDefinitionContext customResourceDefinition;
private ObjectMapper objectMapper;
private final CustomResourceDefinitionContext customResourceDefinition;
private final ObjectMapper objectMapper;

private enum HttpCallMethod { GET, POST, PUT, DELETE };
private enum HttpCallMethod { GET, POST, PUT, DELETE }

public RawCustomResourceOperationsImpl(OkHttpClient client, Config config, CustomResourceDefinitionContext customResourceDefinition) {
this.client = client;
this.config = config;
super(client, config);
this.customResourceDefinition = customResourceDefinition;
this.objectMapper = Serialization.jsonMapper();
}
Expand Down
Expand Up @@ -45,6 +45,8 @@
import okhttp3.Response;
import okhttp3.ResponseBody;

import static org.assertj.core.api.Assertions.assertThat;

public class RawCustomResourceOperationsImplTest {
private OkHttpClient mockClient;
private Config config;
Expand Down Expand Up @@ -146,7 +148,7 @@ void testDeleteUrl() throws IOException {
}

@Test
public void testFetchWatchUrlWithNamespace() throws MalformedURLException {
void testFetchWatchUrlWithNamespace() throws MalformedURLException {
// Given
RawCustomResourceOperationsImpl rawCustomResourceOperations = new RawCustomResourceOperationsImpl(mockClient, config, customResourceDefinitionContext);

Expand All @@ -158,7 +160,7 @@ public void testFetchWatchUrlWithNamespace() throws MalformedURLException {
}

@Test
public void testFetchWatchUrlWithNamespaceAndName() throws MalformedURLException {
void testFetchWatchUrlWithNamespaceAndName() throws MalformedURLException {
// Given
RawCustomResourceOperationsImpl rawCustomResourceOperations = new RawCustomResourceOperationsImpl(mockClient, config, customResourceDefinitionContext);

Expand All @@ -170,7 +172,7 @@ public void testFetchWatchUrlWithNamespaceAndName() throws MalformedURLException
}

@Test
public void testFetchWatchUrlWithNamespaceAndNameAndResourceVersion() throws MalformedURLException {
void testFetchWatchUrlWithNamespaceAndNameAndResourceVersion() throws MalformedURLException {
// Given
RawCustomResourceOperationsImpl rawCustomResourceOperations = new RawCustomResourceOperationsImpl(mockClient, config, customResourceDefinitionContext);

Expand All @@ -182,7 +184,7 @@ public void testFetchWatchUrlWithNamespaceAndNameAndResourceVersion() throws Mal
}

@Test
public void testFetchWatchUrlWithoutAnything() throws MalformedURLException {
void testFetchWatchUrlWithoutAnything() throws MalformedURLException {
// Given
RawCustomResourceOperationsImpl rawCustomResourceOperations = new RawCustomResourceOperationsImpl(mockClient, config, customResourceDefinitionContext);

Expand All @@ -194,7 +196,7 @@ public void testFetchWatchUrlWithoutAnything() throws MalformedURLException {
}

@Test
public void testFetchWatchUrlWithLabels() throws MalformedURLException {
void testFetchWatchUrlWithLabels() throws MalformedURLException {
// Given
RawCustomResourceOperationsImpl rawCustomResourceOperations = new RawCustomResourceOperationsImpl(mockClient, config, customResourceDefinitionContext);

Expand All @@ -210,7 +212,7 @@ public void testFetchWatchUrlWithLabels() throws MalformedURLException {
}

@Test
public void testFetchWatchUrlWithLabelsWithNamespace() throws MalformedURLException {
void testFetchWatchUrlWithLabelsWithNamespace() throws MalformedURLException {
// Given
RawCustomResourceOperationsImpl rawCustomResourceOperations = new RawCustomResourceOperationsImpl(mockClient, config, customResourceDefinitionContext);

Expand All @@ -224,4 +226,30 @@ public void testFetchWatchUrlWithLabelsWithNamespace() throws MalformedURLExcept
// Then
assertEquals("https://localhost:8443/apis/test.fabric8.io/v1alpha1/namespaces/test/hellos?labelSelector=" + Utils.toUrlEncoded("foo=bar") + "," + Utils.toUrlEncoded("foo1=bar1") + "&watch=true", url.url().toString());
}

@Test
void testGetConfigShouldNotReturnNull() {
// Given
Config config = new ConfigBuilder()
.withRequestTimeout(5)
.withWebsocketTimeout(10L)
.withWebsocketPingInterval(10L)
.withConnectionTimeout(10)
.withWatchReconnectLimit(1)
.withWatchReconnectInterval(10)
.build();
RawCustomResourceOperationsImpl rawOp = new RawCustomResourceOperationsImpl(mockClient, config, customResourceDefinitionContext);

// When
Config configFromRawOp = rawOp.getConfig();

// Then
assertThat(configFromRawOp).isNotNull();
assertThat(configFromRawOp.getRequestTimeout()).isEqualTo(5);
assertThat(configFromRawOp.getWebsocketTimeout()).isEqualTo(10L);
assertThat(configFromRawOp.getWebsocketPingInterval()).isEqualTo(10L);
assertThat(configFromRawOp.getConnectionTimeout()).isEqualTo(10L);
assertThat(configFromRawOp.getWatchReconnectInterval()).isEqualTo(10);
assertThat(configFromRawOp.getWatchReconnectLimit()).isEqualTo(1);
}
}
Expand Up @@ -16,25 +16,42 @@
package io.fabric8.kubernetes;

import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import io.fabric8.commons.ClusterEntity;
import io.fabric8.kubernetes.api.model.Status;
import io.fabric8.kubernetes.client.Watcher;
import io.fabric8.kubernetes.client.WatcherException;
import io.fabric8.kubernetes.client.utils.Serialization;
import org.apache.commons.io.FileUtils;
import org.arquillian.cube.kubernetes.api.Session;
import org.arquillian.cube.kubernetes.impl.requirement.RequiresKubernetes;
import org.arquillian.cube.requirement.ArquillianConditionalRunner;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;

import com.fasterxml.jackson.databind.ObjectMapper;

import io.fabric8.kubernetes.api.model.apiextensions.v1beta1.CustomResourceDefinition;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext;

Expand All @@ -51,14 +68,16 @@ public class RawCustomResourceIT {

private CustomResourceDefinitionContext customResourceDefinitionContext;

@BeforeClass
public static void initCrd() {
// Create a Custom Resource Definition Animals:
ClusterEntity.apply(RawCustomResourceIT.class.getResourceAsStream("/test-rawcustomresource-definition.yml"));
}

@Before
public void initCustomResourceDefinition() {
public void initCustomResourceDefinitionContextAndNamespace() {
currentNamespace = session.getNamespace();

// Create a Custom Resource Definition Animals:
CustomResourceDefinition animalCrd = client.apiextensions().v1beta1().customResourceDefinitions().load(getClass().getResourceAsStream("/test-rawcustomresource-definition.yml")).get();
client.apiextensions().v1beta1().customResourceDefinitions().create(animalCrd);

customResourceDefinitionContext = new CustomResourceDefinitionContext.Builder()
.withName("animals.jungle.example.com")
.withGroup("jungle.example.com")
Expand All @@ -79,41 +98,185 @@ public void testCrud() throws IOException {
"\"kind\":\"Animal\",\"metadata\": {\"name\": \"walrus\"}," +
"\"spec\": {\"image\": \"my-awesome-walrus-image\"}}";
object = client.customResource(customResourceDefinitionContext).createOrReplace(currentNamespace, rawJsonCustomResourceObj);
assertThat(((HashMap<String, String>)object.get("metadata")).get("name")).isEqualTo("walrus");
assertThat(((HashMap<String, String>)object.get("spec")).get("image")).isEqualTo("my-awesome-walrus-image");
assertAnimal(object, "walrus", "my-awesome-walrus-image");

// Test replace with object
((HashMap<String, String>)object.get("spec")).put("image", "new-walrus-image");
object = client.customResource(customResourceDefinitionContext).createOrReplace(currentNamespace, object);
assertThat(((HashMap<String, String>)object.get("metadata")).get("name")).isEqualTo("walrus");
assertThat(((HashMap<String, String>)object.get("spec")).get("image")).isEqualTo("new-walrus-image");
assertAnimal(object, "walrus", "new-walrus-image");

// Test Get:
object = client.customResource(customResourceDefinitionContext).get(currentNamespace, "otter");
assertThat(((HashMap<String, String>)object.get("metadata")).get("name")).isEqualTo("otter");

// Test List:
Map<String, Object> list = client.customResource(customResourceDefinitionContext).list(currentNamespace);
assertThat(((ArrayList<Object>)list.get("items")).size()).isEqualTo(2);
assertThat(((ArrayList<Object>)list.get("items")).size()).isGreaterThanOrEqualTo(2);

// List with labels:
list = client.customResource(customResourceDefinitionContext).list(currentNamespace, Collections.singletonMap("foo", "bar"));
assertThat(((ArrayList<Object>)list.get("items")).size()).isEqualTo(1);
assertThat(((ArrayList<Object>)list.get("items")).size()).isGreaterThanOrEqualTo(1);

// Test Update
object = client.customResource(customResourceDefinitionContext).get(currentNamespace, "walrus");
((HashMap<String, Object>)object.get("spec")).put("image", "my-updated-awesome-walrus-image");
object = client.customResource(customResourceDefinitionContext).edit(currentNamespace, "walrus", new ObjectMapper().writeValueAsString(object));
assertThat(((HashMap<String, Object>)object.get("spec")).get("image")).isEqualTo("my-updated-awesome-walrus-image");
assertAnimal(object, "walrus", "my-updated-awesome-walrus-image");

// Test Delete:
client.customResource(customResourceDefinitionContext).delete(currentNamespace, "otter");
client.customResource(customResourceDefinitionContext).delete(currentNamespace);
}

@After
public void cleanup() {
// Delete Custom Resource Definition Animals:
client.apiextensions().v1beta1().customResourceDefinitions().withName(customResourceDefinitionContext.getName()).delete();
@Test
public void testCrudUsingMap() throws IOException {
// Create
String name = "bison";
Map<String, Object> bison = createNewAnimal(name, "wisent");
bison = client.customResource(customResourceDefinitionContext).create(currentNamespace, bison);
assertAnimal(bison, "bison", "wisent");

// Read
bison = client.customResource(customResourceDefinitionContext).get(currentNamespace, name);
assertAnimal(bison, "bison", "wisent");

// Update
((Map<String, Object>)bison.get("spec")).put("image", "bison-bonasus");
bison = client.customResource(customResourceDefinitionContext).edit(currentNamespace, name, bison);
assertAnimal(bison, "bison", "bison-bonasus");

// Delete
Map<String, Object> deletionStatusMap = client.customResource(customResourceDefinitionContext).delete(currentNamespace, name);
assertDeletionStatus(deletionStatusMap, "Success");
}

@Test
public void testCrudUsingInputStream() throws IOException {
// Create
String name = "hippo";
InputStream hippoInputStream = getClass().getResourceAsStream("/rawcustomresourceit-crud-inputstream.yml");
Map<String, Object> hippoCr = client.customResource(customResourceDefinitionContext).create(currentNamespace, hippoInputStream);
assertAnimal(hippoCr, name, "Hippopotamidae");

// Read
hippoCr = client.customResource(customResourceDefinitionContext).get(currentNamespace, name);
assertAnimal(hippoCr, name, "Hippopotamidae");

// Update
((Map<String, Object>)hippoCr.get("spec")).put("image", "river-hippo");
File updatedHippoManifest = Files.createTempFile("hippo", "yml").toFile();
FileUtils.writeStringToFile(updatedHippoManifest, Serialization.jsonMapper().writeValueAsString(hippoCr));
hippoCr = client.customResource(customResourceDefinitionContext).edit(currentNamespace, name, new FileInputStream(updatedHippoManifest));
assertAnimal(hippoCr, name, "river-hippo");

// Delete
Map<String, Object> deletionStatusMap = client.customResource(customResourceDefinitionContext).delete(currentNamespace, name);
assertDeletionStatus(deletionStatusMap, "Success");
}

@Test
public void testCrudUsingString() throws IOException {
// Create
String name = "rhino";
String rhino = "{\"apiVersion\": \"jungle.example.com/v1\"," +
" \"kind\": \"Animal\"," +
" \"metadata\": {\"name\": \"rhino\"}," +
" \"spec\": {\"image\": \"Rhinocerotidae\"}}";
Map<String, Object> rhinoCr = client.customResource(customResourceDefinitionContext).create(currentNamespace, rhino);
assertAnimal(rhinoCr, name, "Rhinocerotidae");

// Read
rhinoCr = client.customResource(customResourceDefinitionContext).get(currentNamespace, name);
assertAnimal(rhinoCr, name, "Rhinocerotidae");

// Update
((Map<String, Object>)rhinoCr.get("spec")).put("image", "rhinoceros");
String rhinoCrAsStr = Serialization.jsonMapper().writeValueAsString(rhinoCr);
rhinoCr = client.customResource(customResourceDefinitionContext).edit(currentNamespace, name, rhinoCrAsStr);
assertAnimal(rhinoCr, name, "rhinoceros");

// Delete
Map<String, Object> deletionStatusMap = client.customResource(customResourceDefinitionContext).delete(currentNamespace, name);
assertDeletionStatus(deletionStatusMap, "Success");
}

@Test
public void testWatch() throws IOException, InterruptedException {
// Given
String name = "chital";
Map<String, Object> deer = createNewAnimal(name, "spotted-deer");
CountDownLatch creationEventReceived = new CountDownLatch(1);

// When
client.customResource(customResourceDefinitionContext).watch(currentNamespace, new Watcher<String>() {
@Override
public void eventReceived(Action action, String resource) {
if (resource.contains(name)) {
creationEventReceived.countDown();
}
}

@Override
public void onClose(WatcherException cause) { }
});
client.customResource(customResourceDefinitionContext).create(currentNamespace, deer);

// Then
assertTrue(creationEventReceived.await(1, TimeUnit.SECONDS));
}

@Test
public void testUpdateStatus() throws IOException {
// Given
String name = "black-buck";
Map<String, Object> deer = createNewAnimal(name, "indian-antelope");
Map<String, Object> status = new HashMap<>();
status.put("conservationStatus", "endangered");

// When
deer = client.customResource(customResourceDefinitionContext).create(currentNamespace, deer);
await().atMost(5, TimeUnit.SECONDS)
.until(() -> client.customResource(customResourceDefinitionContext).get(currentNamespace, name) != null);
deer.put("status", status);
Map<String, Object> updatedDeer = client.customResource(customResourceDefinitionContext).updateStatus(currentNamespace, name, deer);

// Then
assertNotNull(updatedDeer);
assertEquals("endangered", ((Map<String, Object>)deer.get("status")).get("conservationStatus").toString());
}

@AfterClass
public static void cleanup() {
ClusterEntity.remove(RawCustomResourceIT.class.getResourceAsStream("/test-rawcustomresource-definition.yml"));
}

private void assertAnimal(Map<String, Object> animal, String name, String image) {
assertNotNull(animal);
assertFalse(animal.isEmpty());
assertThat(((HashMap<String, String>)animal.get("metadata")).get("name")).isEqualTo(name);
assertThat(((HashMap<String, String>)animal.get("spec")).get("image")).isEqualTo(image);
}

private void assertDeletionStatus(Map<String, Object> deletionStatusAsMap, String status) {
Status deletionStatus = Serialization.jsonMapper().convertValue(deletionStatusAsMap, Status.class);
assertNotNull(deletionStatus);
assertEquals(status, deletionStatus.getStatus());
}

private Map<String, Object> createNewAnimal(String name, String image) {
Map<String, Object> crAsMap = new HashMap<>();
crAsMap.put("apiVersion", "jungle.example.com/v1");
crAsMap.put("kind", "Animal");

Map<String, Object> crMetadata = new HashMap<>();
crMetadata.put("name", name);
crMetadata.put("labels", Collections.singletonMap("foo", "bar"));
Map<String, Object> crSpec = new HashMap<>();
crSpec.put("image", image);

crAsMap.put("metadata", crMetadata);
crAsMap.put("spec", crSpec);

return crAsMap;
}
}