From 2aaa79bc719491dd0efbe761f98bef15f1e86ede Mon Sep 17 00:00:00 2001
From: Rohan Kumar <rohaan@redhat.com>
Date: Tue, 20 Oct 2020 15:30:46 +0530
Subject: [PATCH] Changes in BaseOperation to retry createOrReplace on server
 failure

+ Moved createOrReplace logic to CreateOrReplaceHelper class
+ Added tests
---
 .../client/dsl/base/BaseOperation.java        |  46 ++----
 ...WatchDeleteRecreateWaitApplicableImpl.java |  31 +---
 ...hDeleteRecreateWaitApplicableListImpl.java |  39 ++---
 .../client/utils/CreateOrReplaceHelper.java   |  98 ++++++++++++
 .../client/utils/DeleteAndCreateHelper.java   |  54 +++++++
 .../kubernetes/client/utils/Utils.java        |   1 +
 .../client/dsl/base/BaseOperationTest.java    |  15 +-
 .../utils/CreateOrReplaceHelperTest.java      | 140 ++++++++++++++++++
 .../utils/DeleteAndCreateHelperTest.java      |  83 +++++++++++
 .../fabric8/kubernetes/CreateOrReplaceIT.java | 125 ++++++++++++++--
 .../createorreplace-it-testlist-v1.yml        |  38 +++++
 .../createorreplace-it-testlist-v2.yml        |  39 +++++
 .../client/mock/ResourceListTest.java         |   4 +-
 .../kubernetes/client/mock/ResourceTest.java  |   3 +-
 14 files changed, 608 insertions(+), 108 deletions(-)
 create mode 100644 kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/CreateOrReplaceHelper.java
 create mode 100644 kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/DeleteAndCreateHelper.java
 create mode 100644 kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/CreateOrReplaceHelperTest.java
 create mode 100644 kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/DeleteAndCreateHelperTest.java
 create mode 100644 kubernetes-itests/src/test/resources/createorreplace-it-testlist-v1.yml
 create mode 100644 kubernetes-itests/src/test/resources/createorreplace-it-testlist-v2.yml

diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/base/BaseOperation.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/base/BaseOperation.java
index 935dd89c3e5..d4886225c39 100755
--- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/base/BaseOperation.java
+++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/base/BaseOperation.java
@@ -16,7 +16,7 @@
 package io.fabric8.kubernetes.client.dsl.base;
 
 import io.fabric8.kubernetes.api.model.ObjectReference;
-import io.fabric8.kubernetes.client.utils.KubernetesResourceUtil;
+import io.fabric8.kubernetes.client.utils.CreateOrReplaceHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -71,7 +71,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
@@ -405,37 +404,22 @@ public final T createOrReplace(T... items) {
 
       return withName(itemToCreateOrReplace.getMetadata().getName()).createOrReplace(itemToCreateOrReplace);
     }
-
-    final CompletableFuture<T> future = new CompletableFuture<>();
-    while (!future.isDone()) {
-      try {
-        // Create
-        KubernetesResourceUtil.setResourceVersion(itemToCreateOrReplace, null);
-        future.complete(create(itemToCreateOrReplace));
-      } catch (KubernetesClientException exception) {
-        final T itemFromServer;
-        if (exception.getCode() == HttpURLConnection.HTTP_INTERNAL_ERROR) {
-          itemFromServer = fromServer().get();
-          if (itemFromServer == null) {
-            try {
-              Thread.sleep(200);
-            } catch (InterruptedException e) {
-              Thread.currentThread().interrupt();
-            }
-            continue;
-          }
-        } else if (exception.getCode() != HttpURLConnection.HTTP_CONFLICT) {
-          throw exception;
-        } else {
-          itemFromServer = fromServer().get();
+    T finalItemToCreateOrReplace = itemToCreateOrReplace;
+    CreateOrReplaceHelper<T> createOrReplaceHelper = new CreateOrReplaceHelper<>(
+      this::create,
+      this::replace,
+      m -> {
+        try {
+          return waitUntilCondition(Objects::nonNull, 1, TimeUnit.SECONDS);
+        } catch (InterruptedException interruptedException) {
+          interruptedException.printStackTrace();
         }
+        return null;
+      },
+      m -> fromServer().get()
+    );
 
-        // Conflict; Do Replace
-        KubernetesResourceUtil.setResourceVersion(itemToCreateOrReplace, KubernetesResourceUtil.getResourceVersion(itemFromServer));
-        future.complete(replace(itemToCreateOrReplace));
-      }
-    }
-    return future.join();
+    return createOrReplaceHelper.createOrReplace(finalItemToCreateOrReplace);
   }
 
   @Override
diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableImpl.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableImpl.java
index 2012bfef257..5b76cfc0e9a 100644
--- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableImpl.java
+++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableImpl.java
@@ -17,10 +17,8 @@
 
 import io.fabric8.kubernetes.api.model.DeletionPropagation;
 import io.fabric8.kubernetes.api.model.ListOptions;
-import io.fabric8.kubernetes.client.utils.KubernetesResourceUtil;
 import io.fabric8.kubernetes.client.utils.Utils;
 
-import java.net.HttpURLConnection;
 import java.util.function.Predicate;
 
 import java.io.ByteArrayInputStream;
