You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwhisk.apache.org by ma...@apache.org on 2018/09/05 15:25:37 UTC

[incubator-openwhisk] branch master updated: Reuse a container on ApplicationError. (#3941)

This is an automated email from the ASF dual-hosted git repository.

markusthoemmes pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-openwhisk.git


The following commit(s) were added to refs/heads/master by this push:
     new 1515e41  Reuse a container on ApplicationError. (#3941)
1515e41 is described below

commit 1515e416d95e3a12888b00a4311c7b9bbb6401d9
Author: tysonnorris <ty...@gmail.com>
AuthorDate: Wed Sep 5 08:25:26 2018 -0700

    Reuse a container on ApplicationError. (#3941)
    
    Fixes #3918
    
    Renamed `ActivationResponse.containerError` -> `ActivationResponse.developerError`
    
    * generate ApplicationResponse.containerError during failed init (instead of ApplicationResponse.applicationError)
    
    * timeout on run now produces `ActivationResponse.containerError`
---
 .../scala/whisk/core/containerpool/Container.scala |  4 +-
 .../scala/whisk/core/entity/ActivationResult.scala | 32 ++++-----
 .../whisk/core/containerpool/ContainerProxy.scala  |  9 +--
 .../core/cli/test/WskRestBasicUsageTests.scala     | 10 +--
 .../docker/test/DockerContainerTests.scala         |  4 +-
 .../kubernetes/test/KubernetesContainerTests.scala |  4 +-
 .../containerpool/test/ContainerProxyTests.scala   | 83 ++++++++++++++++++++--
 .../core/controller/test/WebActionsApiTests.scala  |  2 +-
 .../core/entity/test/ActivationResponseTests.scala | 32 ++++-----
 .../whisk/core/limits/ActionLimitsTests.scala      |  4 +-
 .../whisk/core/limits/MaxActionDurationTests.scala |  2 +-
 11 files changed, 130 insertions(+), 56 deletions(-)

diff --git a/common/scala/src/main/scala/whisk/core/containerpool/Container.scala b/common/scala/src/main/scala/whisk/core/containerpool/Container.scala
index dc59b3c..54c8a1b 100644
--- a/common/scala/src/main/scala/whisk/core/containerpool/Container.scala
+++ b/common/scala/src/main/scala/whisk/core/containerpool/Container.scala
@@ -116,7 +116,7 @@ trait Container {
           Future.failed(
             InitializationError(
               result.interval,
-              ActivationResponse.applicationError(Messages.timedoutActivation(timeout, true))))
+              ActivationResponse.developerError(Messages.timedoutActivation(timeout, true))))
         } else {
           Future.failed(
             InitializationError(
@@ -153,7 +153,7 @@ trait Container {
       }
       .map { result =>
         val response = if (result.interval.duration >= timeout) {
-          ActivationResponse.applicationError(Messages.timedoutActivation(timeout, false))
+          ActivationResponse.developerError(Messages.timedoutActivation(timeout, false))
         } else {
           ActivationResponse.processRunResponseContent(result.response, logging)
         }
diff --git a/common/scala/src/main/scala/whisk/core/entity/ActivationResult.scala b/common/scala/src/main/scala/whisk/core/entity/ActivationResult.scala
index 5f8c815..3448ced 100644
--- a/common/scala/src/main/scala/whisk/core/entity/ActivationResult.scala
+++ b/common/scala/src/main/scala/whisk/core/entity/ActivationResult.scala
@@ -44,7 +44,7 @@ protected[core] case class ActivationResponse private (val statusCode: Int, val
 
   def isSuccess = statusCode == ActivationResponse.Success
   def isApplicationError = statusCode == ActivationResponse.ApplicationError
-  def isContainerError = statusCode == ActivationResponse.ContainerError
+  def isContainerError = statusCode == ActivationResponse.DeveloperError
   def isWhiskError = statusCode == ActivationResponse.WhiskError
   def withoutResult = ActivationResponse(statusCode, None)
 
@@ -57,7 +57,7 @@ protected[core] object ActivationResponse extends DefaultJsonProtocol {
 
   val Success = 0 // action ran successfully and produced a result
   val ApplicationError = 1 // action ran but there was an error and it was handled
-  val ContainerError = 2 // action ran but failed to handle an error, or action did not run and failed to initialize
+  val DeveloperError = 2 // action ran but failed to handle an error, or action did not run and failed to initialize
   val WhiskError = 3 // internal system error
 
   protected[core] def messageForCode(code: Int) = {
@@ -71,7 +71,7 @@ protected[core] object ActivationResponse extends DefaultJsonProtocol {
   }
 
   private def error(code: Int, errorValue: JsValue) = {
-    require(code == ApplicationError || code == ContainerError || code == WhiskError)
+    require(code == ApplicationError || code == DeveloperError || code == WhiskError)
     ActivationResponse(code, Some(JsObject(ERROR_FIELD -> errorValue)))
   }
 
@@ -79,8 +79,8 @@ protected[core] object ActivationResponse extends DefaultJsonProtocol {
 
   protected[core] def applicationError(errorValue: JsValue) = error(ApplicationError, errorValue)
   protected[core] def applicationError(errorMsg: String) = error(ApplicationError, JsString(errorMsg))
-  protected[core] def containerError(errorValue: JsValue) = error(ContainerError, errorValue)
-  protected[core] def containerError(errorMsg: String) = error(ContainerError, JsString(errorMsg))
+  protected[core] def developerError(errorValue: JsValue) = error(DeveloperError, errorValue)
+  protected[core] def developerError(errorMsg: String) = error(DeveloperError, JsString(errorMsg))
   protected[core] def whiskError(errorValue: JsValue) = error(WhiskError, errorValue)
   protected[core] def whiskError(errorMsg: String) = error(WhiskError, JsString(errorMsg))
 
@@ -148,21 +148,21 @@ protected[core] object ActivationResponse extends DefaultJsonProtocol {
                 // If the response is a JSON object container an error field, accept it as the response error.
                 val errorOpt = fields.get(ERROR_FIELD)
                 val errorContent = errorOpt getOrElse invalidInitResponse(str).toJson
-                containerError(errorContent)
+                developerError(errorContent)
               case _ =>
-                containerError(invalidInitResponse(str))
+                developerError(invalidInitResponse(str))
             }
 
           case Some((length, maxlength)) =>
-            containerError(truncatedResponse(str, length, maxlength))
+            developerError(truncatedResponse(str, length, maxlength))
         }
 
       case Left(_: MemoryExhausted) =>
-        containerError(memoryExhausted)
+        developerError(memoryExhausted)
 
       case Left(e) =>
         // This indicates a terminal failure in the container (it exited prematurely).
-        containerError(abnormalInitialization)
+        developerError(abnormalInitialization)
     }
   }
 
@@ -194,29 +194,29 @@ protected[core] object ActivationResponse extends DefaultJsonProtocol {
                   // Any non-200 code is treated as a container failure. We still need to check whether
                   // there was a useful error message in there.
                   val errorContent = errorOpt getOrElse invalidRunResponse(str).toJson
-                  containerError(errorContent)
+                  developerError(errorContent)
                 }
 
               case scala.util.Success(notAnObj) =>
                 // This should affect only blackbox containers, since our own containers should already test for that.
-                containerError(invalidRunResponse(str))
+                developerError(invalidRunResponse(str))
 
               case scala.util.Failure(t) =>
                 // This should affect only blackbox containers, since our own containers should already test for that.
                 logger.warn(this, s"response did not json parse: '$str' led to $t")
-                containerError(invalidRunResponse(str))
+                developerError(invalidRunResponse(str))
             }
 
           case Some((length, maxlength)) =>
-            containerError(truncatedResponse(str, length, maxlength))
+            developerError(truncatedResponse(str, length, maxlength))
         }
 
       case Left(_: MemoryExhausted) =>
-        containerError(memoryExhausted)
+        developerError(memoryExhausted)
 
       case Left(e) =>
         // This indicates a terminal failure in the container (it exited prematurely).
-        containerError(abnormalRun)
+        developerError(abnormalRun)
     }
   }
 
diff --git a/core/invoker/src/main/scala/whisk/core/containerpool/ContainerProxy.scala b/core/invoker/src/main/scala/whisk/core/containerpool/ContainerProxy.scala
index 0ddd666..b34ce58 100644
--- a/core/invoker/src/main/scala/whisk/core/containerpool/ContainerProxy.scala
+++ b/core/invoker/src/main/scala/whisk/core/containerpool/ContainerProxy.scala
@@ -154,7 +154,7 @@ class ContainerProxy(
             // the failure is either the system fault, or for docker actions, the application/developer fault
             val response = t match {
               case WhiskContainerStartupError(msg) => ActivationResponse.whiskError(msg)
-              case BlackboxStartupError(msg)       => ActivationResponse.applicationError(msg)
+              case BlackboxStartupError(msg)       => ActivationResponse.developerError(msg)
               case _                               => ActivationResponse.whiskError(Messages.resourceProvisionError)
             }
             val context = UserContext(job.msg.user)
@@ -423,9 +423,10 @@ class ContainerProxy(
 
     // Disambiguate activation errors and transform the Either into a failed/successful Future respectively.
     activationWithLogs.flatMap {
-      case Right(act) if !act.response.isSuccess => Future.failed(ActivationUnsuccessfulError(act))
-      case Left(error)                           => Future.failed(error)
-      case Right(act)                            => Future.successful(act)
+      case Right(act) if !act.response.isSuccess && !act.response.isApplicationError =>
+        Future.failed(ActivationUnsuccessfulError(act))
+      case Left(error) => Future.failed(error)
+      case Right(act)  => Future.successful(act)
     }
   }
 }
diff --git a/tests/src/test/scala/whisk/core/cli/test/WskRestBasicUsageTests.scala b/tests/src/test/scala/whisk/core/cli/test/WskRestBasicUsageTests.scala
index a92bcdf..7fd950a 100644
--- a/tests/src/test/scala/whisk/core/cli/test/WskRestBasicUsageTests.scala
+++ b/tests/src/test/scala/whisk/core/cli/test/WskRestBasicUsageTests.scala
@@ -185,7 +185,7 @@ class WskRestBasicUsageTests extends TestHelpers with WskTestHelpers with WskAct
       withActivation(wsk.activation, wsk.action.invoke(name)) { activation =>
         val response = activation.response
         response.result.get.fields("error") shouldBe Messages.abnormalInitialization.toJson
-        response.status shouldBe ActivationResponse.messageForCode(ActivationResponse.ContainerError)
+        response.status shouldBe ActivationResponse.messageForCode(ActivationResponse.DeveloperError)
       }
   }
 
@@ -199,7 +199,7 @@ class WskRestBasicUsageTests extends TestHelpers with WskTestHelpers with WskAct
       withActivation(wsk.activation, wsk.action.invoke(name)) { activation =>
         val response = activation.response
         response.result.get.fields("error") shouldBe Messages.timedoutActivation(3 seconds, true).toJson
-        response.status shouldBe ActivationResponse.messageForCode(ActivationResponse.ApplicationError)
+        response.status shouldBe ActivationResponse.messageForCode(ActivationResponse.DeveloperError)
       }
   }
 
