Groovy CliBuilder: only last LongOpt is taken in account - groovy

I'm trying to use the groovy CliBuilder to parse command line options. I'm trying to use multiple long options without a short option.
I have the following processor:
def cli = new CliBuilder(usage: 'Generate.groovy [options]')
cli.with {
h longOpt: "help", "Usage information"
r longOpt: "root", args: 1, type: GString, "Root directory for code generation"
x args: 1, type: GString, "Type of processor (all, schema, beans, docs)"
_ longOpt: "dir-beans", args: 1, argName: "directory", type: GString, "Custom location for grails bean classes"
_ longOpt: "dir-orm", args: 1, argName: "directory", type: GString, "Custom location for grails domain classes"
}
options = cli.parse(args)
println "BEANS=${options.'dir-beans'}"
println "ORM=${options.'dir-orm'}"
if (options.h || options == null) {
cli.usage()
System.exit(0)
}
According to the groovy documentation I should be able to use multiple "_" values for an option when I want it to ignore the short option name and use a long option name only. According to the groovy documentation:
Another example showing long options (partial emulation of arg
processing for 'curl' command line):
def cli = new CliBuilder(usage:'curl [options] <url>')
cli._(longOpt:'basic', 'Use HTTP Basic Authentication')
cli.d(longOpt:'data', args:1, argName:'data', 'HTTP POST data')
cli.G(longOpt:'get', 'Send the -d data with a HTTP GET')
cli.q('If used as the first parameter disables .curlrc')
cli._(longOpt:'url', args:1, argName:'URL', 'Set URL to work with')
Which has the following usage message:
usage: curl [options] <url>
--basic Use HTTP Basic Authentication
-d,--data <data> HTTP POST data
-G,--get Send the -d data with a HTTP GET
-q If used as the first parameter disables .curlrc
--url <URL> Set URL to work with
This example shows a common convention. When mixing short and long
names, the short names are often one
character in size. One character
options with arguments don't require a
space between the option and the
argument, e.g. -Ddebug=true. The
example also shows the use of '_' when
no short option is applicable.
Also note that '_' was used multiple times. This is supported but
if any other shortOpt or any longOpt is repeated, then the behavior is undefined.
http://groovy.codehaus.org/gapi/groovy/util/CliBuilder.html
When I use the "_" it only accepts the last one in the list (last one encountered). Am I doing something wrong or is there a way around this issue?
Thanks.

not sure what you mean it only accepts the last one. but this should work...
def cli = new CliBuilder().with {
x 'something', args:1
_ 'something', args:1, longOpt:'dir-beans'
_ 'something', args:1, longOpt:'dir-orm'
parse "-x param --dir-beans beans --dir-orm orm".split(' ')
}
assert cli.x == 'param'
assert cli.'dir-beans' == 'beans'
assert cli.'dir-orm' == 'orm'

I learned that my original code works correctly. What is not working is the function that takes all of the options built in the with enclosure and prints a detailed usage. The function call built into CliBuilder that prints the usage is:
cli.usage()
The original code above prints the following usage line:
usage: Generate.groovy [options]
--dir-orm <directory> Custom location for grails domain classes
-h,--help Usage information
-r,--root Root directory for code generation
-x Type of processor (all, schema, beans, docs)
This usage line makes it look like I'm missing options. I made the mistake of not printing each individual item separate from this usage function call. That's what made this look like it only cared about the last _ item in the with enclosure. I added this code to prove that it was passing values:
println "BEANS=${options.'dir-beans'}"
println "ORM=${options.'dir-orm'}"
I also discovered that you must use = between a long option and it's value or it will not parse the command line options correctly (--long-option=some_value)

Related

pass options to cucumber formatter

