I'm using keycloak 11.0.3 (jboss distribution) with Docker. I'm also writing my custom conditional authenticator for user attribute condition (actually I copied the one from newer keycloak distribution):
Factory class
package org.example;
import org.keycloak.Config;
import org.keycloak.authentication.authenticators.conditional.ConditionalAuthenticator;
import org.keycloak.authentication.authenticators.conditional.ConditionalAuthenticatorFactory;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.provider.ProviderConfigProperty;
import java.util.Arrays;
import java.util.List;
public class ConditionalUserAttributeValueFactory implements ConditionalAuthenticatorFactory {
public static final String PROVIDER_ID = "conditional-user-attribute";
public static final String CONF_ATTRIBUTE_NAME = "attribute_name";
public static final String CONF_ATTRIBUTE_EXPECTED_VALUE = "attribute_expected_value";
public static final String CONF_NOT = "not";
private static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = {
AuthenticationExecutionModel.Requirement.REQUIRED, AuthenticationExecutionModel.Requirement.DISABLED
};
#Override
public void init(Config.Scope config) {
// no-op
}
#Override
public void postInit(KeycloakSessionFactory factory) {
// no-op
}
#Override
public void close() {
// no-op
}
#Override
public String getId() {
return PROVIDER_ID;
}
#Override
public String getDisplayType() {
return "Condition - user attribute";
}
#Override
public String getReferenceCategory() {
return null;
}
#Override
public boolean isConfigurable() {
return true;
}
#Override
public AuthenticationExecutionModel.Requirement[] getRequirementChoices() {
return REQUIREMENT_CHOICES;
}
#Override
public boolean isUserSetupAllowed() {
return false;
}
#Override
public String getHelpText() {
return "Flow is executed only if the user attribute exists and has the expected value";
}
#Override
public List<ProviderConfigProperty> getConfigProperties() {
ProviderConfigProperty authNoteName = new ProviderConfigProperty();
authNoteName.setType(ProviderConfigProperty.STRING_TYPE);
authNoteName.setName(CONF_ATTRIBUTE_NAME);
authNoteName.setLabel("Attribute name");
authNoteName.setHelpText("Name of the attribute to check");
ProviderConfigProperty authNoteExpectedValue = new ProviderConfigProperty();
authNoteExpectedValue.setType(ProviderConfigProperty.STRING_TYPE);
authNoteExpectedValue.setName(CONF_ATTRIBUTE_EXPECTED_VALUE);
authNoteExpectedValue.setLabel("Expected attribute value");
authNoteExpectedValue.setHelpText("Expected value in the attribute");
ProviderConfigProperty negateOutput = new ProviderConfigProperty();
negateOutput.setType(ProviderConfigProperty.BOOLEAN_TYPE);
negateOutput.setName(CONF_NOT);
negateOutput.setLabel("Negate output");
negateOutput.setHelpText("Apply a not to the check result");
return Arrays.asList(authNoteName, authNoteExpectedValue, negateOutput);
}
#Override
public ConditionalAuthenticator getSingleton() {
return ConditionalUserAttributeValue.SINGLETON;
}
}
Authenticator class:
package org.example;
import org.keycloak.authentication.AuthenticationFlowContext;
import org.keycloak.authentication.AuthenticationFlowError;
import org.keycloak.authentication.AuthenticationFlowException;
import org.keycloak.authentication.authenticators.conditional.ConditionalAuthenticator;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import java.util.Map;
import java.util.Objects;
public class ConditionalUserAttributeValue implements ConditionalAuthenticator {
static final ConditionalUserAttributeValue SINGLETON = new ConditionalUserAttributeValue();
#Override
public boolean matchCondition(AuthenticationFlowContext context) {
System.out.println("START MATCH CONDITION");
Map<String, String> config = context.getAuthenticatorConfig().getConfig();
System.out.println("Map<String, String> config = " + config);
String attributeName = config.get(ConditionalUserAttributeValueFactory.CONF_ATTRIBUTE_NAME);
String attributeValue = config.get(ConditionalUserAttributeValueFactory.CONF_ATTRIBUTE_EXPECTED_VALUE);
System.out.println("attributeName = " + attributeName);
System.out.println("attributeValue = " + attributeName);
UserModel user = context.getUser();
if (user == null) {
throw new AuthenticationFlowException("Cannot find user for obtaining particular user attributes. Authenticator: " +
ConditionalUserAttributeValueFactory.PROVIDER_ID, AuthenticationFlowError.UNKNOWN_USER);
}
System.out.println("USER ATTRIBUTES :" + user.getAttributes());
return user.getAttribute(attributeName).stream()
.anyMatch(attr -> Objects.equals(attr, attributeValue));
}
#Override
public void action(AuthenticationFlowContext context) {
}
#Override
public boolean requiresUser() {
return true;
}
#Override
public void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user) {
}
#Override
public void close() {
}
}
And I added a file named
org.keycloak.authentication.AuthenticatorFactory
to resources/META-INF/services folder with the following content
org.example.ConditionalUserAttributeValueFactory
pom.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<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>org.example</groupId>
<artifactId>conditional-authenticator</artifactId>
<version>1.0-SNAPSHOT</version>
<name>conditional-authenticator</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<keycloak.version>11.0.3</keycloak.version>
</properties>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<version>${keycloak.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-services</artifactId>
<version>${keycloak.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi</artifactId>
<version>${keycloak.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi-private</artifactId>
<version>${keycloak.version}</version>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
Dockerfile:
FROM jboss/keycloak:11.0.3
COPY ./deployments /opt/jboss/keycloak/standalone/deployments
ENTRYPOINT [ "/opt/jboss/tools/docker-entrypoint.sh" ]
CMD ["-b", "0.0.0.0"]
But after I run the container I recieve the following error:
16:42:07,288 WARN [org.jboss.modules.define] (ServerService Thread Pool -- 62) Failed to define class org.example.ConditionalUserAttributeValueFactory in Module "deployment.conditional-authenticator-1.0-SNAPSHOT.jar" from Service Module Loader: java.lang.NoClassDefFoundError: Failed to link org/example/ConditionalUserAttributeValueFactory (Module "deployment.conditional-authenticator-1.0-SNAPSHOT.jar" from Service Module Loader): org/keycloak/authentication/authenticators/conditional/ConditionalAuthenticatorFactory
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1017)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1096)
at org.jboss.modules.ModuleClassLoader.doDefineOrLoadClass(ModuleClassLoader.java:424)
at org.jboss.modules.ModuleClassLoader.defineClass(ModuleClassLoader.java:555)
at org.jboss.modules.ModuleClassLoader.loadClassLocal(ModuleClassLoader.java:339)
at org.jboss.modules.ModuleClassLoader$1.loadClassLocal(ModuleClassLoader.java:126)
at org.jboss.modules.Module.loadModuleClass(Module.java:731)
at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:247)
at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:410)
at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:398)
at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:116)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:398)
at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.nextProviderClass(ServiceLoader.java:1209)
at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNextService(ServiceLoader.java:1220)
at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNext(ServiceLoader.java:1264)
at java.base/java.util.ServiceLoader$2.hasNext(ServiceLoader.java:1299)
at java.base/java.util.ServiceLoader$3.hasNext(ServiceLoader.java:1384)
at org.keycloak.keycloak-services#11.0.3//org.keycloak.provider.DefaultProviderLoader.load(DefaultProviderLoader.java:60)
at org.keycloak.keycloak-services#11.0.3//org.keycloak.provider.ProviderManager.load(ProviderManager.java:95)
at org.keycloak.keycloak-services#11.0.3//org.keycloak.services.DefaultKeycloakSessionFactory.loadFactories(DefaultKeycloakSessionFactory.java:248)
at org.keycloak.keycloak-services#11.0.3//org.keycloak.services.DefaultKeycloakSessionFactory.init(DefaultKeycloakSessionFactory.java:88)
at org.keycloak.keycloak-services#11.0.3//org.keycloak.services.resources.KeycloakApplication.createSessionFactory(KeycloakApplication.java:260)
at org.keycloak.keycloak-services#11.0.3//org.keycloak.services.resources.KeycloakApplication.startup(KeycloakApplication.java:124)
at org.keycloak.keycloak-wildfly-extensions#11.0.3//org.keycloak.provider.wildfly.WildflyPlatform.onStartup(WildflyPlatform.java:29)
at org.keycloak.keycloak-services#11.0.3//org.keycloak.services.resources.KeycloakApplication.<init>(KeycloakApplication.java:114)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
It worth noting that preciously I managed to successfully deploy custom SMS Authenticator the same way. But I ran intro such troubles with the conditional one.
Any ideas?
Related
I've sucessfully generated service proxies for service having methods returning Future<T>,
but just after I changed those methods to return Uni<T> according to API Translation - Smallrye Mutiny Vert.x bindings,
when I try to execute mvn clean compile it always tells me this error message :
Could not generate model for com.example.beers.BarmanService#giveMeAStaticBeer(java.lang.String): Proxy methods must have void or Fluent returns
I would need your help to enlighten me how to fix it.
I put those codes on GitHub, and these are some critical ones:
//BarmanService.java
#VertxGen
#ProxyGen
public interface BarmanService {
Uni<Beer> giveMeAStaticBeer(String customerName);
Uni<Integer> getMyBill(String customerName);
Uni<Void> payMyBill(String customerName);
static BarmanService createProxy(Vertx vertx, String address) {
return new BarmanServiceVertxEBProxy(vertx, address);
}
}
//BarmanServiceImpl.java
public class BarmanServiceImpl implements BarmanService {
Map<String, Integer> bills;
public BarmanServiceImpl() {
this.bills = new HashMap<>();
}
#Override
public Uni<Beer> giveMeAStaticBeer(String customerName) {
Beer beer = new Beer("Workshop River Stout", "English Stout", 5);
return Uni.createFrom().item(() -> beer);
}
#Override
public Uni<Integer> getMyBill(String customerName) {
return Uni.createFrom().item(() -> bills.get(customerName));
}
#Override
public Uni<Void> payMyBill(String customerName) {
bills.remove(customerName);
System.out.println("Removed debt of " + customerName);
return Uni.createFrom().voidItem();
}
}
//package-info.java
#ModuleGen(groupPackage = "com.example", name = "beers")
package com.example.beers;
import io.vertx.codegen.annotations.ModuleGen;
<!-- //pom.xml -->
<dependencies>
<!-- // ... -->
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-codegen</artifactId>
<classifier>processor</classifier>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-service-proxy</artifactId>
</dependency>
<!-- // ... -->
<dependency>
<groupId>io.smallrye.reactive</groupId>
<artifactId>smallrye-mutiny-vertx-core</artifactId>
<version>2.30.1</version>
</dependency>
<dependency>
<groupId>io.smallrye.reactive</groupId>
<artifactId>vertx-mutiny-generator</artifactId>
<version>2.30.1</version>
</dependency>
<!-- // ... -->
</dependencies>
PS In the beginning, when I generated service proxies for service having methods returning Future<T>, there is a generated class returning Uni<T>, but I have no idea how to use it:
package com.example.mutiny.beers;
#io.smallrye.mutiny.vertx.MutinyGen(com.example.beers.BarmanService.class)
public class BarmanService {
public static final io.smallrye.mutiny.vertx.TypeArg<BarmanService> __TYPE_ARG = new io.smallrye.mutiny.vertx.TypeArg<>( obj -> new BarmanService((com.example.beers.BarmanService) obj),
BarmanService::getDelegate
);
private final com.example.beers.BarmanService delegate;
public BarmanService(com.example.beers.BarmanService delegate) {
this.delegate = delegate;
}
public BarmanService(Object delegate) {
this.delegate = (com.example.beers.BarmanService)delegate;
}
/**
* Empty constructor used by CDI, do not use this constructor directly.
**/
BarmanService() {
this.delegate = null;
}
public com.example.beers.BarmanService getDelegate() {
return delegate;
}
#CheckReturnValue
public io.smallrye.mutiny.Uni<com.example.beers.Beer> giveMeAStaticBeer(String customerName) {
return io.smallrye.mutiny.vertx.UniHelper.toUni(delegate.giveMeAStaticBeer(customerName));}
public com.example.beers.Beer giveMeAStaticBeerAndAwait(String customerName) {
return giveMeAStaticBeer(customerName).await().indefinitely();
}
public void giveMeAStaticBeerAndForget(String customerName) {
giveMeAStaticBeer(customerName).subscribe().with(io.smallrye.mutiny.vertx.UniHelper.NOOP);
}
// ...
public static com.example.mutiny.beers.BarmanService createProxy(io.vertx.mutiny.core.Vertx vertx, String address) {
com.example.mutiny.beers.BarmanService ret = com.example.mutiny.beers.BarmanService.newInstance((com.example.beers.BarmanService)com.example.beers.BarmanService.createProxy(vertx.getDelegate(), address));
return ret;
}
public static BarmanService newInstance(com.example.beers.BarmanService arg) {
return arg != null ? new BarmanService(arg) : null;
}
}
I just figured it out by myself. About to change service methods from returning Future<T> to Uni<T>,
The wrong apporach I did:
Edit package-info to remove useFutures = true
Edit service interfaces and change returning types
Edit service implimentations and change returning types, also change logic
Edit verticles to handle Uni<T> returned from service
And it turned out that the first three steps I did is unnecessary,
the suitable approach is:
Wrap vertx:
io.vertx.mutiny.core.Vertx mutinyVertx = new io.vertx.mutiny.core.Vertx(vertx);
Change the use of service interface to the generated one
import com.example.mutiny.beers.BarmanService;
Use the wrapped vertx:
BarmanService barmanService = BarmanService.createProxy(mutinyVertx, "beers.services.myapplication");
Edit verticles to handle Uni<T> returned from service
My problem has been solved, but I am not sure is it a good apporach to manually wrap the vertx on the MainVerticle launched by io.vertx.core.Launcher: io.vertx.mutiny.core.Vertx mutinyVertx = new io.vertx.mutiny.core.Vertx(vertx);, any suggestions guys?
Badly stuck. Facing error as above: I am using Cucumber framework to automate Mobile app both on Android and IOS. I have recently started doing automation.
So If I use PageFactory.initElements(driver, this); and try to find elements by using annotation as #FindBy my code works.
But if try to use PageFactory.initElements(new AppiumFieldDecorator(driver), this); and try to find elements by using annotation as #AndroidFindBy or #iOSXCUITFindBy
I get below exception.
Exception
java.lang.ExceptionInInitializerError
at io.appium.java_client.pagefactory.utils.ProxyFactory.getEnhancedProxy(ProxyFactory.java:53)
at io.appium.java_client.pagefactory.utils.ProxyFactory.getEnhancedProxy(ProxyFactory.java:33)
at io.appium.java_client.pagefactory.AppiumFieldDecorator.proxyForAnElement(AppiumFieldDecorator.java:216)
at io.appium.java_client.pagefactory.AppiumFieldDecorator.access$0(AppiumFieldDecorator.java:214)
at io.appium.java_client.pagefactory.AppiumFieldDecorator$1.proxyForLocator(AppiumFieldDecorator.java:107)
at org.openqa.selenium.support.pagefactory.DefaultFieldDecorator.decorate(DefaultFieldDecorator.java:62)
at io.appium.java_client.pagefactory.AppiumFieldDecorator.decorate(AppiumFieldDecorator.java:154)
at org.openqa.selenium.support.PageFactory.proxyFields(PageFactory.java:113)
at org.openqa.selenium.support.PageFactory.initElements(PageFactory.java:105)
at pageObjects.LogInPage.<init>(LogInPage.java:33)
at managers.PageObjectManager.getloginpage(PageObjectManager.java:22)
at stepDefinitions.Steps.User_is_on_login_page(Steps.java:46)
at ✽.User is on login page(file:///Users/ramanjeetaulakh/eclipse-workspace/CoreShare/src/test/resources/functionalTests/LoginTest.feature:6)
Caused by: java.lang.IllegalArgumentException
at org.objectweb.asm.ClassVisitor.<init>(Unknown Source)
at net.sf.cglib.core.DebuggingClassWriter.<init>(DebuggingClassWriter.java:49)
at net.sf.cglib.core.DefaultGeneratorStrategy.getClassVisitor(DefaultGeneratorStrategy.java:30)
at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:24)
at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:332)
at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:96)
at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:94)
at net.sf.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at net.sf.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61)
at net.sf.cglib.core.internal.LoadingCache.get(LoadingCache.java:34)
at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:119)
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:294)
at net.sf.cglib.core.KeyFactory$Generator.create(KeyFactory.java:221)
at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:174)
at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:153)
at net.sf.cglib.proxy.Enhancer.<clinit>(Enhancer.java:73)
at io.appium.java_client.pagefactory.utils.ProxyFactory.getEnhancedProxy(ProxyFactory.java:53)
at io.appium.java_client.pagefactory.utils.ProxyFactory.getEnhancedProxy(ProxyFactory.java:33)
at io.appium.java_client.pagefactory.AppiumFieldDecorator.proxyForAnElement(AppiumFieldDecorator.java:216)
at io.appium.java_client.pagefactory.AppiumFieldDecorator.access$0(AppiumFieldDecorator.java:214)
at io.appium.java_client.pagefactory.AppiumFieldDecorator$1.proxyForLocator(AppiumFieldDecorator.java:107)
at org.openqa.selenium.support.pagefactory.DefaultFieldDecorator.decorate(DefaultFieldDecorator.java:62)
at io.appium.java_client.pagefactory.AppiumFieldDecorator.decorate(AppiumFieldDecorator.java:154)
at org.openqa.selenium.support.PageFactory.proxyFields(PageFactory.java:113)
at org.openqa.selenium.support.PageFactory.initElements(PageFactory.java:105)
at pageObjects.LogInPage.<init>(LogInPage.java:33)
at managers.PageObjectManager.getloginpage(PageObjectManager.java:22)
at stepDefinitions.Steps.User_is_on_login_page(Steps.java:46)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at io.cucumber.java.Invoker.doInvoke(Invoker.java:66)
at io.cucumber.java.Invoker.invoke(Invoker.java:24)
at io.cucumber.java.AbstractGlueDefinition.invokeMethod(AbstractGlueDefinition.java:47)
at io.cucumber.java.JavaStepDefinition.execute(JavaStepDefinition.java:29)
at io.cucumber.core.runner.CoreStepDefinition.execute(CoreStepDefinition.java:66)
at io.cucumber.core.runner.PickleStepDefinitionMatch.runStep(PickleStepDefinitionMatch.java:63)
at io.cucumber.core.runner.ExecutionMode$1.execute(ExecutionMode.java:10)
at io.cucumber.core.runner.TestStep.executeStep(TestStep.java:86)
at io.cucumber.core.runner.TestStep.run(TestStep.java:57)
at io.cucumber.core.runner.PickleStepTestStep.run(PickleStepTestStep.java:51)
at io.cucumber.core.runner.TestCase.run(TestCase.java:95)
at io.cucumber.core.runner.Runner.runPickle(Runner.java:75)
at io.cucumber.junit.PickleRunners$NoStepDescriptions.lambda$run$0(PickleRunners.java:151)
at io.cucumber.core.runtime.CucumberExecutionContext.lambda$runTestCase$3(CucumberExecutionContext.java:110)
at io.cucumber.core.runtime.RethrowingThrowableCollector.executeAndThrow(RethrowingThrowableCollector.java:23)
at io.cucumber.core.runtime.CucumberExecutionContext.runTestCase(CucumberExecutionContext.java:110)
at io.cucumber.junit.PickleRunners$NoStepDescriptions.run(PickleRunners.java:148)
at io.cucumber.junit.FeatureRunner.runChild(FeatureRunner.java:144)
at io.cucumber.junit.FeatureRunner.runChild(FeatureRunner.java:28)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at io.cucumber.junit.FeatureRunner.run(FeatureRunner.java:137)
at io.cucumber.junit.Cucumber.runChild(Cucumber.java:196)
at io.cucumber.junit.Cucumber.runChild(Cucumber.java:89)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at io.cucumber.junit.Cucumber$RunBeforeAllHooks.evaluate(Cucumber.java:266)
at io.cucumber.junit.Cucumber$RunAfterAllHooks.evaluate(Cucumber.java:281)
at io.cucumber.junit.Cucumber$StartTestRun.evaluate(Cucumber.java:233)
at io.cucumber.junit.Cucumber$FinishTestRun.evaluate(Cucumber.java:248)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:93)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:529)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:756)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:452)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
POM
<?xml version="1.0" encoding="UTF-8"?>
<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>Automation</groupId>
<artifactId>CoreShare</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>CoreShare</name>
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>7.0.0</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-junit -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>7.3.4</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-jvm -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-jvm</artifactId>
<version>7.3.4</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>net.sourceforge.cobertura</groupId>
<artifactId>cobertura</artifactId>
<version>2.1.1</version>
<exclusions>
<exclusion>
<artifactId>tools</artifactId>
<groupId>com.sun</groupId>
</exclusion>
</exclusions>
</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>
<dependency>
<groupId>net.masterthought</groupId>
<artifactId>cucumber-reporting</artifactId>
<version>1.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-gherkin -->
<!--
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-gherkin</artifactId>
<version>7.3.4</version>
</dependency>
-->
<!-- https://mvnrepository.com/artifact/io.cucumber/gherkin -->
<!--
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>gherkin</artifactId>
<version>23.0.1</version>
</dependency>
-->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>2.0.2-beta</version>
</dependency>
<!--<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.7.0</version>
</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/org.seleniumhq.selenium/selenium-remote-driver -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-remote-driver</artifactId>
<version>3.141.59</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.appium/java-client -->
<dependency>
<groupId>io.appium</groupId>
<artifactId>java-client</artifactId>
<version>7.4.1</version>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<!--> <plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
PAGE CLASS
package pageObjects;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileElement;
import io.appium.java_client.android.AndroidElement;
import io.appium.java_client.ios.IOSElement;
import io.appium.java_client.pagefactory.AndroidFindBy;
import io.appium.java_client.pagefactory.AppiumFieldDecorator;
import io.appium.java_client.pagefactory.iOSXCUITBy;
import io.appium.java_client.pagefactory.iOSXCUITFindBy;
public class LogInPage {
AppiumDriver<?> driver;
public LogInPage(AppiumDriver<?> driver) {
System.out.println("Entered LogInPage function on Login Page class");
System.out.println("Setting up Driver");
this.driver = driver;
PageFactory.initElements(new AppiumFieldDecorator(driver), this);
// PageFactory.initElements(driver, this);
System.out.println("Pagefactory Driver is set");
}
#AndroidFindBy(id = ":id/server_selection_spinner")
#iOSXCUITFindBy(id = "mobile-oauth-icon-down-arrow")
public WebElement clickONRegionSelector;
public void selectRegion() {
System.out.println(clickONRegionSelector);
clickONRegionSelector.click();
}
PAGE OBJECT MANAGER
package managers;
import io.appium.java_client.AppiumDriver;
import pageObjects.LogInPage;
public class PageObjectManager {
private AppiumDriver<?> driver;
private LogInPage loginpage;
public PageObjectManager(AppiumDriver<?> driver) {
this.driver = driver;
System.out.println("Entered Page Object Manager class");
}
public LogInPage getloginpage(){
System.out.println("Create Object for Login Page in page object manager class");
return (loginpage == null) ? loginpage = new LogInPage(driver) : loginpage;
}
}
Step Definition
package stepDefinitions;
import java.net.MalformedURLException;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import Hooks.myHooks;
import dataProvider.ConfigFileReader;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileElement;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.pagefactory.AppiumFieldDecorator;
import io.cucumber.java.Before;
import io.cucumber.java.PendingException;
import io.cucumber.java.en.And;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import managers.PageObjectManager;
import pageObjects.LogInPage;
//import Hooks.myHooks;
public class Steps{
AppiumDriver<?> driver;
LogInPage loginpage;
PageObjectManager pageobjectmanager;
ConfigFileReader configFileReader;
#Given("^User is on login page$")
public void User_is_on_login_page() throws Throwable {
System.out.println("TEST started - User is on login page");
configFileReader = new ConfigFileReader();
this.driver = myHooks.driver;
driver.manage().timeouts().implicitlyWait(configFileReader.getImplicitlyWait(), TimeUnit.SECONDS);
pageobjectmanager = new PageObjectManager(driver);
loginpage = pageobjectmanager.getloginpage();
System.out.println("Enter Login page");
}
#When("^user select desired region$")
public void user_select_desired_region() throws Throwable {
System.out.println("User is on select desired region on step definstion");
loginpage.selectRegion();}
HOOKS Class
package Hooks;
import java.net.MalformedURLException;
import java.net.URL;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.WebDriverWait;
import dataProvider.ConfigFileReader;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileElement;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.AndroidElement;
import io.appium.java_client.ios.IOSDriver;
import io.appium.java_client.ios.IOSElement;
import io.cucumber.java.Before;
public class myHooks extends ConfigFileReader {
public static AppiumDriver<?> driver;
static ConfigFileReader configFileReader;
#Before("#appium")
public static void startTest() {
configFileReader= new ConfigFileReader();
System.out.println("Setting up Platform");
String platform = null;
try {
platform = getPlatform();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(platform.equalsIgnoreCase("Android")) {
driver = startAppium_Android();
} else {
driver = startAppium_IOS();
}
}
/*
* This method is used for initiate the AppiumDriver with caps and connection protocol
*/
public static AndroidDriver<?> startAppium_Android() {
// Initializing the Appium driver
try {
System.out.println("Initializing Android setup");
DesiredCapabilities caps = new DesiredCapabilities();
caps.setCapability("platformName","Android");
caps.setCapability("deviceName","Android_Emulator");
caps.setCapability("platformVersion","12");
caps.setCapability("udid","emulator-5554");
caps.setCapability("appPackage", "com.opentext.m.core");
caps.setCapability("appActivity","com.opentext.m.core.launch.MainRootActivity");
caps.setCapability("adbExecTimeout","50000");
URL url = new URL("http://127.0.0.1:4723/wd/hub");
driver = new AndroidDriver<WebElement>(url, caps);
}
catch (Exception e) {
e.printStackTrace();
}
//Returning the instance of the driver to the parent method
return (AndroidDriver<?>) driver;
}
/*
* This method is used for initiate the IOSDriver with caps and connection protocol
*/
public static IOSDriver<?> startAppium_IOS() {
// Initializing the Appium driver
try {
System.out.println("Initializing iOS setup");
DesiredCapabilities caps = new DesiredCapabilities();
caps.setCapability("platformName","iOS");
caps.setCapability("deviceName","iPhone Simulator");
caps.setCapability("platformVersion","15.4");
caps.setCapability("udid","73035AA3-9143-46CB-856A-748FA5F17AC1");
// caps.setCapability("app","/Users/tower7/Library/Developer/CoreSimulator/Devices/AC7BD970-3D7F-4043-9ED6-B258F12A9891/data/Containers/Bundle/Application/557F43C6-3D05-4A1C-8AC0-8335E9D8E02B/OpenText Core share.app");
caps.setCapability("app","/Users/ramanjeetaulakh/Library/Developer/CoreSimulator/Devices/73035AA3-9143-46CB-856A-748FA5F17AC1/data/Containers/Bundle/Application/0EC66171-7256-4967-A682-6FA8DE0FFBD4/OpenText Core share.app");
caps.setCapability("automationName","XCUITest");
caps.setCapability("noReset",true);
caps.setCapability("bundleId","com.opentext.e.core");
URL url = new URL("http://127.0.0.1:4723/wd/hub");
driver = new IOSDriver<WebElement>(url, caps);
}
catch (Exception e) {
e.printStackTrace();
}
return (IOSDriver<?>) driver;
}
}
I am learning to use spring webflux and as part of it i developed an application which uses Redis to save and retrieve data. But the problem i face is when the request tries to connect to redis i get following error :
{
"timestamp": "2020-03-25T10:34:07.020+0000",
"status": 500,
"error": "Internal Server Error",
"message": "Async support must be enabled on a servlet and for all filters involved in async request processing. This is done in Java code using the Servlet API or by adding \"<async-supported>true</async-supported>\" to servlet and filter declarations in web.xml.",
"path": "/tax/lines/save/"
}
I have searched enough about this issue and dint find anything useful.
Here is my Redis configuration class:
#Configuration
#EnableAsync
public class RedisConfig {
#Value("${vcap.services.redis.credentials.hostname:10.11.241.101}")
private String host;
#Value("${vcap.services.redis.credentials.port:36516}")
private int port;
#Bean
public ReactiveRedisConnectionFactory reactiveRedisConnectionFactory() {
return new LettuceConnectionFactory(host, port);
}
#Bean
ReactiveRedisOperations<TaxDetails, TaxLine> redisOperations(ReactiveRedisConnectionFactory reactiveRedisConnectionFactory) {
Jackson2JsonRedisSerializer<TaxDetails> serializer = new Jackson2JsonRedisSerializer<>(TaxDetails.class);
Jackson2JsonRedisSerializer<TaxLine> serializer1 = new Jackson2JsonRedisSerializer<>(TaxLine.class);
RedisSerializationContext.RedisSerializationContextBuilder<TaxDetails, TaxLine> builder = RedisSerializationContext
.newSerializationContext(new StringRedisSerializer());
RedisSerializationContext<TaxDetails, TaxLine> context = builder.key(serializer).value(serializer1).build();;
ReactiveRedisTemplate<TaxDetails,TaxLine> template = new ReactiveRedisTemplate<>(reactiveRedisConnectionFactory,context);
return template;
}
}
Here is my redis look up class which actually fetches and saves data from redis
package com.sap.slh.tax.attributes.determination.springwebfluxdemo.lookup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ReactiveRedisOperations;
import org.springframework.stereotype.Service;
import com.sap.slh.tax.attributes.determination.springwebfluxdemo.model.RedisRepo;
import com.sap.slh.tax.attributes.determination.springwebfluxdemo.model.TaxDetails;
import com.sap.slh.tax.attributes.determination.springwebfluxdemo.model.TaxLine;
import com.sap.slh.tax.attributes.determination.springwebfluxdemo.util.JsonUtil;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
#Service
public class RedisTaxLineLookUpService {
private static final Logger log = LoggerFactory.getLogger(RedisTaxLineLookUpService.class);
#Autowired
private ReactiveRedisOperations<TaxDetails, TaxLine> redisOperations;
public Flux<TaxLine> get(TaxDetails taxDetails) {
log.info("going to call redis to fetch tax lines{}", JsonUtil.toJsonString(taxDetails));
return redisOperations.keys(taxDetails).flatMap(redisOperations.opsForValue()::get);
}
public Mono<RedisRepo> set(RedisRepo redisRepo) {
log.info("going to call redis to save tax lines{}", JsonUtil.toJsonString(redisRepo.getTaxDetails()));
return redisOperations.opsForValue().set(redisRepo.getTaxDetails(), redisRepo.getTaxLine())
.map(__ -> redisRepo);
}
}
Controller :
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.sap.slh.tax.attributes.determination.springwebfluxdemo.model.RedisRepo;
import com.sap.slh.tax.attributes.determination.springwebfluxdemo.model.TaxDetails;
import com.sap.slh.tax.attributes.determination.springwebfluxdemo.model.TaxLine;
import com.sap.slh.tax.attributes.determination.springwebfluxdemo.service.TaxLineService;
import com.sap.slh.tax.attributes.determination.springwebfluxdemo.util.JsonUtil;
import reactor.core.publisher.Mono;
#RestController
public class TaxLinesDeterminationController {
private static final Logger log = LoggerFactory.getLogger(TaxLinesDeterminationController.class);
#Autowired
private TaxLineService taxLineService;
#PostMapping(value = "/tax/lines",consumes = MediaType.APPLICATION_JSON_VALUE,produces = MediaType.APPLICATION_JSON_VALUE)
public Mono<TaxLine> determineTaxLines(#RequestBody(required = true) final TaxDetails request)
{
log.info("the request received is{}",JsonUtil.toJsonString(request));
return taxLineService.determineTaxLines(request);
}
#PostMapping(value = "/tax/lines/save",consumes = MediaType.APPLICATION_JSON_VALUE,produces = MediaType.APPLICATION_JSON_VALUE)
public Mono<RedisRepo> saveTaxLines(#RequestBody(required = true) final RedisRepo request)
{
log.info("the request received is{}",JsonUtil.toJsonString(request));
return taxLineService.saveTaxLines(request);
}
}
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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.sap.slh.tax.attributes.determination</groupId>
<artifactId>springwebfluxdemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>springwebfluxdemo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>com.sap.hcp.cf.logging</groupId>
<artifactId>cf-java-logging-support-logback</artifactId>
<version>2.2.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Please help me identify the issue. Thanks in advance !
As per the suggesion of Yauhen Balykin, i have removed Tomcat dependency and also removed the packaging in the jar. now it works fine
I am using to execute my selenium test with Cucumber, Maven and TestNG and Appium. When i started this automation by using TestNG via TestNG.xml. App launched but There is an error on running feature files selenium cucumber. I am getting the below error. Please help to resolve this error.
cucumber.runtime.CucumberException: java.lang.NullPointerException
at cucumber.api.testng.TestNGCucumberRunner.runCucumber(TestNGCucumberRunner.java:69)
at runner.RunnerTest.feature(RunnerTest.java:54)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:133)
at org.testng.internal.TestInvoker.invokeMethod(TestInvoker.java:584)
at org.testng.internal.TestInvoker.invokeTestMethod(TestInvoker.java:172)
at org.testng.internal.MethodRunner.runInSequence(MethodRunner.java:46)
at org.testng.internal.TestInvoker$MethodInvocationAgent.invoke(TestInvoker.java:804)
at org.testng.internal.TestInvoker.invokeTestMethods(TestInvoker.java:145)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:146)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:128)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at org.testng.TestRunner.privateRun(TestRunner.java:770)
at org.testng.TestRunner.run(TestRunner.java:591)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:402)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:396)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:355)
at org.testng.SuiteRunner.run(SuiteRunner.java:304)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:53)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:96)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1180)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1102)
at org.testng.TestNG.runSuites(TestNG.java:1032)
at org.testng.TestNG.run(TestNG.java:1000)
at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:115)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:251)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:77)
Caused by: java.lang.NullPointerException
at com.odealMobile.Login.ClickLogin(Login.java:41)
at ✽.When click on login button(src/main/java/features/Android/Login.feature:6)
Details of Plugins Versions:
TestNG - 6.7
Cucumber - 1.2.6
Maven - 3.6.3
Appium - 1.15.1
My Test Class;
package com.odealMobile;
import cucumber.api.java.en.And;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import runner.RunnerTest;
import org.openqa.selenium.By;
import org.openqa.selenium.support.ui.ExpectedConditions;
public class Login extends RunnerTest {
String loginButtonId = "login";
String registerButtonId = "register";
String TCKNId = "tckn";
String passwordId = "password";
String profileImageId = "profile_image_view";
#Given("^odeal app is opened$")
public void CheckOpenedPage() {
System.out.print(By.id(loginButtonId));
wait.until(ExpectedConditions.elementToBeClickable(By.id(loginButtonId)));
//loginButtonId bekleniyor.
wait.until(ExpectedConditions.elementToBeClickable(By.id(registerButtonId)));
}
#When("^click on login button$")
public void ClickLogin() {
// loginButtonId ye tıklanıyor.
driver.findElement(By.id(loginButtonId)).click();
}
#Then("^login page will be opened$")
public void CheckLoginPage() {
wait.until(ExpectedConditions.elementToBeClickable(By.id(loginButtonId)));
}
#When("^user enters valid TCKN$")
public void EnterTCKN() {
driver.findElement(By.id(TCKNId)).click();
driver.findElement(By.id(TCKNId)).setValue("23231487730");
}
#And("^user enters valid password$")
public void EnterPassword() {
driver.findElement(By.id(passwordId)).click();
driver.findElement(By.id(passwordId)).setValue("135246");
}
#And("^clicks on login button$")
public void ClickLoginonLoginPage() {
driver.findElement(By.id(loginButtonId)).click();
}
#Then("^home page will be opened$")
public void CheckHomePage() {
wait.until(ExpectedConditions.elementToBeClickable(By.id(profileImageId)));
if (driver.findElement(By.id(profileImageId)).isDisplayed()) {
System.out.println("Login Success");
} else {
System.out.println("Login Failed");
}
}
}
My Runner Class;
package runner;
import cucumber.api.CucumberOptions;
import cucumber.api.testng.CucumberFeatureWrapper;
import cucumber.api.testng.TestNGCucumberRunner;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileElement;
import io.appium.java_client.android.AndroidDriver;
import java.net.URL;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
#CucumberOptions(
plugin = {
"pretty",
"json:target/report/cucumber2.json"
},
features = {
"src/main/java/features/Android/Login.feature"
},
glue = {
"com/odealMobile"
}
)
public class RunnerTest {
public AppiumDriver < MobileElement > driver;
public WebDriverWait wait;
private TestNGCucumberRunner testNGCucumberRunner;
#BeforeClass(alwaysRun = true)
public void setUpClass() throws Exception {
DesiredCapabilities cap = new DesiredCapabilities();
cap.setCapability("deviceName", "TestDevice-1");
cap.setCapability("automationName", "UiAutomator2");
cap.setCapability("udid", "emulator-5554");
cap.setCapability("platformName", "Android");
cap.setCapability("platformVersion", "10.0");
//cap.setCapability("autoGrantPermissions", "true");
cap.setCapability("noReset", "false");
cap.setCapability("clearSystemFiles", "true");
cap.setCapability("appPackage", "com.telera.merchant.stage.debug");
cap.setCapability("appActivity", "com.telera.merchant.splash.SplashActivity");
driver = new AndroidDriver < MobileElement > (new URL("http://127.0.0.1:4723/wd/hub"), cap);
wait = new WebDriverWait(driver, 10);
testNGCucumberRunner = new TestNGCucumberRunner(this.getClass());
}
#Test(groups = "Cucumber", description = "Runs Cucumber Feature", dataProvider = "features")
public void feature(CucumberFeatureWrapper cucumberFeature) {
testNGCucumberRunner.runCucumber(cucumberFeature.getCucumberFeature());
}
#DataProvider
public Object[][] features() {
return testNGCucumberRunner.provideFeatures();
}
#AfterClass(alwaysRun = true)
public void tearDownClass() throws Exception {
Thread.sleep(50000);
driver.quit();
//testNGCucumberRunner.finish();
}
}
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>appium.mobile.test</groupId>
<artifactId>odealMobile</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>Odeal Mobile</name>
<description>Appium Testing for Mobile </description>
<properties>
<testng.version>6.7</testng.version>
<cucumber.version>1.2.6</cucumber.version>
</properties>
<dependencies>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-guice</artifactId>
<version>1.2.6</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-html</artifactId>
<version>0.2.3</version>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-testng</artifactId>
<version>${cucumber.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/info.cukes/cucumber-java -->
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-java</artifactId>
<version>${cucumber.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/info.cukes/cucumber-jvm -->
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-jvm</artifactId>
<version>${cucumber.version}</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.appium</groupId>
<artifactId>java-client</artifactId>
<version>7.3.0</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.cucumber/tag-expressions -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>tag-expressions</artifactId>
<version>2.0.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
My testng.xml;
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Suite">
<test thread-count="5" name="Test">
<classes>
<class name="runner.RunnerTest"/>
</classes>
</test> <!-- Test -->
</suite> <!-- Suite -->
The important part of the error is right here:
Caused by: java.lang.NullPointerException
at com.odealMobile.Login.ClickLogin(Login.java:41)
at ✽.When click on login button(src/main/java/features/Android/Login.feature:6)
When you get a null pointer exception this means that a variable or field doesn't have a value. Either because it has been set to null or because it has never been set.
So what happens? In a very simplified way this:
RunnerTest runner = new RunnerTest();
runner.setUpClass() // This sets runner.driver
Login login = new Login();
login.ClickLogin() // This tries to use login.driver
First an instance of the RunnerTest class is created and driver is set when setupClass is called. Then a new instance of Login is created. Because this is a different instance, even though it extends the RunnerTest class, the driver variable is never set. So when call ClickLogin is used a null pointer happens.
You can fix this in a few ways. The easiest is probably making driver static, not having Login extend RunnerTest and referencing driver as RunnerTest.driver.
public class RunnerTest{
public static AppiumDriver<MobileElement> driver;
}
public class Login {
#When("^click on login button$")
public void ClickLogin() {
// loginButtonId ye tıklanıyor.
RunnerTest.driver.findElement(By.id(loginButtonId)).click();
}
}
Starting the app in tomcat I get the following error:
Caused by: java.lang.annotation.AnnotationFormatError: Invalid default: public abstract java.lang.Class org.springframework.data.mongodb.repository.config.EnableMongoRepositories.repositoryBaseClass()
at java.lang.reflect.Method.getDefaultValue(Method.java:612)
at org.springframework.core.annotation.AnnotationUtils.registerDefaultValues(AnnotationUtils.java:1178)
at org.springframework.core.type.classreading.RecursiveAnnotationAttributesVisitor.visitEnd(RecursiveAnnotationAttributesVisitor.java:42)
at org.springframework.core.type.classreading.AnnotationAttributesReadingVisitor.visitEnd(AnnotationAttributesReadingVisitor.java:64)
at org.springframework.asm.ClassReader.readAnnotationValues(ClassReader.java:1869)
at org.springframework.asm.ClassReader.accept(ClassReader.java:657)
at org.springframework.asm.ClassReader.accept(ClassReader.java:523)
at org.springframework.core.type.classreading.SimpleMetadataReader.<init>(SimpleMetadataReader.java:64)
at org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:98)
at org.springframework.core.type.classreading.CachingMetadataReaderFactory.getMetadataReader(CachingMetadataReaderFactory.java:102)
at org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.findCandidateComponents(ClassPathScanningCandidateComponentProvider.java:287)
... 50 more
Here is the pom:
<properties>
<spring.version>4.3.8.RELEASE</spring.version>
<spring.data.version>1.9.10.RELEASE</spring.data.version>
<spring.data.commons.version>1.7.0.RELEASE</spring.data.commons.version>
<spring.data.commons.core.version>1.4.1.RELEASE</spring.data.commons.core.version>
<log4j.version>1.2.17</log4j.version>
<gson.version>2.3.1</gson.version>
<servlet.version>3.1.0</servlet.version>
<bson.version>3.4.2</bson.version>
<commons.fileupload.version>1.3.1</commons.fileupload.version>
<okhttp.version>3.5.0</okhttp.version>
<mongo.java.driver.version>3.4.2</mongo.java.driver.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- JavaEE APIs -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>${spring.data.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>${spring.data.commons.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons-core</artifactId>
<version>${spring.data.commons.core.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet.version}</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${commons.fileupload.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp.version}</version>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>${mongo.java.driver.version}</version>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>bson</artifactId>
<version>${bson.version}</version>
</dependency>
</dependencies>
And here is the configuration file:
package com.somes.sns.persistence;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;
#Configuration
#PropertySource("classpath:mongodb.properties")
#EnableMongoRepositories("com.somes.sns.persistence.repository")
public class PersistenceConfig extends AbstractMongoConfiguration
{
private static final String MONGODB_HOST = "mongodb.host";
private static final String MONGODB_PORT = "mongodb.port";
#Autowired
Environment env;
#Override
protected String getDatabaseName()
{
return "MyDatabase";
}
#Override
#Bean
public MongoClient mongo() throws Exception
{
String mongoHost = env.getProperty(MONGODB_HOST);
String mongoPort = env.getProperty(MONGODB_PORT);
MongoClientURI mongoUri = new MongoClientURI("mongodb://" + mongoHost + ":" + mongoPort);
MongoClient client = new MongoClient(mongoUri);
client.setWriteConcern(WriteConcern.SAFE);
return client;
}
#Override
protected String getMappingBasePackage()
{
return "com.somes.sns.persistence.domain";
}
#Override
#Bean
public MongoTemplate mongoTemplate() throws Exception
{
return new MongoTemplate(mongo(), getDatabaseName());
}
}
It worked in the past until I've upgraded to 1.9. What can cause this error?
Any help will be much appreciated
I suspect you have incompatible versions of the Spring Framework and Spring Data.
Please check for conflicts in your dependencies using https://maven.apache.org/plugins/maven-dependency-plugin/examples/resolving-conflicts-using-the-dependency-tree.html
Upgrading to Spring Data 1.10.4 should be compatible with Spring Framework 2.3.8.
Alternatively downgrading Spring Framework to 4.2.9 should work as well.
I also recommend not explicitly specifying Spring Data Commons as a dependency, because it will get pulled in as a transient dependency anyway. This would give you one less version number to worry about.
Also: You almost certainly don't want a spring-data-commons-core this artifact is outdated and there is no new version for it.