From ce05d108712e372b8a6dd43d778a5c0228f65f07 Mon Sep 17 00:00:00 2001 From: Branko Juric Date: Thu, 24 Oct 2024 14:03:38 +1100 Subject: [PATCH] Manage settings internally without exposing them as system properties --- CHANGELOG | 5 +- .../scala/gwen/web/GwenWebInterpreter.scala | 10 ++-- .../scala/gwen/web/eval/WebSettings.scala | 4 +- .../resources/sample/settings/sample.json | 21 -------- .../sample/settings/sample.properties | 13 ----- src/test/scala/gwen/web/BaseTest.scala | 7 +-- .../gwen/web/eval/WebElementLocatorTest.scala | 2 +- .../scala/gwen/web/eval/WebEngineTest.scala | 14 ++--- .../scala/gwen/web/eval/WebSettingsTest.scala | 51 +++++++++++-------- .../gwen/web/features/BaseFeatureTest.scala | 4 +- 10 files changed, 57 insertions(+), 74 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 34351f58..027cccfa 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,12 +1,15 @@ 4.0.0 ===== -15 October 2024 +24 October 2024 - Introduce Gwen processes to support multiple launch configurations - `-p|--process` option - Require Java 17+ instead of Java 11+ - Use logback instead of log4j for logging - Support `empty` literal in DSLs wherever `blank` is accepted - Replace internal stack of data caches with a single data cache (internal enhancement) +- Internal engine enhancements + - Replace internal stack of data caches with a single data cache + - Manage settings internally without exposing them as system properties - Add implicit variable(s): - `gwen.process.name` - Add environment variable(s) diff --git a/src/main/scala/gwen/web/GwenWebInterpreter.scala b/src/main/scala/gwen/web/GwenWebInterpreter.scala index 08ab6469..83c2e1e6 100644 --- a/src/main/scala/gwen/web/GwenWebInterpreter.scala +++ b/src/main/scala/gwen/web/GwenWebInterpreter.scala @@ -18,12 +18,13 @@ package gwen.web import gwen.GwenInterpreter import gwen.core.Settings +import gwen.core.GwenOptions +import gwen.core.GwenSettings import gwen.web.init.WebProjectInitialiser import gwen.web.eval.WebBrowser import gwen.web.eval.WebEngine import gwen.web.eval.WebSettings -import gwen.core.GwenOptions import java.io.File @@ -44,12 +45,11 @@ object GwenWebInterpreter extends GwenInterpreter(new WebEngine()) with WebProje override def init(options: GwenOptions): GwenOptions = { val opts = if (!options.init) { - val conf = Some(Settings.BootstrapConf) - val baseDir = Settings.get("gwen.baseDir", None, conf) + val baseDir = GwenSettings.`gwen.baseDir` val browserConf = { val browsersDir = new File(new File(baseDir, "conf"), "browsers") if (browsersDir.exists && WebBrowser.findSettingsFile(options.settingsFiles).isEmpty) { - val targetBrowser = Settings.get(`gwen.target.browser`, None, conf) + val targetBrowser = Settings.get(`gwen.target.browser`) List("conf", "json", "properties") map { confType => new File(browsersDir, s"$targetBrowser.$confType") } find { conf => @@ -60,7 +60,7 @@ object GwenWebInterpreter extends GwenInterpreter(new WebEngine()) with WebProje val envConf = { val envDir = new File(new File(baseDir, "conf"), "env") if (envDir.exists && options.settingsFiles.filter(_.getPath.startsWith(s"$baseDir${File.separatorChar}env${File.separatorChar}")).isEmpty) { - val targetEnv = Settings.get(`gwen.target.env`, None, conf) + val targetEnv = Settings.get(`gwen.target.env`) List("conf", "json", "properties") map { confType => new File(envDir, s"$targetEnv.$confType") } find { conf => diff --git a/src/main/scala/gwen/web/eval/WebSettings.scala b/src/main/scala/gwen/web/eval/WebSettings.scala index 29fd51b9..c8cafe67 100644 --- a/src/main/scala/gwen/web/eval/WebSettings.scala +++ b/src/main/scala/gwen/web/eval/WebSettings.scala @@ -219,7 +219,7 @@ object WebSettings extends LazyLogging { */ def `gwen.web.capture.screenshots.enabled`: Boolean = { Settings.getBoolean("gwen.web.capture.screenshots.enabled", Some("gwen.web.capture.screenshots")) tap { isSet => - if (isSet) Settings.set("gwen.report.slideshow.create", true.toString) + if (isSet) sys.props += (("gwen.report.slideshow.create", true.toString)) } } @@ -233,7 +233,7 @@ object WebSettings extends LazyLogging { */ def `gwen.web.capture.screenshots.highlighting`: Boolean = { Settings.getBoolean("gwen.web.capture.screenshots.highlighting") tap { isSet => - if (isSet) Settings.set("gwen.report.slideshow.create", true.toString) + if (isSet) sys.props += (("gwen.report.slideshow.create", true.toString)) } } diff --git a/src/test/resources/sample/settings/sample.json b/src/test/resources/sample/settings/sample.json index 41c7ea9c..18557080 100644 --- a/src/test/resources/sample/settings/sample.json +++ b/src/test/resources/sample/settings/sample.json @@ -1,10 +1,4 @@ { - "rp": { - "endpoint": "http://:", - "uuid": "28b262e7-8a9d-4928-b2a3-649562d5c63d", - "project": "default_personal", - "launch": "Gwen" - }, "gwen": { "behavior": { "rules": "strict" @@ -12,21 +6,6 @@ "report": { "overwrite": false }, - "rp": { - "heartbeat": { - "timeoutSecs": 5 - }, - "send": { - "failed": { - "errorBlocks": "leaf", - "stepDefs": "none" - }, - "stepDefs": "inlined" - }, - "testCaseId": { - "keys": "auto" - } - }, "web": { "sendKeys": { "clearFirst": false, diff --git a/src/test/resources/sample/settings/sample.properties b/src/test/resources/sample/settings/sample.properties index 7dd29865..a9c72669 100644 --- a/src/test/resources/sample/settings/sample.properties +++ b/src/test/resources/sample/settings/sample.properties @@ -1,20 +1,7 @@ -# RP client settings -rp.endpoint = http://localhost:8080 -rp.uuid = 28b262e7-8a9d-4928-b2a3-649562d5c63d -rp.project = default_personal -rp.launch = Gwen - # Gwen core settings gwen.behavior.rules = strict gwen.report.overwrite = false -# Gwen RP settings -gwen.rp.heartbeat.timeoutSecs = 5 -gwen.rp.send.failed.errorBlocks = leaf -gwen.rp.send.failed.stepDefs = none -gwen.rp.send.stepDefs = inlined -gwen.rp.testCaseId.keys = auto - # Chrome settings gwen.web.chrome.args.0000000000 = --ignore-certificate-errors gwen.web.chrome.args.0000000001 = --window-size=1920,1080 diff --git a/src/test/scala/gwen/web/BaseTest.scala b/src/test/scala/gwen/web/BaseTest.scala index ffc1e611..1700033e 100644 --- a/src/test/scala/gwen/web/BaseTest.scala +++ b/src/test/scala/gwen/web/BaseTest.scala @@ -35,11 +35,12 @@ abstract class BaseTest extends AnyFlatSpec { Settings.exclusively { val original = Settings.getOpt(name) try { - Settings.set(name, value) + sys.props += ((name, value)) + Settings.init() body } finally { - original.fold(Settings.clear(name)) { v => - Settings.set(name, v) + original.fold(sys.props -= name) { v => + sys.props += ((name, v)) } } } diff --git a/src/test/scala/gwen/web/eval/WebElementLocatorTest.scala b/src/test/scala/gwen/web/eval/WebElementLocatorTest.scala index 5af0ffcf..bc0142ab 100644 --- a/src/test/scala/gwen/web/eval/WebElementLocatorTest.scala +++ b/src/test/scala/gwen/web/eval/WebElementLocatorTest.scala @@ -53,7 +53,7 @@ import org.scalatest.matchers.should.Matchers class WebElementLocatorTest extends BaseTest with Matchers with MockitoSugar with BeforeAndAfterEach { // disable implicit js locators for unit test - Settings.set("gwen.web.implicit.js.locators", "false") + sys.props += (("gwen.web.implicit.js.locators", "false")) private var mockWebElement: WebElement = uninitialized private var mockWebElements: List[WebElement] = uninitialized diff --git a/src/test/scala/gwen/web/eval/WebEngineTest.scala b/src/test/scala/gwen/web/eval/WebEngineTest.scala index 14985907..0f9ab258 100644 --- a/src/test/scala/gwen/web/eval/WebEngineTest.scala +++ b/src/test/scala/gwen/web/eval/WebEngineTest.scala @@ -1000,17 +1000,19 @@ class WebEngineTest extends BaseTest with Matchers with MockitoSugar with Before """ be defined by property """"" should "evaluate" in { List("is", "will be").zipWithIndex.foreach { case (x, i) => - Settings.set(s"name-$i", s"$i") - evaluate(s"""attribute-$i $x defined by property "name-$i"""") - verify(mockTopScope).set(s"attribute-$i", s"$i") + withSetting(s"name-$i", s"$i") { + evaluate(s"""attribute-$i $x defined by property "name-$i"""") + verify(mockTopScope).set(s"attribute-$i", s"$i") + } } } """ be defined by setting """"" should "evaluate" in { List("is", "will be").zipWithIndex.foreach { case (x, i) => - Settings.set(s"name-$i", s"$i") - evaluate(s"""attribute-$i $x defined by setting "name-$i"""") - verify(mockTopScope).set(s"attribute-$i", s"$i") + withSetting(s"name-$i", s"$i") { + evaluate(s"""attribute-$i $x defined by setting "name-$i"""") + verify(mockTopScope).set(s"attribute-$i", s"$i") + } } } diff --git a/src/test/scala/gwen/web/eval/WebSettingsTest.scala b/src/test/scala/gwen/web/eval/WebSettingsTest.scala index 0bef4b22..edba9a73 100644 --- a/src/test/scala/gwen/web/eval/WebSettingsTest.scala +++ b/src/test/scala/gwen/web/eval/WebSettingsTest.scala @@ -21,7 +21,6 @@ import gwen.web._ import gwen.core.AssertionMode import gwen.core.GwenOptions import gwen.core.GwenSettings -import gwen.core.BootstrapSettings import gwen.core.Settings import gwen.core.behavior.BehaviorMode import gwen.core.behavior.FeatureMode @@ -76,6 +75,7 @@ class WebSettingsTest extends BaseTest with Matchers with MockitoSugar { GwenSettings.`gwen.dryRun.limit.tableData.outline.examples.records` should be (Integer.MAX_VALUE) GwenSettings.`gwen.error.messages.inline.locators` should be (false) GwenSettings.`gwen.logLevel.deprecations` should be (Level.SEVERE) + GwenSettings.`gwen.launch.options.format` should be (List(ReportFormat.html, ReportFormat.results)) } } @@ -126,9 +126,17 @@ class WebSettingsTest extends BaseTest with Matchers with MockitoSugar { Settings.exclusively { withSetting("gwen.initDir", ".") { Settings.init( - new File("src/main/resources/init/gwen.conf"), - new File("src/main/resources/init/conf/browsers/chrome.conf")) - assertInitConf(".", "target") + List( + new File("src/main/resources/init/gwen.conf"), + new File("src/main/resources/init/conf/browsers/chrome.conf") + ) + ) + assertInitConf() + GwenSettings.`gwen.auto.discover.data.csv` should be (false) + GwenSettings.`gwen.behavior.rules` should be (BehaviorMode.strict) + GwenSettings.`gwen.feature.mode` should be (FeatureMode.declarative) + GwenSettings.`gwen.baseDir`.getPath should be (".") + GwenSettings.`gwen.outDir`.getPath should be ("output") } } } @@ -137,31 +145,34 @@ class WebSettingsTest extends BaseTest with Matchers with MockitoSugar { Settings.exclusively { withSetting("gwen.initDir", "gwen") { Settings.init( - new File("src/main/resources/init/gwen.conf"), - new File("src/main/resources/init/conf/browsers/chrome.conf")) - assertInitConf("gwen", "target") + List( + new File("src/main/resources/init/gwen.conf"), + new File("src/main/resources/init/conf/browsers/chrome.conf") + ) + ) + assertInitConf() + GwenSettings.`gwen.auto.discover.data.csv` should be (false) + GwenSettings.`gwen.behavior.rules` should be (BehaviorMode.strict) + GwenSettings.`gwen.feature.mode` should be (FeatureMode.declarative) + GwenSettings.`gwen.baseDir`.getPath should be ("gwen") + GwenSettings.`gwen.outDir`.getPath should be ("gwen/output") } } } - private def assertInitConf(expectedBaseDir: String, expectedOutDir: String): Unit = { + private def assertInitConf(): Unit = { GwenSettings.`gwen.assertion.mode` should be (AssertionMode.hard) GwenSettings.`gwen.associative.meta` should be (true) GwenSettings.`gwen.auto.bind.tableData.outline.examples` should be (true) - GwenSettings.`gwen.auto.discover.data.csv` should be (true) GwenSettings.`gwen.auto.discover.data.json` should be (false) GwenSettings.`gwen.auto.discover.meta` should be (true) GwenSettings.`gwen.auto.trim.data.csv` should be (false) GwenSettings.`gwen.auto.trim.data.json` should be (false) - GwenSettings.`gwen.behavior.rules` should be (BehaviorMode.lenient) GwenSettings.`gwen.feature.dialect` should be ("en") GwenSettings.`gwen.feature.failfast.enabled` should be (true) GwenSettings.`gwen.feature.failfast.exit` should be (false) - GwenSettings.`gwen.feature.mode` should be (FeatureMode.imperative) GwenSettings.`gwen.mask.char` should be ('*') - GwenSettings.`gwen.baseDir`.getPath should be (expectedBaseDir) - GwenSettings.`gwen.outDir`.getPath should be (expectedOutDir) GwenSettings.`gwen.parallel.maxThreads` should be (GwenSettings.availableProcessors) GwenSettings.`gwen.rampup.interval.seconds` should be (None) GwenSettings.`gwen.report.overwrite` should be (false) @@ -178,7 +189,7 @@ class WebSettingsTest extends BaseTest with Matchers with MockitoSugar { GwenSettings.`gwen.console.repl.tabCompletion` should be (true) GwenSettings.`gwen.logLevel.deprecations` should be (Level.SEVERE) - BootstrapSettings.`gwen.launch.options.format` should be (List(ReportFormat.html, ReportFormat.results)) + GwenSettings.`gwen.launch.options.format` should be (List(ReportFormat.html)) WebSettings.`gwen.target.browser` should be (WebBrowser.chrome) WebSettings.`gwen.target.env` should be ("test") @@ -223,21 +234,21 @@ class WebSettingsTest extends BaseTest with Matchers with MockitoSugar { "Sample migration .conf" should "should override defaults" in { Settings.exclusively { - Settings.init(new File("src/test/resources/sample/settings/sample.conf")) + Settings.init(List(new File("src/test/resources/sample/settings/sample.conf"))) assertMigrationSample() } } "Sample migration .json" should "should override defaults" in { Settings.exclusively { - Settings.init(new File("src/test/resources/sample/settings/sample.json")) + Settings.init(List(new File("src/test/resources/sample/settings/sample.json"))) assertMigrationSample() } } "Sample migration .properties" should "should override defaults" in { Settings.exclusively { - Settings.init(new File("src/test/resources/sample/settings/sample.properties")) + Settings.init(List(new File("src/test/resources/sample/settings/sample.properties"))) assertMigrationSample() } } @@ -251,7 +262,7 @@ class WebSettingsTest extends BaseTest with Matchers with MockitoSugar { GwenSettings.`gwen.auto.discover.meta` should be (true) GwenSettings.`gwen.auto.trim.data.csv` should be (false) GwenSettings.`gwen.auto.trim.data.json` should be (false) - GwenSettings.`gwen.behavior.rules` should be (BehaviorMode.lenient) + GwenSettings.`gwen.behavior.rules` should be (BehaviorMode.strict) GwenSettings.`gwen.feature.dialect` should be ("en") GwenSettings.`gwen.feature.failfast.enabled` should be (true) GwenSettings.`gwen.feature.failfast.exit` should be (false) @@ -323,8 +334,8 @@ class WebSettingsTest extends BaseTest with Matchers with MockitoSugar { "Results files in gwen init conf" should "resolve" in { Settings.exclusively { withSetting("gwen.initDir", "gwen") { - Settings.init(new File("src/main/resources/init/gwen.conf")) - val resDir = "target/reports/results" + Settings.init(List(new File("src/main/resources/init/gwen.conf"))) + val resDir = "gwen/output/reports/results" val resFiles = GwenSettings.`gwen.report.results.files`(GwenOptions()) resFiles.size should be (7) val fPassed = resFiles.find(_.id == "feature.passed").get diff --git a/src/test/scala/gwen/web/features/BaseFeatureTest.scala b/src/test/scala/gwen/web/features/BaseFeatureTest.scala index bcd581b3..19374b7e 100644 --- a/src/test/scala/gwen/web/features/BaseFeatureTest.scala +++ b/src/test/scala/gwen/web/features/BaseFeatureTest.scala @@ -20,7 +20,7 @@ import gwen.web.BaseTest import gwen.web.GwenWebInterpreter import gwen.core.GwenOptions -import gwen.core.BootstrapSettings +import gwen.core.GwenSettings import gwen.core.Settings import gwen.core.behavior.BehaviorMode import gwen.core.status.Passed @@ -39,7 +39,7 @@ abstract class BaseFeatureTest extends BaseTest { if (dataFile.nonEmpty) args = args ++ Array("-i", dataFile.get) if (BehaviorMode.isStrict) args = args ++ Array("-t", "~@Lenient") args = args ++ features.toArray.asInstanceOf[Array[String]] - val options = GwenOptions(args, BootstrapSettings.`gwen.baseDir`) + val options = GwenOptions(args, GwenSettings.`gwen.baseDir`) val interpreter = GwenWebInterpreter interpreter.run(options, None) match { case _: Passed => // woo hoo