Calling a method in another method in groovy - groovy

I have some methods in a module (groovy Spock framework. The methods all shared a common pattern. I want to make a method for this common pattern, then call on it from the mentioned methods.
two of the methods which shared the same pattern are: (I show just two of them here but they are more).
void setPayloadIndexRetention(String payloadIndexRetention) {
if (payloadIndexRetention==null){
payloadIndexRetention='30 days(default)'
}
arielRetention.find('input', class: contains('dijitArrowButtonInner')).click()
arielRetentionmenu.find('td', text: payloadIndexRetention).click()
sleep(5000)
}
arielRetention and payloadIndexRetention are defined in the module content as:
arielRetention { $('table', id: 'ARIEL_FREE_TEXT_RETENTION') }
arielRetentionmenu { $('table', id: 'ARIEL_FREE_TEXT_RETENTION_menu') }
if (privacyProtocol==null){
privacyProtocol='DES'
}
snmpPrivacyProtocol.find('input', class: contains('dijitArrowButtonInner')).click()
snmpPrivacyProtocolmenu.find('td', text: privacyProtocol).click()
sleep(5000)
}
snmpPrivacyProtocol and snmpPrivacyProtocolmenu are:
snmpPrivacyProtocol { $('table', id: 'SNMP_V3_DEC_PROTO') }
snmpPrivacyProtocolmenu { $('table', id: 'SNMP_V3_DEC_PROTO_menu') }
I made another method that includes the shared pattern:
void setParameter (String parameter, String defaultValue, def navigator1, def navigator2){
if (parameter==null){
parameter=defaultValue
}
navigator1.find('input', class: contains('dijitArrowButtonInner')).click()
navigator2.find('td', text: parameter).click()
}
When I call setParameter on the setPayloadIndexRetention method, and run my test I get the following error:
geb.error.RequiredPageContentNotPresent: The required page content 'geb.qradar.gebpages.SystemSettingsPage -> settings: geb.qradar.gebmodules.SystemSettingsModule -> arielRetentionmenu: geb.navigator.DefaultNavigator' is not present
Does anyone have any idea where am I making a mistake?
I also use Navigator instead of `def as parameter type, the issue was still there.

Related

How to use closures of Jenkins Job DSL Plugin within groovy classes

I'm new to Job DSL Plugin and even Groovy.
Given the following script:
class MyClass {
def create() {
folder('test') {
}
}
}
new MyClass().create()
I'm getting the following error:
javaposse.jobdsl.dsl.DslScriptException: (script, line 3) No signature of method: MyClass.folder() is applicable for argument types: (java.lang.String, MyClass$_create_closure1) values: [test, MyClass$_create_closure1#62591600]
Possible solutions: find(), collect()
Ok, clear. Groovy does not find a method called "folder" in my class. But this isn't a method. It is a Job DSL command. How can I use them within my classes?
You need to pass the script reference into your class, see the Job DSL wiki.
class MyClass {
def create(def dslFactory) {
dslFactory.folder('test') {
}
}
}
new MyClass().create(this)

How to get a Geb module instance with its declared class?

Up to Geb version 0.10 the example code below has worked just fine:
package whatever
import geb.Module
import geb.Page
import geb.spock.GebSpec
class ExampleSpec extends GebSpec {
def 'MODULE - Y U NO HAVE THE RIGHT CLASS?'() {
when:
ExamplePage page = to ExamplePage
then:
verifySomething(page.theModule)
}
boolean verifySomething(ExampleModule module) {
// ...
}
}
class ExamplePage extends Page {
static content = {
theModule { module ExampleModule }
}
}
class ExampleModule extends Module {
}
I wanted upgrade to the latest 0.13.1 but apparently the breaking (regressive I would say) change has been introduced which results with:
groovy.lang.MissingMethodException: No signature of method:
geb.navigator.NonEmptyNavigator.verifySomething() is applicable for
argument types: (geb.content.TemplateDerivedPageContent) values:
[whatever.ExamplePage -> theModule: whatever.ExampleModule]
I've noticed that the same happens but with different class since version 0.11, the exception message is as follows:
groovy.lang.MissingMethodException: No signature of method:
geb.navigator.NonEmptyNavigator.verifySomething() is applicable for
argument types: (geb.content.SimplePageContent) values: [theModule -
SimplePageContent (owner: whatever.ExamplePage, args: [], value:
null)]
Why module declared with a given, specific class looses it at runtime? How to prevent that?
Objects implementing Navigator interface (which includes classes extending from Module) and returned from content definitions are wrapped with TemplateDerivedPageContent objects which delegate to the underlying object but also allow to produce a meaningful path to the object for error reporting.
The wrapping of modules worked in older versions of Geb, then it got inadvertently removed and now it's back. Even though you can still call all the methods of the module when it's wrapped thanks to TemplateDerivedPageContent dynamically delegating to the underlying object you run into trouble in cases like yours - when you want to strongly type your code that uses modules. Therefore I'm still undecided what we should sacrifice here - better error reporting or ability to strongly type and this wrapping might be removed in a future version of Geb.
Luckily there is a workaround - if you want to strongly type code that consumes modules then use a getter instead of a content definition to declare them. In your case it would be:
class ExamplePage extends Page {
ExampleModule getTheModule() {
module ExampleModule
}
}

Statically load a QML Component without instantiating it

As I understand it, a QML Component is like a kind of like a class in C++. It contains the definition of a QML object but isn't an instance of it. You can create a Component in these ways:
Creating a .qml file with the component name as its filename.
Define it inline with the Component { } syntax.
However these are actually two different things. The second one is more like a factory because you can do things like:
Component {
id: factory
Rectangle { width: 100; height:100; color: "red }
}
Component.onCompleted: {
var rect1 = factory.createObject(parent);
}
Whereas with the separate file you need to first load it into a factory like this:
var factory = Qt.createComponent("RedRectangle.qml")
var rect1 = factory.createObject(parent);
I'm only concerned with dynamic object creation, so this is not an option:
RedRectangle {
id: rect1
}
My question is: is there a way to create the objects dynamically, without having to create the Component factory dynamically too, and without having to specify the Component inline. I.e. I want the first example, but where the Rectangle is specified in another file.
I want this:
Component {
id: factory
url: "RedRectangle.qml"
}
Component.onCompleted: {
var rect1 = factory.createObject(parent);
}
Sadly that doesn't work. I also tried this:
Component {
id: factory
}
Component.onCompleted: factory.loadUrl("RedRectangle.qml");
But it doesn't work either. Am I being stupid or is this just not supported?
Here is some encapsulation:
Fact.qml (for some reason it doesn't let me name it Factory)
QtObject {
property string url
readonly property Component component : Qt.createComponent(url)
function get() { return component }
function load(url) { return Qt.createComponent(url) }
}
usage:
Fact {
id: f
url: "RedRect.qml"
}
StackView {
id: stack
}
Component.onCompleted: {
stack.push(f.component) // redrect
f.url = "BlueRect.qml"
stack.push(f.get()) // bluerect, redundant but shorter
stack.push(f.load("GreenRect.qml")) // greenrect, f.component is still bluerect
}
It will only load the component when its component property is referenced and you can change the url to load other components with the same Fact instance. Also the auxiliary load() method, which returns a component without actually changing the one potentially cached.
Actually the answer is not too bad, though I still think Component should support specifying a url directly.
Here is my solution:
property var factory: Qt.createComponent("RedRectangle.qml")

How to give security voter access to current object

I want to use a Voter to only allow owners to edit a project object in my application.
I have a route /project/42/edit that invokes my action ProjectController.editAction(Project $project). I use a type hint (Project $project) to automatically invoke the ParamConverter to convert the ID 42 from the URI into a project object. This works nicely for the controller action, however it seems to be invoked too late for the voter. Its vote() method gets called with the request as 2nd parameter, not my project.
Is there a way to pass the project to the voter without having to retrieve it from the database again?
UPDATE: I learned that I have to manually call isGranted() on the security context in the edit method. This is very similar in approach to this answer.
Here is my Voter:
namespace FUxCon2013\ProjectsBundle\Security;
use FUxCon2013\ProjectsBundle\Entity\Project;
use Symfony\Component\BrowserKit\Request;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
class OwnerVoter implements VoterInterface
{
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function supportsAttribute($attribute)
{
return $attribute == 'MAY_EDIT';
}
public function supportsClass($class)
{
// your voter supports all type of token classes, so return true
return true;
}
function vote(TokenInterface $token, $object, array $attributes)
{
if (!in_array('MAY_EDIT', $attributes)) {
return self::ACCESS_ABSTAIN;
}
if (!($object instanceof Project)) {
return self::ACCESS_ABSTAIN;
}
$user = $token->getUser();
$securityContext = $this->container->get('security.context');
return $securityContext->isGranted('IS_AUTHENTICATED_FULLY')
&& $user->getId() == $object->getUser()->getId()
? self::ACCESS_GRANTED
: self::ACCESS_DENIED;
}
}
I register this in configure.yml so that it gets the service container as parameter:
services:
fuxcon2013.security.owner_voter:
class: FUxCon2013\ProjectsBundle\Security\OwnerVoter
public: false
arguments: [ #service_container ]
tags:
- { name: security.voter }
The last block is to configure the access decision manager in security.yml to unanimous:
security:
access_decision_manager:
# strategy can be: affirmative, unanimous or consensus
strategy: unanimous
allow_if_all_abstain: true
Please have a look at this answer i have written yesterday.
You can easily adapt it to your needs by checking for the owner of your object.
The current object doesn't get passed in the voter if you use the role security handler.
I had to extend the latter to get the former.
Don't hesitate to comment for details.

how to detect caller instance in SoapUI groovy script?

A SoapUI project can run random script upon load.
Load Script is invoked with log and project variables.
In my shared lib I have method - addAsserts() that traverses the whole project and adds schema compliance assertions to SOAP test steps. In my Load Script I call shared method
addAsserts(this)
passing 'this' as a parameter and set closure.delegate to it inside addAsserts method to make 'project' variable accessible within the closure scope
addAsserts method is defined in sharedUtil.groovy:
static def addAsserts(that){
def closure={
project.testSuites.each { testSuiteName, testSuiteObject ->
testSuiteObject.testCases.each { testCaseName, testCaseObject ->
testCaseObject.testSteps.each { testStepName, testStepObject ->
if ("class com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep" == testStepObject.getClass().toString() ) {
log.info "adding 'Schema Compliance' assertion to ${testSuiteName}/${testCaseName}/${testStepName}"
testStepObject.addAssertion('Schema Compliance')
}
}
}
}
}//closure
closure.delegate=that // <--- i would like NOT to pass 'that' as parameter
// but rather detect in runtime with some kind of
// getCallerInstance() method
return closure.call()
}
QUESTION:
Is it possible to detect caller instance in runtime with some kind of getCallerInstance() method ?
No, I don't believe this is possible. Wasn't in Java either (you can find out the name/method of the calling class using some horrible stacktrace hacking, but not the instance of the class itself)
Edit...
It might be possible with a Category (but I am not experienced with SoapUI, so I don't know if this technique would fit)
Say we have a class Example defined like so:
class Example {
String name
}
We can then write a class very similar to your example code, which in this case will set the delegate of the closure, and the closure will print out the name property of the delegate (as we have set the resolve strategy to DELEGATE_ONLY)
class AssetAddingCategory {
static def addAsserts( that ) {
def closure = {
"Name of object: $name"
}
closure.delegate = that
closure.resolveStrategy = Closure.DELEGATE_ONLY
closure.call()
}
}
Later on in our code, it is then possible to do:
def tim = new Example( name:'tim' )
use( AssetAddingCategory ) {
println tim.addAsserts()
}
And this will print out
Name of object: tim

Resources