@@ -213,7 +213,7 @@ class WskRestBasicUsageTests extends TestHelpers with WskTestHelpers with WskAct
       withActivation(wsk.activation, wsk.action.invoke(name)) { activation =>
         val response = activation.response
         response.result.get.fields("error") shouldBe Messages.abnormalRun.toJson
-        response.status shouldBe ActivationResponse.messageForCode(ActivationResponse.ContainerError)
+        response.status shouldBe ActivationResponse.messageForCode(ActivationResponse.DeveloperError)
       }
   }
 
@@ -285,7 +285,7 @@ class WskRestBasicUsageTests extends TestHelpers with WskTestHelpers with WskAct
 
       val run = wsk.action.invoke(name)
       withActivation(wsk.activation, run) { activation =>
-        activation.response.status shouldBe ActivationResponse.messageForCode(ActivationResponse.ApplicationError)
+        activation.response.status shouldBe ActivationResponse.messageForCode(ActivationResponse.DeveloperError)
         activation.response.result.get
           .fields("error") shouldBe s"Failed to pull container image '$containerName'.".toJson
         activation.annotations shouldBe defined
@@ -375,7 +375,7 @@ class WskRestBasicUsageTests extends TestHelpers with WskTestHelpers with WskAct
       val hungRun = wsk.action.invoke(name, Map("forceHang" -> true.toJson))
       withActivation(wsk.activation, hungRun) { activation =>
         // the first action must fail with a timeout error
-        activation.response.status shouldBe ActivationResponse.messageForCode(ActivationResponse.ApplicationError)
+        activation.response.status shouldBe ActivationResponse.messageForCode(ActivationResponse.DeveloperError)
         activation.response.result shouldBe Some(
           JsObject("error" -> Messages.timedoutActivation(3 seconds, false).toJson))
       }
diff --git a/tests/src/test/scala/whisk/core/containerpool/docker/test/DockerContainerTests.scala b/tests/src/test/scala/whisk/core/containerpool/docker/test/DockerContainerTests.scala
index eb3b2ff..f4c7535 100644
--- a/tests/src/test/scala/whisk/core/containerpool/docker/test/DockerContainerTests.scala
+++ b/tests/src/test/scala/whisk/core/containerpool/docker/test/DockerContainerTests.scala
@@ -426,7 +426,7 @@ class DockerContainerTests
 
     val error = the[InitializationError] thrownBy await(init, initTimeout)
     error.interval shouldBe interval
-    error.response.statusCode shouldBe ActivationResponse.ApplicationError
+    error.response.statusCode shouldBe ActivationResponse.DeveloperError
 
     // assert the finish log is there
     val end = LogMarker.parse(logLines.last)
@@ -474,7 +474,7 @@ class DockerContainerTests
     }
 
     val runResult = container.run(JsObject.empty, JsObject.empty, runTimeout)
