diff --git a/module/src/main/scala/org/scalatestplus/play/BaseOneAppPerSuite.scala b/module/src/main/scala/org/scalatestplus/play/BaseOneAppPerSuite.scala index a46d5c47..48452715 100644 --- a/module/src/main/scala/org/scalatestplus/play/BaseOneAppPerSuite.scala +++ b/module/src/main/scala/org/scalatestplus/play/BaseOneAppPerSuite.scala @@ -15,47 +15,81 @@ */ package org.scalatestplus.play -import org.scalatest.Args -import org.scalatest.Status -import org.scalatest.TestSuite -import org.scalatest.TestSuiteMixin +import org.scalatest._ import play.api.Application import play.api.Play /** * The base abstract trait for one app per suite. */ -trait BaseOneAppPerSuite extends TestSuiteMixin { this: TestSuite with FakeApplicationFactory => +trait BaseOneAppPerSuite extends SuiteMixin with AppProvider with BeforeAndAfterAll with BeforeAndAfterEachTestData { + this: Suite with FakeApplicationFactory => + + @volatile private var privateApp: Application = _ /** * An implicit instance of `Application`. */ - implicit lazy val app: Application = fakeApplication() + final implicit def app: Application = { + require(privateApp != null, "Test isn't running yet so application is not available") + privateApp + } + + protected override def beforeAll: Unit = { + privateApp = fakeApplication() + Play.start(app) + super.beforeAll() + } + + protected override def afterAll(): Unit = { + try { + super.afterAll() + } finally { + val theApp = app + privateApp = null + Play.stop(theApp) + } + } + + /** + * Places a reference to the app into per-test instances + */ + protected override def beforeEach(testData: TestData): Unit = { + if (isInstanceOf[OneInstancePerTest]) + setApplicationFrom(testData.configMap) + super.beforeEach(testData) + } + + private def setApplicationFrom(configMap: ConfigMap): Unit = { + synchronized { privateApp = providerFrom(configMap).app } + } /** - * Invokes `Play.start`, passing in the `Application` provided by `app`, and places - * that same `Application` into the `ConfigMap` under the key `org.scalatestplus.play.app` to make it available - * to nested suites; calls `super.run`; and lastly ensures `Play.stop` is invoked after all tests and nested suites have completed. - * - * @param testName an optional name of one test to run. If `None`, all relevant tests should be run. - * I.e., `None` acts like a wildcard that means run all relevant tests in this `Suite`. - * @param args the `Args` for this run - * @return a `Status` object that indicates when all tests and nested suites started by this method have completed, and whether or not a failure occurred. + * Places the app into the test's ConfigMap */ + abstract override def testDataFor(testName: String, configMap: ConfigMap): TestData = { + super.testDataFor(testName, configMap + ("org.scalatestplus.play.app" -> providerFrom(configMap).app)) + } + + private def providerFrom(configMap: ConfigMap): AppProvider = { + configMap + .getOptional[AppProvider]("org.scalatestplus.play.app.provider") + .getOrElse( + throw new IllegalArgumentException( + "BaseOneAppPerSuite needs an Application value associated with key \"org.scalatestplus.play.app.provider\" in the config map" + ) + ) + } + + //put a provider into the config map(instead of app directly), so that if tests are excluded, the app is never created abstract override def run(testName: Option[String], args: Args): Status = { - Play.start(app) - try { - val newConfigMap = args.configMap + ("org.scalatestplus.play.app" -> app) + // if a test is running under OneInstancePerTest, the config map will already be set + if (args.runTestInNewInstance) super.run(testName, args) + else { + val newConfigMap = args.configMap + ("org.scalatestplus.play.app.provider" -> this) val newArgs = args.copy(configMap = newConfigMap) - val status = super.run(testName, newArgs) - status.whenCompleted { _ => - Play.stop(app) - } - status - } catch { // In case the suite aborts, ensure the app is stopped - case ex: Throwable => - Play.stop(app) - throw ex + super.run(testName, newArgs) } } + } diff --git a/module/src/main/scala/org/scalatestplus/play/BaseOneAppPerTest.scala b/module/src/main/scala/org/scalatestplus/play/BaseOneAppPerTest.scala index 91a476dd..a474cf98 100644 --- a/module/src/main/scala/org/scalatestplus/play/BaseOneAppPerTest.scala +++ b/module/src/main/scala/org/scalatestplus/play/BaseOneAppPerTest.scala @@ -1,15 +1,14 @@ package org.scalatestplus.play -import org.scalatest.TestData -import org.scalatest.TestSuite -import org.scalatest.TestSuiteMixin +import org.scalatest._ import play.api.Application +import play.api.Play import play.api.test.Helpers /** * Trait that provides a new `Application` instance for each test. * - * This `TestSuiteMixin` trait's overridden `withFixture` method creates a new `Application` + * This `SuiteMixin` trait's overridden `withFixture` method creates a new `Application` * before each test and ensures it is cleaned up after the test has completed. You can * access the `Application` from your tests as method `app` (which is marked implicit). * @@ -45,7 +44,10 @@ import play.api.test.Helpers * } * */ -trait BaseOneAppPerTest extends TestSuiteMixin with AppProvider { this: TestSuite with FakeApplicationFactory => +trait BaseOneAppPerTest extends SuiteMixin with BeforeAndAfterEachTestData with AppProvider { + this: Suite with FakeApplicationFactory => + + private var appPerTest: Application = _ /** * Creates new instance of `Application` with parameters set to their defaults. Override this method if you @@ -53,25 +55,23 @@ trait BaseOneAppPerTest extends TestSuiteMixin with AppProvider { this: TestSuit */ def newAppForTest(testData: TestData): Application = fakeApplication() - private var appPerTest: Application = _ - /** * Implicit method that returns the `Application` instance for the current test. */ final implicit def app: Application = synchronized { appPerTest } - /** - * Creates a new `Application` instance before executing each test, and - * ensure it is cleaned up after the test completes. You can access the `Application` from - * your tests via `app`. - * - * @param test the no-arg test function to run with a fixture - * @return the `Outcome` of the test execution - */ - abstract override def withFixture(test: NoArgTest) = { - synchronized { appPerTest = newAppForTest(test) } - Helpers.running(app) { - super.withFixture(test) + protected override def beforeEach(td: TestData): Unit = { + synchronized { appPerTest = newAppForTest(td) } + Play.start(appPerTest) + super.beforeEach(td) + } + + protected override def afterEach(td: TestData): Unit = { + try { + super.afterEach(td) + } finally { + Play.stop(appPerTest) } } + } diff --git a/module/src/main/scala/org/scalatestplus/play/BaseOneServerPerSuite.scala b/module/src/main/scala/org/scalatestplus/play/BaseOneServerPerSuite.scala index 7bb68e97..18ad3cc7 100644 --- a/module/src/main/scala/org/scalatestplus/play/BaseOneServerPerSuite.scala +++ b/module/src/main/scala/org/scalatestplus/play/BaseOneServerPerSuite.scala @@ -28,7 +28,7 @@ import play.api.test._ * `Application` with non-default parameters, override `app`. If it needs a different port number, * override `port`. * - * This `TestSuiteMixin` trait's overridden `run` method calls `start` on the `TestServer` + * This `SuiteMixin` trait's overridden `run` method calls `start` on the `TestServer` * before executing the `Suite` via a call to `super.run`. * In addition, it places a reference to the `Application` provided by `app` into the `ConfigMap` * under the key `org.scalatestplus.play.app` and to the port number provided by `port` under the key @@ -134,41 +134,85 @@ import play.api.test._ * } * */ -trait BaseOneServerPerSuite extends TestSuiteMixin with ServerProvider { this: TestSuite with FakeApplicationFactory => +trait BaseOneServerPerSuite + extends SuiteMixin + with BeforeAndAfterAll + with BeforeAndAfterEachTestData + with ServerProvider { + this: Suite with FakeApplicationFactory => + + @volatile private var privateServer: RunningServer = _ + + final implicit def runningServer: RunningServer = { + require(privateServer != null, "Test isn't running yet so the server endpoints are not available") + privateServer + } /** * An implicit instance of `Application`. */ - implicit lazy val app: Application = fakeApplication() + final implicit def app: Application = { + runningServer.app + } + + protected override def beforeAll(): Unit = { + privateServer = startTestServer + super.beforeAll() + } + + protected def startTestServer: RunningServer = DefaultTestServerFactory.start(fakeApplication()) + + protected override def afterAll(): Unit = { + try { + super.afterAll() + } finally { + val server = runningServer + privateServer = null + server.stopServer.close() + } + } + + /** + * Places a reference to the server into per-test instances + */ + protected override def beforeEach(testData: TestData): Unit = { + super.beforeEach(testData) + if (isInstanceOf[OneInstancePerTest]) + setServerFrom(testData.configMap) + } - protected implicit lazy val runningServer: RunningServer = - DefaultTestServerFactory.start(app) + private def setServerFrom(configMap: ConfigMap): Unit = { + synchronized { privateServer = providerFrom(configMap).runningServer } + } + + private def providerFrom(configMap: ConfigMap): ServerProvider = { + configMap + .getOptional[ServerProvider]("org.scalatestplus.play.server.provider") + .getOrElse( + throw new IllegalArgumentException( + "BaseOneServerPerSuite needs an Application value associated with key \"org.scalatestplus.play.server.provider\" in the config map" + ) + ) + } /** - * Invokes `start` on a new `TestServer` created with the `Application` provided by `app` and the - * port number defined by `port`, places the `Application` and port number into the `ConfigMap` under the keys - * `org.scalatestplus.play.app` and `org.scalatestplus.play.port`, respectively, to make - * them available to nested suites; calls `super.run`; and lastly ensures the `Application` and test server are stopped after - * all tests and nested suites have completed. - * - * @param testName an optional name of one test to run. If `None`, all relevant tests should be run. - * I.e., `None` acts like a wildcard that means run all relevant tests in this `Suite`. - * @param args the `Args` for this run - * @return a `Status` object that indicates when all tests and nested suites started by this method have completed, and whether or not a failure occurred. + * Places the server port into the test's ConfigMap */ + abstract override def testDataFor(testName: String, configMap: ConfigMap): TestData = { + val serverProvider = providerFrom(configMap) + val newConfigMap = configMap + ("org.scalatestplus.play.app" -> serverProvider.app) + ("org.scalatestplus.play.port" -> serverProvider.port) + super.testDataFor(testName, newConfigMap) + } + + //put a provider into the config map(instead of server directly), so that if tests are excluded, the server is never created abstract override def run(testName: Option[String], args: Args): Status = { - try { - val newConfigMap = args.configMap + ("org.scalatestplus.play.app" -> app) + ("org.scalatestplus.play.port" -> port) + // if a test is running under OneInstancePerTest, the config map will already be set + if (args.runTestInNewInstance) super.run(testName, args) + else { + val newConfigMap = args.configMap + ("org.scalatestplus.play.server.provider" -> this) val newArgs = args.copy(configMap = newConfigMap) - val status = super.run(testName, newArgs) - status.whenCompleted { _ => - runningServer.stopServer.close() - } - status - } catch { // In case the suite aborts, ensure the server is stopped - case ex: Throwable => - runningServer.stopServer.close() - throw ex + super.run(testName, newArgs) } } + } diff --git a/module/src/main/scala/org/scalatestplus/play/BaseOneServerPerTest.scala b/module/src/main/scala/org/scalatestplus/play/BaseOneServerPerTest.scala index ba0f4e8b..b7909721 100644 --- a/module/src/main/scala/org/scalatestplus/play/BaseOneServerPerTest.scala +++ b/module/src/main/scala/org/scalatestplus/play/BaseOneServerPerTest.scala @@ -22,7 +22,7 @@ import org.scalatest._ /** * Trait that provides a new `Application` and running `TestServer` instance for each test executed in a ScalaTest `Suite`. * - * This `TestSuiteMixin` trait overrides ScalaTest's `withFixture` method to create a new `Application` and `TestServer` + * This `SuiteMixin` trait overrides ScalaTest's `withFixture` method to create a new `Application` and `TestServer` * before each test, and ensure they are cleaned up after the test has completed. The `Application` is available (implicitly) from * method `app`. The `TestServer`'s port number is available as `port` (and implicitly available as `portNumber`, wrapped * in a [[org.scalatestplus.play.PortNumber PortNumber]]). @@ -73,7 +73,8 @@ import org.scalatest._ * } * */ -trait BaseOneServerPerTest extends TestSuiteMixin with ServerProvider { this: TestSuite with FakeApplicationFactory => +trait BaseOneServerPerTest extends SuiteMixin with BeforeAndAfterEachTestData with ServerProvider { + this: Suite with FakeApplicationFactory => @volatile private var privateApp: Application = _ @volatile private var privateServer: RunningServer = _ @@ -108,28 +109,23 @@ trait BaseOneServerPerTest extends TestSuiteMixin with ServerProvider { this: Te protected def newServerForTest(app: Application, testData: TestData): RunningServer = DefaultTestServerFactory.start(app) - /** - * Creates new `Application` and running `TestServer` instances before executing each test, and - * ensures they are cleaned up after the test completes. You can access the `Application` from - * your tests as `app` and the `TestServer`'s port number as `port`. - * - * @param test the no-arg test function to run with a fixture - * @return the `Outcome` of the test execution - */ - abstract override def withFixture(test: NoArgTest) = { - // Need to synchronize within a suite because we store current app/server in fields in the class - // Could possibly pass app/server info in a ScalaTest object? + protected override def beforeEach(td: TestData): Unit = { lock.synchronized { - privateApp = newAppForTest(test) - privateServer = newServerForTest(app, test) - try super.withFixture(test) - finally { - val rs = privateServer // Store before nulling fields - privateApp = null - privateServer = null - // Stop server and release locks - rs.stopServer.close() - } + privateApp = newAppForTest(td) + privateServer = newServerForTest(app, td) + } + super.beforeEach(td) + } + + protected override def afterEach(td: TestData): Unit = { + try { + super.afterEach(td) + } finally { + val rs = privateServer // Store before nulling fields + privateApp = null + privateServer = null + // Stop server and release locks + rs.stopServer.close() } } } diff --git a/module/src/main/scala/org/scalatestplus/play/ConfiguredApp.scala b/module/src/main/scala/org/scalatestplus/play/ConfiguredApp.scala index 59114511..23d0758a 100644 --- a/module/src/main/scala/org/scalatestplus/play/ConfiguredApp.scala +++ b/module/src/main/scala/org/scalatestplus/play/ConfiguredApp.scala @@ -56,9 +56,9 @@ import play.api.Application * } * */ -trait ConfiguredApp extends TestSuiteMixin { this: TestSuite => +trait ConfiguredApp extends SuiteMixin with BeforeAndAfterAllConfigMap with BeforeAndAfterEachTestData { this: Suite => - private var configuredApp: Application = _ + @volatile private var configuredApp: Application = _ /** * The "configured" `Application` instance that was passed into `run` via the `ConfigMap`. @@ -75,23 +75,41 @@ trait ConfiguredApp extends TestSuiteMixin { this: TestSuite => * If no key matches "org.scalatestplus.play.app" in `args.configMap`, or the associated value is * not a `Application`, throws `IllegalArgumentException`. * - * To prevent discovery of nested suites you can annotate them with `@DoNotDiscover`. - * - * @param testName an optional name of one test to run. If `None`, all relevant tests should be run. - * I.e., `None` acts like a wildcard that means run all relevant tests in this `Suite`. - * @param args the `Args` for this run - * @return a `Status` object that indicates when all tests and nested suites started by this method have completed, and whether or not a failure occurred. - * * @throws java.lang.IllegalArgumentException if the `Application` does not appear in `args.configMap` under the expected key */ - abstract override def run(testName: Option[String], args: Args): Status = { - args.configMap.getOptional[Application]("org.scalatestplus.play.app") match { - case Some(ca) => synchronized { configuredApp = ca } - case None => + protected override def beforeAll(configMap: ConfigMap): Unit = { + super.beforeAll(configMap) + setApplicationFrom(configMap) + } + + /** + * Places a reference to the app into per-test instances + */ + protected override def beforeEach(testData: TestData): Unit = { + super.beforeEach(testData) + if (isInstanceOf[OneInstancePerTest]) + setApplicationFrom(testData.configMap) + } + + private def setApplicationFrom(configMap: ConfigMap): Unit = { + synchronized { configuredApp = providerFrom(configMap).app } + } + + private def providerFrom(configMap: ConfigMap): AppProvider = { + configMap + .getOptional[AppProvider]("org.scalatestplus.play.app.provider") + .getOrElse( throw new IllegalArgumentException( - "ConfiguredApp needs an Application value associated with key \"org.scalatestplus.play.app\" in the config map. Did you forget to annotate a nested suite with @DoNotDiscover?" + "ConfiguredApp needs an Application value associated with key \"org.scalatestplus.play.app.provider\" in the config map. Did you forget to annotate a nested suite with @DoNotDiscover?" ) - } - super.run(testName, args) + ) } + + /** + * Places the app into the test's ConfigMap + */ + abstract override def testDataFor(testName: String, configMap: ConfigMap): TestData = { + super.testDataFor(testName, configMap + ("org.scalatestplus.play.app" -> providerFrom(configMap).app)) + } + } diff --git a/module/src/main/scala/org/scalatestplus/play/ConfiguredBrowser.scala b/module/src/main/scala/org/scalatestplus/play/ConfiguredBrowser.scala index a8c56a62..d8996591 100644 --- a/module/src/main/scala/org/scalatestplus/play/ConfiguredBrowser.scala +++ b/module/src/main/scala/org/scalatestplus/play/ConfiguredBrowser.scala @@ -87,8 +87,8 @@ import org.scalatestplus.selenium.WebBrowser * } * */ -trait ConfiguredBrowser extends TestSuiteMixin with WebBrowser with Eventually with IntegrationPatience { - this: TestSuite with ServerProvider => +trait ConfiguredBrowser extends SuiteMixin with WebBrowser with Eventually with IntegrationPatience { + this: Suite with ServerProvider => private var configuredWebDriver: WebDriver = UninitializedDriver diff --git a/module/src/main/scala/org/scalatestplus/play/ConfiguredServer.scala b/module/src/main/scala/org/scalatestplus/play/ConfiguredServer.scala index 9eff70d1..1046be62 100644 --- a/module/src/main/scala/org/scalatestplus/play/ConfiguredServer.scala +++ b/module/src/main/scala/org/scalatestplus/play/ConfiguredServer.scala @@ -26,11 +26,11 @@ import play.core.server.ServerEndpoints * * The purpose of this trait is to allow nested suites of an enclosing suite that extends [[org.scalatestplus.play.guice.GuiceOneServerPerSuite GuiceOneServerPerSuite]] * to make use of the `Application` and port number provided by `OneServerPerSuite`. Trait `OneServerPerSuite` will ensure - * the `Application` is placed in the `ConfigMap` under the key `org.scalatestplus.play.app` and the port number + * the `ServerProvider` is placed in the `ConfigMap` under the key `org.scalatestplus.play.server.provider` and the port number * under the key `org.scalatestplus.play.port` before nested suites are invoked. This information represents the "configured server" that * is passed from the enclosing suite to the nested suites. Trait `ConfiguredServer` extracts this information from - * from the `ConfigMap` and makes the `Application` available via the `app` method, the port number available as an `Int` from - * the `port` method, and also the port number wrapped in a [[org.scalatestplus.play.PortNumber PortNumber]] available as implicit method `portNumber` (for use + * from the `ConfigMap` and makes the port number available as an `Int` from the `port` method, + * and also the port number wrapped in a [[org.scalatestplus.play.PortNumber PortNumber]] available as implicit method `portNumber` (for use * with trait [[org.scalatestplus.play.WsScalaTestClient WsScalaTestClient]]). * * To prevent discovery of nested suites you can annotate them with `@DoNotDiscover`. Here's an example, @@ -73,35 +73,20 @@ import play.core.server.ServerEndpoints * } * */ -trait ConfiguredServer extends TestSuiteMixin with ServerProvider { this: TestSuite => +trait ConfiguredServer + extends SuiteMixin + with BeforeAndAfterAllConfigMap + with BeforeAndAfterEachTestData + with ServerProvider { this: Suite => - private var configuredApp: Application = _ + @volatile private var privateServer: RunningServer = _ - /** - * The "configured" `Application` instance that was passed into `run` via the `ConfigMap`. - * - * @return the configured `Application` - */ - final implicit def app: Application = synchronized { configuredApp } + final implicit def runningServer: RunningServer = { + require(privateServer != null, "Test isn't running yet so the server endpoints are not available") + privateServer + } - protected implicit lazy val runningServer: RunningServer = - RunningServer( - app, - ServerEndpoints( - Seq( - ServerEndpoint( - description = "ConfiguredServer endpoint", - scheme = "http", - host = "localhost", - port = configuredPort, - protocols = Set.empty, - serverAttribute = None, - ssl = None - ) - ) - ), - new AutoCloseable { def close() = () } - ) + final implicit def app: Application = runningServer.app private var _configuredPort: Int = -1 @@ -113,37 +98,52 @@ trait ConfiguredServer extends TestSuiteMixin with ServerProvider { this: TestSu protected final def configuredPort: Int = synchronized { _configuredPort } /** - * Looks in `args.configMap` for a key named "org.scalatestplus.play.app" whose value is a `Application`, - * and a key named "org.scalatestplus.play.port" whose value is an `Int`, - * and if they exist, sets the `Application` as the value that will be returned from the `app` method and - * the `Int` as the value that will be returned from the `port` method, then calls - * `super.run`. + * Looks in `args.configMap` for a key named "org.scalatestplus.play.provider" whose value is an `ServerProvider`, + * and if they exist, sets the `ServerProvider` as the value that will be returned from the `port` method, then calls * - * If no key matches "org.scalatestplus.play.app" in `args.configMap`, or the associated value is - * not a `Application`, or if no key matches "org.scalatestplus.play.port" in `args.configMap`, - * or the associated value is not an `Int`, throws `IllegalArgumentException`. + * If no key matches "org.scalatestplus.play.provider" in `args.configMap`, + * or the associated value is not a `ServerProvider`, throws `IllegalArgumentException`. * - * @param testName an optional name of one test to run. If `None`, all relevant tests should be run. - * I.e., `None` acts like a wildcard that means run all relevant tests in this `Suite`. - * @param args the `Args` for this run - * @return a `Status` object that indicates when all tests and nested suites started by this method have completed, and whether or not a failure occurred. * @throws java.lang.IllegalArgumentException if the `Application` and/or port number does not appear in `args.configMap` under the expected keys */ - abstract override def run(testName: Option[String], args: Args): Status = { - args.configMap.getOptional[Application]("org.scalatestplus.play.app") match { - case Some(ca) => synchronized { configuredApp = ca } - case None => - throw new Exception( - "Trait ConfiguredServer needs an Application value associated with key \"org.scalatestplus.play.app\" in the config map. Did you forget to annotate a nested suite with @DoNotDiscover?" - ) + protected override def beforeAll(configMap: ConfigMap): Unit = { + super.beforeAll(configMap) + setServerFrom(configMap) + } + + /** + * Places a reference to the server into per-test instances + */ + protected override def beforeEach(testData: TestData): Unit = { + super.beforeEach(testData) + if (isInstanceOf[OneInstancePerTest]) + setServerFrom(testData.configMap) + } + + private def setServerFrom(configMap: ConfigMap): Unit = { + val cp = providerFrom(configMap) + synchronized { + privateServer = cp.runningServer + _configuredPort = cp.port } - args.configMap.getOptional[Int]("org.scalatestplus.play.port") match { - case Some(cp) => synchronized { _configuredPort = cp } - case None => - throw new Exception( - "Trait ConfiguredServer needs an Int value associated with key \"org.scalatestplus.play.port\" in the config map. Did you forget to annotate a nested suite with @DoNotDiscover?" + } + + private def providerFrom(configMap: ConfigMap): ServerProvider = { + configMap + .getOptional[ServerProvider]("org.scalatestplus.play.server.provider") + .getOrElse( + throw new IllegalArgumentException( + "ConfiguredServer needs an Application value associated with key \"org.scalatestplus.play.server.provider\" in the config map. Did you forget to annotate a nested suite with @DoNotDiscover?" ) - } - super.run(testName, args) + ) + } + + /** + * Places the server port into the test's ConfigMap + */ + abstract override def testDataFor(testName: String, configMap: ConfigMap): TestData = { + val serverProvider = providerFrom(configMap) + val newConfigMap = configMap + ("org.scalatestplus.play.app" -> serverProvider.app) + ("org.scalatestplus.play.port" -> serverProvider.port) + super.testDataFor(testName, newConfigMap) } } diff --git a/module/src/main/scala/org/scalatestplus/play/OneAppPerSuite.scala b/module/src/main/scala/org/scalatestplus/play/OneAppPerSuite.scala index 6838bc13..b7f39c61 100644 --- a/module/src/main/scala/org/scalatestplus/play/OneAppPerSuite.scala +++ b/module/src/main/scala/org/scalatestplus/play/OneAppPerSuite.scala @@ -22,6 +22,6 @@ import org.scalatestplus.play.guice.GuiceOneAppPerSuite * Synonym for GuiceOneAppPerSuite. */ @deprecated("Use GuiceOneAppPerSuite instead", "2.0.0") -trait OneAppPerSuite extends GuiceOneAppPerSuite { this: TestSuite => +trait OneAppPerSuite extends GuiceOneAppPerSuite { this: Suite => } diff --git a/module/src/main/scala/org/scalatestplus/play/OneAppPerTest.scala b/module/src/main/scala/org/scalatestplus/play/OneAppPerTest.scala index 724f1cc1..82f4b6f8 100644 --- a/module/src/main/scala/org/scalatestplus/play/OneAppPerTest.scala +++ b/module/src/main/scala/org/scalatestplus/play/OneAppPerTest.scala @@ -22,6 +22,6 @@ import org.scalatestplus.play.guice.GuiceOneAppPerTest * Synonym for GuiceOneAppPerTest */ @deprecated("Use GuiceOneAppPerTest instead", "2.0.0") -trait OneAppPerTest extends GuiceOneAppPerTest { this: TestSuite => +trait OneAppPerTest extends GuiceOneAppPerTest { this: Suite => } diff --git a/module/src/main/scala/org/scalatestplus/play/OneServerPerSuite.scala b/module/src/main/scala/org/scalatestplus/play/OneServerPerSuite.scala index 8c4fbf2e..28226ddc 100644 --- a/module/src/main/scala/org/scalatestplus/play/OneServerPerSuite.scala +++ b/module/src/main/scala/org/scalatestplus/play/OneServerPerSuite.scala @@ -15,13 +15,13 @@ */ package org.scalatestplus.play -import org.scalatest.TestSuite +import org.scalatest.Suite import org.scalatestplus.play.guice.GuiceOneServerPerSuite /** * Synonym for GuiceOneServerPerSuite. */ @deprecated("Use GuiceOneServerPerSuite instead", "2.0.0") -trait OneServerPerSuite extends GuiceOneServerPerSuite { this: TestSuite => +trait OneServerPerSuite extends GuiceOneServerPerSuite { this: Suite => } diff --git a/module/src/main/scala/org/scalatestplus/play/OneServerPerTest.scala b/module/src/main/scala/org/scalatestplus/play/OneServerPerTest.scala index ec022f9a..9f38385b 100644 --- a/module/src/main/scala/org/scalatestplus/play/OneServerPerTest.scala +++ b/module/src/main/scala/org/scalatestplus/play/OneServerPerTest.scala @@ -22,6 +22,6 @@ import org.scalatestplus.play.guice.GuiceOneServerPerTest * Synonym for GuiceOneServerPerTest */ @deprecated("Use GuiceOneServerPerTest instead", "2.0.0") -trait OneServerPerTest extends GuiceOneServerPerTest { this: TestSuite => +trait OneServerPerTest extends GuiceOneServerPerTest { this: Suite => } diff --git a/module/src/main/scala/org/scalatestplus/play/ServerProvider.scala b/module/src/main/scala/org/scalatestplus/play/ServerProvider.scala index 12d693e9..24c3c7a0 100644 --- a/module/src/main/scala/org/scalatestplus/play/ServerProvider.scala +++ b/module/src/main/scala/org/scalatestplus/play/ServerProvider.scala @@ -39,7 +39,7 @@ trait ServerProvider { */ implicit def app: Application - protected implicit def runningServer: RunningServer + protected[play] implicit def runningServer: RunningServer /** * The port used by the `TestServer`. diff --git a/module/src/main/scala/org/scalatestplus/play/components/OneAppPerSuiteWithComponents.scala b/module/src/main/scala/org/scalatestplus/play/components/OneAppPerSuiteWithComponents.scala index f95e2bf8..4f516784 100644 --- a/module/src/main/scala/org/scalatestplus/play/components/OneAppPerSuiteWithComponents.scala +++ b/module/src/main/scala/org/scalatestplus/play/components/OneAppPerSuiteWithComponents.scala @@ -1,6 +1,6 @@ package org.scalatestplus.play.components -import org.scalatest.TestSuite +import org.scalatest.Suite import org.scalatestplus.play.BaseOneAppPerSuite import org.scalatestplus.play.FakeApplicationFactory import play.api.Application @@ -12,7 +12,7 @@ import play.api.Application * * By default, this trait creates a new `Application` for the `Suite` according to the components defined in the test. * - * This `TestSuiteMixin` trait's overridden `run` method calls `Play.start`, passing in the + * This `SuiteMixin` trait's overridden `run` method calls `Play.start`, passing in the * `Application` provided by `app`, before executing the `Suite` via a call to `super.run`. * In addition, it places a reference to the `Application` provided by `app` into the `ConfigMap` * under the key `org.scalatestplus.play.app`. This allows any nested `Suite`s to access the `Suite`'s @@ -70,7 +70,7 @@ import play.api.Application * `Suite`s. Annotate the nested suites with `@DoNotDiscover` and have them extend `ConfiguredApp`. Here's an example: * *
- * import org.scalatest.{DoNotDiscover, Suites, TestSuite}
+ * import org.scalatest.{DoNotDiscover, Suites, Suite}
  * import org.scalatestplus.play.components.OneAppPerSuiteWithComponents
  * import org.scalatestplus.play.{ConfiguredApp, PlaySpec}
  * import play.api._
@@ -86,7 +86,7 @@ import play.api.Application
  *   new TwoSpec,
  *   new RedSpec,
  *   new BlueSpec
- * ) with OneAppPerSuiteWithComponents with TestSuite {
+ * ) with OneAppPerSuiteWithComponents with Suite {
  *   // Override fakeApplication if you need an Application with other than non-default parameters.
  *   override def components: BuiltInComponents = new BuiltInComponentsFromContext(context) with NoHttpFiltersComponents {
  *
@@ -137,7 +137,7 @@ trait OneAppPerSuiteWithComponents
     extends BaseOneAppPerSuite
     with WithApplicationComponents
     with FakeApplicationFactory {
-  this: TestSuite =>
+  this: Suite =>
 
   override def fakeApplication(): Application = newApplication
 }
diff --git a/module/src/main/scala/org/scalatestplus/play/components/OneAppPerTestWithComponents.scala b/module/src/main/scala/org/scalatestplus/play/components/OneAppPerTestWithComponents.scala
index 37989f86..d6ec5969 100644
--- a/module/src/main/scala/org/scalatestplus/play/components/OneAppPerTestWithComponents.scala
+++ b/module/src/main/scala/org/scalatestplus/play/components/OneAppPerTestWithComponents.scala
@@ -1,7 +1,7 @@
 package org.scalatestplus.play.components
 
-import org.scalatest.TestSuite
-import org.scalatest.TestSuiteMixin
+import org.scalatest.Suite
+import org.scalatest.SuiteMixin
 import org.scalatestplus.play.BaseOneAppPerTest
 import org.scalatestplus.play.FakeApplicationFactory
 import play.api.Application
@@ -11,7 +11,7 @@ import play.api.Application
  *
  * Trait that provides a new `Application` instance for each test.
  *
- * This `TestSuiteMixin` trait's overridden `withFixture` method creates a new `Application`
+ * This `SuiteMixin` trait's overridden `withFixture` method creates a new `Application`
  * before each test and ensures it is cleaned up after the test has completed. You can
  * access the `Application` from your tests as method `app` (which is marked implicit).
  *
@@ -63,8 +63,8 @@ trait OneAppPerTestWithComponents
     extends BaseOneAppPerTest
     with WithApplicationComponents
     with FakeApplicationFactory
-    with TestSuiteMixin {
-  this: TestSuite =>
+    with SuiteMixin {
+  this: Suite =>
 
   override def fakeApplication(): Application = newApplication
 }
diff --git a/module/src/main/scala/org/scalatestplus/play/components/OneServerPerSuiteWithComponents.scala b/module/src/main/scala/org/scalatestplus/play/components/OneServerPerSuiteWithComponents.scala
index 62c1fd3d..8b981f27 100644
--- a/module/src/main/scala/org/scalatestplus/play/components/OneServerPerSuiteWithComponents.scala
+++ b/module/src/main/scala/org/scalatestplus/play/components/OneServerPerSuiteWithComponents.scala
@@ -1,6 +1,6 @@
 package org.scalatestplus.play.components
 
-import org.scalatest.TestSuite
+import org.scalatest.Suite
 import org.scalatestplus.play.BaseOneServerPerSuite
 import org.scalatestplus.play.FakeApplicationFactory
 import play.api.Application
@@ -15,7 +15,7 @@ import play.api.Application
  * its `port` field and the `Application` provided by its `app` field. If your `Suite` needs a different port number,
  * override `port`.
  *
- * This `TestSuiteMixin` trait's overridden `run` method calls `start` on the `TestServer`
+ * This `SuiteMixin` trait's overridden `run` method calls `start` on the `TestServer`
  * before executing the `Suite` via a call to `super.run`.
  * In addition, it places a reference to the `Application` provided by `app` into the `ConfigMap`
  * under the key `org.scalatestplus.play.app` and to the port number provided by `port` under the key
@@ -74,7 +74,7 @@ import play.api.Application
  * `Suite`s. Annotate the nested suites with `@DoNotDiscover` and have them extend `ConfiguredServer`. Here's an example:
  *
  * 
- * import org.scalatest.{ DoNotDiscover, Suites, TestSuite }
+ * import org.scalatest.{ DoNotDiscover, Suites, Suite }
  * import org.scalatestplus.play.components._
  * import org.scalatestplus.play.{ ConfiguredServer, PlaySpec }
  * import play.api._
@@ -89,7 +89,7 @@ import play.api.Application
  *   new TwoSpec,
  *   new RedSpec,
  *   new BlueSpec
- * ) with OneServerPerSuiteWithComponents with TestSuite {
+ * ) with OneServerPerSuiteWithComponents with Suite {
  *   // Override fakeApplication if you need an Application with other than non-default parameters.
  *   override def components: BuiltInComponents = new BuiltInComponentsFromContext(context) with NoHttpFiltersComponents {
  *
@@ -147,7 +147,7 @@ trait OneServerPerSuiteWithComponents
     extends BaseOneServerPerSuite
     with WithApplicationComponents
     with FakeApplicationFactory {
-  this: TestSuite =>
+  this: Suite =>
 
   override def fakeApplication(): Application = newApplication
 }
diff --git a/module/src/main/scala/org/scalatestplus/play/components/OneServerPerTestWithComponents.scala b/module/src/main/scala/org/scalatestplus/play/components/OneServerPerTestWithComponents.scala
index a8506a47..5e15decf 100644
--- a/module/src/main/scala/org/scalatestplus/play/components/OneServerPerTestWithComponents.scala
+++ b/module/src/main/scala/org/scalatestplus/play/components/OneServerPerTestWithComponents.scala
@@ -1,6 +1,6 @@
 package org.scalatestplus.play.components
 
-import org.scalatest.TestSuite
+import org.scalatest.Suite
 import org.scalatestplus.play.BaseOneServerPerTest
 import org.scalatestplus.play.FakeApplicationFactory
 import play.api.Application
@@ -10,7 +10,7 @@ import play.api.Application
  *
  * Trait that provides a new `Application` and running `TestServer` instance for each test executed in a ScalaTest `Suite`
  *
- * This `TestSuiteMixin` trait overrides ScalaTest's `withFixture` method to create a new `Application` and `TestServer`
+ * This `SuiteMixin` trait overrides ScalaTest's `withFixture` method to create a new `Application` and `TestServer`
  * before each test, and ensure they are cleaned up after the test has completed. The `Application` is available (implicitly) from
  * method `app`. The `TestServer`'s port number is available as `port` (and implicitly available as `portNumber`, wrapped
  * in a [[org.scalatestplus.play.PortNumber PortNumber]]).
@@ -63,7 +63,7 @@ trait OneServerPerTestWithComponents
     extends BaseOneServerPerTest
     with WithApplicationComponents
     with FakeApplicationFactory {
-  this: TestSuite =>
+  this: Suite =>
 
   override def fakeApplication(): Application = newApplication
 }
diff --git a/module/src/main/scala/org/scalatestplus/play/guice/GuiceOneAppPerSuite.scala b/module/src/main/scala/org/scalatestplus/play/guice/GuiceOneAppPerSuite.scala
index de56c1c0..2b3c3447 100644
--- a/module/src/main/scala/org/scalatestplus/play/guice/GuiceOneAppPerSuite.scala
+++ b/module/src/main/scala/org/scalatestplus/play/guice/GuiceOneAppPerSuite.scala
@@ -15,7 +15,7 @@
  */
 package org.scalatestplus.play.guice
 
-import org.scalatest.TestSuite
+import org.scalatest.Suite
 import org.scalatestplus.play.BaseOneAppPerSuite
 
 /**
@@ -25,7 +25,7 @@ import org.scalatestplus.play.BaseOneAppPerSuite
  * is made available via the `app` field defined in this trait. If your `Suite` needs a `Application` with non-default
  * parameters, override `app` to create it the way you need it.
  *
- * This `TestSuiteMixin` trait's overridden `run` method calls `Play.start`, passing in the
+ * This `SuiteMixin` trait's overridden `run` method calls `Play.start`, passing in the
  * `Application` provided by `app`, before executing the `Suite` via a call to `super.run`.
  * In addition, it places a reference to the `Application` provided by `app` into the `ConfigMap`
  * under the key `org.scalatestplus.play.app`.  This allows any nested `Suite`s to access the `Suite`'s
@@ -108,6 +108,6 @@ import org.scalatestplus.play.BaseOneAppPerSuite
  * }
  * 
*/ -trait GuiceOneAppPerSuite extends BaseOneAppPerSuite with GuiceFakeApplicationFactory { this: TestSuite => +trait GuiceOneAppPerSuite extends BaseOneAppPerSuite with GuiceFakeApplicationFactory { this: Suite => } diff --git a/module/src/main/scala/org/scalatestplus/play/guice/GuiceOneAppPerTest.scala b/module/src/main/scala/org/scalatestplus/play/guice/GuiceOneAppPerTest.scala index 374131d6..68af8a74 100644 --- a/module/src/main/scala/org/scalatestplus/play/guice/GuiceOneAppPerTest.scala +++ b/module/src/main/scala/org/scalatestplus/play/guice/GuiceOneAppPerTest.scala @@ -1,12 +1,12 @@ package org.scalatestplus.play.guice -import org.scalatest.TestSuite +import org.scalatest.Suite import org.scalatestplus.play.BaseOneAppPerTest /** * Trait that provides a new `Application` instance for each test. * - * This `TestSuiteMixin` trait's overridden `withFixture` method creates a new `Application` + * This `SuiteMixin` trait's overridden `withFixture` method creates a new `Application` * before each test and ensures it is cleaned up after the test has completed. You can * access the `Application` from your tests as method `app` (which is marked implicit). * @@ -43,6 +43,6 @@ import org.scalatestplus.play.BaseOneAppPerTest * } *
*/ -trait GuiceOneAppPerTest extends BaseOneAppPerTest with GuiceFakeApplicationFactory { this: TestSuite => +trait GuiceOneAppPerTest extends BaseOneAppPerTest with GuiceFakeApplicationFactory { this: Suite => } diff --git a/module/src/main/scala/org/scalatestplus/play/guice/GuiceOneServerPerSuite.scala b/module/src/main/scala/org/scalatestplus/play/guice/GuiceOneServerPerSuite.scala index e413b80a..3803571c 100644 --- a/module/src/main/scala/org/scalatestplus/play/guice/GuiceOneServerPerSuite.scala +++ b/module/src/main/scala/org/scalatestplus/play/guice/GuiceOneServerPerSuite.scala @@ -1,8 +1,8 @@ package org.scalatestplus.play.guice -import org.scalatest.TestSuite +import org.scalatest.Suite import org.scalatestplus.play.BaseOneServerPerSuite -trait GuiceOneServerPerSuite extends BaseOneServerPerSuite with GuiceFakeApplicationFactory { this: TestSuite => +trait GuiceOneServerPerSuite extends BaseOneServerPerSuite with GuiceFakeApplicationFactory { this: Suite => } diff --git a/module/src/main/scala/org/scalatestplus/play/guice/GuiceOneServerPerTest.scala b/module/src/main/scala/org/scalatestplus/play/guice/GuiceOneServerPerTest.scala index faf4ad20..88b42043 100644 --- a/module/src/main/scala/org/scalatestplus/play/guice/GuiceOneServerPerTest.scala +++ b/module/src/main/scala/org/scalatestplus/play/guice/GuiceOneServerPerTest.scala @@ -1,8 +1,8 @@ package org.scalatestplus.play.guice -import org.scalatest.TestSuite +import org.scalatest.Suite import org.scalatestplus.play.BaseOneServerPerTest -trait GuiceOneServerPerTest extends BaseOneServerPerTest with GuiceFakeApplicationFactory { this: TestSuite => +trait GuiceOneServerPerTest extends BaseOneServerPerTest with GuiceFakeApplicationFactory { this: Suite => } diff --git a/module/src/test/scala/org/scalatestplus/play/ConfiguredAppParallelSpec.scala b/module/src/test/scala/org/scalatestplus/play/ConfiguredAppParallelSpec.scala new file mode 100644 index 00000000..c4ad5272 --- /dev/null +++ b/module/src/test/scala/org/scalatestplus/play/ConfiguredAppParallelSpec.scala @@ -0,0 +1,72 @@ +/* + * Copyright 2001-2016 Artima, Inc. + * + * 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 org.scalatestplus.play + +import org.scalatest._ +import org.scalatestplus.play.guice.GuiceOneAppPerSuite +import play.api.Application +import play.api.inject.guice._ +import java.util.concurrent.atomic.AtomicInteger + +object ConfiguredAppParallelSpec { + var timesApplicationIsBuilt = new AtomicInteger(0) +} + +class ConfiguredAppParallelSpec extends Suites(new ConfiguredAppParallelNestedSpec()) with GuiceOneAppPerSuite { + import ConfiguredAppParallelSpec._ + + override def fakeApplication(): Application = { + timesApplicationIsBuilt.incrementAndGet() + GuiceApplicationBuilder().configure("foo" -> "bar").build() + } +} + +@DoNotDiscover +class ConfiguredAppParallelNestedSpec extends UnitSpec with ConfiguredApp with ParallelTestExecution { + import ConfiguredAppParallelSpec._ + + def getConfig(key: String)(implicit app: Application): Option[String] = app.configuration.getOptional[String](key) + + // Doesn't need synchronization because set by withFixture and checked by the test + // invoked inside same withFixture with super.withFixture(test) + var configMap: ConfigMap = _ + + override def withFixture(test: NoArgTest): Outcome = { + configMap = test.configMap + super.withFixture(test) + } + + "The ConfiguredApp trait, when running in parallel" must { + "provide an Application" in { + app.configuration.getOptional[String]("foo") mustBe Some("bar") + } + "make the Application available implicitly" in { + getConfig("foo") mustBe Some("bar") + } + "put the app in the configMap" in { + val configuredApp = configMap.getOptional[Application]("org.scalatestplus.play.app") + (configuredApp.value must be).theSameInstanceAs(app) + } + + //these two together assert that the app is only constructed once + "must reuse the same app between tests, run1" in { + timesApplicationIsBuilt.get mustBe 1 + } + "must reuse the same app between tests, run2" in { + timesApplicationIsBuilt.get mustBe 1 + } + } +} diff --git a/module/src/test/scala/org/scalatestplus/play/ConfiguredServerParallelSpec.scala b/module/src/test/scala/org/scalatestplus/play/ConfiguredServerParallelSpec.scala new file mode 100644 index 00000000..746982a3 --- /dev/null +++ b/module/src/test/scala/org/scalatestplus/play/ConfiguredServerParallelSpec.scala @@ -0,0 +1,98 @@ +/* + * Copyright 2001-2016 Artima, Inc. + * + * 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 org.scalatestplus.play + +import org.scalatest._ +import org.scalatestplus.play.guice.GuiceOneAppPerSuite +import play.api.Application +import play.api.inject.guice._ +import java.util.concurrent.atomic.AtomicInteger +import org.scalatestplus.play.guice.GuiceOneServerPerSuite +import play.api.test.RunningServer + +object ConfiguredServerParallelSpec { + var timesApplicationIsBuilt = new AtomicInteger(0) + var timesServerIsStarted = new AtomicInteger(0) +} + +class ConfiguredServerParallelSpec + extends Suites(new ConfiguredServerParallelNestedSpec()) + with GuiceOneServerPerSuite { + import ConfiguredServerParallelSpec._ + + override def fakeApplication(): Application = { + timesApplicationIsBuilt.incrementAndGet() + GuiceApplicationBuilder().configure("foo" -> "bar").build() + } + + override def startTestServer: RunningServer = { + timesServerIsStarted.incrementAndGet() + super.startTestServer + } +} + +@DoNotDiscover +class ConfiguredServerParallelNestedSpec extends UnitSpec with ConfiguredServer with ParallelTestExecution { + import ConfiguredServerParallelSpec._ + + def getConfig(key: String)(implicit app: Application): Option[String] = app.configuration.getOptional[String](key) + + // Doesn't need synchronization because set by withFixture and checked by the test + // invoked inside same withFixture with super.withFixture(test) + var configMap: ConfigMap = _ + + override def withFixture(test: NoArgTest): Outcome = { + configMap = test.configMap + super.withFixture(test) + } + + "The ConfiguredServer trait, when running in parallel" must { + "provide an Application" in { + app.configuration.getOptional[String]("foo") mustBe Some("bar") + } + "make the Application available implicitly" in { + getConfig("foo") mustBe Some("bar") + } + "put the app in the configMap" in { + val configuredApp = configMap.getOptional[Application]("org.scalatestplus.play.app") + (configuredApp.value must be).theSameInstanceAs(app) + } + + "make the port available" in { + port must be > 0 + } + "put the port in the configMap" in { + val configuredPort = configMap.getOptional[Int]("org.scalatestplus.play.port") + (configuredPort.value must be > 0) + } + + //these two together assert that the app is only constructed once + "must reuse the same app between tests, run1" in { + timesApplicationIsBuilt.get mustBe 1 + } + "must reuse the same app between tests, run2" in { + timesApplicationIsBuilt.get mustBe 1 + } + + //these two together assert that the app is only constructed once + "must reuse the same server between tests, run1" in { + timesApplicationIsBuilt.get mustBe 1 + } + "must reuse the same server between tests, run2" in { + timesApplicationIsBuilt.get mustBe 1 + } + } +} diff --git a/module/src/test/scala/org/scalatestplus/play/ConfiguredServerSpec.scala b/module/src/test/scala/org/scalatestplus/play/ConfiguredServerSpec.scala index b868107f..29c70867 100644 --- a/module/src/test/scala/org/scalatestplus/play/ConfiguredServerSpec.scala +++ b/module/src/test/scala/org/scalatestplus/play/ConfiguredServerSpec.scala @@ -22,6 +22,34 @@ import play.api.inject.guice._ class ConfiguredServerSpec extends UnitSpec with SequentialNestedSuiteExecution with GuiceOneServerPerSuite { + // Doesn't need synchronization because set by withFixture and checked by the test + // invoked inside same withFixture with super.withFixture(test) + var configMap: ConfigMap = _ + + override def withFixture(test: NoArgTest): Outcome = { + configMap = test.configMap + super.withFixture(test) + } + + "provide an Application" in { + app.configuration.getOptional[String]("foo") mustBe Some("bar") + } + "make the Application available implicitly" in { + getConfig("foo") mustBe Some("bar") + } + "put the app in the configMap" in { + val configuredApp = configMap.getOptional[Application]("org.scalatestplus.play.app") + (configuredApp.value must be).theSameInstanceAs(app) + } + + "make the port available" in { + port must be > 0 + } + "put the port in the configMap" in { + val configuredPort = configMap.getOptional[Int]("org.scalatestplus.play.port") + (configuredPort.value must be > 0) + } + override def nestedSuites = Vector(new ConfiguredServerNestedSuite) override def fakeApplication(): Application = { diff --git a/module/src/test/scala/org/scalatestplus/play/OneAppPerSuiteParallelSpec.scala b/module/src/test/scala/org/scalatestplus/play/OneAppPerSuiteParallelSpec.scala new file mode 100644 index 00000000..0302f8fe --- /dev/null +++ b/module/src/test/scala/org/scalatestplus/play/OneAppPerSuiteParallelSpec.scala @@ -0,0 +1,65 @@ +/* + * Copyright 2001-2016 Artima, Inc. + * + * 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 org.scalatestplus.play + +import org.scalatest._ +import org.scalatestplus.play.guice.GuiceOneAppPerSuite +import play.api.Application +import play.api.inject.guice._ +import java.util.concurrent.atomic.AtomicInteger + +object OneAppPerSuiteParallelSpec { + var timesApplicationIsBuilt = new AtomicInteger(0) +} +class OneAppPerSuiteParallelSpec extends UnitSpec with GuiceOneAppPerSuite with ParallelTestExecution { + import OneAppPerSuiteParallelSpec._ + override def fakeApplication(): Application = { + timesApplicationIsBuilt.incrementAndGet() + GuiceApplicationBuilder().configure("foo" -> "bar").build() + } + + def getConfig(key: String)(implicit app: Application): Option[String] = app.configuration.getOptional[String](key) + + // Doesn't need synchronization because set by withFixture and checked by the test + // invoked inside same withFixture with super.withFixture(test) + var configMap: ConfigMap = _ + + override def withFixture(test: NoArgTest): Outcome = { + configMap = test.configMap + super.withFixture(test) + } + + "The GuiceOneAppPerSuite trait, when running in parallel" must { + "provide an Application" in { + app.configuration.getOptional[String]("foo") mustBe Some("bar") + } + "make the Application available implicitly" in { + getConfig("foo") mustBe Some("bar") + } + "put the app in the configMap" in { + val configuredApp = configMap.getOptional[Application]("org.scalatestplus.play.app") + (configuredApp.value must be).theSameInstanceAs(app) + } + + //these two together assert that the app is only constructed once + "must reuse the same app between tests, run1" in { + timesApplicationIsBuilt.get mustBe 1 + } + "must reuse the same app between tests, run2" in { + timesApplicationIsBuilt.get mustBe 1 + } + } +} diff --git a/module/src/test/scala/org/scalatestplus/play/OneAppPerTestSpec.scala b/module/src/test/scala/org/scalatestplus/play/OneAppPerTestSpec.scala index dce0152a..8e5927e6 100644 --- a/module/src/test/scala/org/scalatestplus/play/OneAppPerTestSpec.scala +++ b/module/src/test/scala/org/scalatestplus/play/OneAppPerTestSpec.scala @@ -20,7 +20,14 @@ import org.scalatestplus.play.guice.GuiceOneAppPerTest import play.api.Application import play.api.inject.guice._ -class OneAppPerTestSpec extends UnitSpec with GuiceOneAppPerTest { +class OneAppPerTestSpec extends UnitSpec with GuiceOneAppPerTest with BeforeAndAfterEachTestData { + + private var appFromBeforeEachTestData: Application = _ + + protected override def beforeEach(testData: TestData): Unit = { + super.beforeEach(testData) + appFromBeforeEachTestData = app + } override def newAppForTest(testData: TestData): Application = { GuiceApplicationBuilder().configure("foo" -> "bar").build() @@ -35,5 +42,8 @@ class OneAppPerTestSpec extends UnitSpec with GuiceOneAppPerTest { "make the Application available implicitly" in { getConfig("foo") mustBe Some("bar") } + "make the Application available in beforeEach(testData)" in { + appFromBeforeEachTestData mustBe app + } } } diff --git a/module/src/test/scala/org/scalatestplus/play/OneServerPerSuiteParallelSpec.scala b/module/src/test/scala/org/scalatestplus/play/OneServerPerSuiteParallelSpec.scala new file mode 100644 index 00000000..b9d320d4 --- /dev/null +++ b/module/src/test/scala/org/scalatestplus/play/OneServerPerSuiteParallelSpec.scala @@ -0,0 +1,88 @@ +/* + * Copyright 2001-2016 Artima, Inc. + * + * 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 org.scalatestplus.play + +import org.scalatest._ +import org.scalatestplus.play.guice.GuiceOneServerPerSuite +import play.api.Application +import play.api.inject.guice._ +import java.util.concurrent.atomic.AtomicInteger +import play.api.test.RunningServer + +object OneServerPerSuiteParallelSpec { + var timesApplicationIsBuilt = new AtomicInteger(0) + var timesServerIsStarted = new AtomicInteger(0) +} +class OneServerPerSuiteParallelSpec extends UnitSpec with GuiceOneServerPerSuite with ParallelTestExecution { + import OneServerPerSuiteParallelSpec._ + override def fakeApplication(): Application = { + timesApplicationIsBuilt.incrementAndGet() + GuiceApplicationBuilder().configure("foo" -> "bar").build() + } + + override def startTestServer: RunningServer = { + timesServerIsStarted.incrementAndGet() + super.startTestServer + } + + def getConfig(key: String)(implicit app: Application): Option[String] = app.configuration.getOptional[String](key) + + // Doesn't need synchronization because set by withFixture and checked by the test + // invoked inside same withFixture with super.withFixture(test) + var configMap: ConfigMap = _ + + override def withFixture(test: NoArgTest): Outcome = { + configMap = test.configMap + super.withFixture(test) + } + + "The GuiceOneServerPerSuite trait, when running in parallel" must { + "provide an Application" in { + app.configuration.getOptional[String]("foo") mustBe Some("bar") + } + "make the Application available implicitly" in { + getConfig("foo") mustBe Some("bar") + } + "put the app in the configMap" in { + val configuredApp = configMap.getOptional[Application]("org.scalatestplus.play.app") + (configuredApp.value must be).theSameInstanceAs(app) + } + + "make the port available" in { + port must be > 0 + } + "put the port in the configMap" in { + val configuredPort = configMap.getOptional[Int]("org.scalatestplus.play.port") + (configuredPort.value must be > 0) + } + + //these two together assert that the app is only constructed once + "must reuse the same app between tests, run1" in { + timesApplicationIsBuilt.get mustBe 1 + } + "must reuse the same app between tests, run2" in { + timesApplicationIsBuilt.get mustBe 1 + } + + //these two together assert that the app is only constructed once + "must reuse the same server between tests, run1" in { + timesApplicationIsBuilt.get mustBe 1 + } + "must reuse the same server between tests, run2" in { + timesApplicationIsBuilt.get mustBe 1 + } + } +} diff --git a/module/src/test/scala/org/scalatestplus/play/OneServerPerTestSpec.scala b/module/src/test/scala/org/scalatestplus/play/OneServerPerTestSpec.scala index 8ff8c8f5..cc92e9ad 100644 --- a/module/src/test/scala/org/scalatestplus/play/OneServerPerTestSpec.scala +++ b/module/src/test/scala/org/scalatestplus/play/OneServerPerTestSpec.scala @@ -19,8 +19,18 @@ import org.scalatest._ import org.scalatestplus.play.guice.GuiceOneServerPerTest import play.api.Application import play.api.inject.guice._ +import play.api.test.RunningServer -class OneServerPerTestSpec extends UnitSpec with GuiceOneServerPerTest { +class OneServerPerTestSpec extends UnitSpec with GuiceOneServerPerTest with BeforeAndAfterEach { + + private var serverFromBeforeEachTestData: RunningServer = _ + private var appFromBeforeEachTestData: Application = _ + + protected override def beforeEach(testData: TestData): Unit = { + super.beforeEach(testData) + appFromBeforeEachTestData = app + serverFromBeforeEachTestData = runningServer + } override def newAppForTest(testData: TestData): Application = { GuiceApplicationBuilder().configure("foo" -> "bar").build() @@ -35,6 +45,12 @@ class OneServerPerTestSpec extends UnitSpec with GuiceOneServerPerTest { "make the Application available implicitly" in { getConfig("foo") mustBe Some("bar") } + "make the Application available in beforeEach(testData)" in { + appFromBeforeEachTestData mustBe app + } + "make the Server available in beforeEach(testData)" in { + serverFromBeforeEachTestData mustBe runningServer + } "provide an http endpoint" in { runningServer.endpoints.httpEndpoint must not be empty }