How to change download directory during test run - capybara

I have a few tests that download files and assert data inside. The problem I am facing is that the tests run in parallel so I can't delete the download directory after each test or else they delete each others files. The issue with not doing so however is that the filename includes timestamp(unique identifier) which is not known to the test so not possible to know which file to open. Is there a way to change default_directory for a given test in the middle of test run? The idea is to be able to tell capybara that for certain tests override the download path to be another path temporarily? I guess there could be cross wiring here too if it was possible as other tests could still be running expecting the original path to be set?
Alternatively, any suggestions on handling this?
My capybara config looks like this
options = Selenium::WebDriver::Chrome::Options.new
preferences = {
prompt_for_download: false,
credentials_enable_service: false,
default_directory: DownloadUtil::PATH
}
options.add_preference(:download, preferences)
options.add_argument('--disable-infobars')
options.add_argument('--headless')
Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)
end

Most multi-process parallel test setups provide you with an environment variable you can use to configure things that need to be different between each instance of test runner (DB name, ports, etc). In the case of parallel_rspec that is TEST_ENV_NUMBER. Using that you can configure the selenium/chrome instance in each test runner to use a different download directory - something like
preferences = {
prompt_for_download: false,
credentials_enable_service: false,
default_directory: DownloadUtil::PATH + ENV['TEST_ENV_NUMBER']
}

Related

new File(...).eachFileRecurse() fails on existing files and folders

Currently I'm refactoring our Jenkins build pipeline. In the stage of gathering our unittests I'm trying to enumerate all '**/.test.dll' files, or '.test.dll' at least. Read somewhere that this could be achieved using eachFileRecurse from the File-object.
But... all calls failed reporting FileNotFoundException.
Using the Scriptconsole on the specific slave I tried the same code and it works as expected. Adding some addition debug lines in our jenkins-file shows that the pipeline always returns false.
def TestFile(path)
{
def file = new File(path)
echo "File '${file}' exists: ${file.exists()}"
}
TestFile(WORKSPACE)
TestFile(pwd())
TestFile(BUILDPATH)
All result a 'exists: false', even though all these paths are already used during the build.
(How) can I use the File-object in a pipeline or how can I get the files I need?
Use fileExists together otherwise it will not work.
For example in your case it will be like this
echo "fileExists '${file}' exists: '${file}'"

How are webdriver and chromedriver options accessed in Spectron's new Application()?