@@ -57,6 +55,9 @@
 import io.fabric8.kubernetes.client.internal.readiness.Readiness;
 import okhttp3.OkHttpClient;
 
+import static io.fabric8.kubernetes.client.utils.CreateOrReplaceHelper.createOrReplaceItem;
+import static io.fabric8.kubernetes.client.utils.DeleteAndCreateHelper.deleteAndCreateItem;
+
 public class NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableImpl extends OperationSupport implements
   NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicable<HasMetadata, Boolean>,
   Waitable<HasMetadata, HasMetadata>,
@@ -135,29 +136,10 @@ public HasMetadata createOrReplace() {
     HasMetadata meta = acceptVisitors(asHasMetadata(item), visitors);
     ResourceHandler<HasMetadata, HasMetadataVisitiableBuilder> h = handlerOf(meta);
     String namespaceToUse = meta.getMetadata().getNamespace();
-
-    String resourceVersion = KubernetesResourceUtil.getResourceVersion(meta);
-    try {
-      // Create
-      KubernetesResourceUtil.setResourceVersion(meta, null);
-      return h.create(client, config, namespaceToUse, meta);
-    } catch (KubernetesClientException exception) {
-      if (exception.getCode() != HttpURLConnection.HTTP_CONFLICT) {
-        throw exception;
-      }
-
-      // Conflict; check deleteExisting flag otherwise replace
-      if (Boolean.TRUE.equals(deletingExisting)) {
-        Boolean deleted = h.delete(client, config, namespaceToUse, propagationPolicy, meta);
-        if (Boolean.FALSE.equals(deleted)) {
-          throw new KubernetesClientException("Failed to delete existing item:" + meta);
-        }
-        return h.create(client, config, namespaceToUse, meta);
-      } else {
-        KubernetesResourceUtil.setResourceVersion(meta, resourceVersion);
-        return h.replace(client, config, namespaceToUse, meta);
-      }
+    if (Boolean.TRUE.equals(deletingExisting)) {
+      return deleteAndCreateItem(client, config, meta, h, namespaceToUse, propagationPolicy);
     }
+    return createOrReplaceItem(client, config, meta, h, namespaceToUse);
   }
 
   @Override
@@ -327,5 +309,4 @@ private static <T> ResourceHandler handlerOf(T item) {
       throw new IllegalArgumentException("Could not find a registered handler for item: [" + item + "].");
     }
   }
-
 }
diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl.java
index 95f707fb12a..b8a4fb1c8cc 100644
--- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl.java
+++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl.java
@@ -34,7 +34,6 @@
 import io.fabric8.kubernetes.client.dsl.base.OperationSupport;
 import io.fabric8.kubernetes.client.handlers.KubernetesListHandler;
 import io.fabric8.kubernetes.client.internal.readiness.Readiness;
-import io.fabric8.kubernetes.client.utils.KubernetesResourceUtil;
 import io.fabric8.kubernetes.client.utils.Serialization;
 import io.fabric8.kubernetes.client.utils.Utils;
 
@@ -45,7 +44,6 @@
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.HttpURLConnection;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -62,6 +60,9 @@
 import java.util.concurrent.TimeoutException;
 import java.util.function.Predicate;
 
