Rails: How to pass data to Bash Script - ruby-on-rails

I have a Rails webapp full of students with test scores. Each student has exactly one test score.
I want the following functionality:
1.) The user enters an arbitrary test score into the website and presses "enter"
2.) "Some weird magic where data is passed from Rails database to bash script"
3.) The following bash script is run:
./tool INPUT file.txt
where:
INPUT = the arbitrary test score
file.txt = a list of all student test scores in the database
4.) "More weird magic where output from the bash script is sent back up to a rails view and made displayable on the webpage"
And that's it.
I have no idea how to do the weird magic parts.
My attempt at a solution:
In the rails dbconsole, I can do this:
SELECT score FROM students;
which gives me a list of all the test scores (which satisfies the "file.txt" argument to the bash script).
But I still don't know how my bash script is supposed to gain access to that data.
Is my controller supposed to pass the data down to the bash script? Or is my model supposed to? And what's the syntax for doing so?
I know I can run a bash script from the controller like this:
system("./tool")
But, unfortunately, I still need to pass the arguments to my script, and I don't see how I can do that...

You can just use the built-in ruby tools for running shell commands:
https://ruby-doc.org/core-2.3.1/Kernel.html#method-i-60
For example, in one of my systems I need to get image orientation:
exif_orientation = `exiftool -Orientation -S "#{image_path}"`.to_s.chomp
Judging from my use of .to_s, running the command may sometimes return nil, and I don't want an error trying to chomp nil. A normal output includes the line ending which I feed to chomp.

Related

Can I get the arguments passed to bazel itself?

I want to create some "build traceability" functionality, and include the actual bazel command that was run to produce one of my build artifacts. So if the user did this:
bazel run //foo/bar:baz --config=blah
I want to actually get the string "bazel run //foo/bar:baz --config=blah" and write that to a file during the build. Is this possible?
Stamping is the "correct" way to get information like that into a Bazel build. Note the implications around caching though. You could also just write a wrapper script that puts the command line into a file or environment variable. Details of each approach below.
I can think of three ways to get the information you want via stamping, each with differing tradeoffs.
First way: Hijack --embed_label. This shows up in the BUILD_EMBED_LABEL stamping key. You'd add a line like build:blah --embed_label blah in your .bazelrc. This is easy, but that label is often used for things like release_50, which you might want to preserve.
Second way: hijack the hostname or username. These show up in the BUILD_HOST and BUILD_USER stamping keys. On Linux, you can write a shell script at tools/bazel which will automatically be used to wrap bazel invocations. In that shell script, you can use unshare --uts --map-root-user, which will work if the machine is set up to enable bazel's sandboxing. Inside that new namespace, you can easily change the hostname and then exec the real bazel binary, like the default /usr/bin/bazel shell script does. That shell script has full access to the command line, so it can encode any information you want.
Third way: put it into an environment variable and have a custom --workspace_status_command that extracts it into a stamping key. Add a line like build:blah --action_env=MY_BUILD_STYLE=blah to your .bazelrc, and then do echo STABLE_MY_BUILD_STYLE ${MY_BUILD_STYLE} in your workspace status script. If you want the full command line, you could have a tools/bazel wrapper script put that into an environment variable, and then use build --action_env=MY_BUILD_STYLE to preserve the value and pass it to all the actions.
Once you pick a stamping key to use, src/test/shell/integration/stamping_test.sh in the Bazel source tree is a good example of writing stamp information to a file. Something like this:
genrule(
name = "stamped",
outs = ["stamped.txt"],
cmd = "grep BUILD_EMBED_LABEL bazel-out/volatile-status.txt | cut -d ' ' -f 2 >\$#",
stamp = True,
)
If you want to do it without stamping, just write the information to a file in the source tree in a tools/bazel wrapper. You'd want to put that file in your .gitignore, of course. echo "$#" > cli_args is all it takes to dump them to a file, and then you can use that as a source file like normal in your build. This approach is simplest, but interacts the most poorly with Bazel's caching, because everything that depends on that file will be rebuilt every time with no way to control it.

JMeter: more than nine parameters from Jenkins

I am trying to pass more than nine parameters from Jenkins to JMeter4.0.
As I was reading, I found out that JMeter does not accept more than 9 parameters. As a workaround, I want to pass all the parameters as a string and split it in JMeter BeanShell.
java -jar -Xms512m -Xmx2048m C:\JMeter4\bin\ApacheJMeter.jar -Jjmeter.save.saveservice.output_format=csv -Jjenkinsparams="%Timetorun%,%Users%" -n -t %JMeterPath%\bin\tests\tests.jmx -l %WORKSPACE%\Results.csv
The tests run on a Windows machine. From this call I have
jenkinsparams = "300,2"
I use a BeanShell PreProcessor like this:
String line = "${__P(jenkinsparams)}";
String[] words = line.split(",");
vars.put("timetorun",words[0]);
vars.put("users",words[1]);
log.info(words[1]);
log.info(users);
I tried few log.info to check the values. For words[1] I have the correct value sent from Jenkins: 2. For the users the value displayed is: void.
I am trying to use it for Number of Threads as: ${__P(users,1)}.
What am I doing wrong? The values clearly arrive from Jenkins but I have a problem passing it to my variable. Thank you
You don't have a script variable named users, so you should either log words[0]:
log.info(words[0]);
Or you can log the value of JMeter variable called users:
log.info(vars.get("users"));
Or you can assign words[0] to variable called users:
String users = words[0];
log.info(users);
Also you are saving it as variable, not property, so you can retrieve it elsewhere in script as
${users}
The syntax __P refers to property, so if you want to use it as property, you need to change how you are saving it:
props.put("users", words[1]);
If you do that, ${__P(users,1)} should work
Now, if you want to use this value as number of threads, then you need to do this:
Have Setup thread group with 1 thread, and your script
In the script you must save users as property, otherwise it won't pass between threads
Next thread group then can use it as number of threads
As long as your command line fits into 8191 characters it should not be a problem to pass as many arguments to JMeter as you want, here is an evidence from Debug Sampler and View Results Tree listener combination
So keep calm and pass as many parameters as needed via -J command line arguments.
Be aware that starting from JMeter version 3.1 users are recommended to use JSR223 Test Elements and Groovy language instead of Beanshell so going forward please consider switching to Groovy.