When running cucumber to perform the test scenario's for a project, I use the pretty formatter cucumber --format pretty.
This gives me output like
#search
Feature: search
Background: # features/zoeken.feature:4
Given I log in as testuser # features/step_definitions/elvis_steps.rb:1
I would like the formatter to skip the mention of the sourceline. In the code of the pretty-formatter, I located the place where it is output and is says
def print_step_data(test_step, result)
base_indent = options[:expand] && in_scenario_outline ? 8 : 4
step_keyword = test_step_keyword(test_step)
indent = options[:source] ? #source_indent - step_keyword.length - test_step.text.length - base_indent : nil
print_comments(test_step.location.lines.max, base_indent)
name_to_report = format_step(step_keyword, #step_matches.fetch(test_step.to_s) { NoStepMatch.new(test_step, test_step.text) }, result.to_sym, indent)
#io.puts(indent(name_to_report, base_indent))
print_multiline_argument(test_step, result, base_indent + 2) unless options[:no_multiline]
#io.flush
end
So I can get the output I want bij setting option :source to false. Which indeed works.
My question is: how can I pass this option to the formatter without changing the code of the formatter? Is there a command line trick for this, or can I specify it in my own code?
Result of adding options[:source] = false to pretty.rb:
#search
Feature: search
Background:
Given I log in as testuser
.... which is what I want.

Codeception doesn't override parameter in Gitlab

I have this issue
*********** codeception.yml ***************
paths:
tests: tests
output: tests/_output
data: tests/_data
support: tests/_support
envs: tests/_envs
actor_suffix: Tester
#amount customer per product
amountPerProduct: 1
wishCountry: 1
wishProduct: 0
I am using the param like this:
$countryIndex = Configuration::config()['wishCountry'];
but on the console I calling the test like this:
codecept run tests/acceptance/ChangeCest.php --env chrome --xml --html -o "wishProduct:55"
I get this error:
enter image description here
QUESTION: how can I override this config in Gitlab?
Thank you
Not entirely sure if this solves your problem but for Codeception v5 (also my current local version v4.2.1) the option is exploded with : , i.e. with an appended space. I notice in your screenshot the exception does show the key/value without the space in between, but you didn't specify which version of Codeception you're using.
From Config.php:
foreach ($configOptions as $option) {
$keys = explode(': ', $option);
// ^ notice the space here
if (count($keys) < 2) {
throw new \InvalidArgumentException('--override should have config passed as "key: value"');
}
https://github.com/Codeception/Codeception/blob/5.0/src/Codeception/Command/Shared/ConfigTrait.php
i find the answer to my problem.
I store the parameters in a new file params.yml
params.yml
parameters:
WISH_PRODUCT: 55
codeception.yml
params:
- params.yml
acceptance.suite.yml
config:
custom_params:
wishProduct: %WISH_PRODUCT%
AcceptanceTester.php
so in AcceptanceTester I can read the values like this
$custom_params = Configuration::suiteSettings('acceptance', Configuration::config())['modules']['custom_params'];

How do I associate a filename with an uploaded file for an openapi autogenerated python call?

Current situation: My team is using openapi autogenerated code to provide the interface between angular an python clients on the one side, and a REST server based on Spring Boot on the other. I'm dealing with an endpoint that uploads files. Now, often when uploading files to Spring, the uploading app will include the name of the file in the headers, which the spring side will receive as Resource.filename. Ive been unable to figure out how to induce the autogenerated python code to do the same, if it is indeed possible at all.
For clarification - openapi autogen has seven different python generators. WE're using the one that's simply called "python"
The pertinent section of the openapi.yaml looks something like this:
/api/{item_id}/data:
post:
parameters:
- $ref: "#/components/parameters/item_id"
requestBody:
content:
"*/*":
schema:
type: string
format: binary
required: true
operationId: postItemData
tags: [ "Item Ops" ]
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/results"
...and the python that I'm trying to write looks something like this:
with open(os.path.join(scriptdir, "testData2.txt")) as newFile:
results = itemOpsAPI.post_item_data(itemID, newFile)
I tried looking at the autogenerated code, but it was not super-useful. the first layer is more or less as follows:
def post_item_data(
self,
item_id,
body,
**kwargs
):
"""
# noqa: E501
This method makes a synchronous HTTP request by default. To make an
asynchronous HTTP request, please pass async_req=True
>>> thread = api.post_item_data(item_id, body, async_req=True)
>>> result = thread.get()
Args:
item_id (str):
body (file_type):
Keyword Args:
_return_http_data_only (bool): response data without head status
code and headers. Default is True.
_preload_content (bool): if False, the urllib3.HTTPResponse object
will be returned without reading/decoding response data.
Default is True.
_request_timeout (int/float/tuple): timeout setting for this request. If
one number provided, it will be total request timeout. It can also
be a pair (tuple) of (connection, read) timeouts.
Default is None.
_check_input_type (bool): specifies if type checking
should be done one the data sent to the server.
Default is True.
_check_return_type (bool): specifies if type checking
should be done one the data received from the server.
Default is True.
_host_index (int/None): specifies the index of the server
that we want to use.
Default is read from the configuration.
async_req (bool): execute request asynchronously
Returns:
Results
If the method is called asynchronously, returns the request
thread.
"""
kwargs['async_req'] = kwargs.get(
'async_req', False
)
kwargs['_return_http_data_only'] = kwargs.get(
'_return_http_data_only', True
)
kwargs['_preload_content'] = kwargs.get(
'_preload_content', True
)
kwargs['_request_timeout'] = kwargs.get(
'_request_timeout', None
)
kwargs['_check_input_type'] = kwargs.get(
'_check_input_type', True
)
kwargs['_check_return_type'] = kwargs.get(
'_check_return_type', True
)
kwargs['_host_index'] = kwargs.get('_host_index')
kwargs['workspace_hash'] = \
workspace_hash
kwargs['element_id'] = \
element_id
kwargs['version_id'] = \
version_id
kwargs['body'] = \
body
return self.post_item_data.call_with_http_info(**kwargs)
I recognize that it might be possible to add the filename to the "file_type" in a way that the generated code would recognize, but I have no real idea of how to do that and have it actually work. I've searched around online reasonably thoroughly already - the bits that I've found that decribe how to do things in python are asking me to make changes within the area that the autogen code has taken over. The bits that I've found on how to handle openapi autogenerated code don't seem to cover this particular issue on the python side.

How to make the translations work with the Python 3 "format" built-in method in Odoo?

Since Python v3, format is the primary API method to make variable substitutions and value formatting. However, Odoo is still using the Python 2 approach with the %s wildcard.
message = _('Scheduled meeting with %s') % invitee.name
# VS
message = 'Scheduled meeting with {}'.format(invitee.name) # this is not translated
I have seen some parts of the Odoo code where they have used some workaround, isolating strings.
exc = MissingError(
_("Record does not exist or has been deleted.")
+ '\n\n({} {}, {} {})'.format(_('Records:'), (self - existing).ids[:6], _('User:'), self._uid)
)
But, does anybody know if there is a more convenient way to use the format method and make it work with translations?
_ return a string, so you can call format on it directly.
_("{} Sequence").format(sec.code)
or like this:
_("{code} Sequence").format(code=invitee.code)
when you export the translation in PO file you should see this for the second example:
# for FR translation you should not translate the special format expression
msgid "{code} Sequence"
msgstr "{code} Séquence"
and this for the first example:
msgid "{} Sequence"
msgstr "{} Séquence"
If you don't see this then Odoo must be checking that _() must not be followed by . so you can work around this by doing this for example by surrounding the expression by parentheses :
# I think + "" is not needed
( _("{} Séquence") + "").format(sec.code)
Because In python "this {}".format("expression") is the same as this ("this {}").format("expression")

jmeter - user defined variables and groovy

this is my objective:
keep the Test Plan more flexible and usable both on win and mac (since some people use mac and other use win).
I created this simple script in groovy:
import org.apache.jmeter.services.FileServer;
import groovy.json.JsonSlurper;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
String winPath;
String macPath;
String winSlash;
String macSlash;
String userPath;
String userSlash;
if (System.properties['os.name'].toLowerCase().contains('windows')) {
winPath="C:\\QA\\";
winSlash="\\";
vars.put("userPath",winPath.toString());
}
if (System.properties['os.name'].toLowerCase().contains('mac')) {
macPath="/Users/macUser/QA/";
macSlash="/";
vars.put("userPath",macPath.toString());
}
and add it into a "JSR223 Sampler" object under my Thread Group object
Then I've added a "User Defined Variables" object with the following var:
Name value
projectDir myProjectDir
rootPath ${__groovy(props.getProperty("userPath"))}${projectDir}
Then I tried to used the rootPath variable for setting the path of my csv files, so I've added ${projectDir}/AUTH.csv to FileName in "CSV Data Set Config" object, but I got this message:
2018-11-23 16:36:40,634 DEBUG o.a.j.t.TestBeanHelper: Ignoring property 'property' in org.apache.jmeter.config.CSVDataSet
2018-11-23 16:36:40,634 DEBUG o.a.j.t.TestBeanHelper: Setting filename=myProjectPath/AUTH.csv
2018-11-23 16:36:40,634 DEBUG o.a.j.t.TestCompiler: Subtracting node, stack size = 2
2018-11-23 16:36:40,634 DEBUG o.a.j.t.TestCompiler: Subtracting node, stack size = 1
2018-11-23 16:36:40,634 INFO o.a.j.t.JMeterThread: Thread started: Thread Group 1-1
2018-11-23 16:36:40,634 INFO o.a.j.s.FileServer: Stored: myProjectPath/AUTH.csv
2018-11-23 16:36:40,635 ERROR o.a.j.t.JMeterThread: Test failed!
java.lang.IllegalArgumentException: Could not read file header line for file myProjectPath/AUTH.csv
as you can see it trying to read myProjectPath/AUTH.csv and then off course it get an exception..
why it doesn't "read" the variable rootPath ?
any suggestions?
According to the User Defined Variables documentation:
Note that all the UDV elements in a test plan - no matter where they are - are processed at the start.
Additionally be aware of JMeter Test Elements Execution Order
0. Configuration elements
1. Pre-Processors
2. Timers
3. Sampler
4. Post-Processors (unless SampleResult is null)
5. Assertions (unless SampleResult is null)
6. Listeners (unless SampleResult is null)
Assuming above points your Groovy code is being executed after User Defined Variables therefore you cannot access the value. So the only way to define dynamic value depending on the operating system in the User Defined Variables is using __groovy() function directly in the Value section like:
${__groovy(if(System.getProperty('os.name').toLowerCase().contains('windows')){return 'C:\\\QA\\\' } else { return '/Users/macUser/QA/' },)}
Make sure to escape commas and backslashes with another backslash as in JMeter Functions comma acts as parameters separator and backslash is an escape character. Check out Apache JMeter Functions - An Introduction guide to learn more about JMeter Functions contept.
The issue is that you try to add it to the properties and try to read it from the variables.
Also, don't bother the \ or / in Java. Java handles both on every platform. (Difference between File.separator and slash in paths)
For me this works fine:
def path;
if (System.properties['os.name'].toLowerCase().contains('windows')) {
path="C:\\QA\\";
} else if (System.properties['os.name'].toLowerCase().contains('mac')) {
path="/Users/macUser/QA/";
}
vars.put("userPath",path);
vars.put("rootPath", path+vars.get("projectDir"));
And to use it: log.info(vars.get("rootPath"))

Resources