Testing multiple environments with different data - best practice - java

I need to be able to run the same tests on different environments (max 3) but with different data for each one.
I have a test method:
#Test (groups = "core", description = "Login: Valid log in")
public void validLogin() {
User user = UserData.user_2();
loginPage.logOn(user);
}
In the UserData class I have:
public static User user_2() {
return new User().newUser("user2", "password");
}
"user2" does not exist on all environments. I may not be able to change the data that is available on all of the environments to match the test data.
The tests will be executed either using Maven and TestNg so I can send in the parameter for the execution environment.
My initial thought is to use:
public static User user_2() {
switch(env) {
case "env1": return new User().newUser("user2", "password"); break;
case "env2": return new User().newUser("user2Z", "password"); break;
case "env3": return new User().newUser("user2X", "password"); break;
}
I have a limited number of data classes and methods (<100) but several thousand tests.
What is the best way of setting up and handling the data required for testing against the different environments?

When it comes to different users ,
You always wish that all my test cases should remain as it is and with minimal change.
So this is what i follow.
I create a file lets say username.properties file in eclipse.
username=xyz#gmail.com
password=passswd1
You can create multiple users here with name i.e.
rohan=rohan#gmail.com
rohan's password: rohan
Now we need to call this file in our class.
See below example.
Main test
SignInPage.SendkeysMethodForSignInPAgeForPropertyFile(driver, By.cssSelector("input[id='Email']") , "username" );
SignInPage.SendkeysMethodForSignInPAgeForPropertyFile(driver, By.cssSelector("input[id='Passwd'][type='password']"), "password");
So here username will be taken from properties file.
This will go to SendkeysMethodForSignInPAgeForPropertyFile which is:
public class SignInPage {
public void SendkeysMethodForSignInPAgeForPropertyFile(WebDriver driver, By by, String Text) {
WebUtils.SendkeysForPropertyFile(driver,by, Text);
}
}
Which will go to SendkeysForPropertyFile method as:
public static void SendkeysForPropertyFile(WebDriver driver, By by, String Text) {
ReadFileData File = new ReadFileData();
Properties Values = File.ReadFile();
WebElement Element = driver.findElement(by);
Element.clear();
if (Text == "username"){
Element.sendKeys(Values.getProperty("username"));
}
else {
Element.sendKeys(Values.getProperty("password"));
}
Which will read from ReadFileData() class which is:
public class ReadFileData {
public Properties ReadFile() {
File file = new File("D:\\Selenium\\Gmail_Web_UI\\Loginproperty.properties");
FileInputStream fileInput = null;
try {
fileInput = new FileInputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Properties prop = new Properties();
//load properties file
try {
prop.load(fileInput);
} catch (IOException e) {
e.printStackTrace();
}
return prop;
}
This helps to keep our username and password safe in a single file.
Reply to me for further query. Happy Learning :-)

Related

JCO_ERROR_RESOURCE: Destination ABAP_AS_WITHOUT_POOL does not exist... error while connecting via JCo

I am working on a Java app that needs to get data from our SAP system laying in SAP table. I try to connect the SW with SAP using SAP Java Connector 3.X, but I'm having trouble with the Destination.
I used the Code-Examples that came with the SAP Java Connector.
public class CustomDestinationDataProvider {
static class MyDestinationDataProvider implements DestinationDataProvider {
private DestinationDataEventListener eL;
private HashMap<String, Properties> secureDBStorage = new HashMap<String, Properties>();
public Properties getDestinationProperties(String ABAP_AS) {
try {
//read the destination from DB
Properties p = secureDBStorage.get(ABAP_AS);
if(p!=null) {
//check if all is correct, for example
if(p.isEmpty())
throw new DataProviderException(DataProviderException.Reason.INVALID_CONFIGURATION, "destination configuration is incorrect", null);
return p;
}
return null;
} catch(RuntimeException re) {
throw new DataProviderException(DataProviderException.Reason.INTERNAL_ERROR, re);
}
}
//An implementation supporting events has to retain the eventListener instance provided
//by the JCo runtime. This listener instance shall be used to notify the JCo runtime
//about all changes in destination configurations.
public void setDestinationDataEventListener(DestinationDataEventListener eventListener) {
this.eL = eventListener;
}
public boolean supportsEvents() {
return true;
}
//implementation that saves the properties in a very secure way
void changeProperties(String ABAP_AS, Properties properties) {
synchronized(secureDBStorage) {
if(properties==null) {
if(secureDBStorage.remove(ABAP_AS)!=null)
eL.deleted(ABAP_AS);
} else {
secureDBStorage.put(ABAP_AS, properties);
eL.updated(ABAP_AS); // create or updated
}
}
}
} // end of MyDestinationDataProvider
//business logic
void executeCalls(String ABAP_AS) {
JCoDestination dest;
try {
dest = JCoDestinationManager.getDestination(ABAP_AS);
dest.ping();
System.out.println("Destination " + ABAP_AS + " works");
} catch(JCoException e) {
e.printStackTrace();
System.out.println("Execution on destination " + ABAP_AS + " failed");
}
}
static Properties getDestinationPropertiesFromUI() {
//adapt parameters in order to configure a valid destination
Properties connectProperties = new Properties();
connectProperties.setProperty(DestinationDataProvider.JCO_ASHOST, "XXX");
connectProperties.setProperty(DestinationDataProvider.JCO_SYSNR, "XX");
connectProperties.setProperty(DestinationDataProvider.JCO_CLIENT, "XXX");
connectProperties.setProperty(DestinationDataProvider.JCO_USER, "XXX");
connectProperties.setProperty(DestinationDataProvider.JCO_PASSWD, "XXX");
connectProperties.setProperty(DestinationDataProvider.JCO_LANG, "XX");
createDestinationDataFile(ABAP_AS, connectProperties);
return connectProperties;
}
static void createDestinationDataFile(String ABAP_AS, Properties connectProperties) {
File destCfg = new File(ABAP_AS + ".jcoDestination");
try {
FileOutputStream fos = new FileOutputStream(destCfg, false);
connectProperties.store(fos, "for tests only!");
fos.close();
} catch (Exception e) {
throw new RuntimeException("Unable to create the destination files", e);
}
}
}
This is the Error-Message I get from NetBeans:
Destination ABAP_AS_WITHOUT_POOL works
Execution on destination ABAP_AS_WITHOUT_POOL failed
com.sap.conn.jco.JCoException: (106) JCO_ERROR_RESOURCE: Destination ABAP_AS_WITHOUT_POOL does not exist
at com.sap.conn.jco.rt.DefaultDestinationManager.update(DefaultDestinationManager.java:217)
at com.sap.conn.jco.rt.DefaultDestinationManager.searchDestination(DefaultDestinationManager.java:382)
at com.sap.conn.jco.rt.DefaultDestinationManager.getDestinationInstance(DefaultDestinationManager.java:100)
at com.sap.conn.jco.JCoDestinationManager.getDestination(JCoDestinationManager.java:104)
at jcotest2.CustomDestinationDataProvider.executeCalls(CustomDestinationDataProvider.java:92)
at jcotest2.Main.main(Main.java:39)
BUILD SUCCESSFUL (total time: 2 seconds)
It looks like your code keeps the logon data in the HashMap "secureDBStorage". Where do you fill this HashMap?
Also: what do you need the method "createDestinationDataFile()" for, if you are using a HashMap and not a file?
Edit: as this post got deleted by review, I'm trying to make it more precise now. So there are two problems with your code:
You keep the logon parameters of your backend systems in a HashMap named "secureDBStorage", but you did not fill this map with parameters for the system/destination named "ABAP_AS_WITHOUT_POOL".
Your code still contains the method "createDestinationDataFile()", which was probably copied from the sample program and then forgotten to delete. As your program is using a HashMap for storing the logon parameters and not the file system, you can delete this method. (Only confuses the program.)
Prior to calling the destination you should create it in Configuration Manager of SAP Java Application Server (NWA Manager) and then only call it.
https://help.sap.com/doc/saphelp_nwpi711/7.1.1/enUS/07/0d27932264284b883dab13ce1008a6/frameset.htm
Here is the sample:
static String ABAP_AS = "WD_MODELDATA_DEST";
PrintWriter out = response.getWriter();
JCoDestination destination;
try {
destination = JCoDestinationManager.getDestination(ABAP_AS);
out.println("Attributes:");
out.println(destination.getAttributes());
out.println();
} catch (JCoException e) {
e.printStackTrace();
out.println(e.getMessage());
}
I don't see where you fill ABAP_AS variable in your code like in the sample.

Java Properties Class

using java 8, tomcat 8
Hi, i am loading a file using properties, but i have a check before loading which returns the same properties object if its already been loaded (not null). which is a normal case scenario but i want to know if there is any way that if any change occur in target file, and some trigger should be called and refreshes all the properties objects. here is my code.
public static String loadConnectionFile(String keyname) {
String message = "";
getMessageFromConnectionFile();
if (propertiesForConnection.containsKey(keyname))
message = propertiesForConnection.getProperty(keyname);
return message;
}
public static synchronized void getMessageFromConnectionFile() {
if (propertiesForConnection == null) {
FileInputStream fileInput = null;
try {
File file = new File(Constants.GET_CONNECTION_FILE_PATH);
fileInput = new FileInputStream(file);
Reader reader = new InputStreamReader(fileInput, "UTF-8");
propertiesForConnection = new Properties();
propertiesForConnection.load(reader);
} catch (Exception e) {
Utilities.printErrorLog(Utilities.convertStackTraceToString(e), logger);
} finally {
try {
fileInput.close();
} catch (Exception e) {
Utilities.printErrorLog(Utilities.convertStackTraceToString(e), logger);
}
}
}
}
the loadConnectionFile method executes first and calls getMessageFromConnectionFile which has check implemented for "null", now if we remove that check it will definitely load updated file every time but it will slower the performance. i want an alternate way.
hope i explained my question.
thanks in advance.
Java has a file watcher service. It is an API. You can "listen" for changes in files and directories. So you can listen for changes to your properties file, or the directory in which your properties file is located. The Java Tutorials on Oracle's OTN Web site has a section on the watcher service.
Good Luck,
Avi.

Issue with sapjco3 driver

I've written a Spring MVC (Spring framework 4.1.1) java 1.8 application that successfully connects to SAP using the sapjco3.jar driver, and I've accomplished this using the CustomDestinationDataProvider technique. I then use this drive to call RFCs in my SAP R/3 system. The java code is executed via api call from an AngularJS front end application.
Something that I've discovered occuring about 5% of the time that the call to SAP happens is the following error occurs:
NestedServletException: Handler processing failed; nested exception is
java.lang.Error: java.lang.IllegalStateException: DestinationDataProvider
already registered
Here's the contents of my CustomDestinationDataProvider.java file:
public class CustomDestinationDataProvider {
public class MyDestinationDataProvider implements DestinationDataProvider {
private DestinationDataEventListener eL;
private HashMap<String, Properties> secureDBStorage = new HashMap<String, Properties>();
public Properties getDestinationProperties(String destinationName) {
try {
Properties p = secureDBStorage.get(destinationName);
if(p!=null) {
if(p.isEmpty())
throw new DataProviderException(DataProviderException.Reason.INVALID_CONFIGURATION, "destination configuration is incorrect", null);
return p;
}
return null;
} catch(RuntimeException re) {
throw new DataProviderException(DataProviderException.Reason.INTERNAL_ERROR, re);
}
}
public void setDestinationDataEventListener(DestinationDataEventListener eventListener) {
this.eL = eventListener;
}
public boolean supportsEvents() {
return true;
}
public void changeProperties(String destName, Properties properties) {
synchronized(secureDBStorage) {
if(properties==null) {
if(secureDBStorage.remove(destName)!=null)
eL.deleted(destName);
} else {
secureDBStorage.put(destName, properties);
eL.updated(destName); // create or updated
}
}
}
}
public ArrayList<MaterialBean> executeAvailabilityCall(Properties connectProperties, String searchString) {
String destName = "ABAP_AS";
SAPDAO sapDAO = new SAPDAO();
ArrayList<MaterialBean> searchResults = new ArrayList<MaterialBean>();
MyDestinationDataProvider myProvider = new MyDestinationDataProvider();
JCoDestination dest;
try {
com.sap.conn.jco.ext.Environment.registerDestinationDataProvider(myProvider);
} catch(IllegalStateException providerAlreadyRegisteredException) {
}
myProvider.changeProperties(destName, connectProperties);
try {
dest = JCoDestinationManager.getDestination(destName);
searchResults = sapDAO.searchAvailability(dest, searchString);
} catch(JCoException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
myProvider.changeProperties(destName, null);
try {
com.sap.conn.jco.ext.Environment.unregisterDestinationDataProvider(myProvider);
} catch(IllegalStateException providerAlreadyRegisteredException) {
throw new Error(providerAlreadyRegisteredException);
}
return searchResults;
} // end method executeAvailabilityCall()
} // end class CustomDestinationProvider()
My guess is that multiple api calls are occuring at the same time, and once the first query registers the destination data provider, the subsequent queries, which try to also register the destination data provider, fail because they are using the same value for 'destName' in the executeAvailabilityCall method.
Upon first glace, it seems to me like I should use a dynamic value for the destName variable instead of just using "ABAP_AS" for all queries. In other words, I should change the following line:
String destName = "ABAP_AS";
to something like this:
String destName = "ABAP_AS_" + LocalDateTime.now();
This would guarantee a unique value for the destName variable, thus a unique destination provider name.
Any thoughts on the wisdom of trying this? If this is not a good idea, what other solution would be worth exploring?
Yes, you should use multiple unique destination names for your various logon Properties configuration sets. Your class MyDestinationDataProvider is already implemented that way. But why putting a timestamp into the destination name? Why not simply using a destination name schema like "TargetSystem_<SID>_with_<username>"?
Regarding your exception, simply register MyDestinationDataProvider only once and do not permanently register and unregister it. This is not how JCo expects this to be implemented. Quote from the JCo JavaDoc at com.sap.conn.jco.ext.DestinationDataProvider:
Only one implementation of DestinationDataProvider can be registered.
For registering another implementation the infrastructure has first to
unregister the implementation that is currently registered. It is not
recommended to permanently exchange DestinationDataProvider
registrations. The one registered instance should globally manage all
destination configurations for the whole infrastructure environment.

How do you access .properties files inside an AppEngine app?

I've got an AppEngine app with two different instances, one for prod and one for staging. Accordingly, I'd like to configure the staging instance slightly differently, since it'll be used for testing. Disabling emails, talking to a different test backend for data, that kind of thing.
My first intuition was to use a .properties file, but I can't seem to get it to work. I'm using Gradle as a build system, so the file is saved in src/main/webapp/WEB-INF/staging.properties (and a matching production.properties next to it). I'm trying to access it like so:
public class Config {
private static Config sInstance = null;
private Properties mProperties;
public static Config getInstance() {
if (sInstance == null) {
sInstance = new Config();
}
return sInstance;
}
private Config() {
// Select properties filename.
String filename;
if (!STAGING) { // PRODUCTION SETTINGS
filename = "/WEB-INF/production.properties";
} else { // DEBUG SETTINGS
filename = "/WEB-INF/staging.properties";
}
// Get handle to file.
InputStream stream = this.getClass().getClassLoader().getResourceAsStream(filename);
if (stream == null) {
// --> Crashes here. <--
throw new ExceptionInInitializerError("Unable to open settings file: " + filename);
}
// Parse.
mProperties = new Properties();
try {
mProperties.load(stream);
} catch (IOException e) {
throw new ExceptionInInitializerError(e);
}
}
The problem is that getResourceAsStream() is always returning null. I checked the build/exploded-app directory, and the .properties file shows up there. I also checked the .war file, and found the .properties file there as well.
I've also tried moving the file into /WEB-INF/classes, but that didn't make a difference either.
What am I missing here?
Try
BufferedReader reader = new BufferedReader(new FileReader(filename));
or
InputStream stream = this.getClass().getResourceAsStream(filename);

How set rights to a group with xml-rpc in eclipse

i try to create a new group, but i cant set permissions
my code is
private static void createNewGroup() throws MalformedURLException, XmlRpcException {
XWikiXmlRpcClient rpc = new XWikiXmlRpcClient("http://localhost:8080/xwiki/xmlrpc/confluence");
try {
rpc.login("Admin", "admin");
// this create the group but without permissions
Page page = new Page();
page.setSpace("XWiki");
page.setParentId("XWiki.XWikiGroups");
page.setTitle("XWikiUsersGroups");
page.setId("XWiki.XWikiUsersGroup");
page.setContent("{{include document=\"XWiki.XWikiGroupSheet\"/}}");
rpc.storePage(page);
//no puedo setearle permisos
XWikiObject xobjgrp = new XWikiObject();
xobjgrp.setClassName("XWiki.XWikiGroups");
xobjgrp.setPageId("XWiki.XWikiUsersGroup");
xobjgrp.setId(-1);
xobjgrp.setProperty("levels", "View"); // this not work
xobjgrp.setProperty("allow", true); //not work, too
rpc.storeObject(xobjgrp);
} catch (XmlRpcException e) {
System.out.println("invalid username/password was specified or communication problem or ");
System.out.println(e);
} finally {
rpc.logout();
}
}
I try to do it the same way that a user is created but I can not assign permissions.
http://platform.xwiki.org/xwiki/bin/view/Features/XMLRPCJavaExamples#HUser:CreateANewUser
Help!!
Groups and rights are two separated things stored in separated objects. The levels and allow properties are set in a XWiki.XWikiRights (document related rights) or a XWiki.XWikiGlobalRights (space and wiki related rights).
You can look at http://extensions.xwiki.org/xwiki/bin/view/Extension/Setting+Rights for an example, it's a velocity script but it's the same logic.

Categories