-    await(runResult) shouldBe (interval, ActivationResponse.applicationError(
+    await(runResult) shouldBe (interval, ActivationResponse.developerError(
       Messages.timedoutActivation(runTimeout, false)))
 
     // assert the finish log is there
diff --git a/tests/src/test/scala/whisk/core/containerpool/kubernetes/test/KubernetesContainerTests.scala b/tests/src/test/scala/whisk/core/containerpool/kubernetes/test/KubernetesContainerTests.scala
index 4214cf7..227d3c9 100644
--- a/tests/src/test/scala/whisk/core/containerpool/kubernetes/test/KubernetesContainerTests.scala
+++ b/tests/src/test/scala/whisk/core/containerpool/kubernetes/test/KubernetesContainerTests.scala
@@ -241,7 +241,7 @@ class KubernetesContainerTests
 
     val error = the[InitializationError] thrownBy await(init, initTimeout)
     error.interval shouldBe interval
-    error.response.statusCode shouldBe ActivationResponse.ApplicationError
+    error.response.statusCode shouldBe ActivationResponse.DeveloperError
 
     // assert the finish log is there
     val end = LogMarker.parse(logLines.last)
@@ -287,7 +287,7 @@ class KubernetesContainerTests
     }
 
     val runResult = container.run(JsObject.empty, JsObject.empty, runTimeout)
-    await(runResult) shouldBe (interval, ActivationResponse.applicationError(
+    await(runResult) shouldBe (interval, ActivationResponse.developerError(
       Messages.timedoutActivation(runTimeout, false)))
 
     // assert the finish log is there
diff --git a/tests/src/test/scala/whisk/core/containerpool/test/ContainerProxyTests.scala b/tests/src/test/scala/whisk/core/containerpool/test/ContainerProxyTests.scala
index 4a2a133..da1d8e9 100644
--- a/tests/src/test/scala/whisk/core/containerpool/test/ContainerProxyTests.scala
+++ b/tests/src/test/scala/whisk/core/containerpool/test/ContainerProxyTests.scala
@@ -80,6 +80,11 @@ class ContainerProxyTests
     Interval(now, now.plusMillis(200))
   }
 
+  val errorInterval = {
+    val now = initInterval.end.plusMillis(75) // delay between init and run
+    Interval(now, now.plusMillis(150))
+  }
+
   val uuid = UUID()
 
   val message = ActivationMessage(
@@ -386,6 +391,73 @@ class ContainerProxyTests
     }
   }
 
+  it should "complete the transaction and reuse the container on a failed run IFF failure was applicationError" in within(
+    timeout) {
+    val container = new TestContainer {
+      override def run(parameters: JsObject, environment: JsObject, timeout: FiniteDuration)(
+        implicit transid: TransactionId): Future[(Interval, ActivationResponse)] = {
+        runCount += 1
+        //every other run fails
+        if (runCount % 2 == 0) {
+          Future.successful((runInterval, ActivationResponse.success()))
+        } else {
+          Future.successful((errorInterval, ActivationResponse.applicationError(("boom"))))
+        }
+      }
+    }
+    val factory = createFactory(Future.successful(container))
+    val acker = createAcker()
+    val store = createStore
+    val collector = createCollector()
+
+    val machine =
+      childActorOf(
+        ContainerProxy
+          .props(factory, acker, store, collector, InvokerInstanceId(0), poolConfig, pauseGrace = timeout))
+    registerCallback(machine)
+    preWarm(machine)
+
+    //first one will fail
+    run(machine, Started)
+
+    // Note that there are no intermediate state changes
+    //second one will succeed
+    run(machine, Ready)
+
+    //With exception of the error on first run, the assertions should be the same as in
+    //         `run an action and continue with a next run without pausing the container`
+    awaitAssert {
+      factory.calls should have size 1
+      container.initializeCount shouldBe 1
+      container.runCount shouldBe 2
+      collector.calls should have size 2
+      container.suspendCount shouldBe 0
+      container.destroyCount shouldBe 0
+      acker.calls should have size 2
+      store.calls should have size 2
+
+      val initErrorActivation = acker.calls(0)._2
+      initErrorActivation.duration shouldBe Some((initInterval.duration + errorInterval.duration).toMillis)
+      initErrorActivation.annotations
+        .get(WhiskActivation.initTimeAnnotation)
+        .get
+        .convertTo[Int] shouldBe initInterval.duration.toMillis
+      initErrorActivation.annotations
+        .get(WhiskActivation.waitTimeAnnotation)
+        .get
+        .convertTo[Int] shouldBe
+        Interval(message.transid.meta.start, initInterval.start).duration.toMillis
+
+      val runOnlyActivation = acker.calls(1)._2
+      runOnlyActivation.duration shouldBe Some(runInterval.duration.toMillis)
+      runOnlyActivation.annotations.get(WhiskActivation.initTimeAnnotation) shouldBe empty
+      runOnlyActivation.annotations.get(WhiskActivation.waitTimeAnnotation).get.convertTo[Int] shouldBe {
+        Interval(message.transid.meta.start, runInterval.start).duration.toMillis
+      }
+    }
+
+  }
+
   /*
    * ERROR CASES
    */
@@ -424,7 +496,7 @@ class ContainerProxyTests
       override def initialize(initializer: JsObject,
                               timeout: FiniteDuration)(implicit transid: TransactionId): Future[Interval] = {
         initializeCount += 1
-        Future.failed(InitializationError(initInterval, ActivationResponse.applicationError("boom")))
+        Future.failed(InitializationError(initInterval, ActivationResponse.developerError("boom")))
       }
     }
     val factory = createFactory(Future.successful(container))
