Browse Source

Fix up Play 2 Activate and ReactiveMongo tests

* Move tests into play2-scala directory
* Upgrade ReactiveMongo so it will run
* Refactor Play 2 config generation script so it can handle
  MongoDB tests and so it will tag tests that shouldn't
  be included in results.
Rich Dougherty 11 years ago
parent
commit
31b55efa98
35 changed files with 465 additions and 184 deletions
  1. 0 1
      .travis.yml
  2. 107 23
      frameworks/Java/play2-java/generate_config.py
  3. 0 27
      frameworks/Scala/play-activate-mysql/README.md
  4. 0 62
      frameworks/Scala/play-activate-mysql/app/controllers/Application.scala
  5. 0 26
      frameworks/Scala/play-activate-mysql/benchmark_config
  6. 0 3
      frameworks/Scala/play-activate-mysql/install.sh
  7. 40 19
      frameworks/Scala/play2-scala/benchmark_config
  8. 0 0
      frameworks/Scala/play2-scala/play2-scala-activate/.gitignore
  9. 0 0
      frameworks/Scala/play2-scala/play2-scala-activate/app/Global.scala
  10. 91 0
      frameworks/Scala/play2-scala/play2-scala-activate/app/controllers/Application.scala
  11. 0 0
      frameworks/Scala/play2-scala/play2-scala-activate/app/models/Migrations.scala
  12. 0 0
      frameworks/Scala/play2-scala/play2-scala-activate/app/models/Models.scala
  13. 0 0
      frameworks/Scala/play2-scala/play2-scala-activate/app/models/PersistenceContext.scala
  14. 0 0
      frameworks/Scala/play2-scala/play2-scala-activate/app/views/fortune.scala.html
  15. 0 0
      frameworks/Scala/play2-scala/play2-scala-activate/app/views/main.scala.html
  16. 0 0
      frameworks/Scala/play2-scala/play2-scala-activate/conf/application.conf
  17. 0 0
      frameworks/Scala/play2-scala/play2-scala-activate/conf/play.plugins
  18. 3 2
      frameworks/Scala/play2-scala/play2-scala-activate/conf/routes
  19. 1 1
      frameworks/Scala/play2-scala/play2-scala-activate/project/Build.scala
  20. 0 0
      frameworks/Scala/play2-scala/play2-scala-activate/project/build.properties
  21. 0 0
      frameworks/Scala/play2-scala/play2-scala-activate/project/plugins.sbt
  22. 1 1
      frameworks/Scala/play2-scala/play2-scala-anorm/app/controllers/Application.scala
  23. 33 0
      frameworks/Scala/play2-scala/play2-scala-reactivemongo/.gitignore
  24. 75 0
      frameworks/Scala/play2-scala/play2-scala-reactivemongo/app/controllers/Application.scala
  25. 11 0
      frameworks/Scala/play2-scala/play2-scala-reactivemongo/build.sbt
  26. 68 0
      frameworks/Scala/play2-scala/play2-scala-reactivemongo/conf/application.conf
  27. 1 0
      frameworks/Scala/play2-scala/play2-scala-reactivemongo/conf/play.plugins
  28. 9 0
      frameworks/Scala/play2-scala/play2-scala-reactivemongo/conf/routes
  29. 1 0
      frameworks/Scala/play2-scala/play2-scala-reactivemongo/project/build.properties
  30. 8 0
      frameworks/Scala/play2-scala/play2-scala-reactivemongo/project/plugins.sbt
  31. 3 0
      frameworks/Scala/play2-scala/play2-scala-reactivemongo/source_code
  32. 1 1
      frameworks/Scala/play2-scala/play2-scala-slick/app/controllers/Application.scala
  33. 0 18
      frameworks/Scala/play2-scala/play2-scala/README.md
  34. 6 0
      frameworks/Scala/play2-scala/setup_scala_activate.py
  35. 6 0
      frameworks/Scala/play2-scala/setup_scala_reactivemongo.py

+ 0 - 1
.travis.yml

@@ -137,7 +137,6 @@ env:
     - "TESTDIR=Scala/finagle"
     - "TESTDIR=Scala/lift-stateless"
     - "TESTDIR=Scala/plain"
