I am currently trying to achieve parallel test run with cucumber. I managed to run two different runners at the same time with the sure-fire plugin. Now I want to check whether is it possible to run SingleRunner file multiple times in parallel.
Ex: I have SignUpRunnerTest.java so I need to run this against few platforms parally.Is it possible?
This is my Runner file
import cucumber.api.CucumberOptions;
import cucumber.api.cli.Main;
import cucumber.api.junit.Cucumber;
import java.util.List;
import javax.management.MXBean;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
#RunWith(Cucumber.class)
#CucumberOptions(plugin = {"pretty", "html:target/html/", "json:target/cucumber.json", "junit:TEST-all.xml"},
features = "src/test/java/resources/features/Search.feature", glue = {"com.browserstack.stepdefs"})
public class SignUpeRunnerTest {
}
Without Runner Approach
public class SignUpeRunnerTest {
#Test
public void test2() {
Main.main(new String[]{"--threads", "4","-g", "com.browserstack.stepdefs", "src/test/java/resources/features/"});
}
}
Factory Class
`import org.openqa.selenium.WebDriver;
public final class DriverFactory {
private static ThreadLocal<WebDriver> drivers = new ThreadLocal();
//To quit the drivers and browsers at the end only.
private static List<WebDriver> storedDrivers = new ArrayList();
static {
Runtime.getRuntime().addShutdownHook(new Thread(){
public void run(){
storedDrivers.stream().forEach(WebDriver::quit);
}
});
}
private DriverFactory() {}
public static WebDriver getDriver() {
return drivers.get();
}
public static void addDriver(WebDriver driver) {
storedDrivers.add(driver);
drivers.set(driver);
}
public static void removeDriver() {
storedDrivers.remove(drivers.get());
drivers.remove();
}
}
`
Step Class
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class SearchPage {
private static WebDriver webDriver;
public SearchPage(WebDriver webDriver) {
this.webDriver = webDriver;
DriverFactory.addDriver(webDriver);
}
private By searchTermField = By.name("q");
private By submitSearch = By.id("_fZl");
public void enterSearchTerm(String searchTerm) {
DriverFactory.getDriver().findElement(searchTermField).sendKeys(searchTerm);
}
public void submitSearch() {
DriverFactory.getDriver().findElement(submitSearch).click();
}
}
This is my POM file
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.browserstack</groupId>
<artifactId>cucumber-jvm-java-browserstack</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>cucumber-jvm-java-browserstack</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<cucumber.jvm.parallel.version>2.2.0</cucumber.jvm.parallel.version>
<surefire.maven.plugin.version>2.19.1</surefire.maven.plugin.version>
<acceptance.test.parallel.count>4</acceptance.test.parallel.count>
</properties>
<dependencies>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>4.2.3</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>4.2.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>datatable</artifactId>
<version>1.1.12</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-testng</artifactId>
<version>4.2.3</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-picocontainer</artifactId>
<version>4.2.3</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.gfk.senbot/senbot-maven-plugin -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.0.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
<configuration>
<parallel>methods</parallel>
<threadCount>4</threadCount>
<reuserForks>false</reuserForks>
<testErrorIgnore>true</testErrorIgnore>
<testFailureIgnore>true</testFailureIgnore>
<includes>
<include>**/*RunnerTest.java</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
</project>
info.cukes dependency (are pretty old) which support cucumber till v 1.2.5 only and No more support for this after 12 September 2016
Other side, io.cucumber dependency supports Cucumber starting from v 2.0.x till latest v 4.3.x available as of now (Cucumber-JVM 4.0 gives you much flexibility for implementing parallel execution) and below are the steps to implement parallel execution using io.cucumber (Here you do not need to create individual runners per feature file & No need to use any old plug in like jvm-parallel plug in)
1.Adding correct set of dependency. I have followed JUnit during the implementation.
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>4.2.3</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>4.2.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>datatable</artifactId>
<version>1.1.12</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-picocontainer</artifactId>
<version>4.2.3</version>
<scope>test</scope>
</dependency>
2.Adding Maven-Surefire-Plugin under POM.XML
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
<configuration>
<parallel>methods</parallel>
<threadCount>1</threadCount>
<reuserForks>false</reuserForks>
<testErrorIgnore>true</testErrorIgnore>
<testFailureIgnore>true</testFailureIgnore>
<includes>
<include>**/*RunCukeTest.java</include>
</includes>
</configuration>
</plugin>
Cucumber feature files can be executed without using any runner by using the main() method in class Main of package cucumber.api.cli. Refer to this cli usage and this article. Using this maybe it will work. Need some changes though.
Copy the code of BrowserStackJUnitTest into a new class rename it to something else say NewBSTest. This class will be used for running the test.
Some change will be required in how the driver created for each thread will be accessed by selenium and cucumber code.
Need to use a factory to store the drivers in a ThreadLocal variable in NewBSTest. U can refer to this class.
In the NewBSTest class that u have created remove line no 30 - public WebDriver driver;. Change line 94 to add the created RemoteWebDriver to the ThreadLocal variable. SOmething like DriverFactory.addDriver(driver). Add DriverFactory.removeDriver() in method tearDown() line 98, maybe the first line. Change existing driver.quit(); to DriverFactory.getDriver().quit().
5.Remove the shutdown hook in the DriverFactory, BrowserStack will be quitting the actual driver anyways.
Now in selenium or cucumber code u can access the driver using DriverFactory.getDriver(). This will impact your existing code pretty heavily.
In the NewBSTest class add a test method like this. Hopefully this will work and the same features will be executed in each of the configured browserstack environments.
#Test
public void test() {
Main.main(new String[]{""-g", "stepdef", "src/test/resources/features/"});
}
You might have got answer for this question.To run testcases in parallel ,there are additional settings required as given below in the link-
https://cucumber.io/docs/guides/parallel-execution/
According to this link if you are using surefire plugin, then package name should be parallel for the runner class.
For choosing the device type ,you can add tag for the feature file and further get the tag in before hook. I think for choosing the capability there might be better way available.Below logic is working for me-
#Before(order=2)
public void LaunchBrowser(Scenario sc)
{
String browser= "firefox";
//
ArrayList s = (ArrayList) sc.getSourceTagNames();
//scenarios having this tag will be ignored and not run
if(s.contains("#chrome"))
browser = "chrome";
else if(s.contains("#firefox"))
browser = "firefox";
driverfactory=new DriverFactory();
driver=driverfactory.init_driver(browser);
}
Related
It was working for me. I have closed Eclipse and executed the same runner(BDD, with Maven Project). I am getting the error:
java.lang.NoSuchMethodError: 'byte[] org.apache.commons.io.IOUtils.byteArray(int)'
at org.apache.commons.io.output.AbstractByteArrayOutputStream.needNewBuffer(AbstractByteArrayOutputStream.java:104)
at org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream.(UnsynchronizedByteArrayOutputStream.java:51)
at org.apache.poi.util.IOUtils.peekFirstNBytes(IOUtils.java:139)
at org.apache.poi.poifs.filesystem.FileMagic.valueOf(FileMagic.java:209)
at org.apache.poi.openxml4j.opc.internal.ZipHelper.verifyZipHeader(ZipHelper.java:143)
at org.apache.poi.openxml4j.opc.internal.ZipHelper.openZipStream(ZipHelper.java:175)
at org.apache.poi.openxml4j.opc.ZipPackage.(ZipPackage.java:130)
at org.apache.poi.openxml4j.opc.OPCPackage.open(OPCPackage.java:312)
at org.apache.poi.ooxml.util.PackageHelper.open(PackageHelper.java:59)
at org.apache.poi.xssf.usermodel.XSSFWorkbook.(XSSFWorkbook.java:289)
at org.apache.poi.xssf.usermodel.XSSFWorkbook.(XSSFWorkbook.java:285)
at StepDefinition.Steps.when_user_enters_filename(Steps.java:80)
at ✽.a user enters "C:\Sejars\TestData.xlsx" and "Sheet1"(file:///C:/Users/Ashok%20Kumar/eclipse-workspace/CucumberWithSelenium/Features/MyTest.feature:20)
Infact it was working for me. But all of sudden it has started throwing errors. I have referred the previous posting suggested during posting this. One of the suggestions is to include ">poi-ooxml". But my POM is already having the same. I have changed the version of commons-io version. But still no use. Same error. Note that no error while building the code and build is successful at CMD prompt. But it's throwing at runtime is surpring me. I am using Eclipse and my JDK version is 17.0.2 and Maven version is: 3.8.5 Here I am listing my POM:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>CucumberWithSelenium</groupId>
<artifactId>CucumberWithSelenium</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>17</release>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>7.2.3</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>7.2.3</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-jvm-deps</artifactId>
<version>1.0.6</version>
</dependency>
<dependency>
<groupId>net.masterthought</groupId>
<artifactId>cucumber-reporting</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>gherkin</artifactId>
<version>22.0.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/info.cukes/cucumber-picocontainer -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-picocontainer</artifactId>
<version>7.2.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.10.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-log4j2 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<version>2.6.6</version>
</dependency>
</dependencies>
</project
I did test some more on this problem and did debug the code. My guess is that there is a mismatch of versions of some JAR files. I did degrade the versions of Junit and commons-io. But still I am facing the same error. I have applied toggle breakpoint and found the error is at:
XSSFWorkbook wb = new XSSFWorkbook(fis);
Here is full code of my step file. For debugging purpose I am printing to know which line is throwing error. Requesting somebody to guide me:
#When("^a user enters \"(.*)\" and \"(.*)\"$")
public void when_user_enters_filename(String filename, String sheetname) throws Throwable{
System.out.println("This is from RegressionTest: " + filename + " " + sheetname);
String[][] data = null;
try {
FileInputStream fis = new FileInputStream(filename);
//InputStream fis = new FileInputStream(filename);
byte[] bytes = IOUtils.toByteArray(fis);
System.out.println("Byte array size: " + bytes.length);
try (**XSSFWorkbook wb = new XSSFWorkbook(fis)**) {
System.out.println("Byte array size2: " + bytes.length);
XSSFSheet sh = wb.getSheet(sheetname);
System.out.println("Byte array size3: " + bytes.length);
XSSFRow row = sh.getRow(0);
int noOfRows = sh.getPhysicalNumberOfRows();
int noOfCols = row.getLastCellNum();
System.out.println("No of rows data = "+ noOfRows + " No of cols data = " + noOfCols);
Cell cell;
data = new String[noOfRows-1][noOfCols];
for(int i =1; i<noOfRows;i++){
for(int j=0;j<noOfCols;j++){
row = sh.getRow(i);
cell= row.getCell(j);
data[i-1][j] = cell.getStringCellValue();
System.out.println("row and col = " + i +" , " + j);
System.out.println("This is reading excel data" + cell.getStringCellValue());
}
}
}
fis.close();
} catch (Exception e) {
e.printStackTrace();
}
}
I wanted to run my cucumber features with TestNG for parallel execution. I continue to keep on running into the issue where testNG fails to find the matching glue code. Although the code is written and mapped correctly with Steps.
Test Execution is skipped and error states that There were undefined steps that needs to be defined.
I then moved the Step Definitions class into the same package where my Test Runner class was, and the execution went on successfully.
I fail to understand that why testNG is not able to recognize the glue code in different package. I tried to work on different dependencies as well but that didn't worked as well. Is there any other way to make sure testNG looks at the right place for step definitions ?
Below is the POM :
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>CucumberPractice</groupId>
<artifactId>CucumberPractice</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>CucumberPractice</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-core</artifactId>
<version>4.7.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-java -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>4.7.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-junit -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>4.7.2</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-jvm-deps -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-jvm-deps</artifactId>
<version>1.0.6</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hamcrest/hamcrest-core -->
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>2.1</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.cucumber/gherkin -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>gherkin</artifactId>
<version>5.1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-html -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-html</artifactId>
<version>0.2.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-all -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-testng -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-testng</artifactId>
<version>4.7.2</version>
</dependency>
</dependencies>
</project>
Below is the Step Definition class :
package CucumberPageLogic;
import java.util.Set;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.Select;
import org.openqa.selenium.support.ui.WebDriverWait;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import junit.framework.Assert;
public class PageLogic {
public WebDriver driver;
public WebDriverWait wait;
#Before("#Chrome")
public void driverSetup() {
System.out.println("In Before");
System.setProperty("webdriver.chrome.driver", "driverPath");
driver= new ChromeDriver();
wait= new WebDriverWait(driver,20);
}
#After
public void tearDown() {
driver.quit();
}
#Given("User opens Salesforce.com")
public void userOpensSalesforceCom() {
driver.get("https://www.salesforce.com/in/?ir=1");
driver.manage().window().maximize();
}
#Given("Home Page is sucessfully loaded")
public void homePageIsSucessfullyLoaded() {
wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//div[#class='btn-container hidden-xs']//span[contains(text(),'Try')]")));
}
#When("User clicks on Try For Free button")
public void userClicksOnTryForFreeButton() {
wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//div[#class='btn-container hidden-xs']//span[contains(text(),'Try')]"))).click();
}
#When("^User enters SignUp \"(.*)\" \"(.*)\" \"(.*)\" information$")
public void userEntersSignUpInformation(String firstname, String lastname, String jobtitle) {
driver.findElement(By.name("UserFirstName")).sendKeys(firstname);
driver.findElement(By.name("UserLastName")).sendKeys(lastname);
Select select = new Select(driver.findElement(By.name("UserTitle")));
select.selectByVisibleText(jobtitle);
}
#Then("New Tab is opened")
public void newTabIsOpened() {
Set<String> handles = driver.getWindowHandles();
if(handles.isEmpty()) {
Assert.fail();
}
System.out.println("these are the handles :"+handles);
System.out.println("Current Handle :"+driver.getWindowHandle());
for(String handle:handles) {
if(!handle.equals(driver.getWindowHandle())) {
System.out.println("Switching to "+handle);
driver.switchTo().window(handle);
break;
}
}
}
#Then("User goes back to home page")
public void userGoesBackToHomeTab() {
Set<String> handles = driver.getWindowHandles();
if(handles.isEmpty()) {
Assert.fail();
}
System.out.println("these are the handles :"+handles);
System.out.println("Current Handle :"+driver.getWindowHandle());
for(String handle:handles) {
if(!handle.equals(driver.getWindowHandle())) {
System.out.println("Switching to "+handle);
driver.switchTo().window(handle);
break;
}
}
}
#Then("Sign up form is visible")
public void signUpFormIsVisible() {
wait.until(ExpectedConditions.visibilityOfElementLocated(By.name("UserFirstName")));
}
#Then("validate home page content")
public void validateHomePageContent() {
wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//div[#class='btn-container hidden-xs']//span[contains(text(),'Try')]")));
}
}
Below is the Test Runner Class :
package CucumberPractice;
import org.testng.annotations.DataProvider;
import io.cucumber.junit.CucumberOptions;
import io.cucumber.junit.CucumberOptions.SnippetType;
import io.cucumber.testng.AbstractTestNGCucumberTests;
//#RunWith(Cucumber.class)
#CucumberOptions(features= {"C:\\Users\\komehta\\eclipse-workspace\\CucumberPractice\\src\\test\\java\\CucumberPractice"},
dryRun=false,
glue= {"CucumberPageLogic"},
snippets= SnippetType.CAMELCASE,
tags= {"#NewTabFeature"},
strict=false,
plugin= {
"pretty","html:test-outout",
"json:json_output/cucumber.json",
"junit:junit_xml/cucumber.xml"
})
public class CucumberTestRunner extends AbstractTestNGCucumberTests {
#Override
#DataProvider(parallel = true)
public Object[][] scenarios() {
return super.scenarios();
}
}
Feature File :
#NewTabFeature #Chrome
Feature: Opening the WebPage in New Tab
#NewTabSnr1
Scenario: Open the link in a New WebPage and Validate the Content
Given User opens Salesforce.com
And Home Page is sucessfully loaded
When User clicks on Try For Free button
Then New Tab is opened
And Sign up form is visible
#NewTabSnr2
Scenario Outline: Validate the Content on HomePage after entering details on new tab
Given User opens Salesforce.com
And Home Page is sucessfully loaded
When User clicks on Try For Free button
And New Tab is opened
And User enters SignUp "<firstname>" "<lastname>" "<jobtitle>" information
Then User goes back to home page
And validate home page content
Examples:
| firstname | lastname | jobtitle |
| Kovid |Mehta | Sales Manager |
| Vikas |Bhat | IT Manager |
If you remove dependencies you don't use or pull in transitively and let Maven do the dependency management for you you'll see that you have to replace:
import io.cucumber.junit.CucumberOptions;
import io.cucumber.junit.CucumberOptions.SnippetType;
with:
import io.cucumber.testng.CucumberOptions;
import io.cucumber.testng.CucumberOptions.SnippetType;
Currently you can remove:
junit
cucumber-junit
cucumber-jvm-dep
gherkin
cucumber-html
I am trying to implement parallel test execution using cucumber 4.0, but observing issues.
As per details on cucumbers website: https://cucumber.io/docs/guides/parallel-execution/#testng
I included following dependency in pom.xml: (apart from other existing dependencies for testng, etc)
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-jvm</artifactId>
<version>4.4.0</version>
<type>pom</type>
</dependency>
I added following code in runner file:
#Override
#DataProvider(parallel = true)
public Object[][] scenarios() {
return super.scenarios();
}
I am seeing following errors on above mentioned code:
The method scenarios() of type Baserunner must override or implement a supertype method. (error on line 62)
The method scenarios() is undefined for the type AbstractTestNGCucumberTests (error on line 63)
If my implementation looks wrong, please let me know!
You should create the one more abstract class like AbstractTestNGCucumberParallelTest within same package and extend to #cucumberOptions annotation like below:
package runner;
import cucumber.api.CucumberOptions;
#CucumberOptions(glue = "stepdefs", features = ".")
public class RunnerIT extends AbstractTestNGCucumberParallelTest{
}
*********************************************
package runner;
import org.testng.annotations.DataProvider;
import cucumber.api.testng.AbstractTestNGCucumberTests;
public abstract class AbstractTestNGCucumberParallelTest extends AbstractTestNGCucumberTests {
#Override
#DataProvider(parallel = true)
public Object[][] scenarios() {
return super.scenarios();
}
}
I have created a sample project here is the link below:
https://github.com/racchouhan12/SeleniumCucumber5/blob/master/src/test/java/com/testautomation/test/stepdefinitions/Runners/TestRunner.java.
The TestRunner.java extends AbstractTestNGCucumber class and it uses Cucumber 5.
Also you can match dependencies with above project so in case if any dependencies are missing you can add them.
Here are the cucumber dependencies
<cucumber.version>5.7.0</cucumber.version>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java8</artifactId>
<version>${cucumber.version}</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>${cucumber.version}</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-testng</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-core</artifactId>
<version>${cucumber.version}</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
cucumber-java8 dependency requires only if you write lambda style step definitions.
Let me know if it helps.
I have a simple jsf app with one Bean.
import org.omnifaces.cdi.ViewScoped;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Named;
import java.io.Serializable;
#Named
#ViewScoped
public class IndexMg implements Serializable {
List list;
#PostConstruct
public void init() {
list = new ArrayList();
list.add("as");
list.add("dsu");
}
#PreDestroy()
public void end() {
System.out.println("predestroy called");
}
}
according to this answer and conversation down this post and also OmniFaces documentation OmniFaces ViewScoped bean should invoke #PreDestroy function when I navigate away by GET, or close the browser tab/window but nothings happens until session destroy.
I'm using Wildfly 15 as Application Server and i can see activeViewMaps in sessions. Yoy can see sessions content here .
It's something like this :
com.sun.faces.application.view.activeViewMaps {1d31c745-c202-4256-a2c6-60035bfdd8e7={org.omnifaces.cdi.viewscope.ViewScopeStorageInSession=b557d2aa-ba35-4ff2-9f4e-3cc4ac312c9a}, ca02df9d-be65-4a75-a399-3df9eabbcfd3={org.omnifaces.cdi.viewscope.ViewScopeStorageInSession=aaef6a5a-d385-4e33-a990-200f94b67583}}
I opened multiple windows an closed them but non of them destroyed until session destroy(30 minutes later). What's wrong? did i forget anything?
this is my pom
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
</properties>
<dependencies>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.faces</artifactId>
<version>2.3.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.enterprise/cdi-api -->
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>2.0.SP1</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.omnifaces/omnifaces -->
<dependency>
<groupId>org.omnifaces</groupId>
<artifactId>omnifaces</artifactId>
<version>3.2</version>
</dependency>
</dependencies>
I'm trying to get a Custom Security Realm in Glassfish working (i tried 3.0.1 final and 3.1 B33). I read nearly all tutorials about this, but it doesn't not work on my System. I'm getting the error
Login failed: javax.security.auth.login.LoginException: unable to find LoginModule class: com.company.security.realm.CustomLoginModule
when trying to login.
Here is what i did:
I created a little Maven project, which contains the needed Realm class, CustomRealm, and the corresponding LoginModule, CustomLoginModule.
My pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany</groupId>
<artifactId>security.realm</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Custom JDBCRealm</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.glassfish.security</groupId>
<artifactId>security</artifactId>
<version>3.1-b33</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
<optimise>true</optimise>
<debug>true</debug>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
My Custom Realm class:
package com.company.security.realm;
import com.sun.appserv.security.AppservRealm;
import com.sun.enterprise.security.auth.realm.BadRealmException;
import com.sun.enterprise.security.auth.realm.InvalidOperationException;
import com.sun.enterprise.security.auth.realm.NoSuchRealmException;
import com.sun.enterprise.security.auth.realm.NoSuchUserException;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;
public class CustomRealm extends AppservRealm
{
Vector<String> groups = new Vector<String>();
private String jaasCtxName;
private String startWith;
#Override
public void init(Properties properties)
throws BadRealmException, NoSuchRealmException {
jaasCtxName = properties.getProperty("jaas-context", "customRealm");
startWith = properties.getProperty("startWith", "z");
groups.add("dummy");
}
#Override
public String getAuthType()
{
return "Custom Realm";
}
public String[] authenticate(String username, char[] password)
{
// if (isValidLogin(username, password))
return (String[]) groups.toArray();
}
#Override
public Enumeration getGroupNames(String username)
throws InvalidOperationException, NoSuchUserException
{
return groups.elements();
}
#Override
public String getJAASContext()
{
return jaasCtxName;
}
public String getStartWith()
{
return startWith;
}
}
My LoginModule class:
package com.company.security.realm;
import com.sun.appserv.security.AppservPasswordLoginModule;
import com.sun.enterprise.security.auth.login.common.LoginException;
import java.util.Set;
import org.glassfish.security.common.PrincipalImpl;
public class CustomLoginModule extends AppservPasswordLoginModule
{
#Override
protected void authenticateUser() throws LoginException
{
_logger.info("CustomRealm : authenticateUser for " + _username);
final CustomRealm realm = (CustomRealm)_currentRealm;
if ( (_username == null) || (_username.length() == 0) || !_username.startsWith(realm.getStartWith()))
throw new LoginException("Invalid credentials");
String[] grpList = realm.authenticate(_username, getPasswordChar());
if (grpList == null) {
throw new LoginException("User not in groups");
}
_logger.info("CustomRealm : authenticateUser for " + _username);
Set principals = _subject.getPrincipals();
principals.add(new PrincipalImpl(_username));
this.commitUserAuthentication(grpList);
}
}
I compiled this Maven project and copyied the resulting JAR-file to the Glassfish/lib directory. Then i added the Security Realm "customRealm" to my Glassfish with asadmin:
asadmin create-auth-realm
--classname com.company.security.realm.CustomRealm
--property jaas-context=customRealm:startWith=a customRealm
I also referenced the LoginModule class for the JAAS context of my Custom Realm, therefore i inserted this into the login.conf of my domain:
customRealm {
com.company.security.realm.CustomLoginModule required;
};
Although this LoginModule SHOULD BE on the Glassfish classpath, as it's classfile is packaged in the JAR that i put into the Glassfish/lib-dir, it cannot be found when i try to login. For login, i build a simple JSF-project, which calls the HttpServletRequest-login-method of Servlet 3.0.
When trying to login i'm getting the following Exception:
2010-12-24T14:41:31.613+0100|WARNING|glassfish3.0.1|
javax.enterprise.system.container.web.com.sun.web.security|_ThreadID=25;
_ThreadName=Thread-1;|Web login failed: Login failed:
javax.security.auth.login.LoginException: unable to find LoginModule class:
com.company.security.realm.CustomLoginModule
Anybody got an idea what i can do that Glassfish loads the LoginModule-class?
Got it. Seems like newer Glassfish versions require that the Security Realm and the LoginModule are packaged as an OSGi module, which should then be copied into glassfish/modules.
Therefore i changed my pom.xml to create an OSGi bundle, which contains both the CustomRealm and the CustomLoginModule.
Here it is:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany</groupId>
<artifactId>security.realm</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>bundle</packaging>
<name>Custom JDBCRealm OSGi</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.glassfish.security</groupId>
<artifactId>security</artifactId>
<version>3.1-b33</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
<optimise>true</optimise>
<debug>true</debug>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Export-Package>
${project.groupId}.${project.artifactId};version=${project.version}
</Export-Package>
<Import-Package>
com.sun.appserv.security,
org.glassfish.security.common,
com.sun.enterprise.security.auth.realm,
com.sun.enterprise.security.auth.login.common,
java.util,
javax.security.auth
</Import-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>
EDIT
Found a good additional resource here:
http://blogs.oracle.com/nithya/entry/modularized_osgi_custom_realms_in
, where the Realm and it's LoginModule is build as a hk2-jar.
This was driving me crazy, I've finally cracked creating a custom realm in glassfish 3.1, turns out that of course its really easy. The following documentation is the key: http://docs.oracle.com/cd/E18930_01/html/821-2418/beabo.html ... note that it has changed somewhat from the answers above.