When I start a new Spectron application (for each test suite) I would like to fix the size of the app (for consistency across all machines and reloads).
Commands like setBounds and maximise do change dimensions, but they only do so after the app has started (which means that some components have already assumed certain dimensions, which then changes test results).
In the Spectron docs various launch options are available. I've tired to use webdriver and chromedriver options but they don't seem to work. Here is an example:
app = new Application({
path: kElectronPath,
webdriverOptions: {
width:1368,
height:769,
},
I just assumed that the webdriver options came from the browserwindow class. How are webdriver and chromedriver options accessed in Spectron?
This should help
this.app = new Application({
path: './ac.exe',
args: ['app'],
webdriverOptions: ({deprecationWarnings : false})
});
pass the parameters that need to be changed during app launch
and have your new application config in before hook

How to tell Grails application which environment it is in?

I would like to load Environment specific configurations in my grails application so that depending on which JVM the grails application is running on, I can point to that environment specific urls. In my case, I have 4 different environments to work with (instead of the default 3 that grails app assumes) when my app goes from dev to prod.
My JVMs all have a System property defined that, when I do "System.getProperty()", tell me which environment that application is running on.
My question is, what is the best place to check and load the environment-specific configurations during run-time? Inside BootStrap.groovy? I do not have the option to build my war file using command line or grails {env_name} war.
Thanks.
Set the variable grailsEnv as a environment Java variable for Tomcat below is an example:
set CATALINA_OPTS=%CATALINA_OPTS% -Xms256m -Xmx1024m -Dgrails.env=development
On a grails command line you add the environment variable:
grails run-app -Dgrails.env=stage
You can use check the environment variable like this:
if (grails.util.Environment.current.name == "development") {
UsageCodeDefinition ucd = new UsageCodeDefinition()
ucd.setDescription("UFARSFileUpload Upload Development")
ucd.setFiscalYear("12-13")
ucd.setInstructions("Welcome to UFARSFileUpload Development were Open")
ucd.save(failOnError: true)
}
You can use the Enumerated values instead of the name variable but if you use custom environmental values then they are mapped to the enumeration custom and using the name works to distinguish between the custom values.
if (grails.util.Environment.current == grails.util.Environment.DEVELOPMENT) {
Without setting the JVM startup parameter:
-Dgrails.env=whatever
Your grails app will use the value set in
<yourapp>/WEB-INF/classes/application.properties
There will be a value set like this:
grails.env=development
This default environment value is determined by what options are used when building the war. You can build the war with
-Dgrails.env=development war
Then the application.properties will have grails.env=development, if you leave that off, it defaults to grails.env=production
As far as your question, you are not specific about what is being configured to use "environment specific urls". And it is not clear how you are storing these environment specific urls. If, for example, the URL variable is a member variable of a Grails service and you are storing the environment specific URLs in the Config.groovy, then you could
import grails.util.Environment
...
//inject the GrailsApplication Configuration in Config.groovy
def grailsApplication
//Hold the URL value from Config.groovy
String environmentUrl
...
Environment current = Environment.getCurrent()
if(Environment.PRODUCTION == current) {
environmentUrl = grailsApplication.config.PRODUCTION_URL
} else {
environmentUrl = grailsApplication.config.DEVELOPMENT_URL
}
Where Config.groovy has
PRODUCTION_URL = "http://blah.com/blah/"
DEVELOPMENT_URL = "http://blah.dev/blah"
Hope that helps.
If you have a System property available that tells you what environment you're in you can simply add if statements or a switch statement in your Config.groovy file, like this:
if (System.getProperty("foo") == "myTestEnvironment") {
myConfigSetting = "test"
} else if (System.getProperty("foo") == "myProductionEnvironment") {
myConfigSetting = "production"
}
This solution also works in other config files under grails-app/conf
Grails config files are parsed using groovy ConfigSlurper so you can put executable code in there without a problem.
Sorry this is way late, but another way is to inject a configuration property in BootStrap.groovy.
For Example:
if (currentEnv == Environment.DEVELOPMENT) {
...
grailsApplication.config.some.property = DEVELOPMENT_ENVRIONMENT
...
}
else if (currentEnv == Environment.TEST) {
...
grailsApplication.config.some.property = TEST_ENVIRONMENT
...
}
I have used this recently and it works really well. We are using Grails 2.5.2
As an addendum to the other answers:
You can use Environment.isDevelopmentMode() or in a groovier way Environment.developmentMode to check if the environment is set to development. This is useful when you take the aproach of only modifying settings for development on your code where production settings are default.

Gradle - different task use different parameter

I have two tasks,task_1 should compress png files and task_2 should not compress png files,so i want to add an parameter to control it.
project.ext.set("compressPngs", 1);
task taskCompressPngs(type:Exec){
commandLine "myshell.sh"
args compressPngs
}
task task_1(dependsOn:'taskCompressPngs'){}
task task_2(dependsOn:'taskCompressPngs'){}
gradle.taskGraph.whenReady { taskGraph ->
if (taskGraph.hasTask(task_1))
{
compressPngs=1
}
if (taskGraph.hasTask(task_2))
{
compressPngs=0
}
}
But when i run task_1 or task_2,in task 'taskCompressPngs', 'compressPngs' passed to my script 'myshell.sh' always be 1, why? how to solve it?
taskCompressPngs gets configured before the configuration value is changed. Conditional configuration is rarely a good solution. A better approach is to declare two Exec tasks.
As others have mentioned, it's probably best to take the advice of #PeterNiederwieser and use two separate tasks, but if you really don't think you can, here are a couple other options that should work.
1) Check Gradle startParameter
Configure your reusable task based on which task is passed to gradle on the command line.
task taskCompressPngs(type: Exec) {
def compressPngs = 1
if(gradle.startParameter.taskNames.toString().toLowerCase().contains("task_2")) compressPngs = 0
commandLine "myshell.sh $compressPngs".tokenize()
}
This gives you a variable to use (gradle.startParameter.taskNames) that is available at configuration-time.
Here we change compressPngs to 0 only if task_2 is specified on the command line when running gradle.
I.E. gradlew task_1 will run myshell.sh 1, but gradlew task_2 (or even gradlew task_1 task_2) will run myshell.sh 0.
This logic could also be applied to a project property outside of the taskCompressPngs task - if, for example, you wanted to change other tasks too.
Again, this only works if "task_2" is specified in the command used to run gradle.
2) Use DefaultExecAction instead of Exec task
Instead of using a task of type Exec, you could write a custom task and check the taskGraph in it.
task taskCompressPngs << {
def compressPngs = 1
if(gradle.taskGraph.hasTask(two)) compressPngs = 2
org.gradle.process.internal.DefaultExecAction e = new org.gradle.process.internal.DefaultExecAction(getServices().get(org.gradle.api.internal.file.FileResolver.class))
e.commandLine("myshell.sh $compressPngs".tokenize())
e.execute()
}
This is just moves your existing logic from configuration-time to execution-time.
This requires the use of "internal" Gradle classes (which is bad), but it gives you a little more flexibility in how/when the shell command is run.
Note that these solutions were checked against Gradle 1.7 and Gradle 1.11.

Azure: Unable to start cloud service running vbs startup task

For some specific purpose, I need to install some fonts on the instances. It comes as no surprise when I choose StartUp Task to accomplish that goal. I've configured the Service Definitions as below:
<Startup>
<Task commandLine="Fonts\InstallFonts.vbs" executionContext="elevated" taskType="simple" />
</Startup>
Nothing special here. Click and run, it failed. However, if I changed the commandLine into a cmd file including just nonsense, namely "echo test", the instance would run without ado. So there must be some issue with my scripting:
Const FONTS = &H14&
Set objShell = CreateObject("Shell.Application")
Set objFolder = objShell.Namespace(CreateObject("Scripting.FileSystemObject").GetAbsolutePathName("."))
Set fontFolder = objShell.Namespace(FONTS)
Set rxTTF = New RegExp
rxTTF.IgnoreCase = True
rxTTF.Pattern = "\.ttf$"
Set fso = CreateObject("Scripting.FileSystemObject")
FOR EACH FontFile IN objFolder.Items()
IF rxTTF.Test(FontFile.Path) THEN
IF NOT fso.FileExists(fontFolder.Self.Path+"\\"+FontFile.Name) THEN
FontFile.InvokeVerb("Install")
END IF
END IF
NEXT
The script should come with no error because I've tested it either locally or on Azure via RDP.
Weirdly, when I put it in the startup, the role just won't start. The instance just keeps recycling and at last says "I'm unhealthy". Even if I deprecate the vbs into just one line of code - the first line Const FONTS = &H14&, it just won't start. Even if I wrap the invocation of the vbs into a cmd file, namely to put something like "cscript /B file.vbs", it won't run either.
So I'm concluding that there must be some issue regarding the communication between the script and the Windows Azure monitor. I'm not sure but I think the monitor might take the running script as a failed task. Besides, I'm wondering if there is any timeout for the startup task, which should be the problem though, because the script can guarantee that no UI interaction block the process.
Any idea would be greatly appreciated.
I am sure you must have but just for the sake of confirmation, have you checked that the InstallFonts.vbs file is exported with the package? I mean is the "Copy To Output Directory" is set to "Copy Always/Copy if newer"?
This is pretty much possible that it is not able to locate your file.
You need to write a cmd file as a start up task. In your cmd file, you can call the vbs file using the command line tool cscript.
Azure start up can compile only command line tools.
Oh god, I finally solved the problem.
Although the compiler does quite a good job usually, it allows to use subfolder as a source of command, I mean something like "Subfolder\command.cmd", which will not work always. I've seen examples in which people put whatever we do in cmd in commandLine property, such as "copy fileA fileB" and it really works. But as for vbs, you need to be cautious. Until now I still don't know what's under the cover, but there should be some problem with the path. And the solution is definitely simple, instead of doing the subfolder work for tidiness, just leave the command file in the root folder like most people do:
<Startup>
<Task commandLine="InstallFonts.vbs" executionContext="elevated" taskType="simple" />
</Startup>
And thank you all the same, Kunal. :)

Resources