-    - "TESTDIR=Scala/play-activate-mysql"
     - "TESTDIR=Scala/play2-scala"
     - "TESTDIR=Scala/scalatra"
     - "TESTDIR=Scala/scruffy"

+ 107 - 23
frameworks/Java/play2-java/generate_config.py

@@ -8,15 +8,74 @@ import collections, json, os, textwrap
 # Each line corresponds to a test application.
 # Format is: (language, orm, (opsys, ...), (test, ...))
 # See the dir_name logic below to see the directory name for each test application.
+Config = collections.namedtuple('Config', ['lang', 'orm', 'db', 'operatingSystems', 'tests', 'shouldIncludeResults'])
 configurations = [
-  ('Java',  None,    			['Linux'],            ['json', 'plaintext']),
-  ('Java',  'Ebean BoneCP', 	['Linux'],            ['db', 'query', 'fortune', 'update']),
-  ('Java',  'Ebean HikariCP', 	['Linux'],            ['db', 'query', 'fortune', 'update']),
-  ('Java',  'JPA BoneCP',		['Linux'],            ['db', 'query', 'fortune', 'update']),
-  ('Java',  'JPA HikariCP',		['Linux'],            ['db', 'query', 'fortune', 'update']),
-  ('Scala', None,    			['Linux'],            ['json']),
-  ('Scala', 'Anorm', 			['Linux', 'Windows'], ['db', 'query', 'fortune', 'update']),
-  ('Scala', 'Slick', 			['Linux'],            ['db', 'query', 'fortune', 'update']),
+
+  # Plain Java test
+
+  Config(
+    'Java', None, None,
+    operatingSystems = ['Linux'],
+    tests = ['json'],
+    shouldIncludeResults = True
+  ),
+
+  # Java database tests
+
+  Config(
+    'Java', 'Ebean', 'MySQL',
+    operatingSystems = ['Linux'],
+    tests = ['db', 'query'],
+    shouldIncludeResults = True
+  ),
+  Config(
+    'Java', 'JPA', 'MySQL',
+    operatingSystems = ['Linux'],
+    tests = ['db', 'query', 'fortune', 'update', 'plaintext'],
+    shouldIncludeResults = True
+  ),
+  Config(
+    'Java', 'JPA HikariCP', 'MySQL',
+    operatingSystems = ['Linux'],
+    tests = ['db', 'query', 'fortune', 'update', 'plaintext'],
+    shouldIncludeResults = True
+  ),
+
+  # Plain Scala test
+
+  Config(
+    'Scala', None, None,
+    operatingSystems = ['Linux'],
+    tests = ['json'],
+    shouldIncludeResults = True
+  ),
+
+  # Scala database tests
+
+  Config(
+    'Scala', 'Activate', 'MySQL',
+    operatingSystems = ['Linux'],
+    tests = ['db', 'query', 'fortune', 'update'],
+    shouldIncludeResults = False # Uses old versions of Play and Activate
+  ),
+  Config(
+    'Scala', 'Anorm', 'MySQL',
+    operatingSystems = ['Linux', 'Windows'],
+    tests = ['db', 'query', 'fortune', 'update'],
+    shouldIncludeResults = True
+  ),
+  Config(
+    'Scala', 'ReactiveMongo', 'MongoDB',
+    operatingSystems = ['Linux'],
+    tests = ['db', 'query'],
+    shouldIncludeResults = True # Updated to Play 2.3 and ReactiveMongo 0.10, but no maintainer
+  ),
+  Config(
+    'Scala', 'Slick', 'MySQL',
+    operatingSystems = ['Linux'],
+    tests = ['db', 'query', 'fortune', 'update'],
+    shouldIncludeResults = True
+  )
 ]
 
 # All play2 test applications must use the same URLs.
@@ -39,15 +98,28 @@ def frameworksPath():
   'Get the absolute path of ROOT/frameworks'
   return os.path.abspath(os.path.join(__file__, '..', '..', '..'))
 
+def maybe(item):
+  'Maps None => [] and item => [item]'
+  if item is None:
+    return []
+  else:
+    return [item]
+
+def namify(bits, sep):
+  'Joins a list of bits together then replaces spaces with sep.'
+  return ' '.join(bits).replace(' ', sep).lower()
+
 lang_test_configs = {}
 for lang, _ in langs.iteritems():
   lang_test_configs[lang] = collections.OrderedDict()
 