+import static io.fabric8.kubernetes.client.utils.CreateOrReplaceHelper.createOrReplaceItem;
+import static io.fabric8.kubernetes.client.utils.DeleteAndCreateHelper.deleteAndCreateItem;
+
 public class NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl extends OperationSupport implements ParameterNamespaceListVisitFromServerGetDeleteRecreateWaitApplicable<HasMetadata, Boolean>,
 Waitable<List<HasMetadata>, HasMetadata>, Readiable {
 
@@ -285,29 +286,11 @@ public List<HasMetadata> createOrReplace() {
     List<HasMetadata> result = new ArrayList<>();
     for (HasMetadata meta : acceptVisitors(asHasMetadata(item, true), visitors)) {
       ResourceHandler<HasMetadata, HasMetadataVisitiableBuilder> h = handlerOf(meta);
-      String namespaceToUse =  meta.getMetadata().getNamespace();
+      String namespaceToUse = meta.getMetadata().getNamespace();
 
-      String resourceVersion = KubernetesResourceUtil.getResourceVersion(meta);
-      try {
-        // Create
-        KubernetesResourceUtil.setResourceVersion(meta, null);
-        result.add(h.create(client, config, namespaceToUse, meta));
-      } catch (KubernetesClientException exception) {
-        if (exception.getCode() != HttpURLConnection.HTTP_CONFLICT) {
-          throw exception;
-        }
-
-        // Conflict; check deleteExisting flag otherwise replace
-        if (Boolean.TRUE.equals(deletingExisting)) {
-          Boolean deleted = h.delete(client, config, namespaceToUse, propagationPolicy, meta);
-          if (Boolean.FALSE.equals(deleted)) {
-            throw new KubernetesClientException("Failed to delete existing item:" + meta);
-          }
-          result.add(h.create(client, config, namespaceToUse, meta));
-        } else {
-          KubernetesResourceUtil.setResourceVersion(meta, resourceVersion);
-          result.add(h.replace(client, config, namespaceToUse, meta));
-        }
+      HasMetadata createdItem = createOrReplaceOrDeleteExisting(meta, h, namespaceToUse);
+      if (createdItem != null) {
+        result.add(createdItem);
       }
     }
     return result;
@@ -455,4 +438,12 @@ private static <T> ResourceHandler handlerOf(T item) {
       throw new IllegalArgumentException("Could not find a registered handler for item: [" + item + "].");
     }
   }
+
+  private HasMetadata createOrReplaceOrDeleteExisting(HasMetadata meta, ResourceHandler<HasMetadata, HasMetadataVisitiableBuilder> h, String namespaceToUse) {
+      if (Boolean.TRUE.equals(deletingExisting)) {
+        return deleteAndCreateItem(client, config, meta, h, namespaceToUse, propagationPolicy);
+      }
+      return createOrReplaceItem(client, config, meta, h, namespaceToUse);
+  }
+
 }
diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/CreateOrReplaceHelper.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/CreateOrReplaceHelper.java
new file mode 100644
index 00000000000..cd8e46a2392
--- /dev/null
+++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/CreateOrReplaceHelper.java
@@ -0,0 +1,98 @@
+/**
+ * Copyright (C) 2015 Red Hat, Inc.
+ *
+ * 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.fabric8.kubernetes.client.utils;
+
+import io.fabric8.kubernetes.api.model.HasMetadata;
+import io.fabric8.kubernetes.client.Config;
+import io.fabric8.kubernetes.client.HasMetadataVisitiableBuilder;
+import io.fabric8.kubernetes.client.KubernetesClientException;
+import io.fabric8.kubernetes.client.ResourceHandler;
+import okhttp3.OkHttpClient;
+
+import java.net.HttpURLConnection;
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.function.UnaryOperator;
+
+public class CreateOrReplaceHelper<T extends HasMetadata> {
+  public static final int CREATE_OR_REPLACE_RETRIES = 3;
+  private final UnaryOperator<T> createTask;
+  private final UnaryOperator<T> replaceTask;
+  private final UnaryOperator<T> waitTask;
+  private final UnaryOperator<T> reloadTask;
+
+  public CreateOrReplaceHelper(UnaryOperator<T> createTask, UnaryOperator<T> replaceTask, UnaryOperator<T> waitTask, UnaryOperator<T> reloadTask) {
+    this.createTask = createTask;
+    this.replaceTask = replaceTask;
+    this.waitTask = waitTask;
+    this.reloadTask = reloadTask;
+  }
+
+  public T createOrReplace(T item) {
+    String resourceVersion = KubernetesResourceUtil.getResourceVersion(item);
+    final CompletableFuture<T> future = new CompletableFuture<>();
+    int nTries = 0;
+    while (!future.isDone() && nTries < CREATE_OR_REPLACE_RETRIES) {
+      try {
+        // Create
+        KubernetesResourceUtil.setResourceVersion(item, null);
+        return createTask.apply(item);
+      } catch (KubernetesClientException exception) {
+        if (shouldRetry(exception.getCode())) {
+          T itemFromServer = reloadTask.apply(item);
+          if (itemFromServer == null) {
+            waitTask.apply(item);
+            nTries++;
+            continue;
+          }
+        } else if (exception.getCode() != HttpURLConnection.HTTP_CONFLICT) {
+          throw exception;
+        }
+
+        future.complete(replace(item, resourceVersion));
+      }
+    }
+    return future.join();
+  }
+
+  public static HasMetadata createOrReplaceItem(OkHttpClient client, Config config, HasMetadata meta, ResourceHandler<HasMetadata, HasMetadataVisitiableBuilder> h, String namespaceToUse) {
+    CreateOrReplaceHelper<HasMetadata> createOrReplaceHelper = new CreateOrReplaceHelper<>(
+      m -> h.create(client, config, namespaceToUse, m),
+      m -> h.replace(client, config, namespaceToUse, m),
+      m -> {
+        try {
+          return h.waitUntilCondition(client, config, namespaceToUse, m, Objects::nonNull, 1, TimeUnit.SECONDS);
+        } catch (InterruptedException interruptedException) {
+          interruptedException.printStackTrace();
+        }
+        return null;
+      },
+      m -> h.reload(client, config, namespaceToUse, m)
+    );
+
+    return createOrReplaceHelper.createOrReplace(meta);
+  }
+
+  private T replace(T item, String resourceVersion) {
+      KubernetesResourceUtil.setResourceVersion(item, resourceVersion);
+      return replaceTask.apply(item);
+  }
+
+  private boolean shouldRetry(int responseCode) {
+    return responseCode > 499;
+  }
+}
diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/DeleteAndCreateHelper.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/DeleteAndCreateHelper.java
new file mode 100644
index 00000000000..da3502579c5
--- /dev/null
+++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/DeleteAndCreateHelper.java
@@ -0,0 +1,54 @@
+/**
+ * Copyright (C) 2015 Red Hat, Inc.
+ *
+ * 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.fabric8.kubernetes.client.utils;
+
+import io.fabric8.kubernetes.api.model.DeletionPropagation;
+import io.fabric8.kubernetes.api.model.HasMetadata;
+import io.fabric8.kubernetes.client.Config;
+import io.fabric8.kubernetes.client.HasMetadataVisitiableBuilder;
+import io.fabric8.kubernetes.client.KubernetesClientException;
+import io.fabric8.kubernetes.client.ResourceHandler;
+import okhttp3.OkHttpClient;
+
+import java.util.function.Function;
+import java.util.function.UnaryOperator;
+
+public class DeleteAndCreateHelper<T extends HasMetadata> {
+  private final UnaryOperator<T> createTask;
+  private final Function<T, Boolean> deleteTask;
+
+  public DeleteAndCreateHelper(UnaryOperator<T> createTask, Function<T, Boolean> deleteTask) {
+    this.createTask = createTask;
+    this.deleteTask = deleteTask;
+  }
+
+  public T deleteAndCreate(T item) {
+    Boolean deleted = deleteTask.apply(item);
+    if (Boolean.FALSE.equals(deleted)) {
+      throw new KubernetesClientException("Failed to delete existing item:" + item.getMetadata().getName());
+    }
+    return createTask.apply(item);
+  }
+
+  public static HasMetadata deleteAndCreateItem(OkHttpClient client, Config config, HasMetadata meta, ResourceHandler<HasMetadata, HasMetadataVisitiableBuilder> h, String namespaceToUse, DeletionPropagation propagationPolicy) {
+    DeleteAndCreateHelper<HasMetadata> deleteAndCreateHelper = new DeleteAndCreateHelper<>(
+      m -> h.create(client, config, namespaceToUse, m),
+      m -> h.delete(client, config, namespaceToUse, propagationPolicy, m)
+    );
+
+    return deleteAndCreateHelper.deleteAndCreate(meta);
+  }
+}
diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/Utils.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/Utils.java
index 99a90c2315e..8c7aa2192b9 100644
--- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/Utils.java
+++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/Utils.java
@@ -472,4 +472,5 @@ public static List<String> getCommandPlatformPrefix() {
   private static String getOperatingSystemFromSystemProperty() {
     return System.getProperty(OS_NAME);
   }
+
 }
diff --git a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/base/BaseOperationTest.java b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/base/BaseOperationTest.java
index b8d371e822d..b9e2a89fa21 100644
--- a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/base/BaseOperationTest.java
+++ b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/base/BaseOperationTest.java
@@ -38,16 +38,13 @@
 import io.fabric8.kubernetes.client.utils.URLUtils;
 import org.junit.jupiter.api.Test;
 
-import io.fabric8.kubernetes.client.Watch;
-import io.fabric8.kubernetes.client.Watcher;
-import io.fabric8.kubernetes.client.dsl.FilterWatchListDeletable;
 import io.fabric8.kubernetes.client.dsl.internal.PodOperationContext;
 import io.fabric8.kubernetes.client.dsl.internal.core.v1.PodOperationsImpl;
 
-public class BaseOperationTest {
+class BaseOperationTest {
 
   @Test
-  public void testSimpleFieldQueryParamConcatenation() {
+  void testSimpleFieldQueryParamConcatenation() {
     Map<String, String> fieldsMap = new HashMap<>();
     fieldsMap.put("yesKey1", "yesValue1");
     fieldsMap.put("yesKey2", "yesValue2");
@@ -68,7 +65,7 @@ public void testSimpleFieldQueryParamConcatenation() {
   }
 
   @Test
-  public void testSkippingFieldNotMatchingNullValues() {
+  void testSkippingFieldNotMatchingNullValues() {
     final PodOperationsImpl operation = new PodOperationsImpl(new PodOperationContext());
     operation
       .withField("key1", "value1")
@@ -83,14 +80,14 @@ public void testSkippingFieldNotMatchingNullValues() {
   }
 
   @Test
-  public void testDefaultGracePeriod() {
+  void testDefaultGracePeriod() {
     final BaseOperation operation = new BaseOperation(new OperationContext());
 
     assertThat(operation.getGracePeriodSeconds(), is(-1L));
   }
 
   @Test
-  public void testChainingGracePeriodAndPropagationPolicy() {
+  void testChainingGracePeriodAndPropagationPolicy() {
     final BaseOperation operation = new BaseOperation(new OperationContext());
     EditReplacePatchDeletable<?, ?, ?, Boolean> operationWithPropagationPolicy = operation.withPropagationPolicy(DeletionPropagation.FOREGROUND);
     assertThat(operationWithPropagationPolicy, is(notNullValue()));
@@ -98,7 +95,7 @@ public void testChainingGracePeriodAndPropagationPolicy() {
   }
 
   @Test
-  public void testListOptions() throws MalformedURLException {
+  void testListOptions() throws MalformedURLException {
     // Given
     URL url = new URL("https://172.17.0.2:8443/api/v1/namespaces/default/pods");
     final BaseOperation<Pod, PodList, DoneablePod, Resource<Pod, DoneablePod>> operation = new BaseOperation<>(new OperationContext());
diff --git a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/CreateOrReplaceHelperTest.java b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/CreateOrReplaceHelperTest.java
new file mode 100644
index 00000000000..627d54a11e1
--- /dev/null
+++ b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/CreateOrReplaceHelperTest.java
@@ -0,0 +1,140 @@
+/**
+ * Copyright (C) 2015 Red Hat, Inc.
+ *
+ * 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.fabric8.kubernetes.client.utils;
+
+import io.fabric8.kubernetes.api.model.Pod;
+import io.fabric8.kubernetes.api.model.PodBuilder;
+import io.fabric8.kubernetes.api.model.StatusBuilder;
+import io.fabric8.kubernetes.client.KubernetesClientException;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import java.net.HttpURLConnection;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Function;
+import java.util.function.UnaryOperator;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+class CreateOrReplaceHelperTest {
+
+  @Test
+  void testCreateOrReplaceShouldCreate() {
+    // Given
+    AtomicBoolean wasPodCreated = new AtomicBoolean(false);
+    UnaryOperator<Pod> createPodTask = p -> {
+      wasPodCreated.set(true);
+      return getPod();
+    };
+    CreateOrReplaceHelper<Pod> podCreateOrReplaceHelper = new CreateOrReplaceHelper<>(
+      createPodTask,
+      p -> getPod(),
+      p -> getPod(),
+      p -> getPod()
+    );
+
+    // When
+    Pod podCreated = podCreateOrReplaceHelper.createOrReplace(getPod());
+
+    // Then
+    assertNotNull(podCreated);
+    assertTrue(wasPodCreated.get());
+  }
+
+  @Test
+  void testCreateOrReplaceShouldReplace() {
+    // Given
+    AtomicBoolean wasPodReplaced = new AtomicBoolean(false);
+    UnaryOperator<Pod> createPodTask = p -> {
+      throw new KubernetesClientException("Already exist",
+        HttpURLConnection.HTTP_CONFLICT, new StatusBuilder().withCode(HttpURLConnection.HTTP_CONFLICT).build());
+    };
+    UnaryOperator<Pod> replacePodTask = p -> {
+      wasPodReplaced.set(true);
+      return getPod();
+    };
+    CreateOrReplaceHelper<Pod> podCreateOrReplaceHelper = new CreateOrReplaceHelper<>(
+      createPodTask,
+      replacePodTask,
+      p -> getPod(),
+      p -> getPod()
+    );
+
+    // When
+    Pod podCreated = podCreateOrReplaceHelper.createOrReplace(getPod());
+
+    // Then
+    assertNotNull(podCreated);
+    assertTrue(wasPodReplaced.get());
+  }
+
+  @Test
+  void testCreateOrReplaceShouldRetryOnInternalServerError() {
+    // Given
+    AtomicBoolean waitedForPod = new AtomicBoolean(false);
+    UnaryOperator<Pod> createPodTask = Mockito.mock(UnaryOperator.class, Mockito.RETURNS_DEEP_STUBS);
+    UnaryOperator<Pod> reloadTask = Mockito.mock(UnaryOperator.class, Mockito.RETURNS_DEEP_STUBS);
+    when(reloadTask.apply(any())).thenReturn(null);
+    when(createPodTask.apply(any())).thenThrow(new KubernetesClientException("The POST operation could not be completed at " +
+      "this time, please try again",
+      HttpURLConnection.HTTP_INTERNAL_ERROR, new StatusBuilder().withCode(HttpURLConnection.HTTP_INTERNAL_ERROR).build()))
+      .thenReturn(getPod());
+    UnaryOperator<Pod> waitTask = p -> {
+      waitedForPod.set(true);
+      return getPod();
+    };
+    CreateOrReplaceHelper<Pod> podCreateOrReplaceHelper = new CreateOrReplaceHelper<>(
+      createPodTask,
+      p -> getPod(),
+      waitTask,
+      reloadTask
+    );
+
+    // When
+    Pod podCreated = podCreateOrReplaceHelper.createOrReplace(getPod());
+
+    // Then
+    assertNotNull(podCreated);
+    assertTrue(waitedForPod.get());
+  }
+
+  @Test
+  void testCreateOrReplaceThrowExceptionOnErrorCodeLessThan500() {
+    // Given
+    UnaryOperator<Pod> createPodTask = p -> {
+      throw new KubernetesClientException("The POST operation could not be completed at " +
+        "this time, please try again",
+        HttpURLConnection.HTTP_BAD_REQUEST, new StatusBuilder().withCode(HttpURLConnection.HTTP_BAD_REQUEST).build());
+    };
+    CreateOrReplaceHelper<Pod> podCreateOrReplaceHelper = new CreateOrReplaceHelper<>(createPodTask,
+      p -> getPod(), p ->getPod(), p -> getPod());
+    Pod podToCreate = getPod();
+
+    // When
+    assertThrows(KubernetesClientException.class, () -> podCreateOrReplaceHelper.createOrReplace(podToCreate));
+  }
+
+
+  private Pod getPod() {
+    return new PodBuilder()
+      .withNewMetadata().withName("p1").endMetadata()
+      .build();
+  }
+}
diff --git a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/DeleteAndCreateHelperTest.java b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/DeleteAndCreateHelperTest.java
new file mode 100644
index 00000000000..f0fa06b33a8
--- /dev/null
+++ b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/DeleteAndCreateHelperTest.java
@@ -0,0 +1,83 @@
+/**
+ * Copyright (C) 2015 Red Hat, Inc.
+ *
+ * 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.fabric8.kubernetes.client.utils;
+
+import io.fabric8.kubernetes.api.model.Pod;
+import io.fabric8.kubernetes.api.model.PodBuilder;
+import io.fabric8.kubernetes.api.model.StatusBuilder;
+import io.fabric8.kubernetes.client.KubernetesClientException;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import java.net.HttpURLConnection;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Function;
+import java.util.function.UnaryOperator;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+class DeleteAndCreateHelperTest {
+  @Test
+  void testDeleteAndCreate() {
+    // Given
+    AtomicBoolean wasPodDeleted = new AtomicBoolean(false);
+    Function<Pod, Boolean> deletePodTask = p -> {
+      wasPodDeleted.set(true);
+      return true;
+    };
+    UnaryOperator<Pod> createPodTask = Mockito.mock(UnaryOperator.class, Mockito.RETURNS_DEEP_STUBS);
+    when(createPodTask.apply(any()))
+      .thenReturn(getPod());
+    DeleteAndCreateHelper<Pod> podDeleteAndCreateHelper = new DeleteAndCreateHelper<>(
+      createPodTask,
+      p -> true
+    );
+
+    // When
+    Pod podCreated = podDeleteAndCreateHelper.deleteAndCreate(getPod());
+
+    // Then
+    assertNotNull(podCreated);
+    assertTrue(deletePodTask.apply(podCreated));
+  }
+
+  @Test
+  void testDeleteAndCreateWhenDeletionFailed() {
+    // Given
+    UnaryOperator<Pod> createPodTask = Mockito.mock(UnaryOperator.class, Mockito.RETURNS_DEEP_STUBS);
+    when(createPodTask.apply(any())).thenThrow(new KubernetesClientException("The POST operation could not be completed at " +
+      "this time, please try again",
+      HttpURLConnection.HTTP_CONFLICT, new StatusBuilder().withCode(HttpURLConnection.HTTP_CONFLICT).build()));
+    DeleteAndCreateHelper<Pod> podDeleteAndCreateHelper = new DeleteAndCreateHelper<>(
+      createPodTask,
+      p -> false
+    );
+
+    // When
+    Pod podToDeleteAndCreate = getPod();
+    assertThrows(KubernetesClientException.class,() -> podDeleteAndCreateHelper.deleteAndCreate(podToDeleteAndCreate));
+  }
+
+  private Pod getPod() {
+    return new PodBuilder()
+      .withNewMetadata().withName("p1").endMetadata()
+      .build();
+  }
+}
diff --git a/kubernetes-itests/src/test/java/io/fabric8/kubernetes/CreateOrReplaceIT.java b/kubernetes-itests/src/test/java/io/fabric8/kubernetes/CreateOrReplaceIT.java
index 01b086b3bb5..c86926d40ae 100644
--- a/kubernetes-itests/src/test/java/io/fabric8/kubernetes/CreateOrReplaceIT.java
+++ b/kubernetes-itests/src/test/java/io/fabric8/kubernetes/CreateOrReplaceIT.java
@@ -17,6 +17,7 @@
 
 import io.fabric8.kubernetes.api.model.ConfigMap;
 import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
+import io.fabric8.kubernetes.api.model.HasMetadata;
 import io.fabric8.kubernetes.api.model.IntOrString;
 import io.fabric8.kubernetes.api.model.Secret;
 import io.fabric8.kubernetes.api.model.SecretBuilder;
@@ -33,15 +34,22 @@
 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.Test;
 import org.junit.runner.RunWith;
 
+import java.io.InputStream;
+import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 @RunWith(ArquillianConditionalRunner.class)
 @RequiresKubernetes
@@ -52,6 +60,9 @@ public class CreateOrReplaceIT {
   @ArquillianResource
   Session session;
 
+  private HasMetadata resource = null;
+  private List<HasMetadata> resourceList = null;
+
   @Test
   public void testCreateOrReplaceConfigMap() {
     ConfigMap configMap = new ConfigMapBuilder()
@@ -76,9 +87,6 @@ public void testCreateOrReplaceConfigMap() {
     assertNotNull(configMap);
     assertEquals("2nd", configMap.getData().get("second"));
     assertEquals("3rd", configMap.getData().get("third"));
-
-    // Cleanup
-    client.configMaps().inNamespace(session.getNamespace()).withName(configMap.getMetadata().getName()).delete();
   }
 
   @Test
@@ -113,9 +121,6 @@ public void testCreateOrReplaceService() {
     service = client.services().inNamespace(session.getNamespace()).createOrReplace(service);
     assertNotNull(service);
     assertEquals(9090, service.getSpec().getPorts().get(0).getTargetPort().getIntVal().intValue());
-
-    // Cleanup
-    client.services().inNamespace(session.getNamespace()).withName(service.getMetadata().getName()).delete();
   }
 
   @Test
@@ -159,9 +164,6 @@ public void testCreateOrReplaceDeployment() {
     deployment = client.apps().deployments().inNamespace(session.getNamespace()).createOrReplace(deployment);
     assertNotNull(deployment);
     assertEquals("busybox:1.32", deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage());
-
-    // Cleanup
-    client.apps().deployments().inNamespace(session.getNamespace()).withName(deployment.getMetadata().getName()).delete();
   }
 
   @Test
@@ -187,9 +189,6 @@ public void testCreateOrReplaceSecret() {
     secret = client.secrets().inNamespace(session.getNamespace()).createOrReplace(secret);
     assertNotNull(secret);
     assertEquals("c29tZXRva2Vu", secret.getData().get("apitoken"));
-
-    // Cleanup
-    client.secrets().inNamespace(session.getNamespace()).withName(secret.getMetadata().getName()).delete();
   }
 
   @Test
@@ -227,12 +226,110 @@ public void testCreateOrReplaceIngress() {
     ingress = client.extensions().ingresses().inNamespace(session.getNamespace()).createOrReplace(ingress);
     assertNotNull(ingress);
     assertEquals("/", ingress.getMetadata().getAnnotations().get("nginx.ingress.kubernetes.io/rewrite-target"));
+  }
+
+  @Test
+  public void testCreateOrReplaceGenericResource() {
+    // Given
+    ConfigMap configMap = new ConfigMapBuilder()
+      .withNewMetadata().withName("resource-cm-1").endMetadata()
+      .addToData("a1", "A1")
+      .addToData("a2", "A2")
+      .build();
+
+    // When
+    ConfigMap createdResource = client.resource(configMap).inNamespace(session.getNamespace()).createOrReplace();
+    configMap.setData(Collections.singletonMap("b1", "B1"));
+    this.resource = client.resource(configMap).inNamespace(session.getNamespace()).createOrReplace();
 
-    // Cleanup
-    client.network().ingresses().inNamespace(session.getNamespace()).withName(ingress.getMetadata().getName()).delete();
+    // Then
+    assertNotNull(createdResource);
+    assertEquals(2, createdResource.getData().size());
+    assertEquals("A1", createdResource.getData().get("a1"));
+    assertEquals("A2", createdResource.getData().get("a2"));
+    ConfigMap replacedResource = (ConfigMap) this.resource;
+    assertNotNull(replacedResource);
+    assertEquals(1, replacedResource.getData().size());
+    assertEquals("B1", replacedResource.getData().get("b1"));
+  }
+
+  @Test
+  public void testCreateOrReplaceGenericResourceList() {
+    // Given
+    InputStream resourceListV1 = getClass().getResourceAsStream("/createorreplace-it-testlist-v1.yml");
+    InputStream resourceListV2 = getClass().getResourceAsStream("/createorreplace-it-testlist-v2.yml");
+
+    // When
+    List<HasMetadata> listCreated = client.load(resourceListV1).inNamespace(session.getNamespace()).createOrReplace();
+    resourceList = client.load(resourceListV2).inNamespace(session.getNamespace()).createOrReplace();
+
+    // Then
+    assertNotNull(listCreated);
+    assertEquals(2, listCreated.size());
+    Optional<HasMetadata> serviceResult = listCreated.stream().filter(p -> p instanceof Service).findFirst();
+    assertTrue(serviceResult.isPresent());
+    Service service = (Service) serviceResult.get();
+    assertEquals(9376, service.getSpec().getPorts().get(0).getTargetPort().getIntVal().intValue());
+
+    assertNotNull(resourceList);
+    assertEquals(2, resourceList.size());
+    Optional<HasMetadata> serviceV2Result = resourceList.stream().filter(p -> p instanceof Service).findFirst();
+    assertTrue(serviceV2Result.isPresent());
+    Service serviceV2 = (Service) serviceV2Result.get();
+    assertEquals(9090, serviceV2.getSpec().getPorts().get(0).getTargetPort().getIntVal().intValue());
+  }
+
+  @Test
+  public void testCreateOrReplaceDeletingExisting() {
+    // Given
+    List<HasMetadata> listToCreate = new ArrayList<>();
+    listToCreate.add(new ConfigMapBuilder().withNewMetadata().withName("createorreplace-it-delete-existing-configmap").endMetadata()
+      .addToData("A", "a")
+      .addToData("B", "b")
+      .build());
+    listToCreate.add(new SecretBuilder().withNewMetadata().withName("createorreplace-it-delete-existing-secret").endMetadata()
+      .addToData("USERNAME", "YWRtaW4=")
+      .addToData("PASSWORD", "MWYyZDFlMmU2N2Rm")
+      .build());
+
+    // When
+    List<HasMetadata> listCreated = client.resourceList(listToCreate).inNamespace(session.getNamespace()).createOrReplace();
+    resourceList = client.resourceList(listToCreate)
+      .inNamespace(session.getNamespace())
+      .deletingExisting()
+      .createOrReplace();
+
+    // Then
+    assertNotNull(listCreated);
+    assertEquals(2, listCreated.size());
+    listCreated.sort(Comparator.comparing(HasMetadata::getKind));
+
+    assertNotNull(resourceList);
+    assertEquals(2, resourceList.size());
+    resourceList.sort(Comparator.comparing(HasMetadata::getKind));
+    assertEquals(listCreated.get(0).getMetadata().getName(), resourceList.get(0).getMetadata().getName());
+    assertNotEquals(listCreated.get(0).getMetadata().getUid(), resourceList.get(0).getMetadata().getUid());
+    assertEquals(listCreated.get(1).getMetadata().getName(), resourceList.get(1).getMetadata().getName());
+    assertNotEquals(listCreated.get(1).getMetadata().getUid(), resourceList.get(1).getMetadata().getUid());
   }
 
   private String getTestResourcePrefix() {
     return getClass().getSimpleName().toLowerCase();
   }
+
+  @After
+  public void cleanup() {
+    client.network().ingresses().inNamespace(session.getNamespace()).withName(getTestResourcePrefix() + "-ing").delete();
+    client.secrets().inNamespace(session.getNamespace()).withName(getTestResourcePrefix() + "-secret").delete();
+    client.apps().deployments().inNamespace(session.getNamespace()).withName(getTestResourcePrefix() + "-deploy").delete();
+    client.services().inNamespace(session.getNamespace()).withName(getTestResourcePrefix() + "-svc").delete();
+    client.configMaps().inNamespace(session.getNamespace()).withName(getTestResourcePrefix() + "-configmap").delete();
+    if (resource != null) {
+      client.resource(resource).inNamespace(session.getNamespace()).delete();
+    }
+    if (resourceList != null) {
+      client.resourceList(resourceList).inNamespace(session.getNamespace()).delete();
+    }
+  }
+
 }
diff --git a/kubernetes-itests/src/test/resources/createorreplace-it-testlist-v1.yml b/kubernetes-itests/src/test/resources/createorreplace-it-testlist-v1.yml
new file mode 100644
index 00000000000..f0f529ac287
--- /dev/null
+++ b/kubernetes-itests/src/test/resources/createorreplace-it-testlist-v1.yml
@@ -0,0 +1,38 @@
+#
+# Copyright (C) 2015 Red Hat, Inc.
+#
+# 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.
+#
+
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: createorreplace-it-resourcelist-service
+spec:
+  selector:
+    app: MyApp
+  ports:
+    - protocol: TCP
+      port: 80
+      targetPort: 9376
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: createorreplace-it-resourcelist-configmap
+  namespace: default
+data:
+  allowed: '"true"'
+  enemies: aliens
+  lives: "3"
diff --git a/kubernetes-itests/src/test/resources/createorreplace-it-testlist-v2.yml b/kubernetes-itests/src/test/resources/createorreplace-it-testlist-v2.yml
new file mode 100644
index 00000000000..db9af34051d
--- /dev/null
+++ b/kubernetes-itests/src/test/resources/createorreplace-it-testlist-v2.yml
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2015 Red Hat, Inc.
+#
+# 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.
+#
+
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: createorreplace-it-resourcelist-service
+spec:
+  selector:
+    app: MyApp
+  ports:
+    - protocol: TCP
+      port: 80
+      targetPort: 9090
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: createorreplace-it-resourcelist-configmap
+  namespace: default
+data:
+  allowed: '"true"'
+  enemies: aliens
+  updated: true
+  lives: "3"
diff --git a/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/ResourceListTest.java b/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/ResourceListTest.java
index c10184d5191..59b143bb61e 100644
--- a/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/ResourceListTest.java
+++ b/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/ResourceListTest.java
@@ -155,8 +155,6 @@ void testCreateOrReplaceWithoutDeleteExisting() throws Exception {
 
   @Test
   void testCreateOrReplaceWithDeleteExisting() throws Exception {
-    server.expect().post().withPath("/api/v1/namespaces/ns1/services").andReturn(HTTP_CONFLICT, service).once();
-    server.expect().post().withPath("/api/v1/namespaces/ns1/configmaps").andReturn(HTTP_CONFLICT, configMap).once();
     server.expect().delete().withPath("/api/v1/namespaces/ns1/services/my-service").andReturn(HTTP_OK , service).once();
     server.expect().delete().withPath("/api/v1/namespaces/ns1/configmaps/my-configmap").andReturn(HTTP_OK, configMap).once();
     server.expect().post().withPath("/api/v1/namespaces/ns1/services").andReturn(HTTP_OK, updatedService).once();
@@ -164,7 +162,7 @@ void testCreateOrReplaceWithDeleteExisting() throws Exception {
 
     client.resourceList(resourcesToUpdate).inNamespace("ns1").deletingExisting().createOrReplace();
 
-    assertEquals(6, server.getMockServer().getRequestCount());
+    assertEquals(4, server.getMockServer().getRequestCount());
     RecordedRequest request = server.getLastRequest();
     assertEquals("/api/v1/namespaces/ns1/configmaps", request.getPath());
     assertEquals("POST", request.getMethod());
diff --git a/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/ResourceTest.java b/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/ResourceTest.java
index ed59e3b46d6..4295567412b 100644
--- a/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/ResourceTest.java
+++ b/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/ResourceTest.java
@@ -105,7 +105,6 @@ void testCreateWithExplicitNamespace() {
     void testCreateOrReplaceWithDeleteExisting() throws Exception {
       Pod pod1 = new PodBuilder().withNewMetadata().withName("pod1").withNamespace("test").and().build();
 
-      server.expect().post().withPath("/api/v1/namespaces/ns1/pods").andReturn(HttpURLConnection.HTTP_CONFLICT, pod1).once();
       server.expect().delete().withPath("/api/v1/namespaces/ns1/pods/pod1").andReturn(HttpURLConnection.HTTP_OK, pod1).once();
       server.expect().post().withPath("/api/v1/namespaces/ns1/pods").andReturn(HttpURLConnection.HTTP_CREATED, pod1).once();
 
@@ -114,7 +113,7 @@ void testCreateOrReplaceWithDeleteExisting() throws Exception {
       assertEquals(pod1, response);
 
       RecordedRequest request = server.getLastRequest();
-      assertEquals(3, server.getMockServer().getRequestCount());
+      assertEquals(2, server.getMockServer().getRequestCount());
       assertEquals("/api/v1/namespaces/ns1/pods", request.getPath());
       assertEquals("POST", request.getMethod());
     }