diff --git a/e2e/src/test/groovy/io/kubernetes/client/e2e/dynamic/DynamicApiTest.groovy b/e2e/src/test/groovy/io/kubernetes/client/e2e/dynamic/DynamicApiTest.groovy new file mode 100644 index 0000000000..551a3f761a --- /dev/null +++ b/e2e/src/test/groovy/io/kubernetes/client/e2e/dynamic/DynamicApiTest.groovy @@ -0,0 +1,26 @@ +package io.kubernetes.client.e2e.dynamic + + +import io.kubernetes.client.openapi.models.V1Namespace +import io.kubernetes.client.openapi.models.V1ObjectMeta +import io.kubernetes.client.util.ClientBuilder +import io.kubernetes.client.util.generic.dynamic.DynamicKubernetesApi +import io.kubernetes.client.util.generic.dynamic.Dynamics +import spock.lang.Specification + +class DynamicApiTest extends Specification { + def "Create Namespace then Delete should work"() { + given: + def apiClient = ClientBuilder.defaultClient() + def dynamicApi = new DynamicKubernetesApi("", "v1", "namespaces", apiClient) + def namespaceFoo = new V1Namespace().metadata(new V1ObjectMeta().name("e2e-dynamic")) + when: + def createdNamespace = dynamicApi.create(Dynamics.newFromJson(apiClient.getJSON().serialize(namespaceFoo))) + then: + createdNamespace != null + when: + def deleted = dynamicApi.delete("e2e-dynamic").throwsApiException().getObject() + then: + deleted != null + } +} diff --git a/examples/examples-release-12/pom.xml b/examples/examples-release-12/pom.xml index 961892a6e1..85389435e4 100644 --- a/examples/examples-release-12/pom.xml +++ b/examples/examples-release-12/pom.xml @@ -5,7 +5,7 @@ io.kubernetes client-java-examples-parent 11.0.1-SNAPSHOT - .. + ../pom.xml client-java-examples-release-12 diff --git a/examples/examples-release-12/src/main/java/io/kubernetes/client/examples/DynamicClientExample.java b/examples/examples-release-12/src/main/java/io/kubernetes/client/examples/DynamicClientExample.java new file mode 100644 index 0000000000..7bb9a50cb1 --- /dev/null +++ b/examples/examples-release-12/src/main/java/io/kubernetes/client/examples/DynamicClientExample.java @@ -0,0 +1,47 @@ +/* +Copyright 2021 The Kubernetes Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at +http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package io.kubernetes.client.examples; + +import java.io.FileReader; +import java.io.IOException; + +import io.kubernetes.client.openapi.ApiClient; +import io.kubernetes.client.openapi.ApiException; +import io.kubernetes.client.util.ClientBuilder; +import io.kubernetes.client.util.KubeConfig; +import io.kubernetes.client.util.generic.dynamic.DynamicKubernetesApi; +import io.kubernetes.client.util.generic.dynamic.DynamicKubernetesObject; + +public class DynamicClientExample { + + public static void main(String[] args) throws IOException, ApiException { + + ApiClient apiClient = ClientBuilder.standard().build(); + + // retrieving the latest state of the default namespace + DynamicKubernetesApi dynamicApi = new DynamicKubernetesApi("", "v1", "namespaces", apiClient); + DynamicKubernetesObject defaultNamespace = dynamicApi.get("default") + .throwsApiException() + .getObject(); + + // attaching a "foo=bar" label to the default namespace + defaultNamespace.setMetadata(defaultNamespace.getMetadata().putLabelsItem("foo", "bar")); + DynamicKubernetesObject updatedDefaultNamespace = dynamicApi.update(defaultNamespace) + .throwsApiException() + .getObject(); + + System.out.println(updatedDefaultNamespace); + + apiClient.getHttpClient().connectionPool().evictAll(); + } +} diff --git a/util/src/main/java/io/kubernetes/client/util/generic/dynamic/DynamicKubernetesApi.java b/util/src/main/java/io/kubernetes/client/util/generic/dynamic/DynamicKubernetesApi.java new file mode 100644 index 0000000000..6dff9f97b4 --- /dev/null +++ b/util/src/main/java/io/kubernetes/client/util/generic/dynamic/DynamicKubernetesApi.java @@ -0,0 +1,77 @@ +/* +Copyright 2021 The Kubernetes Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at +http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package io.kubernetes.client.util.generic.dynamic; + +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; +import io.kubernetes.client.common.KubernetesListObject; +import io.kubernetes.client.common.KubernetesObject; +import io.kubernetes.client.openapi.ApiClient; +import io.kubernetes.client.util.generic.GenericKubernetesApi; + +/** + * DynamicKubernetesApi can be used for reading and writing arbitrary resources without knowing it's + * java definitions. + */ +public class DynamicKubernetesApi + extends GenericKubernetesApi { + + private final Gson gson; + + /** + * Instantiates a new Dynamic kubernetes api. + * + * @param apiGroup the api group + * @param apiVersion the api version + * @param resourcePlural the resource plural + * @param apiClient the api client + */ + public DynamicKubernetesApi( + String apiGroup, String apiVersion, String resourcePlural, ApiClient apiClient) { + super( + DynamicKubernetesObject.class, + DynamicKubernetesListObject.class, + apiGroup, + apiVersion, + resourcePlural, + apiClient); + TypeAdapter objAdapter = + apiClient.getJSON().getGson().getAdapter(KubernetesObject.class); + TypeAdapter objListAdapter = + apiClient.getJSON().getGson().getAdapter(KubernetesListObject.class); + if (!DynamicKubernetesTypeAdaptorFactory.GenericListObjectCreator.class.equals( + objListAdapter.getClass()) + || !DynamicKubernetesTypeAdaptorFactory.GenericObjectCreator.class.equals( + objAdapter.getClass())) { + apiClient + .getJSON() + .setGson( + apiClient + .getJSON() + .getGson() + .newBuilder() + .registerTypeAdapterFactory(new DynamicKubernetesTypeAdaptorFactory()) + .create()); + } + gson = apiClient.getJSON().getGson(); + } + + /** + * Gets gson instance. + * + * @return the gson + */ + public Gson getGson() { + return gson; + } +} diff --git a/util/src/main/java/io/kubernetes/client/util/generic/dynamic/DynamicKubernetesListObject.java b/util/src/main/java/io/kubernetes/client/util/generic/dynamic/DynamicKubernetesListObject.java new file mode 100644 index 0000000000..a11fb44221 --- /dev/null +++ b/util/src/main/java/io/kubernetes/client/util/generic/dynamic/DynamicKubernetesListObject.java @@ -0,0 +1,96 @@ +/* +Copyright 2021 The Kubernetes Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at +http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package io.kubernetes.client.util.generic.dynamic; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import io.kubernetes.client.common.KubernetesListObject; +import io.kubernetes.client.openapi.Configuration; +import io.kubernetes.client.openapi.models.V1ListMeta; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * DynamicKubernetesListObject is a wrapper for {@link JsonObject} that fits the common kubernetes + * list type interface {@link KubernetesListObject}. + */ +public class DynamicKubernetesListObject implements KubernetesListObject { + + public DynamicKubernetesListObject() { + this(new JsonObject()); + } + + public DynamicKubernetesListObject(JsonObject obj) { + this.raw = obj; + } + + private final JsonObject raw; + + @Override + public V1ListMeta getMetadata() { + return Configuration.getDefaultApiClient() + .getJSON() + .getGson() + .fromJson(this.raw.get("metadata"), V1ListMeta.class); + } + + @Override + public String getApiVersion() { + return this.raw.get("apiVersion").getAsString(); + } + + @Override + public String getKind() { + return this.raw.get("kind").getAsString(); + } + + @Override + public List getItems() { + List list = new ArrayList<>(); + for (JsonElement e : this.raw.get("items").getAsJsonArray()) { + list.add(new DynamicKubernetesObject(e.getAsJsonObject())); + } + return list; + } + + public JsonObject getRaw() { + return raw; + } + + public void setApiVersion(String apiVersion) { + this.raw.addProperty("apiVersion", apiVersion); + } + + public void setKind(String kind) { + this.raw.addProperty("kind", kind); + } + + public void setMetadata(V1ListMeta objectMeta) { + this.raw.add( + "metadata", Configuration.getDefaultApiClient().getJSON().getGson().toJsonTree(objectMeta)); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DynamicKubernetesListObject that = (DynamicKubernetesListObject) o; + return Objects.equals(raw, that.raw); + } + + @Override + public int hashCode() { + return Objects.hash(raw); + } +} diff --git a/util/src/main/java/io/kubernetes/client/util/generic/dynamic/DynamicKubernetesObject.java b/util/src/main/java/io/kubernetes/client/util/generic/dynamic/DynamicKubernetesObject.java new file mode 100644 index 0000000000..2133a23581 --- /dev/null +++ b/util/src/main/java/io/kubernetes/client/util/generic/dynamic/DynamicKubernetesObject.java @@ -0,0 +1,84 @@ +/* +Copyright 2021 The Kubernetes Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at +http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package io.kubernetes.client.util.generic.dynamic; + +import com.google.gson.JsonObject; +import io.kubernetes.client.common.KubernetesObject; +import io.kubernetes.client.openapi.Configuration; +import io.kubernetes.client.openapi.models.V1ObjectMeta; +import java.util.Objects; + +/** + * DynamicKubernetesObject is a wrapper for {@link JsonObject} that fits the common kubernetes type + * interface {@link KubernetesObject}. + */ +public class DynamicKubernetesObject implements KubernetesObject { + + public DynamicKubernetesObject() { + this(new JsonObject()); + } + + public DynamicKubernetesObject(JsonObject obj) { + this.raw = obj; + } + + private final JsonObject raw; + + @Override + public V1ObjectMeta getMetadata() { + return Configuration.getDefaultApiClient() + .getJSON() + .getGson() + .fromJson(this.raw.get("metadata"), V1ObjectMeta.class); + } + + @Override + public String getApiVersion() { + return this.raw.get("apiVersion").getAsString(); + } + + @Override + public String getKind() { + return this.raw.get("kind").getAsString(); + } + + public JsonObject getRaw() { + return raw; + } + + public void setApiVersion(String apiVersion) { + this.raw.addProperty("apiVersion", apiVersion); + } + + public void setKind(String kind) { + this.raw.addProperty("kind", kind); + } + + public void setMetadata(V1ObjectMeta objectMeta) { + this.raw.add( + "metadata", Configuration.getDefaultApiClient().getJSON().getGson().toJsonTree(objectMeta)); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DynamicKubernetesObject that = (DynamicKubernetesObject) o; + return Objects.equals(raw, that.raw); + } + + @Override + public int hashCode() { + return Objects.hash(raw); + } +} diff --git a/util/src/main/java/io/kubernetes/client/util/generic/dynamic/DynamicKubernetesTypeAdaptorFactory.java b/util/src/main/java/io/kubernetes/client/util/generic/dynamic/DynamicKubernetesTypeAdaptorFactory.java new file mode 100644 index 0000000000..9a67fa384e --- /dev/null +++ b/util/src/main/java/io/kubernetes/client/util/generic/dynamic/DynamicKubernetesTypeAdaptorFactory.java @@ -0,0 +1,103 @@ +/* +Copyright 2021 The Kubernetes Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at +http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package io.kubernetes.client.util.generic.dynamic; + +import com.google.gson.Gson; +import com.google.gson.InstanceCreator; +import com.google.gson.JsonObject; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import io.kubernetes.client.common.KubernetesListObject; +import io.kubernetes.client.common.KubernetesObject; +import java.io.IOException; +import java.lang.reflect.Type; + +public class DynamicKubernetesTypeAdaptorFactory implements TypeAdapterFactory { + @Override + public TypeAdapter create(Gson gson, TypeToken typeToken) { + if (shouldHandleAsSingleObject(typeToken)) { + return (TypeAdapter) (new GenericObjectCreator(gson)); + } + if (shouldHandleAsListObject(typeToken)) { + return (TypeAdapter) (new GenericListObjectCreator(gson)); + } + return gson.getDelegateAdapter(this, typeToken); + } + + private boolean shouldHandleAsSingleObject(TypeToken typeToken) { + if (TypeToken.get(KubernetesObject.class).equals(typeToken)) { + return true; + } + return TypeToken.get(DynamicKubernetesObject.class).equals(typeToken); + } + + private boolean shouldHandleAsListObject(TypeToken typeToken) { + if (TypeToken.get(KubernetesListObject.class).equals(typeToken)) { + return true; + } + return TypeToken.get(DynamicKubernetesListObject.class).equals(typeToken); + } + + class GenericListObjectCreator extends TypeAdapter + implements InstanceCreator { + + GenericListObjectCreator(Gson delegate) { + this.delegate = delegate; + } + + private final Gson delegate; + + @Override + public DynamicKubernetesListObject createInstance(Type type) { + return new DynamicKubernetesListObject(); + } + + @Override + public void write(JsonWriter jsonWriter, DynamicKubernetesListObject t) throws IOException { + jsonWriter.jsonValue(delegate.toJson(t.getRaw())); + } + + @Override + public DynamicKubernetesListObject read(JsonReader jsonReader) throws IOException { + return new DynamicKubernetesListObject(delegate.fromJson(jsonReader, JsonObject.class)); + } + } + + class GenericObjectCreator extends TypeAdapter + implements InstanceCreator { + + GenericObjectCreator(Gson delegate) { + this.delegate = delegate; + } + + private final Gson delegate; + + @Override + public DynamicKubernetesObject createInstance(Type type) { + return new DynamicKubernetesObject(); + } + + @Override + public void write(JsonWriter jsonWriter, DynamicKubernetesObject t) throws IOException { + jsonWriter.jsonValue(delegate.toJson(t.getRaw())); + } + + @Override + public DynamicKubernetesObject read(JsonReader jsonReader) throws IOException { + return new DynamicKubernetesObject(delegate.fromJson(jsonReader, JsonObject.class)); + } + } +} diff --git a/util/src/main/java/io/kubernetes/client/util/generic/dynamic/Dynamics.java b/util/src/main/java/io/kubernetes/client/util/generic/dynamic/Dynamics.java new file mode 100644 index 0000000000..6ea57c592f --- /dev/null +++ b/util/src/main/java/io/kubernetes/client/util/generic/dynamic/Dynamics.java @@ -0,0 +1,38 @@ +/* +Copyright 2021 The Kubernetes Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at +http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package io.kubernetes.client.util.generic.dynamic; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import io.kubernetes.client.openapi.Configuration; + +public class Dynamics { + + public static DynamicKubernetesObject newFromJson(String jsonContent) { + return newFromJson(Configuration.getDefaultApiClient().getJSON().getGson(), jsonContent); + } + + public static DynamicKubernetesObject newFromJson(Gson gson, String jsonContent) { + JsonElement raw = gson.fromJson(jsonContent, JsonElement.class); + return new DynamicKubernetesObject(raw.getAsJsonObject()); + } + + public static DynamicKubernetesListObject newListFromJson(String jsonContent) { + return newListFromJson(Configuration.getDefaultApiClient().getJSON().getGson(), jsonContent); + } + + public static DynamicKubernetesListObject newListFromJson(Gson gson, String jsonContent) { + JsonElement raw = gson.fromJson(jsonContent, JsonElement.class); + return new DynamicKubernetesListObject(raw.getAsJsonObject()); + } +} diff --git a/util/src/test/java/io/kubernetes/client/util/generic/dynamic/DynamicKubernetesApiTest.java b/util/src/test/java/io/kubernetes/client/util/generic/dynamic/DynamicKubernetesApiTest.java new file mode 100644 index 0000000000..e10e9b12e6 --- /dev/null +++ b/util/src/test/java/io/kubernetes/client/util/generic/dynamic/DynamicKubernetesApiTest.java @@ -0,0 +1,133 @@ +/* +Copyright 2021 The Kubernetes Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at +http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package io.kubernetes.client.util.generic.dynamic; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.put; +import static com.github.tomakehurst.wiremock.client.WireMock.putRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; +import static org.junit.Assert.*; + +import com.github.tomakehurst.wiremock.junit.WireMockRule; +import io.kubernetes.client.openapi.ApiClient; +import io.kubernetes.client.openapi.ApiException; +import io.kubernetes.client.openapi.models.V1Namespace; +import io.kubernetes.client.openapi.models.V1NamespaceList; +import io.kubernetes.client.openapi.models.V1ObjectMeta; +import io.kubernetes.client.util.ClientBuilder; +import java.io.IOException; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +public class DynamicKubernetesApiTest { + + private static final String jsonContent = + new StringBuilder() + .append("{") + .append("\"apiVersion\":\"v1\",") + .append("\"kind\":\"CustomResource\",") + .append("\"metadata\":{") + .append("\"namespace\":\"default\",") + .append("\"name\":\"foo\"") + .append("}") + .append("}") + .toString(); + + private ApiClient apiClient; + + @Rule public WireMockRule wireMockRule = new WireMockRule(options().dynamicPort(), false); + + @Before + public void setup() throws IOException { + apiClient = new ClientBuilder().setBasePath("http://localhost:" + wireMockRule.port()).build(); + } + + @Test + public void testListNamespaceShouldWork() throws ApiException { + V1NamespaceList expectedList = + new V1NamespaceList() + .addItemsItem(new V1Namespace().metadata(new V1ObjectMeta().name("foo1"))) + .addItemsItem(new V1Namespace().metadata(new V1ObjectMeta().name("foo2"))); + wireMockRule.stubFor( + get(urlPathEqualTo("/api/v1/namespaces")) + .willReturn( + aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBody(apiClient.getJSON().serialize(expectedList)))); + DynamicKubernetesApi api = new DynamicKubernetesApi("", "v1", "namespaces", apiClient); + DynamicKubernetesListObject listObj = api.list().throwsApiException().getObject(); + assertEquals(expectedList.getItems().size(), listObj.getItems().size()); + wireMockRule.verify(getRequestedFor(urlPathEqualTo("/api/v1/namespaces"))); + } + + @Test + public void testUpdateNamespaceShouldWork() throws ApiException { + V1Namespace updating = new V1Namespace().metadata(new V1ObjectMeta().name("foo1")); + wireMockRule.stubFor( + put(urlPathEqualTo("/api/v1/namespaces/foo1")) + .willReturn( + aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBody(apiClient.getJSON().serialize(updating)))); + DynamicKubernetesApi api = new DynamicKubernetesApi("", "v1", "namespaces", apiClient); + DynamicKubernetesObject updatingObj = + Dynamics.newFromJson(apiClient.getJSON().serialize(updating)); + DynamicKubernetesObject updatedObj = api.update(updatingObj).throwsApiException().getObject(); + assertEquals(updatingObj, updatedObj); + wireMockRule.verify(putRequestedFor(urlPathEqualTo("/api/v1/namespaces/foo1"))); + } + + @Test + public void testListCustomResourceShouldWork() throws ApiException { + wireMockRule.stubFor( + get(urlPathEqualTo("/apis/mygroup.io/myversion/namespaces/default/customresources")) + .willReturn( + aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBody("{}"))); + DynamicKubernetesApi api = + new DynamicKubernetesApi("mygroup.io", "myversion", "customresources", apiClient); + DynamicKubernetesListObject listObj = api.list("default").throwsApiException().getObject(); + assertNotNull(listObj); + wireMockRule.verify( + getRequestedFor( + urlPathEqualTo("/apis/mygroup.io/myversion/namespaces/default/customresources"))); + } + + @Test + public void testUpdateCustomResourceShouldWork() throws ApiException { + wireMockRule.stubFor( + put(urlPathEqualTo("/apis/mygroup.io/myversion/namespaces/default/customresources/foo")) + .willReturn( + aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBody("{}"))); + DynamicKubernetesApi api = + new DynamicKubernetesApi("mygroup.io", "myversion", "customresources", apiClient); + DynamicKubernetesObject updatingObj = Dynamics.newFromJson(jsonContent); + DynamicKubernetesObject updatedObj = api.update(updatingObj).throwsApiException().getObject(); + assertNotNull(updatedObj); + assertEquals("{}", apiClient.getJSON().serialize(updatedObj)); + wireMockRule.verify( + putRequestedFor( + urlPathEqualTo("/apis/mygroup.io/myversion/namespaces/default/customresources/foo"))); + } +} diff --git a/util/src/test/java/io/kubernetes/client/util/generic/dynamic/DynamicKubernetesTypeAdaptorFactoryTest.java b/util/src/test/java/io/kubernetes/client/util/generic/dynamic/DynamicKubernetesTypeAdaptorFactoryTest.java new file mode 100644 index 0000000000..4c90b6baf4 --- /dev/null +++ b/util/src/test/java/io/kubernetes/client/util/generic/dynamic/DynamicKubernetesTypeAdaptorFactoryTest.java @@ -0,0 +1,82 @@ +/* +Copyright 2021 The Kubernetes Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at +http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package io.kubernetes.client.util.generic.dynamic; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import com.google.gson.Gson; +import io.kubernetes.client.common.KubernetesListObject; +import io.kubernetes.client.common.KubernetesObject; +import io.kubernetes.client.openapi.models.V1ObjectMeta; +import org.junit.Before; +import org.junit.Test; + +public class DynamicKubernetesTypeAdaptorFactoryTest { + + private Gson gson; + + private static final String jsonContent = + new StringBuilder() + .append("{") + .append("\"apiVersion\":\"v1\",") + .append("\"kind\":\"Namespace\",") + .append("\"metadata\":{") + .append("\"name\":\"foo\"") + .append("}") + .append("}") + .toString(); + + @Before + public void setup() { + gson = + new Gson() + .newBuilder() + .registerTypeAdapterFactory(new DynamicKubernetesTypeAdaptorFactory()) + .create(); + } + + @Test + public void testSingleDynamicObjectRoundTrip() { + KubernetesObject dynamicObj = gson.fromJson(jsonContent, KubernetesObject.class); + assertTrue(dynamicObj instanceof DynamicKubernetesObject); + + assertEquals("v1", dynamicObj.getApiVersion()); + assertEquals("Namespace", dynamicObj.getKind()); + assertEquals(new V1ObjectMeta().name("foo"), dynamicObj.getMetadata()); + + String dumped = gson.toJson(dynamicObj); + assertEquals(jsonContent, dumped); + } + + @Test + public void testListDynamicObjectRoundTrip() { + String listJsonContent = + new StringBuilder() + .append("{") + .append("\"items\":[") + .append(jsonContent) + .append("]") + .append("}") + .toString(); + + KubernetesListObject dynamicListObj = + gson.fromJson(listJsonContent, KubernetesListObject.class); + assertTrue(dynamicListObj instanceof DynamicKubernetesListObject); + + assertEquals(1, dynamicListObj.getItems().size()); + + String dumped = gson.toJson(dynamicListObj); + assertEquals(listJsonContent, dumped); + } +}