blob: 2a4388a1f9b4beb6f58319805165d04f62c4f459 [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.openwhisk.core.database.test.behavior
import java.time.Instant
import org.apache.openwhisk.common.TransactionId
import org.apache.openwhisk.core.database.{
DocumentConflictException,
DocumentProvider,
DocumentRevisionMismatchException,
NoDocumentException
}
import org.apache.openwhisk.core.entity._
trait ArtifactStoreCRUDBehaviors extends ArtifactStoreBehaviorBase {
behavior of s"${storeType}ArtifactStore put"
it should "put document and get a revision 1" in {
implicit val tid: TransactionId = transid()
val doc = put(authStore, newAuth())
doc.rev.empty shouldBe false
}
it should "put and update document" in {
implicit val tid: TransactionId = transid()
val auth = newAuth()
val doc = put(authStore, auth)
val auth2 =
getWhiskAuth(doc)
.copy(namespaces = Set(wskNS("foo1")))
.revision[WhiskAuth](doc.rev)
val doc2 = put(authStore, auth2)
doc2.rev should not be doc.rev
doc2.rev.empty shouldBe false
}
it should "put delete and then recreate document with same id with different rev" in {
implicit val tid: TransactionId = transid()
val auth = newAuth()
val doc = put(authStore, auth)
delete(authStore, doc) shouldBe true
val auth2 = auth.copy(namespaces = Set(wskNS("foo1")))
val doc2 = put(authStore, auth2)
doc2.rev should not be doc.rev
doc2.rev.empty shouldBe false
}
it should "throw DocumentConflictException when updated with old revision" in {
implicit val tid: TransactionId = transid()
val auth = newAuth()
val doc = put(authStore, auth)
val auth2 = getWhiskAuth(doc).copy(namespaces = Set(wskNS("foo1"))).revision[WhiskAuth](doc.rev)
val doc2 = put(authStore, auth2)
//Updated with _rev set to older one
val auth3 = getWhiskAuth(doc2).copy(namespaces = Set(wskNS("foo2"))).revision[WhiskAuth](doc.rev)
intercept[DocumentConflictException] {
put(authStore, auth3)
}
}
it should "throw DocumentConflictException if document with same id is inserted twice" in {
implicit val tid: TransactionId = transid()
val auth = newAuth()
val doc = put(authStore, auth)
intercept[DocumentConflictException] {
put(authStore, auth)
}
}
it should "work if same document was deleted earlier" in {
implicit val tid: TransactionId = transid()
val auth = newAuth()
//1. Create a document
val doc = put(authStore, auth)
//2. Now delete the document
delete(authStore, doc) shouldBe true
//3. Now recreate the same document.
val doc2 = put(authStore, auth)
//Recreating a deleted document should work
doc2.rev.empty shouldBe false
}
behavior of s"${storeType}ArtifactStore delete"
it should "deletes existing document" in {
implicit val tid: TransactionId = transid()
val doc = put(authStore, newAuth())
delete(authStore, doc) shouldBe true
}
it should "throws IllegalArgumentException when deleting without revision" in {
intercept[IllegalArgumentException] {
implicit val tid: TransactionId = transid()
delete(authStore, DocInfo("doc-with-empty-revision"))
}
}
it should "throws NoDocumentException when document does not exist" in {
intercept[NoDocumentException] {
implicit val tid: TransactionId = transid()
delete(authStore, DocInfo ! ("non-existing-doc", "42"))
}
}
it should "throws DocumentConflictException when revision does not match" in {
implicit val tid: TransactionId = transid()
val auth = newAuth()
val doc = put(authStore, auth)
val auth2 = getWhiskAuth(doc).copy(namespaces = Set(wskNS("foo1"))).revision[WhiskAuth](doc.rev)
val doc2 = put(authStore, auth2)
intercept[DocumentConflictException] {
delete(authStore, doc)
}
}
behavior of s"${storeType}ArtifactStore get"
it should "get existing entity matching id and rev" in {
implicit val tid: TransactionId = transid()
val auth = newAuth()
val doc = put(authStore, auth)
val authFromGet = getWhiskAuth(doc)
authFromGet shouldBe auth
authFromGet.docinfo.rev shouldBe doc.rev
}
it should "get existing entity matching id only" in {
implicit val tid: TransactionId = transid()
val auth = newAuth()
val doc = put(authStore, auth)
val authFromGet = getWhiskAuth(doc)
authFromGet shouldBe auth
}
it should "get entity with timestamp" in {
implicit val tid: TransactionId = transid()
val activation = WhiskActivation(
EntityPath("testnamespace"),
EntityName("activation1"),
Subject(),
ActivationId.generate(),
start = Instant.now.inMills,
end = Instant.now.inMills)
val activationDoc = put(activationStore, activation)
val activationFromDb = activationStore.get[WhiskActivation](activationDoc).futureValue
activationFromDb shouldBe activation
}
it should "throws DocumentRevisionMismatchException when document revision does not match" in {
implicit val tid: TransactionId = transid()
val auth = newAuth()
val doc = put(authStore, auth)
val auth2 = getWhiskAuth(doc).copy(namespaces = Set(wskNS("foo1"))).revision[WhiskAuth](doc.rev)
val doc2 = put(authStore, auth2)
authStore.get[WhiskAuth](doc).failed.futureValue shouldBe a[DocumentRevisionMismatchException]
val authFromGet = getWhiskAuth(doc2)
authFromGet shouldBe auth2
}
it should "throws NoDocumentException when document does not exist" in {
implicit val tid: TransactionId = transid()
authStore.get[WhiskAuth](DocInfo("non-existing-doc")).failed.futureValue shouldBe a[NoDocumentException]
}
it should "not get a deleted document" in {
implicit val tid: TransactionId = transid()
val auth = newAuth()
//1. Create a document
val docInfo = put(authStore, auth)
//2. Now delete the document
delete(authStore, docInfo) shouldBe true
//3. Now getting a deleted document should fail
authStore.get[WhiskAuth](docInfo).failed.futureValue shouldBe a[NoDocumentException]
//Check get by id flow also which return none for such "soft" deleted document
authStore match {
case provider: DocumentProvider =>
provider.get(docInfo.id).futureValue shouldBe None
case _ =>
}
}
}