blob: fff4bab658e731b7d6f9abf745c37f7be6d3321c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.iota.fey
import play.api.libs.json._
import akka.actor.{ActorRef, PoisonPill, Props}
import akka.testkit.{EventFilter, TestActorRef, TestProbe}
import scala.concurrent.duration.DurationInt
class OrchestrationSpec extends BaseAkkaSpec{
val parent = TestProbe("ORCHESTRATION")
val orchName = "ORCHESTRATION-TEST"
val monitor = TestProbe()
val orchRef = TestActorRef[Orchestration]( Props(new Orchestration("TESTING",orchName,"123124324324"){
override val monitoring_actor = monitor.ref
}), parent.ref, orchName)
val orchState = orchRef.underlyingActor
val orchestrationJson = getJSValueFromString(Utils_JSONTest.create_json_test)
val ensembles = (orchestrationJson \ JSON_PATH.ENSEMBLES).as[List[JsObject]]
val ensemble1 = ensembles(0)
val ensemble2 = ensembles(1)
var ensemble1ref:ActorRef = _
var ensemble2ref:ActorRef = _
"Creating an Orchestration " should {
"result in sending START message to Monitor actor" in {
monitor.expectMsgClass(1.seconds, classOf[Monitor.START])
}
"result in one paths added to IdentifyFeyActors.actorsPath" in{
globalIdentifierRef ! IdentifyFeyActors.IDENTIFY_TREE(parent.ref.path.toString)
Thread.sleep(500)
IdentifyFeyActors.actorsPath should have size(1)
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName")
}
"result in empty Orchestration.ensembles state variable" in{
orchState.ensembles shouldBe empty
}
}
"Sending Orchestration.CREATE_ENSEMBLES to Orchestration" should {
s"result in creation of Ensemble '${(ensemble1 \ JSON_PATH.GUID).as[String]}'" in {
orchRef ! Orchestration.CREATE_ENSEMBLES(ensembles)
ensemble1ref = TestProbe().expectActor(s"${orchRef.path}/${(ensemble1 \ JSON_PATH.GUID).as[String]}")
}
s"result in creation of Ensemble '${(ensemble2 \ JSON_PATH.GUID).as[String]}'" in {
ensemble2ref = TestProbe().expectActor(s"${orchRef.path}/${(ensemble2 \ JSON_PATH.GUID).as[String]}")
}
s"result in creation of two Performers" in {
TestProbe().expectActor(s"${orchRef.path}/${(ensemble2 \ JSON_PATH.GUID).as[String]}/TEST-0001")
TestProbe().expectActor(s"${orchRef.path}/${(ensemble1 \ JSON_PATH.GUID).as[String]}/TEST-0001")
}
s"result in two entries in Orchestration.ensembles matching the created ensembles" in {
orchState.ensembles should have size(2)
orchState.ensembles should contain key((ensemble1 \ JSON_PATH.GUID).as[String])
orchState.ensembles should contain key((ensemble2 \ JSON_PATH.GUID).as[String])
orchState.ensembles.get((ensemble1 \ JSON_PATH.GUID).as[String]).get should equal(ensemble1ref)
orchState.ensembles.get((ensemble2 \ JSON_PATH.GUID).as[String]).get should equal(ensemble2ref)
}
s"result in two entries in ORCHESTRATION_CACHE.orchestration_metadata for $orchName" in {
ORCHESTRATION_CACHE.orchestration_metadata should contain key(orchName)
ORCHESTRATION_CACHE.orchestration_metadata.get(orchName).get should have size(2)
}
s"result in right entry in ORCHESTRATION_CACHE.orchestration_metadata for $orchName and ${(ensemble1 \ JSON_PATH.GUID).as[String]}" in {
ORCHESTRATION_CACHE.orchestration_metadata.get(orchName).get should contain key((ensemble1 \ JSON_PATH.GUID).as[String])
ORCHESTRATION_CACHE.orchestration_metadata
.get(orchName).get
.get((ensemble1 \ JSON_PATH.GUID).as[String]).get should equal(ensemble1)
}
s"result in right entry in ORCHESTRATION_CACHE.orchestration_metadata for $orchName and ${(ensemble2 \ JSON_PATH.GUID).as[String]}" in {
ORCHESTRATION_CACHE.orchestration_metadata.get(orchName).get should contain key((ensemble2 \ JSON_PATH.GUID).as[String])
ORCHESTRATION_CACHE.orchestration_metadata
.get(orchName).get
.get((ensemble2 \ JSON_PATH.GUID).as[String]).get should equal(ensemble2)
}
"result in five paths added to IdentifyFeyActors.actorsPath" in{
globalIdentifierRef ! IdentifyFeyActors.IDENTIFY_TREE(parent.ref.path.toString)
Thread.sleep(500)
IdentifyFeyActors.actorsPath should have size(5)
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName/MY-ENSEMBLE-0001")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName/MY-ENSEMBLE-0001/TEST-0001")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName/MY-ENSEMBLE-0002")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName/MY-ENSEMBLE-0002/TEST-0001")
}
}
"Sending Orchestration.CREATE_ENSEMBLES to Orchestration with the same previous created Ensembles" should {
s"result in logging 'already exists' at Warn " in {
EventFilter.warning(pattern = "^Ensembles.*already exists", occurrences = 2) intercept {
orchRef ! Orchestration.CREATE_ENSEMBLES(ensembles)
}
}
s"not change state variable Orchestration.ensembles" in {
orchState.ensembles should have size(2)
orchState.ensembles should contain key((ensemble1 \ JSON_PATH.GUID).as[String])
orchState.ensembles should contain key((ensemble2 \ JSON_PATH.GUID).as[String])
orchState.ensembles.get((ensemble1 \ JSON_PATH.GUID).as[String]).get should equal(ensemble1ref)
orchState.ensembles.get((ensemble2 \ JSON_PATH.GUID).as[String]).get should equal(ensemble2ref)
}
}
val orch2Name = "TEST-ORCH-2"
var orch2ref: TestActorRef[Orchestration] = _
var orch2ensRef: ActorRef = _
val orchestration2Json = getJSValueFromString(Utils_JSONTest.orchestration_test_json)
val orch2ensembles = (orchestration2Json \ JSON_PATH.ENSEMBLES).as[List[JsObject]]
val orch2ensemble1 = orch2ensembles(0)
val monitor2 = TestProbe()
var orch2state:Orchestration = null
"Creating a second Orchestration" should {
s"result in sending START message to Monitor actor" in {
orch2ref = TestActorRef[Orchestration]( Props(new Orchestration("TESTING",orch2Name,"123124324324"){
override val monitoring_actor = monitor2.ref
}), parent.ref, orch2Name)
monitor2.expectMsgClass(1.seconds, classOf[Monitor.START])
orch2state = orch2ref.underlyingActor
}
"result in empty Orchestration.ensembles state variable" in{
orch2state.ensembles shouldBe empty
}
"result in six paths added to IdentifyFeyActors.actorsPath" in{
globalIdentifierRef ! IdentifyFeyActors.IDENTIFY_TREE(parent.ref.path.toString)
Thread.sleep(500)
IdentifyFeyActors.actorsPath should have size(6)
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName/MY-ENSEMBLE-0001")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName/MY-ENSEMBLE-0001/TEST-0001")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName/MY-ENSEMBLE-0002")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName/MY-ENSEMBLE-0002/TEST-0001")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orch2Name")
}
}
"Sending Orchestration.CREATE_ENSEMBLES to the second Orchestration" should {
s"result in creation of Ensemble '${(orch2ensemble1 \ JSON_PATH.GUID).as[String]}'" in {
orch2ref ! Orchestration.CREATE_ENSEMBLES(orch2ensembles)
orch2ensRef = TestProbe().expectActor(s"${orch2ref.path}/${(orch2ensemble1 \ JSON_PATH.GUID).as[String]}")
}
s"result in creation of one Performers" in {
TestProbe().expectActor(s"${orch2ref.path}/${(orch2ensemble1 \ JSON_PATH.GUID).as[String]}/TEST-0001")
}
s"result in one entry in Orchestration.ensembles matching the craeted ensemble" in {
orch2state.ensembles should have size(1)
orch2state.ensembles should contain key((orch2ensemble1 \ JSON_PATH.GUID).as[String])
orch2state.ensembles.get((orch2ensemble1 \ JSON_PATH.GUID).as[String]).get should equal(orch2ensRef)
}
s"result in one entries in ORCHESTRATION_CACHE.orchestration_metadata for $orch2Name" in {
ORCHESTRATION_CACHE.orchestration_metadata should contain key(orch2Name)
ORCHESTRATION_CACHE.orchestration_metadata.get(orch2Name).get should have size(1)
}
s"result in right entry in ORCHESTRATION_CACHE.orchestration_metadata for $orch2Name and ${(orch2ensemble1 \ JSON_PATH.GUID).as[String]}" in {
ORCHESTRATION_CACHE.orchestration_metadata.get(orch2Name).get should contain key((orch2ensemble1 \ JSON_PATH.GUID).as[String])
ORCHESTRATION_CACHE.orchestration_metadata
.get(orch2Name).get
.get((orch2ensemble1 \ JSON_PATH.GUID).as[String]).get should equal(orch2ensemble1)
}
"result in eight paths added to IdentifyFeyActors.actorsPath" in{
globalIdentifierRef ! IdentifyFeyActors.IDENTIFY_TREE(parent.ref.path.toString)
Thread.sleep(500)
IdentifyFeyActors.actorsPath should have size(8)
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName/MY-ENSEMBLE-0001")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName/MY-ENSEMBLE-0001/TEST-0001")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName/MY-ENSEMBLE-0002")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName/MY-ENSEMBLE-0002/TEST-0001")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orch2Name")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orch2Name/MY-ENSEMBLE-0001")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orch2Name/MY-ENSEMBLE-0001/TEST-0001")
}
}
"Sending Orchestration.DELETE_ENSEMBLES to the second Orchestration" should {
"result in termination of ensembles and the Orchestration itself" in {
orch2ref ! Orchestration.DELETE_ENSEMBLES(orch2ensembles)
TestProbe().verifyActorTermination(orch2ensRef)
}
s"result in sending TERMINATED message to Monitor actor" in {
monitor2.expectMsgAllClassOf(classOf[Monitor.TERMINATE])
}
s"result in FeyCore.STOP_EMPTY_ORCHESTRATION triggered by $orch2Name to parent" in {
parent.expectMsg(FeyCore.STOP_EMPTY_ORCHESTRATION(orch2Name))
}
"result in six paths added to IdentifyFeyActors.actorsPath" in{
globalIdentifierRef ! IdentifyFeyActors.IDENTIFY_TREE(parent.ref.path.toString)
Thread.sleep(500)
IdentifyFeyActors.actorsPath should have size(6)
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName/MY-ENSEMBLE-0001")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName/MY-ENSEMBLE-0001/TEST-0001")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName/MY-ENSEMBLE-0002")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName/MY-ENSEMBLE-0002/TEST-0001")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orch2Name")
}
"result in empty state variable Orchestration.ensembles" in {
orch2state.ensembles shouldBe empty
}
}
"Stopping second Orchestration" should {
s"result in sending STOP message to Monitor actor" in {
orch2ref ! PoisonPill
monitor2.expectMsgAllClassOf(classOf[Monitor.STOP])
}
}
"Sending Orchestration.UPDATE_ENSEMBLES with Ensemble that does not exist" should {
s"result in logging 'no Ensemble' at Warn " in {
EventFilter.warning(pattern = s"^There is no Ensemble.*$orchName", occurrences = 1) intercept {
val updateEnsemble = (getJSValueFromString(Utils_JSONTest.orchestration_update2_test_json) \ JSON_PATH.ENSEMBLES).as[List[JsObject]]
orchRef ! Orchestration.UPDATE_ENSEMBLES(updateEnsemble)
}
}
}
"Sending Orchestration.UPDATE_ENSEMBLES to Orchestration" should {
val updateEnsemble = (getJSValueFromString(Utils_JSONTest.orchestration_update_test_json) \ JSON_PATH.ENSEMBLES).as[List[JsObject]]
s"result in termination of Ensemble '$orchName/MY-ENSEMBLE-0001'" in {
orchRef ! Orchestration.UPDATE_ENSEMBLES(updateEnsemble)
TestProbe().verifyActorTermination(ensemble1ref)
}
s"result in termination of '$orchName/MY-ENSEMBLE-0001/TEST-0001'" in {
TestProbe().notExpectActor(s"${parent.ref.path}/$orchName/MY-ENSEMBLE-0001/TEST-0001")
}
s"result in creation of two new performers" in {
TestProbe().expectActor(s"${parent.ref.path}/$orchName/MY-ENSEMBLE-0001/TEST-0004")
TestProbe().expectActor(s"${parent.ref.path}/$orchName/MY-ENSEMBLE-0001/TEST-0005")
}
"result in six paths added to IdentifyFeyActors.actorsPath" in{
globalIdentifierRef ! IdentifyFeyActors.IDENTIFY_TREE(parent.ref.path.toString)
Thread.sleep(500)
IdentifyFeyActors.actorsPath should have size(6)
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName/MY-ENSEMBLE-0001")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName/MY-ENSEMBLE-0001/TEST-0005")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName/MY-ENSEMBLE-0001/TEST-0004")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName/MY-ENSEMBLE-0002")
IdentifyFeyActors.actorsPath should contain(s"${parent.ref.path}/$orchName/MY-ENSEMBLE-0002/TEST-0001")
}
s"result in right entry in ORCHESTRATION_CACHE.orchestration_metadata for $orchName and ${(ensemble1 \ JSON_PATH.GUID).as[String]}" in {
ORCHESTRATION_CACHE.orchestration_metadata.get(orchName).get should contain key((ensemble1 \ JSON_PATH.GUID).as[String])
ORCHESTRATION_CACHE.orchestration_metadata
.get(orchName).get
.get((ensemble1 \ JSON_PATH.GUID).as[String]).get should equal(updateEnsemble(0))
}
}
//TODO: Test restart
}