Rewrite test script.
Remove bash script.
diff --git a/tests/src/whisk/core/database/test/CacheConcurrencyTests.scala b/tests/src/whisk/core/database/test/CacheConcurrencyTests.scala
index 96f3f95..a91b520 100644
--- a/tests/src/whisk/core/database/test/CacheConcurrencyTests.scala
+++ b/tests/src/whisk/core/database/test/CacheConcurrencyTests.scala
@@ -16,60 +16,122 @@
package whisk.core.database.test
-import scala.util.Try
-
-
+import scala.collection.parallel._
+import scala.concurrent.forkjoin.ForkJoinPool
import org.junit.runner.RunWith
-import org.scalatest.BeforeAndAfterAll
+import org.scalatest.BeforeAndAfter
import org.scalatest.FlatSpec
-import org.scalatest.Matchers
import org.scalatest.junit.JUnitRunner
import common.TestUtils
+import common.TestUtils._
import common.Wsk
import common.WskProps
-import whisk.common.SimpleExec
+import common.WskTestHelpers
+import spray.json.JsString
import whisk.common.TransactionId
@RunWith(classOf[JUnitRunner])
class CacheConcurrencyTests extends FlatSpec
- with BeforeAndAfterAll
- with Matchers {
+ with WskTestHelpers
+ with BeforeAndAfter {
- private val wsk = new Wsk
-
- implicit private val logger = this
implicit private val transId = TransactionId.testing
implicit private val wp = WskProps()
+ private val wsk = new Wsk
val nExternalIters = 1
- val nInternalIters = 10
+ val nInternalIters = 5
+ val nThreads = nInternalIters * 30
- for (i <- 1 to nExternalIters)
- "the cache" should s"support concurrent CRUD without bogus residual cache entries, iter ${i}" in {
- try {
- val scriptPath = TestUtils.getTestActionFilename("CacheConcurrencyTests.sh")
- val actionFile = TestUtils.getTestActionFilename("empty.js")
- val fullCmd = Seq(scriptPath, Wsk.baseCommand.mkString, actionFile, nInternalIters.toString(), "--auth", wp.authKey) ++ wp.overrides
+ val parallel = (1 to nInternalIters).par
+ parallel.tasksupport = new ForkJoinTaskSupport(new ForkJoinPool(nThreads))
- val (stdout, stderr, exitCode) = SimpleExec.syncRunCmd(fullCmd)
+ def run[W](phase: String)(block: String => W) = parallel.map { i =>
+ val name = s"testy${i}"
+ withClue(s"$phase: failed for $name") { (name, block(name)) }
+ }
- if (!stdout.isEmpty) {
- println(stdout)
- }
- if (!stderr.isEmpty) {
- println(this, stderr)
- }
+ before {
+ run("pre-test sanitize") {
+ name => wsk.action.sanitize(name)
+ }
+ }
- exitCode should be(0)
+ after {
+ run("post-test sanitize") {
+ name => wsk.action.sanitize(name)
+ }
+ }
- } finally {
- // clean up
- {
- for (i <- 1 to nInternalIters)
- yield Try { wsk.action.delete(s"testy${i}") }
- }.forall(_.isSuccess)
+ for (n <- 1 to nExternalIters)
+ "the cache" should s"support concurrent CRUD without bogus residual cache entries, iter ${n}" in {
+ val scriptPath = TestUtils.getTestActionFilename("CacheConcurrencyTests.sh")
+ val actionFile = TestUtils.getTestActionFilename("empty.js")
+
+ run("create") {
+ name => wsk.action.create(name, Some(actionFile))
+ }
+
+ run("update") {
+ name => wsk.action.create(name, None, update = true)
+ }
+
+ run("delete+get") {
+ name =>
+ // run 30 operations in parallel: 15 get, 1 delete, 14 more get
+ val para = (1 to 30).par
+ para.tasksupport = new ForkJoinTaskSupport(new ForkJoinPool(nThreads))
+ para.map {
+ i =>
+ if (i != 16) {
+ val rr = wsk.action.get(name, expectedExitCode = DONTCARE_EXIT)
+ withClue(s"expecting get to either succeed or fail with not found: $rr") {
+ // some will succeed and some should fail with not found
+ rr.exitCode should (be(SUCCESS_EXIT) or be(NOT_FOUND))
+ }
+ } else {
+ wsk.action.delete(name)
+ }
+ }
+ }
+
+ run("get after delete") {
+ name => wsk.action.get(name, expectedExitCode = NOT_FOUND)
+ }
+
+ run("recreate") {
+ name => wsk.action.create(name, Some(actionFile))
+ }
+
+ run("reupdate") {
+ name => wsk.action.create(name, None, parameters = Map("color" -> JsString("red")), update = true)
+ }
+
+ run("update+get") {
+ name =>
+ // run 30 operations in parallel: 15 get, 1 update, 14 more get
+ val para = (1 to 30).par
+ para.tasksupport = new ForkJoinTaskSupport(new ForkJoinPool(nThreads))
+ para.map {
+ i =>
+ if (i != 16) {
+ wsk.action.get(name)
+ } else {
+ wsk.action.create(name, None, parameters = Map("color" -> JsString("blue")), update = true)
+ }
+ }
+ }
+
+ run("get after update") {
+ name => wsk.action.get(name)
+ } map {
+ case (name, rr) =>
+ withClue(s"get after update: failed check for $name") {
+ rr.stdout should include("blue")
+ rr.stdout should not include ("red")
+ }
}
}
}