-for lang, orm, opsyses, tests in configurations:
-  dir_name = 'play2-' + lang.lower() + (('-'+orm.replace(' ', '-').lower()) if orm else '')
-  setup_name = 'setup_' + lang.lower() + (('_'+orm.replace(' ', '_').lower()) if orm else '')
+for config in configurations:
 
-  setup_path = os.path.join(pathForLang(lang), setup_name+'.py')
+  core_name_bits = [config.lang] + maybe(config.orm)
+  dir_name = namify(['play2'] + core_name_bits, '-')
+  setup_name = namify(['setup'] + core_name_bits, '_')
+
+  setup_path = os.path.join(pathForLang(config.lang), setup_name+'.py')
   print 'Generating', setup_path
   with open(setup_path, 'w') as f:
     f.write(textwrap.dedent("""
@@ -58,19 +130,31 @@ for lang, orm, opsyses, tests in configurations:
       make_setup_for_dir(globals(), '"""+dir_name+"""')
     """))
 
-  for opsys in opsyses:
-    if len(opsyses) == 1:
-      test_name = lang.lower() + (('-'+orm.replace(' ', '-').lower()) if orm else '')
-    else:
-      test_name = lang.lower() + (('-'+orm.replace(' ', '-').lower()) if orm else '') + '-'+opsys.lower()
+  # We make a separate test config entry for each operating system
+  # that the test runs on.
+  for opsys in config.operatingSystems:
+
+    # Note the test name may differ from the directory name because
+    # it may have the OS name or a word to show that results shouldn't
+    # be included.
+
+    # If there is more than one OS then add the current OS to the test name
+    # so we can distinguish between the tests.
+    opsys_name_bit = [] if len(config.operatingSystems) == 1 else [opsys]
+
+    # If the test is out of date then add 'do not include' to the end of the
+    # test name to make it harder to accidentally include in final results.
+    tags_bit = [] if config.shouldIncludeResults else ['do not include']
+    test_name_bits = core_name_bits + opsys_name_bit + tags_bit
+
     test_config_json = collections.OrderedDict([
-      ('display_name', 'play2-'+test_name),
+      ('display_name', namify(['play2'] + test_name_bits, '-')),
       ('setup_file', setup_name),
       ('framework', 'play2'),
-      ('language', lang),
-      ('orm', 'Full' if orm else 'Raw'),
+      ('language', config.lang),
+      ('orm', 'Full' if config.orm else 'Raw'),
       ('os', opsys),
-      ('database', 'MySQL' if orm else 'None'),
+      ('database', config.db if config.db else 'None'),
       ('approach', 'Realistic'),
       ('classification', 'Fullstack'),
       ('platform', 'Netty'),
@@ -80,9 +164,9 @@ for lang, orm, opsyses, tests in configurations:
       ('versus', 'netty'),
       ('port', '9000'),
     ])
-    for test in tests:
+    for test in config.tests:
       test_config_json[test+'_url'] = test_urls[test]
-      lang_test_configs[lang][test_name] = test_config_json
+      lang_test_configs[config.lang][namify(test_name_bits, '-')] = test_config_json
 
 for lang, _ in langs.iteritems():
   benchmark_config_path = os.path.join(pathForLang(lang), 'benchmark_config')

+ 0 - 27
frameworks/Scala/play-activate-mysql/README.md

