17
17
18
18
package org .apache .openwhisk .core .containerpool .v2 .test
19
19
20
- import java .net .InetSocketAddress
21
- import java .time .Instant
22
- import java .util .concurrent .TimeUnit
23
- import java .util .concurrent .atomic .AtomicInteger
24
-
25
20
import akka .actor .FSM .{CurrentState , StateTimeout , SubscribeTransitionCallBack , Transition }
26
21
import akka .actor .{Actor , ActorRef , ActorRefFactory , ActorSystem , Props }
27
22
import akka .http .scaladsl .model
28
23
import akka .io .Tcp .Connect
29
24
import akka .stream .scaladsl .{Sink , Source }
30
- import akka .testkit .{ImplicitSender , TestKit , TestProbe }
25
+ import akka .testkit .{ImplicitSender , TestFSMRef , TestKit , TestProbe }
31
26
import akka .util .ByteString
32
27
import com .ibm .etcd .api .{DeleteRangeResponse , KeyValue , PutResponse }
33
28
import com .ibm .etcd .client .{EtcdClient => Client }
34
29
import common .{LoggedFunction , StreamLogging , SynchronizedLoggedFunction }
35
- import org .apache .openwhisk .common .{Logging , TransactionId }
30
+ import org .apache .openwhisk .common .{GracefulShutdown , Logging , TransactionId }
36
31
import org .apache .openwhisk .core .ack .ActiveAck
37
32
import org .apache .openwhisk .core .connector .{AcknowledegmentMessage , ActivationMessage }
38
33
import org .apache .openwhisk .core .containerpool .logging .LogCollectingException
@@ -51,7 +46,7 @@ import org.apache.openwhisk.core.database.{ArtifactStore, StaleParameter, UserCo
51
46
import org .apache .openwhisk .core .entity .ExecManifest .{ImageName , RuntimeManifest }
52
47
import org .apache .openwhisk .core .entity .size ._
53
48
import org .apache .openwhisk .core .entity .types .AuthStore
54
- import org .apache .openwhisk .core .entity .{ ExecutableWhiskAction , _ }
49
+ import org .apache .openwhisk .core .entity ._
55
50
import org .apache .openwhisk .core .etcd .EtcdClient
56
51
import org .apache .openwhisk .core .etcd .EtcdKV .ContainerKeys
57
52
import org .apache .openwhisk .core .etcd .EtcdType ._
@@ -65,6 +60,10 @@ import org.scalatest.{Assertion, BeforeAndAfterAll, FlatSpecLike, Matchers}
65
60
import spray .json .DefaultJsonProtocol ._
66
61
import spray .json .{JsObject , _ }
67
62
63
+ import java .net .InetSocketAddress
64
+ import java .time .Instant
65
+ import java .util .concurrent .TimeUnit
66
+ import java .util .concurrent .atomic .AtomicInteger
68
67
import scala .collection .mutable
69
68
import scala .collection .mutable .{Map => MutableMap }
70
69
import scala .concurrent .duration ._
@@ -291,8 +290,9 @@ class FunctionPullingContainerProxyTests
291
290
Future .successful(count)
292
291
}
293
292
294
- def getLiveContainerCountFail (count : Long ) = LoggedFunction { (_ : String , _ : FullyQualifiedEntityName , _ : DocRevision ) =>
295
- Future .failed(new Exception (" failure" ))
293
+ def getLiveContainerCountFail (count : Long ) = LoggedFunction {
294
+ (_ : String , _ : FullyQualifiedEntityName , _ : DocRevision ) =>
295
+ Future .failed(new Exception (" failure" ))
296
296
}
297
297
298
298
def getLiveContainerCountFailFirstCall (count : Long ) = {
@@ -961,7 +961,7 @@ class FunctionPullingContainerProxyTests
961
961
}
962
962
client.send(machine, ClientClosed )
963
963
964
- probe.expectMsgAllOf(ContainerRemoved (true ), Transition (machine, Running , Removing ))
964
+ probe.expectMsgAllOf(ContainerRemoved (false ), Transition (machine, Running , Removing ))
965
965
966
966
awaitAssert {
967
967
factory.calls should have size 1
@@ -1137,7 +1137,8 @@ class FunctionPullingContainerProxyTests
1137
1137
}
1138
1138
}
1139
1139
1140
- it should " destroy container proxy when stopping due to timeout and getting live count fails permanently" in within(timeout) {
1140
+ it should " destroy container proxy when stopping due to timeout and getting live count fails permanently" in within(
1141
+ timeout) {
1141
1142
val authStore = mock[ArtifactWhiskAuthStore ]
1142
1143
val namespaceBlacklist : NamespaceBlacklist = new NamespaceBlacklist (authStore)
1143
1144
val get = getWhiskAction(Future (action.toWhiskAction))
@@ -1532,6 +1533,96 @@ class FunctionPullingContainerProxyTests
1532
1533
}
1533
1534
}
1534
1535
1536
+ it should " remove the ETCD data first when disabling the container proxy" in within(timeout) {
1537
+ val authStore = mock[ArtifactWhiskAuthStore ]
1538
+ val namespaceBlacklist : NamespaceBlacklist = new NamespaceBlacklist (authStore)
1539
+ val get = getWhiskAction(Future (action.toWhiskAction))
1540
+ val dataManagementService = TestProbe ()
1541
+ val container = new TestContainer
1542
+ val factory = createFactory(Future .successful(container))
1543
+ val acker = createAcker()
1544
+ val store = createStore
1545
+ val collector = createCollector()
1546
+ val counter = getLiveContainerCount(1 )
1547
+ val limit = getWarmedContainerLimit(Future .successful((1 , 10 .seconds)))
1548
+ val (client, clientFactory) = testClient
1549
+
1550
+ val instanceId = InvokerInstanceId (0 , userMemory = defaultUserMemory)
1551
+ val probe = TestProbe ()
1552
+ val machine =
1553
+ TestFSMRef (
1554
+ new FunctionPullingContainerProxy (
1555
+ factory,
1556
+ entityStore,
1557
+ namespaceBlacklist,
1558
+ get,
1559
+ dataManagementService.ref,
1560
+ clientFactory,
1561
+ acker,
1562
+ store,
1563
+ collector,
1564
+ counter,
1565
+ limit,
1566
+ instanceId,
1567
+ invokerHealthManager.ref,
1568
+ poolConfig,
1569
+ timeoutConfig,
1570
+ healthchecksConfig(),
1571
+ None ),
1572
+ probe.ref)
1573
+
1574
+ registerCallback(machine, probe)
1575
+
1576
+ machine ! Initialize (invocationNamespace.asString, fqn, action, schedulerHost, rpcPort, messageTransId)
1577
+ probe.expectMsg(Transition (machine, Uninitialized , CreatingClient ))
1578
+ client.expectMsg(StartClient )
1579
+ client.send(machine, ClientCreationCompleted ())
1580
+
1581
+ val containerId = machine.underlyingActor.stateData.getContainer match {
1582
+ case Some (container) => container.containerId
1583
+ case None => ContainerId (" " )
1584
+ }
1585
+
1586
+ dataManagementService.expectMsg(RegisterData (
1587
+ s " ${ContainerKeys .existingContainers(invocationNamespace.asString, fqn, action.rev, Some (instanceId), Some (containerId))}" ,
1588
+ " " ))
1589
+
1590
+ probe.expectMsg(Transition (machine, CreatingClient , ClientCreated ))
1591
+ expectInitialized(probe)
1592
+ client.expectMsg(RequestActivation ())
1593
+ client.send(machine, message)
1594
+
1595
+ probe.expectMsg(Transition (machine, ClientCreated , Running ))
1596
+ client.expectMsg(ContainerWarmed )
1597
+ client.expectMsgPF() {
1598
+ case RequestActivation (Some (_), None ) => true
1599
+ }
1600
+ client.send(machine, message)
1601
+ client.expectMsgPF() {
1602
+ case RequestActivation (Some (_), None ) => true
1603
+ }
1604
+ machine ! GracefulShutdown
1605
+
1606
+ dataManagementService.expectMsg(
1607
+ UnregisterData (ContainerKeys
1608
+ .existingContainers(invocationNamespace.asString, fqn, action.rev, Some (instanceId), Some (containerId))))
1609
+
1610
+ client.expectMsg(CloseClientProxy )
1611
+ client.send(machine, ClientClosed )
1612
+
1613
+ probe.expectMsgAllOf(ContainerRemoved (false ), Transition (machine, Running , Removing ))
1614
+
1615
+ awaitAssert {
1616
+ factory.calls should have size 1
1617
+ container.initializeCount shouldBe 1
1618
+ container.runCount shouldBe 2
1619
+ collector.calls.length shouldBe 2
1620
+ container.destroyCount shouldBe 1
1621
+ acker.calls.length shouldBe 2
1622
+ store.calls.length shouldBe 2
1623
+ }
1624
+ }
1625
+
1535
1626
it should " pause itself when timeout and recover when got a new Initialize" in within(timeout) {
1536
1627
val authStore = mock[ArtifactWhiskAuthStore ]
1537
1628
val namespaceBlacklist : NamespaceBlacklist = new NamespaceBlacklist (authStore)
0 commit comments