GaleniumConfiguration.java
/*
* #%L
* wcm.io
* %%
* Copyright (C) 2017 wcm.io
* %%
* 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.
* #L%
*/
package io.wcm.qa.glnm.configuration;
/**
* Central place to integrate test run and environment configuration from Maven et al.
*
* @since 1.0.0
*/
public final class GaleniumConfiguration {
private static final String DEFAULT_AUTHOR_PASS = "admin";
private static final String DEFAULT_AUTHOR_USER = "admin";
private static final String DEFAULT_BASE_URL = "http://localhost:4502";
private static final int DEFAULT_GRID_PORT = 4444;
private static final String DEFAULT_MEDIA_QUERY_PATH = "/mediaqueries.properties";
private static final String DEFAULT_REPORT_DIR = "./target/glnm-reports";
private static final String DEFAULT_SPEC_PATH = "/galen/specs";
private static final int DEFAULT_WEBDRIVER_TIMEOUT = 10;
private static final String SYSTEM_PROPERTY_NAME_AUTHOR_PASS = "io.wcm.qa.aem.author.pass";
private static final String SYSTEM_PROPERTY_NAME_AUTHOR_USER = "io.wcm.qa.aem.author.user";
private static final String SYSTEM_PROPERTY_NAME_BASE_URL = "io.wcm.qa.baseUrl";
private static final String SYSTEM_PROPERTY_NAME_CHROME_BINARY_PATH = "galenium.webdriver.chrome.binary";
private static final String SYSTEM_PROPERTY_NAME_GALEN_JS_TEST_PATH = "galenium.jsTestPath";
private static final String SYSTEM_PROPERTY_NAME_GALEN_SPEC_PATH = "galenium.specPath";
private static final String SYSTEM_PROPERTY_NAME_GALEN_SUPPRESS_AUTO_ADJUST_BROWSERSIZE = "galenium.suppressAutoAdjustBrowserSize";
private static final String SYSTEM_PROPERTY_NAME_HEADLESS = "galenium.headless";
private static final String SYSTEM_PROPERTY_NAME_HTTP_PASS = "io.wcm.qa.http.pass";
private static final String SYSTEM_PROPERTY_NAME_HTTP_USER = "io.wcm.qa.http.user";
private static final String SYSTEM_PROPERTY_NAME_LAZY_DRIVER = "galenium.webdriver.lazy";
private static final String SYSTEM_PROPERTY_NAME_LOG_DIR = "galenium.logging.testlogs";
private static final String SYSTEM_PROPERTY_NAME_MEDIA_QUERY_HEIGHT = "galenium.mediaquery.height";
private static final String SYSTEM_PROPERTY_NAME_MEDIA_QUERY_PROPERTIES = "galenium.mediaquery.properties";
private static final String SYSTEM_PROPERTY_NAME_MEDIA_QUERY_WIDTH_MAX = "galenium.mediaquery.width.max";
private static final String SYSTEM_PROPERTY_NAME_MEDIA_QUERY_WIDTH_MIN = "galenium.mediaquery.width.min";
private static final String SYSTEM_PROPERTY_NAME_REPORT_DIRECTORY = "galenium.report.rootPath";
private static final String SYSTEM_PROPERTY_NAME_REPORT_ERRORS_ONLY = "galenium.report.galen.errorsOnly";
private static final String SYSTEM_PROPERTY_NAME_REPORT_SKIP_EXTENT = "galenium.report.extent.skip";
private static final String SYSTEM_PROPERTY_NAME_RETRY_BROWSER_INSTANTIATION_MAX = "galenium.webdriver.retryMax";
private static final String SYSTEM_PROPERTY_NAME_RETRY_MAX = "galenium.retryMax";
private static final String SYSTEM_PROPERTY_NAME_SAMPLING_IMAGE_CHROMEFIX = "galenium.sampling.image.chromefix";
private static final String SYSTEM_PROPERTY_NAME_SAMPLING_IMAGE_DIRECTORY_ACTUAL = "galenium.sampling.image.directory.actual";
private static final String SYSTEM_PROPERTY_NAME_SAMPLING_IMAGE_DIRECTORY_EXPECTED = "galenium.sampling.image.directory.expected";
private static final String SYSTEM_PROPERTY_NAME_SAMPLING_TEXT_OUTPUT_DIRECTORY = "galenium.sampling.text.directory.actual";
private static final String SYSTEM_PROPERTY_NAME_SAMPLING_VERIFICATION_IGNORE_ERRORS = "galenium.sampling.verification.ignoreErrors";
private static final String SYSTEM_PROPERTY_NAME_SCREENSHOT_ON_SKIPPED = "galenium.screenshotOnSkipped";
private static final String SYSTEM_PROPERTY_NAME_SCREENSHOT_ON_SUCCESS = "galenium.screenshotOnSuccess";
private static final String SYSTEM_PROPERTY_NAME_SELENIUM_HOST = "selenium.host";
private static final String SYSTEM_PROPERTY_NAME_SELENIUM_PORT = "selenium.port";
private static final String SYSTEM_PROPERTY_NAME_SPARSE_REPORTING = "galenium.report.sparse";
private static final String SYSTEM_PROPERTY_NAME_WEB_DRIVER_ALWAYS_NEW = "galenium.webdriver.alwaysNew";
private static final String SYSTEM_PROPERTY_NAME_WEB_DRIVER_SSL_REFUSE = "galenium.webdriver.ssl.refuse";
private static final String SYSTEM_PROPERTY_NAME_WEB_DRIVER_SSL_TRUSTED_ONLY = "galenium.webdriver.ssl.trusted";
private static final String SYSTEM_PROPERTY_NAME_WEB_DRIVER_TIMEOUT = "galenium.webdriver.timeout";
private GaleniumConfiguration() {
// do not instantiate
}
/**
* The root directory for storing sample images of current run.
* <ul>
* <li>Key:
*
* <pre>
* galenium.sampling.image.directory.actual
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* "./target/galenium-reports"
* </pre>
*
* </li>
* </ul>
*
* @return path to root folder
* @since 3.0.0
*/
public static String getActualImagesDirectory() {
return asString(SYSTEM_PROPERTY_NAME_SAMPLING_IMAGE_DIRECTORY_ACTUAL, DEFAULT_REPORT_DIR);
}
/**
* Password to use when logging into author.
* <ul>
* <li>Key:
*
* <pre>
* io.wcm.qa.aem.author.pass
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* "admin"
* </pre>
*
* </li>
* </ul>
*
* @return password to author instance
* @since 3.0.0
*/
public static String getAuthorPass() {
return asString(SYSTEM_PROPERTY_NAME_AUTHOR_PASS, DEFAULT_AUTHOR_PASS);
}
/**
* Username to use when logging into author.
* <ul>
* <li>Key:
*
* <pre>
* io.wcm.qa.aem.author.user
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* "admin"
* </pre>
*
* </li>
* </ul>
*
* @return username for author instance
* @since 3.0.0
*/
public static String getAuthorUser() {
return asString(SYSTEM_PROPERTY_NAME_AUTHOR_USER, DEFAULT_AUTHOR_USER);
}
/**
* The base URL to use when running tests. This is the URL called from the browsers when controlled by Selenium. You
* can add basic HTTP auth if needed for your SUTs.
* <ul>
* <li>Key:
*
* <pre>
* io.wcm.qa.baseUrl
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* "http://localhost:4502"
* </pre>
*
* </li>
* </ul>
*
* @return base URL with HTTP basic auth, if configured
* @since 3.0.0
*/
public static String getBaseUrl() {
return asString(SYSTEM_PROPERTY_NAME_BASE_URL, DEFAULT_BASE_URL);
}
/**
* Path to Chrome binary which is passed to driver.
* <ul>
* <li>Key:
*
* <pre>
* galenium.webdriver.chrome.binary
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* null
* </pre>
*
* </li>
* </ul>
*
* @return path to chrome binary or null
* @since 3.0.0
*/
public static String getChromeBinaryPath() {
return asString(SYSTEM_PROPERTY_NAME_CHROME_BINARY_PATH);
}
/**
* Default timeout for webdriver in seconds.
* <ul>
* <li>Key:
*
* <pre>
* galenium.webdriver.timeout
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* 10
* </pre>
*
* </li>
* </ul>
*
* @return default timeout used by Galenium
* @since 3.0.0
*/
public static int getDefaultWebdriverTimeout() {
return asInteger(SYSTEM_PROPERTY_NAME_WEB_DRIVER_TIMEOUT, DEFAULT_WEBDRIVER_TIMEOUT);
}
/**
* Path to root folder of expected image samples to verify against.
* <ul>
* <li>Key:
*
* <pre>
* galenium.sampling.image.directory.expected
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* "./target/specs"
* </pre>
*
* </li>
* </ul>
*
* @return path to root folder of expected image samples
* @since 3.0.0
*/
public static String getExpectedImagesDirectory() {
return asString(SYSTEM_PROPERTY_NAME_SAMPLING_IMAGE_DIRECTORY_EXPECTED, DEFAULT_SPEC_PATH);
}
/**
* Path to root folder containing Galen JS tests.
* <ul>
* <li>Key:
*
* <pre>
* galenium.jsTestPath
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* {@link #getGalenSpecPath()}
* </pre>
*
* </li>
* </ul>
*
* @return path to root folder of Galen JS tests
* @since 3.0.0
*/
public static String getGalenJsTestPath() {
return asString(SYSTEM_PROPERTY_NAME_GALEN_JS_TEST_PATH, getGalenSpecPath());
}
/**
* Path to root folder containing Galen specs.
* <ul>
* <li>Key:
*
* <pre>
* galenium.specPath
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* "./target/specs"
* </pre>
*
* </li>
* </ul>
*
* @return path to root folder of Galen specs
* @since 3.0.0
*/
public static String getGalenSpecPath() {
return asString(SYSTEM_PROPERTY_NAME_GALEN_SPEC_PATH, DEFAULT_SPEC_PATH);
}
/**
* Selenium Grid hostname or address.
* <ul>
* <li>Key:
*
* <pre>
* selenium.host
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* null
* </pre>
*
* </li>
* </ul>
*
* @return Selenium Grid host
* @since 3.0.0
*/
public static String getGridHost() {
return asString(SYSTEM_PROPERTY_NAME_SELENIUM_HOST);
}
/**
* Selenium Grid port number.
* <ul>
* <li>Key:
*
* <pre>
* selenium.port
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* 4444
* </pre>
*
* </li>
* </ul>
*
* @return Selenium Grid port number
* @since 3.0.0
*/
public static int getGridPort() {
return asInteger(SYSTEM_PROPERTY_NAME_SELENIUM_PORT, DEFAULT_GRID_PORT);
}
/**
* HTTP password to use in HTTP basic auth.
* <ul>
* <li>Key:
*
* <pre>
* io.wcm.qa.http.pass
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* null
* </pre>
*
* </li>
* </ul>
*
* @return HTTP password
* @since 3.0.0
*/
public static String getHttpPass() {
return asString(SYSTEM_PROPERTY_NAME_HTTP_PASS);
}
/**
* HTTP username to use in HTTP basic auth.
* <ul>
* <li>Key:
*
* <pre>
* io.wcm.qa.http.user
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* null
* </pre>
*
* </li>
* </ul>
*
* @return HTTP username
* @since 3.0.0
*/
public static String getHttpUser() {
return asString(SYSTEM_PROPERTY_NAME_HTTP_USER);
}
/**
* Height to use when instantiating devices using media queries.
* <ul>
* <li>Key:
*
* <pre>
* galenium.mediaquery.height
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* 800
* </pre>
*
* </li>
* </ul>
*
* @return height for use with device creation
* @since 3.0.0
*/
public static Integer getMediaQueryHeight() {
return asInteger(SYSTEM_PROPERTY_NAME_MEDIA_QUERY_HEIGHT, 800);
}
/**
* Height to use when instantiating devices using media queries.
* <ul>
* <li>Key:
*
* <pre>
* galenium.mediaquery.width.max
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* 2000
* </pre>
*
* </li>
* </ul>
*
* @return minimal width to use with media query instantiation
* @since 3.0.0
*/
public static Integer getMediaQueryMaximalWidth() {
return asInteger(SYSTEM_PROPERTY_NAME_MEDIA_QUERY_WIDTH_MAX, 2000);
}
/**
* Height to use when instantiating devices using media queries.
* <ul>
* <li>Key:
*
* <pre>
* galenium.mediaquery.width.min
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* 320
* </pre>
*
* </li>
* </ul>
*
* @return minimal width to use with media query instantiation
* @since 3.0.0
*/
public static Integer getMediaQueryMinimalWidth() {
return asInteger(SYSTEM_PROPERTY_NAME_MEDIA_QUERY_WIDTH_MIN, 320);
}
/**
* Path to media query definitions.
* <ul>
* <li>Key:
*
* <pre>
* galenium.mediaquery.properties
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* ./target/test-classes/mediaqueries.properties
* </pre>
*
* </li>
* </ul>
*
* @return path to {@link java.util.Properties} file containing media query definitions
* @since 3.0.0
*/
public static String getMediaQueryPropertiesPath() {
return asString(SYSTEM_PROPERTY_NAME_MEDIA_QUERY_PROPERTIES, DEFAULT_MEDIA_QUERY_PATH);
}
/**
* Number of retries when instantiating browsers. Use this to handle flaky browser initializations.
* <ul>
* <li>Key:
*
* <pre>
* galenium.webdriver.retryMax
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* 0
* </pre>
*
* </li>
* </ul>
*
* @return HTTP username
* @since 3.0.0
*/
public static int getNumberOfBrowserInstantiationRetries() {
return asInteger(SYSTEM_PROPERTY_NAME_RETRY_BROWSER_INSTANTIATION_MAX, 0);
}
/**
* Number of retries for failed tests. Use this to handle flaky test results.
* <ul>
* <li>Key:
*
* <pre>
* galenium.retryMax
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* 2
* </pre>
*
* </li>
* </ul>
*
* @return maximum number of retries
* @since 3.0.0
*/
public static int getNumberOfRetries() {
return asInteger(SYSTEM_PROPERTY_NAME_RETRY_MAX, 2);
}
/**
* Report root folder.
* <ul>
* <li>Key:
*
* <pre>
* galenium.report.rootPath
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* "./target/galenium-reports"
* </pre>
*
* </li>
* </ul>
*
* @return root folder for storing report artefacts
* @since 3.0.0
*/
public static String getReportDirectory() {
return asString(SYSTEM_PROPERTY_NAME_REPORT_DIRECTORY, DEFAULT_REPORT_DIR);
}
/**
* Test log root folder.
* <ul>
* <li>Key:
*
* <pre>
* galenium.logging.testlogs
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* "./target/testlogs"
* </pre>
*
* </li>
* </ul>
*
* @return root folder for storing test logs
*/
public static String getTestLogDirectory() {
return asString(SYSTEM_PROPERTY_NAME_LOG_DIR, "target/testlogs");
}
/**
* Directory to retrieve the text samples from.
* <ul>
* <li>Key:
*
* <pre>
* galenium.sampling.text.directory.actual
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* "./target/sampled"
* </pre>
*
* </li>
* </ul>
*
* @return output directory for new baseline samples
* @since 3.0.0
*/
public static String getTextComparisonOutputDirectory() {
return asString(SYSTEM_PROPERTY_NAME_SAMPLING_TEXT_OUTPUT_DIRECTORY, "./target/sampled");
}
/**
* Headless Chrome Windows workaround flag.
* <ul>
* <li>Key:
*
* <pre>
* galenium.sampling.image.chromefix
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* true
* </pre>
*
* </li>
* </ul>
*
* @return whether to use workaround to fix Chrome's image comparison behavior
* @since 3.0.0
*/
public static boolean isFixChromeImageComparison() {
if (asString(SYSTEM_PROPERTY_NAME_SAMPLING_IMAGE_CHROMEFIX) == null) {
// default is to fix chrome behavior
return true;
}
return asBoolean(SYSTEM_PROPERTY_NAME_SAMPLING_IMAGE_CHROMEFIX);
}
/**
* Headless browser flag.
* <ul>
* <li>Key:
*
* <pre>
* galenium.headless
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* false
* </pre>
*
* </li>
* </ul>
*
* @return whether browser is running in headless mode
* @since 3.0.0
*/
public static boolean isHeadless() {
return asBoolean(SYSTEM_PROPERTY_NAME_HEADLESS);
}
/**
* Lazy web driver intialization takes control away from WebDriverListener and lets the test itself decide
* when or whether to initialize a webdriver.
* <ul>
* <li>Key:
*
* <pre>
* galenium.webdriver.lazy
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* false
* </pre>
*
* </li>
* </ul>
*
* @return whether to use lazy web driver initialization
* @since 3.0.0
*/
public static boolean isLazyWebDriverInitialization() {
return asBoolean(SYSTEM_PROPERTY_NAME_LAZY_DRIVER);
}
/**
* Only report Galen errors and leave successful tests out of report. This drastically reduces the size of reports in
* the target folder. Useful to save disk space on CI.
* <ul>
* <li>Key:
*
* <pre>
* galenium.report.galen.errorsOnly
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* false
* </pre>
*
* </li>
* </ul>
*
* @return whether to skip reporting of successful tests
* @since 3.0.0
*/
public static boolean isOnlyReportGalenErrors() {
return asBoolean(SYSTEM_PROPERTY_NAME_REPORT_ERRORS_ONLY);
}
/**
* Ignore sampling verification errors and continue running test. This is useful when generating initial samples.
* <ul>
* <li>Key:
*
* <pre>
* galenium.sampling.verification.ignoreErrors
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* false
* </pre>
*
* </li>
* </ul>
*
* @return whether to ignore errors when validating samples
* @since 3.0.0
*/
public static boolean isSamplingVerificationIgnore() {
return asBoolean(SYSTEM_PROPERTY_NAME_SAMPLING_VERIFICATION_IGNORE_ERRORS);
}
/**
* Usually Galenium will log to ExtentReports, but it can be skipped.
* <ul>
* <li>Key:
*
* <pre>
* galenium.report.extent.skip
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* false
* </pre>
*
* </li>
* </ul>
*
* @return whether TestNG is used
* @since 3.0.0
*/
public static boolean isSkipExtentReports() {
return asBoolean(SYSTEM_PROPERTY_NAME_REPORT_SKIP_EXTENT);
}
/**
* Sparse reporting is a different set of logging configuration. This allows to configure to different kinds of
* reporting for local development with more debugging needs and for CI which should give you a quick view of the
* important test steps and their results.
* <ul>
* <li>Key:
*
* <pre>
* galenium.report.sparse
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* false
* </pre>
*
* </li>
* </ul>
*
* @return whether to use sparse reporting on this run
* @since 3.0.0
*/
public static boolean isSparseReporting() {
return asBoolean(SYSTEM_PROPERTY_NAME_SPARSE_REPORTING);
}
/**
* Adjusting the browser size is important to ensure the correct viewport size, but it can lead to problems with
* certain browser/driver/OS combinations.
* <ul>
* <li>Key:
*
* <pre>
* galenium.suppressAutoAdjustBrowserSize
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* false
* </pre>
*
* </li>
* </ul>
*
* @return whether to skip automatic adjusting of browser size
* @since 3.0.0
*/
public static boolean isSuppressAutoAdjustBrowserSize() {
return asBoolean(SYSTEM_PROPERTY_NAME_GALEN_SUPPRESS_AUTO_ADJUST_BROWSERSIZE);
}
/**
* Take screenshots for skipped tests.
* <ul>
* <li>Key:
*
* <pre>
* galenium.screenshotOnSkipped
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* false
* </pre>
*
* </li>
* </ul>
*
* @return whether to take and store screenshots of skipped tests for reporting
* @since 3.0.0
*/
public static boolean isTakeScreenshotOnSkippedTest() {
return asBoolean(SYSTEM_PROPERTY_NAME_SCREENSHOT_ON_SKIPPED);
}
/**
* Take screenshots for successful tests.
* <ul>
* <li>Key:
*
* <pre>
* galenium.screenshotOnSuccess
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* false
* </pre>
*
* </li>
* </ul>
*
* @return whether to take and store screenshots of successful tests for reporting
* @since 3.0.0
*/
public static boolean isTakeScreenshotOnSuccessfulTest() {
return asBoolean(SYSTEM_PROPERTY_NAME_SCREENSHOT_ON_SUCCESS);
}
/**
* Control whether to only accept secure SSL certificates
* <ul>
* <li>Key:
*
* <pre>
* galenium.webdriver.ssl.trusted
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* false
* </pre>
*
* </li>
* </ul>
*
* @return whether browser accepts secure SSL certificates only
* @since 3.0.0
*/
public static boolean isWebDriverAcceptTrustedSslCertificatesOnly() {
return asBoolean(SYSTEM_PROPERTY_NAME_WEB_DRIVER_SSL_TRUSTED_ONLY);
}
/**
* Control whether to attempt reuse of drivers.
* <ul>
* <li>Key:
*
* <pre>
* galenium.webdriver.alwaysNew
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* false
* </pre>
*
* </li>
* </ul>
*
* @return whether to always instantiate a new webdriver for each test
* @since 3.0.0
*/
public static boolean isWebDriverAlwaysNew() {
return asBoolean(SYSTEM_PROPERTY_NAME_WEB_DRIVER_ALWAYS_NEW);
}
/**
* Control whether to refuse SSL certificates
* <ul>
* <li>Key:
*
* <pre>
* galenium.webdriver.ssl.refuse
* </pre>
*
* </li>
* <li>
* Default:
*
* <pre>
* false
* </pre>
*
* </li>
* </ul>
*
* @return whether browser refuses SSL certificates
* @since 3.0.0
*/
public static boolean isWebDriverRefuseSslCertificates() {
return asBoolean(SYSTEM_PROPERTY_NAME_WEB_DRIVER_SSL_REFUSE);
}
private static boolean asBoolean(String systemPropertyName) {
return Boolean.getBoolean(systemPropertyName);
}
private static Integer asInteger(String systemPropertyName, int defaultValue) {
return Integer.getInteger(systemPropertyName, defaultValue);
}
private static String asString(String systemPropertyName) {
return System.getProperty(systemPropertyName);
}
private static String asString(String systemPropertyName, String defaultValue) {
return System.getProperty(systemPropertyName, defaultValue);
}
}