How to read a user input in a text filed in ruby on rails and pass the value to a shell script command

I am very new to ruby on rails and I have a very simple question.
I am able to read the user input from a text field in ruby on rails
#user = params[:user]
I have to pass this value as an argument to a shell script
I tried a number of things, but nothing works
run_command "./file.sh #{#user}"
and
%x(./file.sh #{#user})
The script receives "{user="
Any help is appreciated!
First, make sure you escape any parameters you pass to command line. You may be easily attacked via command line injection this way. Try this instead:
system "/path/to/file.sh #{#user.shellescape}"
You may also want to try exec, depending on how you want to track output. Please see http://ruby-doc.org/core-2.3.0/Kernel.html for more details on both

Feature test for command line program Ruby / RSpec

I have a script that I want to run within some tests using RSpec that I want to test the input / output on.
For example,
I have a script 'script.rb' that I run using 'ruby script.rb'
The script then outputs to STDOUT and takes an input using STDIN. I want to test this using RSPec and check that everything works appropriately (a feature test). How would I go about doing this? Just do an execute 'ruby script.rb' within RSPec and then test that the output is what I expect and that it takes input from STDIN?
Since you want to test your script as a black box (only STDIN/STDOUT), you may perfectly do it via system() call: just make sure to clean up all side effects your script is leaving (for example, temporary files).
EDIT: Just create some file with needed content, say stdin.txt.
After that you may run your command this way:
system('cat stdin.txt | ruby myscript.rb')

Cucumber errors suppressed (not displayed fully)

I just installed cucumber, and I tested it. I got the following error:
teefcomp:cucumber-intro teef$ cucumber features/manage_users.feature
Using the default profile...
F----F
Failing Scenarios:
cucumber features/manage_users.feature:6 # Scenario: User List
1 scenario (1 failed)
4 steps (4 skipped)
0m0.029s
It seems to be suppressing the error. I was expecting something like:
Feature: Manage users
In order to understand my user base better
As an administrator
I want to view a list of users
Scenario: User List
Given I have users named George, Mary
uninitialized constant User (NameError)
./features/step_definitions/user_steps.rb:3
./features/step_definitions/user_steps.rb:2:in '/^I have users named (.*)$/'
features/manage_users.feature:7:in 'Given I have users named George, Mary'
Anyone know how to get cucumber to display the errors in full?
--backtrace, --verbose, -b and --trace do not work; I still see F----F and the failing scenario is listed, but I still expect something like description on the "NameError" line. Is this a feature of an older version of cucumber? (I'm using screencasts to start using cucumber.)
running with the -b flag should give you a full backtrace
cucumber features/manage_users.feature -b
EDIT:
Additionally, you can use the full notation of --backtrace. If you are running via rake, run with the --trace flag
to get full output, you can use the --format flag. I generally use --format pretty to get a line-by-line walk through.
from the --help output.
-f, --format FORMAT How to format features (Default: pretty). Available formats:
debug : For developing formatters - prints the calls made to the listeners.
html : Generates a nice looking HTML report.
json : Prints the feature as JSON
json_pretty : Prints the feature as pretty JSON
junit : Generates a report similar to Ant+JUnit.
pdf : Generates a PDF report. You need to have the
prawn gem installed. Will pick up logo from
features/support/logo.png or
features/support/logo.jpg if present.
pretty : Prints the feature as is - in colours.
progress : Prints one character per scenario.
rerun : Prints failing files with line numbers.
stepdefs : Prints All step definitions with their locations. Same as
the usage formatter, except that steps are not printed.
tag_cloud : Prints a tag cloud of tag usage.
usage : Prints where step definitions are used.
The slowest step definitions (with duration) are
listed first. If --dry-run is used the duration
is not shown, and step definitions are sorted by
filename instead.
Use --format rerun --out features.txt to write out failing
features. You can rerun them with cucumber #rerun.txt.
FORMAT can also be the fully qualified class name of
your own custom formatter. If the class isn't loaded,
Cucumber will attempt to require a file with a relative
file name that is the underscore name of the class name.
Example: --format Foo::BarZap -> Cucumber will look for
foo/bar_zap.rb. You can place the file with this relative
path underneath your features/support directory or anywhere
on Ruby's LOAD_PATH, for example in a Ruby gem.
If your application is a Rails app, you can use the #allow-rescue tag for the scenario-of-interest, then your rails test_log will include more details about where in your application the error was originally raised.
From the command line you can quickly look at the end of the test log with tail -n200 log/test_log.rb (adjust the number of lines to see the portion of interest).

Resources