@@ -1,27 +0,0 @@
-#Play Benchmarking Test
-
-This is the Play portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
-
-### JSON Encoding Test
-
-* [JSON test source](app/controllers/Application.scala)
-
-### Data-Store/Database Mapping Test
-
-* [Database test controller](app/controllers/Application.scala)
-* [Database test model](app/models/World.scala)
-
-## Infrastructure Software Versions
-The tests were run with:
-
-* [Java OpenJDK 1.7.0_09](http://openjdk.java.net/)
-* [Play 2.1.0](http://http://www.playframework.com/)
-
-## Test URLs
-### JSON Encoding Test
-
-http://localhost/json
-
-### Data-Store/Database Mapping Test
-
-http://localhost/db?queries=5

+ 0 - 62
frameworks/Scala/play-activate-mysql/app/controllers/Application.scala

@@ -1,62 +0,0 @@
-package controllers
-
-import play.api.Play.current
-import play.api.mvc._
-import play.api.libs.json.Json
-import java.util.concurrent._
-import scala.concurrent._
-import scala.concurrent.Future
-import play.api.libs.concurrent.Execution.Implicits._
-import play.core.NamedThreadFactory
-import models.ActivateWorld
-import models.Models._
-import models.ActivateFortune
-import models.persistenceContext._
-
-object Application extends Controller {
-
-    private val TestDatabaseRows = 10000
-
-    def db(queries: Int) =
-        Action {
-            transactional {
-                val random = ThreadLocalRandom.current()
-
-                val worlds =
-                    for (_ <- 1 to queries) yield {
-                        ActivateWorld.fingByLegacyId(random.nextInt(TestDatabaseRows) + 1)
-                    }
-
-                Ok(Json.toJson(worlds))
-            }
-        }
-
-    def fortunes() =
-        Action {
-            val transaction = new Transaction
-            try
-                transactional(transaction) {
-                    val fortunes =
-                        ActivateFortune.all ++ List(new ActivateFortune(0, "Additional fortune added at request time."))
-                    Ok(views.html.fortune(fortunes))
-                }
-            finally
-                transaction.rollback
-        }
-
-    def update(queries: Int) =
-        Action {
-
-            val random = ThreadLocalRandom.current()
-
-            transactional {
-                val worlds =
-                    for (_ <- 1 to queries) yield {
-                        val world = ActivateWorld.fingByLegacyId(random.nextInt(TestDatabaseRows) + 1)
-                        world.randomNumber = random.nextInt(TestDatabaseRows) + 1
-                        world
-                    }
-                Ok(Json.toJson(worlds)).withHeaders("Server" -> "Netty")
-            }
-        }
-}

+ 0 - 26
frameworks/Scala/play-activate-mysql/benchmark_config

@@ -1,26 +0,0 @@
-{
-  "framework": "play-activate-mysql",
-  "tests": [{
-    "default": {
-      "setup_file": "setup",
-      "db_url": "/db",
-      "query_url": "/db?queries=",
-      "fortune_url": "/fortunes",
-      "update_url": "/update?queries=",
-      "port": 9000,
-      "approach": "Realistic",
-      "classification": "Fullstack",
-      "database": "MySQL",
-      "framework": "play2",
-      "language": "Scala",
-      "orm": "Full",
-      "platform": "Netty",
-      "webserver": "None",
-      "os": "Linux",
-      "database_os": "Linux",
-      "display_name": "play-scala-activate",
-      "notes": "",
-      "versus": "netty"
-    }
-  }]
-}

+ 0 - 3
frameworks/Scala/play-activate-mysql/install.sh

@@ -1,3 +0,0 @@
-#!/bin/bash
-
-fw_depends java maven play2 sbt

+ 40 - 19
frameworks/Scala/play2-scala/benchmark_config

@@ -20,6 +20,27 @@
         "port": "9000", 
         "json_url": "/json"
       }, 
+      "activate": {
+        "display_name": "play2-scala-activate", 
+        "setup_file": "setup_scala_activate", 
+        "framework": "play2", 
+        "language": "Scala", 
+        "orm": "Full", 
+        "os": "Linux", 
+        "database": "MySQL", 
+        "approach": "Realistic", 
+        "classification": "Fullstack", 
+        "platform": "Netty", 
+        "webserver": "None", 
+        "database_os": "Linux", 
+        "notes": "", 
+        "versus": "netty", 
+        "port": "9000", 
+        "db_url": "/db", 
+        "query_url": "/queries?queries=", 
+        "fortune_url": "/fortunes", 
+        "update_url": "/update?queries="
+      }, 
       "anorm-linux": {
         "display_name": "play2-scala-anorm-linux", 
         "setup_file": "setup_scala_anorm", 
@@ -62,6 +83,25 @@
         "fortune_url": "/fortunes", 
         "update_url": "/update?queries="
       }, 
+      "reactivemongo": {
+        "display_name": "play2-scala-reactivemongo", 
+        "setup_file": "setup_scala_reactivemongo", 
+        "framework": "play2", 
+        "language": "Scala", 
+        "orm": "Full", 
+        "os": "Linux", 
+        "database": "MongoDB", 
+        "approach": "Realistic", 
+        "classification": "Fullstack", 
+        "platform": "Netty", 
+        "webserver": "None", 
+        "database_os": "Linux", 
+        "notes": "", 
+        "versus": "netty", 
+        "port": "9000", 
+        "db_url": "/db", 
+        "query_url": "/queries?queries="
+      }, 
       "slick": {
         "display_name": "play2-scala-slick", 
         "setup_file": "setup_scala_slick", 
@@ -82,25 +122,6 @@
         "query_url": "/queries?queries=", 
         "fortune_url": "/fortunes", 
         "update_url": "/update?queries="
-      },
-      "scala-mongodb": {
-        "setup_file": "setup_scala_mongodb",
-        "db_url": "/db",
-        "query_url": "/queries?queries=",
-        "port": 9000,
-        "approach": "Realistic",
-        "classification": "Fullstack",
-        "database": "MongoDB",
-        "framework": "play2",
-        "language": "Scala",
-        "orm": "Raw",
-        "platform": "Netty",
-        "webserver": "None",
-        "os": "Linux",
-        "database_os": "Linux",
-        "display_name": "play2-scala-mongodb",
-        "notes": "Uses Reactive Mongo",
-        "versus": "netty"
       }
     }
   ]

