I am new to geb, spock and groovy. The script I am working on is I have a groovy class containing my json. In my groovy class I count how many objects are there in the json and for each object I read key values and then I have another unit testSpec in spock and Geb where I have create my login test script to login to the application which is very simple.
The scenario I am trying to achieve is I want to generate data table in spock test based on data present in json file.
Here what I have achieved till now
My InputDataJson.groovy file
package resources
import geb.spock.GebSpec
import groovy.json.JsonSlurper
import spock.lang.Shared
class InputDataJson extends GebSpec{
#Shared
def inputJSON,
idValue, passwordValue, jsonSize
#Shared
def credsList = []
def setup() {
inputJSON = '''{
"validLogin":{
"username" : "abc",
"password" : "correcttest"
},
"invalidLogin":{
"username" : "xyz",
"password" : "badtest"
}
}'''
def JsonSlurper slurper = new JsonSlurper()
def TreeMap parsedJson = slurper.parseText(inputJSON)
jsonSize = parsedJson.size()
Set keySet = parsedJson.keySet()
int keySetCount = keySet.size()
for(String key : keySet){
credsList.add(new Creds(username: parsedJson[key].username,password:
parsedJson[key].password))
}
}
}
and here is my sample spock geb test
package com.test.demo
import grails.test.mixin.TestMixin
import grails.test.mixin.support.GrailsUnitTestMixin
import pages.LoginPage
import resources.InputDataJson
/**
* See the API for {#link grails.test.mixin.support.GrailsUnitTestMixin} for usage instructions
*/
#TestMixin(GrailsUnitTestMixin)
class SampleTest1Spec extends InputDataJson {
def credentialsList = []
def setup() {
credentialsList = credsList
}
def cleanup() {
}
void "test something"() {
}
def "This LoginSpec test"() {
given:
to LoginPage
when:'I am entering username and password'
setUsername(username)
setPassword(password)
login()
then: "I am being redirected to the homepage"
println("Hello")
where:
[username,password]<< getCreds()
//credsList[0]['username'] | credsList[0]['password']
}
def getCreds(){
println(" CREDS inside " + credsList)
println(" credentialsList : " + credentialsList)
}
}
The problem is when I run this test in debug mode (I understand in spock test first where clause is executed first) my credsList and credentialsList both are coming null and when execution mode reaches to "when" section it fetches the correct user name and password. I am not sure where I am making mistake.
Any help is well appreciated.
Leonard Brünings said:
try replacing setup with setupSpec
Exactly, this is the most important thing. You want something that is initialised before any feature method or iteration thereof starts. So if you want to initialise static or shared fields, this is the way to go.
Additionally, credsList contains Creds objects, not just pairs of user names and passwords. Therefore, if you want those in separate data variables, you need to dereference them in the Creds objects. Here is a simplified version of your Spock tests without any Grails or Geb, because your question is really just a plain Spock question:
package de.scrum_master.stackoverflow.q71122575
class Creds {
String username
String password
#Override
String toString() {
"Creds{" + "username='" + username + '\'' + ", password='" + password + '\'' + '}'
}
}
package de.scrum_master.stackoverflow.q71122575
import groovy.json.JsonSlurper
import spock.lang.Shared
import spock.lang.Specification
class InputDataJson extends Specification {
#Shared
List<Creds> credsList = []
def setupSpec() {
def inputJSON = '''{
"validLogin" : {
"username" : "abc",
"password" : "correcttest"
},
"invalidLogin" : {
"username" : "xyz",
"password" : "badtest"
}
}'''
credsList = new JsonSlurper().parseText(inputJSON)
.values()
.collect { login -> new Creds(username: login.username, password: login.password) }
}
}
package de.scrum_master.stackoverflow.q71122575
import spock.lang.Unroll
class CredsTest extends InputDataJson {
#Unroll("verify credentials for user #username")
def "verify parsed credentials"() {
given:
println "$username, $password"
expect:
username.length() >= 3
password.length() >= 6
where:
cred << credsList
username = cred.username
password = cred.password
}
}
The result in IntelliJ IDEA looks like this:
Try it in the Groovy web console
Related
I Have a file json named production_2.json
[
{
"v":{
"id":"rep_01564526",
"name":"tuttoverde.pgmx",
"type":"PRODUCTION_STARTED",
"ute":"CDL",
"ver":"1.0",
"status":"EXE"
},
"ts":"2020-11-19T08:00:00Z"
},
{
"v":{
"id":"rep_01564526",
"name":"tuttoverde.pgmx",
"type":"PRODUCTION_ENDED",
"ute":"CDL",
"ver":"1.0",
"status":"EXE"
},
"ts":"2020-11-19T17:00:00Z"
}
]
And have the folling Karate code, that:
Read the file production_2.json
and for each element of the array send a topic
I * def sendtopics =
"""
function(i){
var topic = "data." + machineID + ".Production";
var payload = productions[i];
karate.log('topic: ', topic )
karate.log('payload: ', payload )
return mqtt.sendMessage(payload, topic);
}
"""
* def productions = read('this:productions_json/production_2.json')
* def totalProductionEvents = productions.length
* def isTopicWasSent = karate.repeat(totalProductionEvents, sendtopics)
* match each isTopicWasSent == true
The function
mqtt.sendMessage(payload, topic);
is a function in java, that have the following segnature
public Boolean sendMessage(String payload, String topic) {
System.out.println("Publishing message: ");
System.out.println("payload " + payload);
System.out.println("topic " + topic);
return true;
}
the problem is that the value of the "payload" inside the javascript function is correct and is printed correctly, while inside the "sendMessage" function the value of the payload is formatted incorrectly.
For example here is what it prints inside karate.log('payload: ', payload )
payload: {
"v": {
"id": "rep_01564526",
"name": "tuttoverde.pgmx",
"type": "PRODUCTION_STARTED",
"ute": "CDL",
"ver": "1.0",
"status": "EXE"
},
"ts": "2021-01-08T08:00:00Z"
}
And Here instead what is printed on the function "sendMessage" of the java class
payload {v={id=rep_01564526, name=tuttoverde.pgmx, type=PRODUCTION_STARTED, ute=CDL, ver=1.0, status=EXE, ts=2021-01-08T08:00:00Z}
I don't understand why the payload is formatted incorrectly (= instead of : ) and is it not a string. I also tried using the following solution and it doesn't work for me
* def sendtopics =
"""
function(i){
var topic = "data." + machineID + ".Production";
var payload = productions[i];
var payload2 = JSON.stringify(payload);
return mqtt.sendMessage(payload2, topic);
}
"""
How do I convert an object inside javascript to a string so I can pass it to java?
You are doing some really advanced stuff in Karate. I strongly suggest you start looking at the new version (close to release) and you can find details here: https://github.com/intuit/karate/wiki/1.0-upgrade-guide
The reason is because the async and Java interop has some breaking changes - and there are some new API-s you can call on the karate object in JS to do format conversions:
var temp = karate.fromString(payload);
And karate.log() should work better and not give you that odd formatting you are complaining about. With the current version you can try karate.toJson() if that gives you the conversion you expect.
Given your advanced usage, I recommend you start using the new version and provide feedback on anything that may be still needed.
I came across a use-case where I need to update a specific field in the ElasticSearch document. So for this use-case, I have used the Update API with a script ES doc. But I faced an issue(compilation error) with Script Constructor which accepts the following parameters:--> type, lang, idOrCode and params and the issue was with params(java.util.Map) parameter.
I have even tried the Scala to Java converters but could not solve it.
Code snippet
import org.elasticsearch.action.update.UpdateRequest
import org.elasticsearch.client.RequestOptions
import org.elasticsearch.script.{Script, ScriptType}
object Testing extends App {
val result = updateByScript("testing", "hW7BBnQBn2nWmIjS_b0C", 10.0)
println("######result:---> " + result)
high_level_client.close()
def updateByScript(index: String, id: String, count: Double) = {
//import scala.collection.JavaConversions.mapAsJavaMap
//import collection.JavaConverters._
import scala.collection.JavaConverters._
val updateRequest = new UpdateRequest(index, id)
val params = Map[String, Double]("count" -> count)
val script = new Script(ScriptType.INLINE, "painless", "ctx._source.count += params.count", mapAsJavaMap(params))
updateRequest.script(script)
high_level_client.update(updateRequest, RequestOptions.DEFAULT)
}
}
For the above issue, I have tried the Script Constructor with the idOrCode parameter and which solved my use-case but still I did not get the solution for other Script Constructors.
Working code with Constructor which accept idOrCode parameter.
Code snippet
import org.elasticsearch.action.update.UpdateRequest
import org.elasticsearch.client.RequestOptions
import org.elasticsearch.script.{Script, ScriptType}
object Testing extends App {
val result = updateByScript("testing", "hW7BBnQBn2nWmIjS_b0C", 10.0)
println("######result:---> " + result)
high_level_client.close()
def updateByScript(index: String, id: String, count: Double) = {
val updateRequest = new UpdateRequest(index, id)
val script = new Script(s"""ctx._source.count += $count""")
updateRequest.script(script)
high_level_client.update(updateRequest, RequestOptions.DEFAULT)
}
}
I'm USING GATLING AND trying to use in java's library "Base64" in scala for sending encode uder:password in header ("authorization") request, with dynamic values:
I'm trying to do as follow :
val register = {
exec(request.asJSON
.check(status.is(200))
.check(jsonPath("$..user").saveAs("user"))
.check(jsonPath("$..password").saveAs("password"))
).pause(1)
}
val myvalue: HttpRequestBuilder = Utils.createPostFormParamsRequest(
"myvalue",
login,
Map("value"-> ("Basic " + Base64.getEncoder.encodeToString((("${user}").getBytes() + ":" + ("${password}").getBytes()).getBytes("utf-8")))),
Map())
I'd tried also Base64.getEncoder.encodeToString(("${uesr}" + ":" + "${password}").getBytes("utf-8"))))
But it seems like the Base64 take the String "${user}" and not the actual value, so the encryption does not work properly.
I'd tried to :
val helper = {
exec { session =>
val user : String= (session("user").as[String])
val password : String= (session("password").as[String])
val temp = "Basic " + Base64.getEncoder.encodeToString((user + ":" + password).getBytes("utf-8"))
val temp2: HttpRequestBuilder = Utils.createPostFormParamsRequest(
"bla",
login,
Map("value"-> temp),
Map())
val assert = {
exec(helper.asJSON
.check(status.is(200))
.check(header("answer").saveAs("answer"))
).pause(1)
}
session
}
And here the encryption works properly, but the "exec" do not.
There is a way to save the values in run time without part of the exec?
I don't know Gatling that well, but I think this should work. It's not the prettiest but without seeing the full code and how it's used it's a bit difficult to come up with something that looks good:
var token: String = null
val registerAssert = exec(...)
def finalToken = {
Utils.createPostFormParamsRequest(
"Final token",
Constants.LOGIN,
Map("Authorization"-> token),
Map())
}
def saveToken(s: Session) = {
token = "Basic " + Base64.getEncoder.encodeToString((s("uuid").as[String].getBytes() + ":" + s("secret").as[String].getBytes()).getBytes("utf-8")
s
}
// now you're actually executing the above
scenario(...)
.exec(registerAssert)
.exec(saveToken(_))
.exec(finalToken) // I'm assuming finalToken is executable
The intention of this is to first save the token value in a class variable, and then only construct the finalToken request (which uses that token) afterwards. Hence the def, and when it's called the token value will have been set.
I have taken a written sample from this link to write my Python + Java integration code.
http://www.jython.org/jythonbook/en/1.0/JythonAndJavaIntegration.html
The code looks like below.
package org.jython.book.interfaces;
import org.jython.book.interfaces.JythonObjectFactory;
import org.python.core.Py;
import org.python.core.PyString;
import org.python.core.PySystemState;
public class Main {
public static void main(String args[]) {
String projDir = System.getProperty("user.dir");
String rootPath = projDir + "/src/org/jython/book/interfaces/";
String modulesDir = projDir + "/src/org/jython/book/interfaces/";
System.out.println("Project dir: " + projDir);
PySystemState sysSt = Py.getSystemState();
JythonObjectFactory factory = new JythonObjectFactory(sysSt, BuildingType.class, "Building", "Building");
BuildingType building = (BuildingType) factory.createObject();
building.setBuildingName("BUIDING-A");
building.setBuildingAddress("100 MAIN ST.");
building.setBuildingId(1);
System.out.println(building.getBuildingId() + " " +
building.getBuildingName() + " " +
building.getBuildingAddress());
}
}
When I run this code, it throws an error that it did not find the python module. I have kept the .py and .pyc files under the path provided as 'modulesDir'.
The literature says that "the requested module must be contained somewhere on the sys.path"; however, I did not understand how this can be set from this Java program. Can someone please provide some help?
Project dir: /Users/eclipsews/PythonJava
Exception in thread "main" ImportError: No module named Building
Hi found the answer to this issue!
Added the PySystemState.initialize method where I explicitly provide the "python.path" property, which is initialized to my project's path, where python modules are available.
private static Properties setDefaultPythonPath(Properties props) {
String pythonPathProp = props.getProperty("python.path");
String new_value;
if (pythonPathProp == null) {
new_value = System.getProperty("user.dir") + "/src/org/jython/book/interfaces/";
}
props.setProperty("python.path", new_value);
return props;
}
Properties props = setDefaultPythonPath(System.getProperties());
PySystemState.initialize( System.getProperties(), props, null );
This produces the correct output as follows:
module=<module 'Building' from '/Users/eclipsews/PythonJava/src/org/jython/book/interfaces/Building$py.class'>,class=<class 'Building.Buildin
g'>
1 BUIDING-A 100 MAIN ST.
i am trying to customize secure social methods on play framework using java APIs.
basically i need to send requests in J SON and also responses in J SON.
what i want to do is a back end for I-phone App. there is no many resources about secure social on the internet.
i need to implement log in using username and password and using providers(face book,twitter,...).
i used this code but did not work:
import play.api.libs.json.Json
import play.api.mvc._
import securesocial.core._
class AuthController extends Controller {
private implicit val readsOAuth2Info = Json.reads[OAuth2Info]
// Some of the below code is taken from ProviderController in SecureSocial
def authenticateMobile(providerName: String) = Action(parse.json) { implicit request =>
// format: { "accessToken": "..." }
val oauth2Info = request.body.asOpt[OAuth2Info]
val provider = Registry.providers.get(providerName).get
val filledUser = provider.fillProfile(
SocialUser(IdentityId("", provider.id), "", "", "", None, None, provider.authMethod, oAuth2Info = oauth2Info))
UserService.find(filledUser.identityId) map { user =>
val newSession = Events.fire(new LoginEvent(user)).getOrElse(session)
Authenticator.create(user).fold(
error => throw error,
authenticator => Ok(Json.obj("sessionId" -> authenticator.id))
.withSession(newSession - SecureSocial.OriginalUrlKey - IdentityProvider.SessionId - OAuth1Provider.CacheKey)
.withCookies(authenticator.toCookie)
)
} getOrElse NotFound(Json.obj("error" -> "user not found"))
}
// any other methods you might have relating to authentication ...
}
any idea how i can start with that?
thanks