@@ -449,7 +521,7 @@ class ContainerProxyTests
       collector.calls should have size 1
       container.destroyCount shouldBe 1
       val activation = acker.calls(0)._2
-      activation.response shouldBe ActivationResponse.applicationError("boom")
+      activation.response shouldBe ActivationResponse.developerError("boom")
       activation.annotations
         .get(WhiskActivation.initTimeAnnotation)
         .get
@@ -459,12 +531,13 @@ class ContainerProxyTests
     }
   }
 
-  it should "complete the transaction and destroy the container on a failed run" in within(timeout) {
+  it should "complete the transaction and destroy the container on a failed run IFF failure was containerError" in within(
+    timeout) {
     val container = new TestContainer {
       override def run(parameters: JsObject, environment: JsObject, timeout: FiniteDuration)(
         implicit transid: TransactionId): Future[(Interval, ActivationResponse)] = {
         runCount += 1
-        Future.successful((initInterval, ActivationResponse.applicationError("boom")))
+        Future.successful((initInterval, ActivationResponse.developerError(("boom"))))
       }
     }
     val factory = createFactory(Future.successful(container))
@@ -488,7 +561,7 @@ class ContainerProxyTests
       container.runCount shouldBe 1
       collector.calls should have size 1
       container.destroyCount shouldBe 1
-      acker.calls(0)._2.response shouldBe ActivationResponse.applicationError("boom")
+      acker.calls(0)._2.response shouldBe ActivationResponse.developerError("boom")
       store.calls should have size 1
     }
   }