+ 0 - 0
frameworks/Scala/play-activate-mysql/.gitignore → frameworks/Scala/play2-scala/play2-scala-activate/.gitignore


+ 0 - 0
frameworks/Scala/play-activate-mysql/app/Global.scala → frameworks/Scala/play2-scala/play2-scala-activate/app/Global.scala


+ 91 - 0
frameworks/Scala/play2-scala/play2-scala-activate/app/controllers/Application.scala

@@ -0,0 +1,91 @@
+package controllers
+
+import play.api.Play.current
+import play.api.mvc._
+import play.api.libs.json.Json
+import java.util.concurrent._
+import scala.concurrent._
+import scala.concurrent.Future
+import play.api.libs.concurrent.Execution.Implicits._
+import play.core.NamedThreadFactory
+import models.ActivateWorld
+import models.Models._
+import models.ActivateFortune
+import models.persistenceContext._
+
+object Application extends Controller {
+
+  def getRandomWorlds(n: Int): Seq[ActivateWorld] = {
+      val random = ThreadLocalRandom.current()
+      for (_ <- 1 to n) yield {
+          val randomId = random.nextInt(TestDatabaseRows) + 1
+          ActivateWorld.fingByLegacyId(randomId)
+      }
+  }
+
+  def getFortunes(): Seq[ActivateFortune] = {
+      ActivateFortune.all
+  }
+
+  def updateWorlds(n: Int): Seq[ActivateWorld] = {
+      val random = ThreadLocalRandom.current()
+      for (_ <- 1 to n) yield {
+            val randomId = random.nextInt(TestDatabaseRows) + 1
+            val world = ActivateWorld.fingByLegacyId(randomId)
+            world.randomNumber = random.nextInt(10000) + 1
+            world
+      }
+  }
+
+  // Common(ish) code between Scala database code
+
+  protected val TestDatabaseRows = 10000
+
+  def db = Action {
+      transactional {
+          val worlds = getRandomWorlds(1)
+          Ok(Json.toJson(worlds.head))
+      }
+  }
+
+  def queries(countString: String) = Action {
+      val n = parseCount(countString)
+      transactional {
+          val worlds = getRandomWorlds(n)
+          Ok(Json.toJson(worlds))
+      }
+  }
+
+  def fortunes() = Action {
+      val transaction = new Transaction
+      try
+          transactional(transaction) {
+              val dbFortunes = getFortunes()
+              val appendedFortunes =  new ActivateFortune(0, "Additional fortune added at request time.") :: (dbFortunes.to[List])
+              Ok(views.html.fortune(appendedFortunes))
+          }
+      finally
+          transaction.rollback
+  }
+
+  def update(queries: String) = Action {
+      transactional {
+          val n = parseCount(queries)
+          val worlds = updateWorlds(n)
+          Ok(Json.toJson(worlds))
+      }
+  }
+
+  private def parseCount(s: String): Int = {
+      try {
+          val parsed = java.lang.Integer.parseInt(s, 10)
+          parsed match {
+              case i if i < 1 => 1
+              case i if i > 500 => 500
+              case i => i
+          }
+      } catch {
+          case _: NumberFormatException => 1
+      }
+  }
+}

