How to make synchronized work when using maven-surefire plugin? - synchronized

I'm using the maven-surefire plugin to execute the Cucumber Runner in parallel. In each of the Runners, I'm invoking a synchronized static method of a Utilities class. But all the Runners running in parallel are able to invoke the method in a non-synchronized way.
#RunWith(CucumberWithSerenity.class)
#CucumberOptions(...)
public class SampleRunner {
#BeforeClass
public static void loadLocators() {
Utilities.doSomething();
}
}
public class Utilities {
public synchronized static void doSomething() {
System.out.println("Start");
.
.
.
System.out.println("Stop");
}
}
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
<configuration>
<includes>
<include>**/*Runner.java</include>
</includes>
<parallel>classes</parallel>
<threadCount>${parallel.tests}</threadCount>
<forkCount>${parallel.tests}</forkCount>
<perCoreThreadCount>true</perCoreThreadCount>
<!-- <skip>true</skip> -->
</configuration>
</plugin>
And when I have the threadCount as say 3, and execute mvn clean verify serenity:aggregate
I get the following logs
Start
Start
Stop
Stop
Start
Stop
What I am Expecting is
Start
Stop
Start
Stop
Start
Stop

Set the forkCount to 1 and only 1 JVM will be used by the plugin to execute the tests. If more than 1 then multiple JVMs will be used and hence different synchronized static method will be used.
Reference: https://maven.apache.org/surefire/maven-surefire-plugin/examples/fork-options-and-parallel-execution.html

Related

Log custom text to Cucumber JVM or Extent Reports

Please guide me in logging custom text which are there inside a method into Cucumber JVM (Masterthought) or Extent Reports.
I am using Cucumber Junit BDD Framework and have the below dependencies in my POM file -
<!-- Cucumber JVM Report -->
<dependency>
<groupId>net.masterthought</groupId>
<artifactId>cucumber-reporting</artifactId>
<version>5.1.0</version>
</dependency>
<!-- Extent Report -->
<dependency>
<groupId>com.aventstack</groupId>
<artifactId>extentreports-cucumber4-adapter</artifactId>
<version>1.2.1</version>
</dependency>
And my Runner file is as below -
#CucumberOptions(
tags = {"#SANITY,#REGRESSION,#E2E"},
features = "src/test/resources/cta-features/features/",
plugin = {
"json:target/cucumber-reports/cucumber.json", "com.aventstack.extentreports.cucumber.adapter.ExtentCucumberAdapter:",
"pretty"
},
glue = {
"e2e.steps",
"e2e.hooks"
})
#RunWith(Cucumber.class)
public class TestRunner {
#BeforeClass
public static void init() throws Exception {
}
#AfterClass
public static void generateReport() throws Exception {
File reportOutputDirectory = new File("target");
List<String> jsonFiles = new ArrayList<>();
jsonFiles.add("target/cucumber-reports/cucumber.json");
String buildNumber = "1";
String projectName = "Project";
Configuration configuration = new Configuration(reportOutputDirectory, projectName);
// optional configuration - check javadoc for details
configuration.addPresentationModes(PresentationMode.RUN_WITH_JENKINS);
// do not make scenario failed when step has status SKIPPED
configuration.setNotFailingStatuses(Collections.singleton(Status.SKIPPED));
configuration.setBuildNumber(buildNumber);
// addidtional metadata presented on main page
configuration.addClassifications("Platform", "Windows");
configuration.addClassifications("Browser", "Chrome");
configuration.addClassifications("Branch", "release/1.0");
ReportBuilder reportBuilder = new ReportBuilder(jsonFiles, configuration);
Reportable result = reportBuilder.generateReports();
// and here validate 'result' to decide what to do if report has failed
}
I am able to successfully generate report in both master thought and Extent which will contain Feature level statements and Step Level statements (I have used scenario.write for this). But my client wants one more level deeper where he can get info as to which link or button was clicked etc which i am currently publishing to my console using Log4j
Example :
Log.info("Random Button or Link was clicked and Operation is successful")
My clients wants this to be integrated into the report (In Either Masterthought or Extent). Is there a way to do this ?
Extent cucumber adapter provides addtestlog to log additional steps .
Please check below example -
ExtentCucumberAdapter.addAddTestStepLog(BTN.getText());
As per your Pom.xml file you are using adapter 4 if you cannot find method try to switch into cucumber adapter 6 and other essential dependency of cucumber 6. That will surely help you :)

Configure Ignite logger and appender using java

I want to configure the ignite log4j2 configuration programatically instead of xml.
How to configure ignite log4j2 configuration using java? Can anyone help?
Unfortunately built-it Ignite integration doesn't support pure programmatic way of configuration at the moment.
But in fact you're able to use slf4j logging facade backed by the log4j2 under the hood. In this case you'll have some sort of a full power over logging configuration.
In order to achieve that you should add log4j2 dependencies manually as well as ignite-slf4j dependency. In the meanwhile you need log4j2 slf4j binding to allow Ignite logging facilities transfer calls to the log4j2.
For instance if you use maven then your pom.xml should contain:
<dependency>
<groupId>org.apache.ignite</groupId>
<artifactId>ignite-slf4j</artifactId>
<version>${ignite.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.13.3</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.13.3</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.13.3</version>
</dependency>
After that you'll be able to follow official insеructions to configure that stuff. For example you can try adding a class that extends org.apache.logging.log4j.core.config.ConfigurationFactory to your classpath. It could look somehow like that:
import java.net.URI;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.Order;
import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder;
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
import org.apache.logging.log4j.core.config.plugins.Plugin;
#Plugin(name = "CustomConfigurationFactory", category = ConfigurationFactory.CATEGORY)
#Order(50)
public class CustomConfigurationFactory extends ConfigurationFactory {
static Configuration createConfiguration(final String name, ConfigurationBuilder<BuiltConfiguration> builder) {
builder.setConfigurationName(name);
builder.setStatusLevel(Level.ERROR);
builder.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.NEUTRAL).
addAttribute("level", Level.DEBUG));
AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE").
addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
appenderBuilder.add(builder.newLayout("PatternLayout").
addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable"));
appenderBuilder.add(builder.newFilter("MarkerFilter", Filter.Result.DENY,
Filter.Result.NEUTRAL).addAttribute("marker", "FLOW"));
builder.add(appenderBuilder);
builder.add(builder.newLogger("org.apache.logging.log4j", Level.DEBUG).
add(builder.newAppenderRef("Stdout")).
addAttribute("additivity", false));
builder.add(builder.newRootLogger(Level.ERROR).add(builder.newAppenderRef("Stdout")));
return builder.build();
}
#Override
public Configuration getConfiguration(final LoggerContext loggerContext, final ConfigurationSource source) {
return getConfiguration(loggerContext, source.toString(), null);
}
#Override
public Configuration getConfiguration(final LoggerContext loggerContext, final String name, final URI configLocation) {
ConfigurationBuilder<BuiltConfiguration> builder = newConfigurationBuilder();
return createConfiguration(name, builder);
}
#Override
protected String[] getSupportedTypes() {
return new String[] {"*"};
}
}
It would be possible to make logging customization there.

Migrating from Selenium RC to Webdriver

I'm trying to migrate to webdriver, as it is faster. How do I do this?
Currently I'm using the setUp() command for selenium. Do I need to add any new jar files for the webdriver?
I 'd like to describe in common features approach I use on my project.
I'm using selenium webDriver. Working on java.
IDE: IDEA.
build manager: maven.
So I got POM.xml file.
So I simply add there depencdencies in POM xml:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.4</version>
</dependency>
<dependency> <groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>2.24.1</version>
</dependency>
On building the project maven will get needed jars automatically.
In my project I got BaseSeleniumTest.java: with the following:
public class BaseSeleniumTest extends SeleneseTestBase {
static WebDriver driver;
#BeforeClass
public static void firefoxSetUp() throws MalformedURLException {
driver = new FirefoxDriver();
}
#Before
public void homePageRefresh() throws IOException {
driver.get("login.base.url");
}
#AfterClass
public static void closeFirefox(){
driver.quit();
}
...
}
And have some other classes inherinting from BaseSekeniumTest.java
where I describe pack of my selenium tests annotated by #Test
That's kind of structure on my project.
Hope this helps you.

How to start and stop mule in maven

I need to start Mule before I run my tests, and stop it when the tests are finished. It is unclear to me how to alter my Maven pom to accomplish this. So far I have the following in my pom:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<executable>java</executable>
<arguments>
<argument>-classpath</argument>
<classpath/>
<argument>org.mule.MuleServer</argument>
<argument>-config</argument>
<argument>my-config.xml</argument>
</arguments>
</configuration>
</plugin>
--- Update ---
After some replies below I decided to add some additional details.
I have several unit tests extending Mules FunctionalTestCase class:
public class SomeUnitTest extends FunctionalTestCase
I started writing some new customer acceptance tests using JBehave which are wired to run during mavens "integration-test" phase. These tests cannot succeed without an instance of mule running. The main class that loads and executes the stories already extends the JUnitStories class:
public class MyStories extends JUnitStories
Since I cannot inherit from FunctionalTestCase in this class, I need to look at alternatives to getting mule to run and stop when I need it for these stories.
Why don't you use Mule's FunctionalTestCase instead? It fires up an in-memory Mule and loads up your configs. Not sure what you gain from starting the whole standalone Mule.
You could probably accomplish what you want by leveraging maven's phases. You'd have to define 2 executions. One to start mule and one to stop it. You'd start mule in one of the pre-test phases (maybe something like process-test-classes) and then stat mule after the test phase. It could be pretty tricky, though.
Another possibility is to fire mule up in junit, somewhere like in a BeforeClass setup function. This will probably be much easier. See:
http://junit.sourceforge.net/javadoc/org/junit/BeforeClass.html
class muleDriver {
#BeforeClass
public static startMule() {
....programmatically initialize Mule....
....You should be able to grab the config files from the classpath....
}
#Test
public void testSomething() {
....Run Some Tests...
}
}
The other question I'd ask is why you'd want to fire up the whole mule framework for tests. I was on a team that did this, and tests ended up taking a tremendous amount of time during builds because they were firing up mule many times throughout the testing cycle (and other teams copied the pattern.)
Try using junit #ClassRule. The side effect is that individual test cases can not be executed any more.
#RunWith(Suite.class)
#Suite.SuiteClasses({MuleFlowTest.class})
public class MuleSuite {
#ClassRule
public static ExternalResource testRule = new ExternalResource() {
#Override
protected void before() throws Throwable {
final String CLI_OPTIONS[] = {"-config", FlowTestUtil.getURI() };
MuleServer server = new MuleServer(CLI_OPTIONS);
server.start(false, true);
mc = server.getMuleContext();
muleServer = server;
};
#Override
protected void after() {
System.out.println("Shutdown");
muleServer.shutdown();
muleServer = null;
}
};
private static MuleServer muleServer;
public static MuleContext mc;
}
public class MuleFlowTest {
#Test
public void flowTest() {
assertNotNull(MuleSuite.mc);
}
}

How to conditionalize GUI tests using Netbeans/Maven vs maven on command line invocation

I'd like to have a single project pom but have my GUI tests always run when I'm invoking JUnit on Netbeans, but have them conditional (on an environment variable?) when building on the command line (usually for production build - on a headless machine, but sometimes just for build speed).
I don't mind instrumenting my JUnit tests for this, as I already have to set up my GUI test infrastructure, but how do I conditionalize my pom!
Netbeans 6.5 with Maven plugin.
Any ideas how I can accomplish this?
Ilane
The Surefire plugin can specify which tests to run.
You could specify different sets to run for different profiles, and select your profile using -P{profilename}.
One solution would be to use a profile (that could be indeed activated by an environment variable) and to exclude GUI tests from the Maven Surefire Plugin configuration using excludes in this profile, based on a naming convention. Something like this:
<profile>
<id>headless</id>
<activation>
<property>
<name>env.FOO</name>
<value>foo</value>
</property>
</activation>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.5</version>
<configuration>
<excludes>
<exclude>**/*$*</exclude><!-- to exclude inner classes -->
<exclude>**/gui/**</exclude>
</excludes>
</configuration>
</plugin>
...
</plugins>
</build>
</profile>
Another option would be to use TestNG and to leverage the excludeGroups parameter.
To achieve the desired behavior in my Maven project on Netbeans, I set up a profile defining an environment variable in my project's pom and modified the Test file action in my project's properties to activate my new profile. In this way I could check the enviroment variable in my tests. (This could have been done similarly with a system property.)
To keep from having to add a check to each and every GUI test, however, I found that I could add a JUnit filter, which would automatically ignore the UI tests in the case where I didn't want to run them and put the number of skipped tests in the test result line.
Here what my profile looks like:
<profile>
<id>test-gui</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>false</skipTests>
<excludes>
<exclude>**/TestSuite.java</exclude>
</excludes>
<environmentVariables>
<GUI_TEST>true</GUI_TEST>
</environmentVariables>
</configuration>
</plugin>
</plugins>
</build>
</profile>
Here's a description of how to update the Netbeans Action:
(Right click on project in Projects window)->Properies
In Categories box, select 'Actions'
In Actions box, select 'Test file'
In Activate Profiles textfield, enter 'test-gui'
Click 'OK' button to save.
To add the JUnit filter (and the documentation was sparse, so I may not have done this in the most effective manner), I subclassed the default test runner, TestClassRunner and had it call my Filter, which checks the test name and the environment variable. To get JUnit to call my class, I annotated the test class.
public class GUITestClassRunner extends TestClassRunner {
public GUITestClassRunner(Class klazz) throws InitializationError {
super(klazz);
}
public GUITestClassRunner(Class klazz, Runner runner)
throws InitializationError, NoTestsRemainException {
super(klazz, runner);
}
#Override
public void run(RunNotifier notifier) {
if (getDescription().testCount() > 0) {
try {
filter(new GUIFilter(notifier));
} catch (NoTestsRemainException ex) {
Description description = getDescription();
notifier.fireTestStarted(description);
notifier.fireTestIgnored(description);
notifier.fireTestFinished(description);
return;
}
}
super.run(notifier);
}
class GUIFilter extends Filter {
private boolean isGUI = false;
private RunNotifier notifier;
public GUIFilter(RunNotifier notifier) {
this.notifier = notifier;
isGUI = UI.isGUITestEnvironment();
}
#Override
public boolean shouldRun(Description desc) {
if (!isGUI && UI.isGUITest(desc.getDisplayName())) {
Description description = getDescription();
notifier.fireTestStarted(description);
notifier.fireTestIgnored(description);
notifier.fireTestFinished(description);
return false;
}
return true;
}
#Override
public String describe() {
return "all tests except GUI tests if headless";
}
}
}
To call this runner, the test class needs to be annotated with:
#RunWith(GUITestClassRunner.class)
public class MyJUnitTestClass
{
....
#Test
public void testAlpha() {...}
#Test
public void testBeta_UI() {...}
}
So, now, from Netbeans, I just run my unit test class and the GUI tests automatically run. I can run from the command line with no environment variables set or GUI_TEST set to false, and my GUI tests are skipped, or I can run from the command line with GUI_TEST set to true, or use mvn -Ptest-gui and all my GUI tests run.
My sincerest thanks to Brian and Pascal for pointing me in the right direction.
Ilane