diff --git a/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala b/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala
index a0acf18..ba9e2cc 100644
--- a/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala
+++ b/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala
@@ -286,7 +286,7 @@ trait WebActionsApiBaseTests extends ControllerTestCommon with BeforeAndAfterEac
             r.fields.get("application_error").map { e =>
               ActivationResponse.applicationError(e)
             } orElse r.fields.get("developer_error").map { e =>
-              ActivationResponse.containerError(e)
+              ActivationResponse.developerError(e)
             } orElse r.fields.get("whisk_error").map { e =>
               ActivationResponse.whiskError(e)
             } orElse None // for clarity
diff --git a/tests/src/test/scala/whisk/core/entity/test/ActivationResponseTests.scala b/tests/src/test/scala/whisk/core/entity/test/ActivationResponseTests.scala
index 78dd296..bbc5257 100644
--- a/tests/src/test/scala/whisk/core/entity/test/ActivationResponseTests.scala
+++ b/tests/src/test/scala/whisk/core/entity/test/ActivationResponseTests.scala
@@ -43,14 +43,14 @@ class ActivationResponseTests extends FlatSpec with Matchers {
       {
         val response = ContainerResponse(okStatus = false, m.take(max.toBytes.toInt - 1), Some(m.length.B, max))
         val init = processInitResponseContent(Right(response), logger)
-        init.statusCode shouldBe ContainerError
+        init.statusCode shouldBe DeveloperError
         init.result.get.asJsObject
           .fields(ERROR_FIELD) shouldBe truncatedResponse(response.entity, m.length.B, max).toJson
       }
       {
         val response = ContainerResponse(okStatus = true, m.take(max.toBytes.toInt - 1), Some(m.length.B, max))
         val run = processRunResponseContent(Right(response), logger)
-        run.statusCode shouldBe ContainerError
+        run.statusCode shouldBe DeveloperError
         run.result.get.asJsObject
           .fields(ERROR_FIELD) shouldBe truncatedResponse(response.entity, m.length.B, max).toJson
       }
@@ -62,7 +62,7 @@ class ActivationResponseTests extends FlatSpec with Matchers {
       .map(Left(_))
       .foreach { e =>
         val ar = processInitResponseContent(e, logger)
-        ar.statusCode shouldBe ContainerError
+        ar.statusCode shouldBe DeveloperError
         ar.result.get.asJsObject.fields(ERROR_FIELD) shouldBe abnormalInitialization.toJson
       }
   }
@@ -70,7 +70,7 @@ class ActivationResponseTests extends FlatSpec with Matchers {
   it should "interpret failed init that responds with null string" in {
     val response = ContainerResponse(okStatus = false, null)
     val ar = processInitResponseContent(Right(response), logger)
-    ar.statusCode shouldBe ContainerError
+    ar.statusCode shouldBe DeveloperError
     ar.result.get.asJsObject.fields(ERROR_FIELD) shouldBe invalidInitResponse(response.entity).toJson
     ar.result.get.toString should not include regex("null")
   }
@@ -78,7 +78,7 @@ class ActivationResponseTests extends FlatSpec with Matchers {
   it should "interpret failed init that responds with empty string" in {
     val response = ContainerResponse(okStatus = false, "")
     val ar = processInitResponseContent(Right(response), logger)
-    ar.statusCode shouldBe ContainerError
+    ar.statusCode shouldBe DeveloperError
     ar.result.get.asJsObject.fields(ERROR_FIELD) shouldBe invalidInitResponse(response.entity).toJson
     ar.result.get.asJsObject.fields(ERROR_FIELD).toString.endsWith(".\"") shouldBe true
   }
@@ -86,7 +86,7 @@ class ActivationResponseTests extends FlatSpec with Matchers {
   it should "interpret failed init that responds with non-empty string" in {
     val response = ContainerResponse(okStatus = false, "string")
     val ar = processInitResponseContent(Right(response), logger)
-    ar.statusCode shouldBe ContainerError
+    ar.statusCode shouldBe DeveloperError
     ar.result.get.asJsObject.fields(ERROR_FIELD) shouldBe invalidInitResponse(response.entity).toJson
     ar.result.get.toString should include(response.entity)
   }
@@ -94,7 +94,7 @@ class ActivationResponseTests extends FlatSpec with Matchers {
   it should "interpret failed init that responds with JSON string not object" in {
     val response = ContainerResponse(okStatus = false, Vector(1).toJson.compactPrint)
     val ar = processInitResponseContent(Right(response), logger)
-    ar.statusCode shouldBe ContainerError
+    ar.statusCode shouldBe DeveloperError
     ar.result.get.asJsObject.fields(ERROR_FIELD) shouldBe invalidInitResponse(response.entity).toJson
     ar.result.get.toString should include(response.entity)
   }
@@ -102,14 +102,14 @@ class ActivationResponseTests extends FlatSpec with Matchers {
   it should "interpret failed init that responds with JSON object containing error" in {
     val response = ContainerResponse(okStatus = false, Map(ERROR_FIELD -> "foobar").toJson.compactPrint)
     val ar = processInitResponseContent(Right(response), logger)
-    ar.statusCode shouldBe ContainerError
+    ar.statusCode shouldBe DeveloperError
     ar.result.get shouldBe response.entity.parseJson
   }
 
   it should "interpret failed init that responds with JSON object" in {
     val response = ContainerResponse(okStatus = false, Map("foobar" -> "baz").toJson.compactPrint)
     val ar = processInitResponseContent(Right(response), logger)
-    ar.statusCode shouldBe ContainerError
+    ar.statusCode shouldBe DeveloperError
     ar.result.get.asJsObject.fields(ERROR_FIELD) shouldBe invalidInitResponse(response.entity).toJson
     ar.result.get.toString should include("baz")
   }
@@ -126,7 +126,7 @@ class ActivationResponseTests extends FlatSpec with Matchers {
       .map(Left(_))
       .foreach { e =>
         val ar = processRunResponseContent(e, logger)
-        ar.statusCode shouldBe ContainerError
+        ar.statusCode shouldBe DeveloperError
         ar.result.get.asJsObject.fields(ERROR_FIELD) shouldBe abnormalRun.toJson
       }
   }
@@ -134,7 +134,7 @@ class ActivationResponseTests extends FlatSpec with Matchers {
   it should "interpret failed run that responds with null string" in {
     val response = ContainerResponse(okStatus = false, null)
     val ar = processRunResponseContent(Right(response), logger)
-    ar.statusCode shouldBe ContainerError
+    ar.statusCode shouldBe DeveloperError
     ar.result.get.asJsObject.fields(ERROR_FIELD) shouldBe invalidRunResponse(response.entity).toJson
     ar.result.get.toString should not include regex("null")
   }
@@ -142,7 +142,7 @@ class ActivationResponseTests extends FlatSpec with Matchers {
   it should "interpret failed run that responds with empty string" in {
     val response = ContainerResponse(okStatus = false, "")
     val ar = processRunResponseContent(Right(response), logger)
-    ar.statusCode shouldBe ContainerError
+    ar.statusCode shouldBe DeveloperError
     ar.result.get.asJsObject.fields(ERROR_FIELD) shouldBe invalidRunResponse(response.entity).toJson
     ar.result.get.asJsObject.fields(ERROR_FIELD).toString.endsWith(".\"") shouldBe true
   }
@@ -150,7 +150,7 @@ class ActivationResponseTests extends FlatSpec with Matchers {
   it should "interpret failed run that responds with non-empty string" in {
     val response = ContainerResponse(okStatus = false, "string")
     val ar = processRunResponseContent(Right(response), logger)
-    ar.statusCode shouldBe ContainerError
+    ar.statusCode shouldBe DeveloperError
     ar.result.get.asJsObject.fields(ERROR_FIELD) shouldBe invalidRunResponse(response.entity).toJson
     ar.result.get.toString should include(response.entity)
   }
@@ -158,7 +158,7 @@ class ActivationResponseTests extends FlatSpec with Matchers {
   it should "interpret failed run that responds with JSON string not object" in {
     val response = ContainerResponse(okStatus = false, Vector(1).toJson.compactPrint)
     val ar = processRunResponseContent(Right(response), logger)
-    ar.statusCode shouldBe ContainerError
+    ar.statusCode shouldBe DeveloperError
     ar.result.get.asJsObject.fields(ERROR_FIELD) shouldBe invalidRunResponse(response.entity).toJson
     ar.result.get.toString should include(response.entity)
   }
@@ -166,14 +166,14 @@ class ActivationResponseTests extends FlatSpec with Matchers {
   it should "interpret failed run that responds with JSON object containing error" in {
     val response = ContainerResponse(okStatus = false, Map(ERROR_FIELD -> "foobar").toJson.compactPrint)
     val ar = processRunResponseContent(Right(response), logger)
-    ar.statusCode shouldBe ContainerError
+    ar.statusCode shouldBe DeveloperError
     ar.result.get shouldBe response.entity.parseJson
   }
 
   it should "interpret failed run that responds with JSON object" in {
     val response = ContainerResponse(okStatus = false, Map("foobar" -> "baz").toJson.compactPrint)
     val ar = processRunResponseContent(Right(response), logger)
-    ar.statusCode shouldBe ContainerError
+    ar.statusCode shouldBe DeveloperError
     ar.result.get.asJsObject.fields(ERROR_FIELD) shouldBe invalidRunResponse(response.entity).toJson
     ar.result.get.toString should include("baz")
   }
diff --git a/tests/src/test/scala/whisk/core/limits/ActionLimitsTests.scala b/tests/src/test/scala/whisk/core/limits/ActionLimitsTests.scala
index bd78db3..f2a759b 100644
--- a/tests/src/test/scala/whisk/core/limits/ActionLimitsTests.scala
+++ b/tests/src/test/scala/whisk/core/limits/ActionLimitsTests.scala
@@ -185,7 +185,7 @@ class ActionLimitsTests extends TestHelpers with WskTestHelpers with WskActorSys
       val run = wsk.action.invoke(name, Map("sleepTimeInMs" -> allowedActionDuration.plus(1 second).toMillis.toJson))
       withActivation(wsk.activation, run) { result =>
         withClue("Activation result not as expected:") {
-          result.response.status shouldBe ActivationResponse.messageForCode(ActivationResponse.ApplicationError)
+          result.response.status shouldBe ActivationResponse.messageForCode(ActivationResponse.DeveloperError)
           result.response.result.get.fields("error") shouldBe {
             Messages.timedoutActivation(allowedActionDuration, init = false).toJson
           }
@@ -272,7 +272,7 @@ class ActionLimitsTests extends TestHelpers with WskTestHelpers with WskActorSys
       def checkResponse(activation: ActivationResult) = {
         val response = activation.response
         response.success shouldBe false
-        response.status shouldBe ActivationResponse.messageForCode(ActivationResponse.ContainerError)
+        response.status shouldBe ActivationResponse.messageForCode(ActivationResponse.DeveloperError)
         val msg = response.result.get.fields(ActivationResponse.ERROR_FIELD).convertTo[String]
         val expected = Messages.truncatedResponse((allowedSize + 10).B, allowedSize.B)
         withClue(s"is: ${msg.take(expected.length)}\nexpected: $expected") {
diff --git a/tests/src/test/scala/whisk/core/limits/MaxActionDurationTests.scala b/tests/src/test/scala/whisk/core/limits/MaxActionDurationTests.scala
index 1a854f1..591c8a9 100644
--- a/tests/src/test/scala/whisk/core/limits/MaxActionDurationTests.scala
+++ b/tests/src/test/scala/whisk/core/limits/MaxActionDurationTests.scala
@@ -86,7 +86,7 @@ class MaxActionDurationTests extends TestHelpers with WskTestHelpers with WskAct
           pollPeriod = 1.minute,
           totalWait = TimeLimit.MAX_DURATION + 2.minutes) { activation =>
           withClue("Activation result not as expected:") {
-            activation.response.status shouldBe ActivationResponse.messageForCode(ActivationResponse.ApplicationError)
+            activation.response.status shouldBe ActivationResponse.messageForCode(ActivationResponse.DeveloperError)
             activation.response.result shouldBe Some(
               JsObject("error" -> Messages.timedoutActivation(TimeLimit.MAX_DURATION, init = false).toJson))
             activation.duration.toInt should be >= TimeLimit.MAX_DURATION.toMillis.toInt