+ 0 - 0
frameworks/Scala/play-activate-mysql/app/models/Migrations.scala → frameworks/Scala/play2-scala/play2-scala-activate/app/models/Migrations.scala


+ 0 - 0
frameworks/Scala/play-activate-mysql/app/models/Models.scala → frameworks/Scala/play2-scala/play2-scala-activate/app/models/Models.scala


+ 0 - 0
frameworks/Scala/play-activate-mysql/app/models/PersistenceContext.scala → frameworks/Scala/play2-scala/play2-scala-activate/app/models/PersistenceContext.scala


+ 0 - 0
frameworks/Scala/play-activate-mysql/app/views/fortune.scala.html → frameworks/Scala/play2-scala/play2-scala-activate/app/views/fortune.scala.html


+ 0 - 0
frameworks/Scala/play-activate-mysql/app/views/main.scala.html → frameworks/Scala/play2-scala/play2-scala-activate/app/views/main.scala.html


+ 0 - 0
frameworks/Scala/play-activate-mysql/conf/application.conf → frameworks/Scala/play2-scala/play2-scala-activate/conf/application.conf


+ 0 - 0
frameworks/Scala/play-activate-mysql/conf/play.plugins → frameworks/Scala/play2-scala/play2-scala-activate/conf/play.plugins


+ 3 - 2
frameworks/Scala/play-activate-mysql/conf/routes → frameworks/Scala/play2-scala/play2-scala-activate/conf/routes

@@ -3,9 +3,10 @@
 # ~~~~
 
 # Home page
-GET     /db                             controllers.Application.db(queries: Int ?= 1)
+GET     /db                             controllers.Application.db
+GET     /queries                        controllers.Application.queries(queries ?= "1")
 GET     /fortunes                       controllers.Application.fortunes
