blob: eaa13600f0025b3673adf81e8322c63340cf5532 [file] [log] [blame]
/*
* Copyright 2015-2016 IBM Corporation
*
* 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 whisk.core.controller.test
import scala.concurrent.{ Await, Future }
import scala.concurrent.ExecutionContext
import scala.concurrent.duration.{ DurationInt, FiniteDuration }
import scala.language.postfixOps
import org.scalatest.BeforeAndAfter
import org.scalatest.BeforeAndAfterAll
import org.scalatest.FlatSpec
import org.scalatest.Matchers
import common.StreamLogging
import spray.http.BasicHttpCredentials
import spray.json.DefaultJsonProtocol
import spray.json.JsString
import spray.routing.HttpService
import spray.testkit.ScalatestRouteTest
import whisk.common.TransactionCounter
import whisk.common.TransactionId
import whisk.core.WhiskConfig
import whisk.core.connector.ActivationMessage
import whisk.core.controller.WhiskActionsApi
import whisk.core.controller.WhiskServices
import whisk.core.database.DocumentFactory
import whisk.core.database.test.DbUtils
import whisk.core.entitlement._
import whisk.core.entity._
import whisk.core.iam.NamespaceProvider
import whisk.core.loadBalancer.LoadBalancer
protected trait ControllerTestCommon
extends FlatSpec
with BeforeAndAfter
with BeforeAndAfterAll
with ScalatestRouteTest
with Matchers
with TransactionCounter
with DbUtils
with WhiskServices
with HttpService
with StreamLogging {
override val actorRefFactory = null
implicit val routeTestTimeout = RouteTestTimeout(90 seconds)
implicit val actorSystem = system // defined in ScalatestRouteTest
val executionContext = actorSystem.dispatcher
override val whiskConfig = new WhiskConfig(WhiskAuthStore.requiredProperties ++ WhiskActionsApi.requiredProperties)
assert(whiskConfig.isValid)
override val loadBalancer = new DegenerateLoadBalancerService(whiskConfig)
override val iam = new NamespaceProvider(whiskConfig, forceLocal = true)
override lazy val entitlementProvider: EntitlementProvider = new LocalEntitlementProvider(whiskConfig, loadBalancer, iam)
override val activationIdFactory = new ActivationId.ActivationIdGenerator() {
// need a static activation id to test activations api
private val fixedId = ActivationId()
override def make = fixedId
}
override val consulServer = "???"
val entityStore = WhiskEntityStore.datastore(whiskConfig)
val activationStore = WhiskActivationStore.datastore(whiskConfig)
val authStore = WhiskAuthStore.datastore(whiskConfig)
val authStoreV2 = WhiskAuthV2Store.datastore(whiskConfig)
def createTempCredentials(implicit transid: TransactionId) = {
val subject = Subject()
val key = AuthKey()
val auth = WhiskAuthV2.withDefaultNamespace(subject, key)
put(authStoreV2, auth)
waitOnView(authStore, key, 1)
(subject.toIdentity(key), BasicHttpCredentials(key.uuid.asString, key.key.asString))
}
def deleteAction(doc: DocId)(implicit transid: TransactionId) = {
Await.result(WhiskAction.get(entityStore, doc) flatMap { doc =>
logging.info(this, s"deleting ${doc.docinfo}")
WhiskAction.del(entityStore, doc.docinfo)
}, dbOpTimeout)
}
def deleteActivation(doc: DocId)(implicit transid: TransactionId) = {
Await.result(WhiskActivation.get(entityStore, doc) flatMap { doc =>
logging.info(this, s"deleting ${doc.docinfo}")
WhiskActivation.del(entityStore, doc.docinfo)
}, dbOpTimeout)
}
def deleteTrigger(doc: DocId)(implicit transid: TransactionId) = {
Await.result(WhiskTrigger.get(entityStore, doc) flatMap { doc =>
logging.info(this, s"deleting ${doc.docinfo}")
WhiskAction.del(entityStore, doc.docinfo)
}, dbOpTimeout)
}
def deleteRule(doc: DocId)(implicit transid: TransactionId) = {
Await.result(WhiskRule.get(entityStore, doc) flatMap { doc =>
logging.info(this, s"deleting ${doc.docinfo}")
WhiskRule.del(entityStore, doc.docinfo)
}, dbOpTimeout)
}
def deleteAuth(doc: DocId)(implicit transid: TransactionId) = {
Await.result(WhiskAuth.get(authStore, doc) flatMap { doc =>
logging.info(this, s"deleting ${doc.docinfo}")
WhiskAuth.del(authStore, doc.docinfo)
}, dbOpTimeout)
}
def deletePackage(doc: DocId)(implicit transid: TransactionId) = {
Await.result(WhiskPackage.get(entityStore, doc) flatMap { doc =>
logging.info(this, s"deleting ${doc.docinfo}")
WhiskPackage.del(entityStore, doc.docinfo)
}, dbOpTimeout)
}
def stringToFullyQualifiedName(s: String) = FullyQualifiedEntityName.serdes.read(JsString(s))
object MakeName {
@volatile var counter = 1
def next(prefix: String = "test")(): EntityName = {
counter = counter + 1
EntityName(s"${prefix}_name$counter")
}
}
Collection.initialize(entityStore)
val ACTIONS = Collection(Collection.ACTIONS)
val TRIGGERS = Collection(Collection.TRIGGERS)
val RULES = Collection(Collection.RULES)
val ACTIVATIONS = Collection(Collection.ACTIVATIONS)
val NAMESPACES = Collection(Collection.NAMESPACES)
val PACKAGES = Collection(Collection.PACKAGES)
after {
cleanup()
}
override def afterAll() {
println("Shutting down db connections");
entityStore.shutdown()
activationStore.shutdown()
authStore.shutdown()
}
protected case class BadEntity(
namespace: EntityPath,
override val name: EntityName,
version: SemVer = SemVer(),
publish: Boolean = false,
annotations: Parameters = Parameters())
extends WhiskEntity(name) {
override def toJson = BadEntity.serdes.write(this).asJsObject
}
protected object BadEntity
extends DocumentFactory[BadEntity]
with DefaultJsonProtocol {
implicit val serdes = jsonFormat5(BadEntity.apply)
override val cacheEnabled = true
override def cacheKeyForUpdate(w: BadEntity) = w.docid.asDocInfo
}
}
class DegenerateLoadBalancerService(config: WhiskConfig)(implicit ec: ExecutionContext)
extends LoadBalancer {
import scala.concurrent.blocking
// unit tests that need an activation via active ack/fast path should set this to value expected
var whiskActivationStub: Option[(FiniteDuration, WhiskActivation)] = None
override def getActiveUserActivationCounts: Map[String, Long] = Map()
override def publish(action: WhiskAction, msg: ActivationMessage, timeout: FiniteDuration)(implicit transid: TransactionId): (Future[Unit], Future[WhiskActivation]) =
(Future.successful {},
whiskActivationStub map {
case (timeout, activation) => Future {
blocking {
println("waiting.....")
Thread.sleep(timeout.toMillis)
println(".... done waiting")
}
activation
}
} getOrElse Future.failed(new IllegalArgumentException("Unit test does not need fast path")))
}