-GET     /update                         controllers.Application.update(queries: Int ?= 1)
+GET     /update                         controllers.Application.update(queries ?= "1")
 
 # Map static resources from the /public folder to the /assets URL path
 GET     /assets/*file                   controllers.Assets.at(path="/public", file)

+ 1 - 1
frameworks/Scala/play-activate-mysql/project/Build.scala → frameworks/Scala/play2-scala/play2-scala-activate/project/Build.scala

@@ -4,7 +4,7 @@ import play.Project._
 
 object ApplicationBuild extends Build {
 
-  val appName         = "play-activate-mysql"
+  val appName         = "play2-scala-activate"
   val appVersion      = "1.0-SNAPSHOT"
 
   val activateVersion = "1.4.4"

+ 0 - 0
frameworks/Scala/play-activate-mysql/project/build.properties → frameworks/Scala/play2-scala/play2-scala-activate/project/build.properties


+ 0 - 0
frameworks/Scala/play-activate-mysql/project/plugins.sbt → frameworks/Scala/play2-scala/play2-scala-activate/project/plugins.sbt


+ 1 - 1
frameworks/Scala/play2-scala/play2-scala-anorm/app/controllers/Application.scala

@@ -42,7 +42,7 @@ object Application extends Controller {
     }
   }
 
-  // Common code between Anorm and Slick
+  // Common code between Scala database code
 
   protected val TestDatabaseRows = 10000
 

+ 33 - 0
frameworks/Scala/play2-scala/play2-scala-reactivemongo/.gitignore

@@ -0,0 +1,33 @@
+logs
+project/project
+project/target
+public
+target
+test
+tmp
+.history
+dist
+conf/evolutions
+
+# Ignore all dotfiles...
+.*
+# except for .gitignore
+!.gitignore
+
+# Ignore Play! working directory #
+db
+eclipse
+lib
+log
+logs
+modules
+precompiled
+project/project
+project/target
+target
+tmp
+test-result
+server.pid
+*.iml
+*.eml
+

+ 75 - 0
frameworks/Scala/play2-scala/play2-scala-reactivemongo/app/controllers/Application.scala

@@ -0,0 +1,75 @@
+package controllers
+
+import play.api.Play.current
+import play.api.mvc._
+import play.api.libs.json._
+import scala.concurrent.forkjoin.ThreadLocalRandom
+import scala.concurrent.{Future, ExecutionContext}
+import scala.collection.convert.WrapAsScala.collectionAsScalaIterable
+import play.modules.reactivemongo.ReactiveMongoPlugin
+import play.modules.reactivemongo.json.collection.JSONCollection
+import play.api.libs.concurrent.Execution.Implicits._
+import play.api.libs.concurrent.Akka
+
+object Application extends Controller {
+
+  val DEFAULT_HOST = "localhost:27017"
+  val servers = current.configuration.getStringList("mongodb.servers") match {
+    case Some(servers) => collectionAsScalaIterable(servers).toList
+    case None => List(DEFAULT_HOST)
+  }
+
+  val DEFAULT_DB = "hello_world"
+  val dbName = current.configuration.getString("mongodb.db").getOrElse(DEFAULT_DB)
+
+  //private val dbExecutionContext: ExecutionContext = Akka.system.dispatchers.lookup("dbExecutionContext")
+  private val database = {
+    ReactiveMongoPlugin
+      .driver
+      .connection(servers, nbChannelsPerNode = 10)
+      .db(dbName)//(dbExecutionContext)
+  }
+
+  private val projection = Json.obj("_id" -> 0)
+
+  def getRandomWorlds(n: Int): Future[Seq[JsValue]] = {
+    val random = ThreadLocalRandom.current()
+    Future.sequence((for {
+      _ <- 1 to n
+    } yield {
+      database.collection[JSONCollection]("world")
+        .find(Json.obj("id" -> (random.nextInt(TestDatabaseRows) + 1)), projection)
+        .one[JsValue].map(_.get)
+    }))
+  }
+
+  // Common code between Scala database code
+
+  private val TestDatabaseRows = 10000
+
+  def db = Action.async {
+    getRandomWorlds(1).map { worlds =>
+      Ok(Json.toJson(worlds.head))
+    }
+  }
+
+  def queries(countString: String) = Action.async {
+    val n = parseCount(countString)
+    getRandomWorlds(n).map { worlds =>
+      Ok(Json.toJson(worlds))
+    }
+  }
+
+  private def parseCount(s: String): Int = {
+    try {
+      val parsed = java.lang.Integer.parseInt(s, 10)
+      parsed match {
+        case i if i < 1 => 1
+        case i if i > 500 => 500
+        case i => i
+      }
+    } catch {
+      case _: NumberFormatException => 1
+    }
+  }
+}

+ 11 - 0
frameworks/Scala/play2-scala/play2-scala-reactivemongo/build.sbt

@@ -0,0 +1,11 @@
+name := "play2-scala-reactivemongo"
+
+version := "1.0-SNAPSHOT"
+
+scalaVersion := "2.11.4"
+
+lazy val root = (project in file(".")).enablePlugins(PlayScala)
+
+libraryDependencies ++= Seq(
+  "org.reactivemongo" %% "play2-reactivemongo" % "0.10.5.0.akka23"
+)

+ 68 - 0
frameworks/Scala/play2-scala/play2-scala-reactivemongo/conf/application.conf

@@ -0,0 +1,68 @@
+# This is the main configuration file for the application.
+# ~~~~~
+
+# Secret key
+# ~~~~~
+# The secret key is used to secure cryptographics functions.
+# If you deploy your application to several instances be sure to use the same key!
+application.secret="RItx1I:80?W@]8GAtPDuF8Ydd3mXM85p/<7og]Q;uBOdijQAauRDgu73B6`wQP59"
+
+# The application languages
+# ~~~~~
+application.langs="en"
+
+# Global object class
+# ~~~~~
+# Define the Global object class for this application.
+# Default to Global in the root package.
+# global=Global
+
+# Database configuration
+# ~~~~~ 
+# You can declare as many datasources as you want.
+# By convention, the default datasource is named `default`
+#
+#db.default.driver=org.h2.Driver
+#db.default.url="jdbc:h2:mem:play"
+#db.default.user=sa
+# db.default.password=
+#
+# You can expose this datasource via JNDI if needed (Useful for JPA)
+# db.default.jndiName=DefaultDS
+
+#mongodb.servers = ["192.168.100.101:27017"]
+mongodb.servers = ["localhost:27017"]
+mongodb.db = "hello_world"
+
+# Evolutions
+# ~~~~~
+# You can disable evolutions if needed
+# evolutionplugin=disabled
+
+# Logger
+# ~~~~~
+# You can also configure logback (http://logback.qos.ch/), by providing a logger.xml file in the conf directory .
+
+# Root logger:
+logger.root=ERROR
+
+# Logger used by the framework:
+logger.play=ERROR
+
+# Logger provided to your application:
+logger.application=ERROR
+
+#play {
+#  akka {
+#    event-handlers = ["akka.event.slf4j.Slf4jEventHandler"]
+#    loglevel = ERROR
+#    actor {
+#      dbExecutionContext = {
+#        fork-join-executor {
+#          parallelism-min = 128
+#          parallelism-max = 128
+#        }
+#      }
+#    }
+#  }
+#}

+ 1 - 0
frameworks/Scala/play2-scala/play2-scala-reactivemongo/conf/play.plugins

@@ -0,0 +1 @@
+400:play.modules.reactivemongo.ReactiveMongoPlugin

+ 9 - 0
frameworks/Scala/play2-scala/play2-scala-reactivemongo/conf/routes

@@ -0,0 +1,9 @@
+# Routes
+# This file defines all application routes (Higher priority routes first)
+# ~~~~
+
+GET     /db                             controllers.Application.db
+GET     /queries                        controllers.Application.queries(queries ?= "1")
+
+# Map static resources from the /public folder to the /assets URL path
+GET     /assets/*file                   controllers.Assets.at(path="/public", file)

+ 1 - 0
frameworks/Scala/play2-scala/play2-scala-reactivemongo/project/build.properties

@@ -0,0 +1 @@
+sbt.version=0.13.5

+ 8 - 0
frameworks/Scala/play2-scala/play2-scala-reactivemongo/project/plugins.sbt

@@ -0,0 +1,8 @@
+// Comment to get more information during initialization
+logLevel := Level.Warn
+
+// The Typesafe repository 
+resolvers += "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/"
+
+// Use the Play sbt plugin for Play projects
+addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.3.6")

+ 3 - 0
frameworks/Scala/play2-scala/play2-scala-reactivemongo/source_code

@@ -0,0 +1,3 @@
+./play2-scala-reactivemongo/app/
+./play2-scala-reactivemongo/app/controllers
+./play2-scala-reactivemongo/app/controllers/Application.scala

+ 1 - 1
frameworks/Scala/play2-scala/play2-scala-slick/app/controllers/Application.scala

@@ -44,7 +44,7 @@ object Application extends Controller {
     }
   }
 
-  // Common code between Anorm and Slick
+  // Common code between Scala database code
 
   protected val TestDatabaseRows = 10000
 

+ 0 - 18
frameworks/Scala/play2-scala/play2-scala/README.md

@@ -1,18 +0,0 @@
-#Play Benchmarking Test
-
-This is the Play portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
-
-### JSON Encoding Test
-
-* [JSON test source](app/controllers/Application.scala)
-
-## Infrastructure Software Versions
-The tests were run with:
-
-* [Java OpenJDK 1.7.0_09](http://openjdk.java.net/)
-* [Play 2](http://http://www.playframework.com/)
-
-## Test URLs
-### JSON Encoding Test
-
-http://localhost/json

+ 6 - 0
frameworks/Scala/play2-scala/setup_scala_activate.py

@@ -0,0 +1,6 @@
+
+# This file was generated by frameworks/Java/play2-java/generate_config.py.
+# Do not edit this file directly, use the script to regenerate.
+from .setup_common import make_setup_for_dir
+
+make_setup_for_dir(globals(), 'play2-scala-activate')

+ 6 - 0
frameworks/Scala/play2-scala/setup_scala_reactivemongo.py

@@ -0,0 +1,6 @@
+
+# This file was generated by frameworks/Java/play2-java/generate_config.py.
+# Do not edit this file directly, use the script to regenerate.
+from .setup_common import make_setup_for_dir
+
+make_setup_for_dir(globals(), 'play2-scala-reactivemongo')