Does Serverspec support expectations or do I have to use should? - expectations

I hear I should be using expectations rather than "should" statements in Serverspec
I have been Googling around for expectations that can be used for file matching but all of the tutorials I see for Serverspec use should rather than expect. Is this because Serverspec hasn't been updated to use expectations?
describe file('/etc/yum.conf') do
it { should be_file }
it { should be_owned_by 'root' }
it { should be_grouped_into 'root' }
it { should be_mode 644 }
its(:content) { should match /^gpgcheck=1$/ }
its(:content) { should match /^clean_requirements_on_remove=1$/ }
end
So how would I write the test using expectations instead of should?

Your first question:
... all of the tutorials I see for Serverspec use should rather than expect. Is this because Serverspec hasn't been updated to use expectations?
No, it is mostly because the author of the Serverspec project has a preference for the "should" syntax, and that's why the Serverspec documentation continues to use it. He has explained here that:
I'm using should syntax instead of expect syntax because I think should syntax is more readable than expect syntax and I like it.
Using expect syntax is recommended way because adding should to every object causes failures when used with BasicObject-subclassed proxy objects.
But the one-liner syntax used with the examples in this page doesn't add should to any objects, so this syntax doesn't cause the above problems. That's why I'm using the one-liner should syntax.
Be aware that should and expect come from the rspec-expectations project, and the Serverspec author is correct "should" rather than "expect" is fine the way he is using it.
There is more info on the original motivation for the expect syntax from the Rspec author Myron Marston here.
Your second question:
... how would I write the test using expectations instead of should?
If you still want to use the expect syntax, just replace should everywhere with is_expected.to everywhere. This works fine:
describe file("/etc/passwd") do
it { is_expected.to be_file }
its(:content) { is_expected.to match /root/ }
end
You can also write it this way:
describe "passwd file" do
it "the passwd file should be a file" do
expect(file("/etc/passwd")).to be_file }
end
it "and it should contain root" do
expect(file("/etc/passwd").content).to match /root/
end
end
Or even:
describe file("/etc/passwd") do
it { expect(subject).to be_file }
it { expect(subject.content).to match /root/ }
end
See also:
should and should_not syntax (rspec-expectations project).

Related

Elegant way to prevent unused assignment?

Context
Sometimes I find strict typing warnings more distracting than useful while still putting some idea into code, and before having reviewed it for sanity.
I'm looking for a quick programmatic way to prevent "unused declaration" warning, in order to boost my workflow.
Example
I'll try to illustrate what I mean by an example.
// use rand::Rng;
fn breaking_out_of_nested_loops_using_labels() {
let mut innermost_loop_reached: bool = false;
'outermost_loop: loop {
loop {
// if rand::thread_rng().gen::<u8>() >= u8::MAX / 2 {
// break;
// }
loop {
innermost_loop_reached = true;
break 'outermost_loop;
}
}
}
println!(
"Inner loop was {}reached",
if innermost_loop_reached { "" } else { "not " }
)
}
The code results with the following warning:
Obviously the compiler is correct.
Question
I'm curious if there is a quick way to "trick" or ignore unused assignment warnings during typing some initial code, when all you want to know is if the code still compiles.
How do experienced rust programmers go about this? or do you just learn to ignore the warnings until you're ready to process them?
Please note
The commented out code is what I used to prevent the warning from popping up, while still trying the code. Obviously importing a crate and using a random condition is a lot of work, so it's not ideal.
At that point I might as well put the #[allow(unused_assignments)]-allow-rule above my function. But that's what I'm trying to prevent having to do, because;
I might forget to remove it.
It would already interrupt my workflow if I have to copy warnings from the compiler output.
You can try naming the variable _innermost_loop_reached instead.
Adding an underscore in the beginning of the name of a variable prevents the compiler from showing the unused_assignments warning.
You can control lint levels via rustc flags - so for example -A unused_assignments would banish the unused assignments warning.
You can configure Cargo so that it applys specific flags when it calls rustc using a config.toml file, which you can place in the project, or your in ~/.cargo/config.toml, or a number of other places - refer to the cargo documentation.
You place the desired rust flags inside the [build] section like this:
[build]
rustflags = ["-A", "unused_assignments"]
Of course you still need to remember to remove this when you are finished the initial experimental coding phase, but at least it is not sprinkled throughout your code.
Unfortunately it is not possible yet to set the rustflags per profile - it might be great to be able to dampen down the warnings for debug but keep them all for release. There is a feature request open for this so maybe it will be possible in the future.
You can also control the rust arguments with the RUSTFLAGS environment variable. I generally find this less useful for environments like IDEs though, which might make it hard to control the environment variables under which cargo is running.
One solution is to avoid the problem altogether by making using of the fact that loop can be an expression, and assign that expresion to innermost_loop_reached:
fn breaking_out_of_nested_loops_using_labels() {
// Directly assign to `innermost_loop_reached`
let innermost_loop_reached: bool = 'outermost_loop: loop {
loop {
if rand::thread_rng().gen::<u8>() >= u8::MAX / 2 {
break;
}
loop {
// break directly to the top-loop, "returning" `true`
break 'outermost_loop true;
}
}
// "return" `false`
break false;
};
println!(
"Inner loop was {}reached",
if innermost_loop_reached { "" } else { "not " }
)
}
This has the added benefit that all exits from the loop (via break) must be of type bool because innermost_loop_reached is a bool. That is, you avoid most cases where innermost_loop_reached should get a value in the loops but doesn't, wrongfully leaving the default false from your example in place.

NixOS - Module imports with arguments

Let's say I have my NixOS configuration.nix set up as follows:
{config, pkgs, ...}:
{
services.openssh.enable = true;
}
I now want to have a second file called networking.nix which sets my hostname based on an argument.
{config, pkgs, hostname, ...}:
{
networking.hostName = hostname
}
Is this possible? How can I include the file. I already tried doing it by using imports = [ ./networking.nix { hostname = "helloworld"; } ]; but that didn't work.
Thanks.
A 'NixOS configuration file' is simply a module that doesn't define options, so there is really no distinction. A configuration.nix file is just a module, and typically it does not define any options, so it can be written in the abbreviated form.
Defining options is the normal way for NixOS modules to pass information around, so that's the most idiomatic way to go about.
However, if you really must, for some very special reason, because you're doing very unusual things with NixOS, you can put arbitrary functions in imports. But you shouldn't, because it doesn't work well with the module system's custom error messages and potentially other aspects that rely on knowing where a module is defined. If you do so, do make sure it is an actual function. In your case, that would imply modifying the first line of networking.nix to make it a curried function:
hostname: {config, pkgs, ...}:
Not very pretty in my opinion. Although it is very explicit about what is going on, it deviates from what is to be expected of a NixOS module.
I encountered this problem today and came up with a fairly simple solution recommended in the manual.
foobar.nix
{ lib, withFoo ? "bar", ... }:
# simple error checking to ensure garbage isn't passed in
assert lib.asserts.assertOneOf "withFoo" withFoo [
"bar"
"baz"
# other valid choices ...
];
{
# ...
}
configuration.nix
args#{ ... }:
{
imports = [
# ...
(
import ./foobar.nix (
args
// { withFoo = "baz"; }
)
)
# ...
];
}
This is ideal for 'one off' options in your configurations.
You should be able to use the _module.argsoption [1] to do that. So your configuration.nix would be like:
{config, pkgs, ...}:
{
_module.args.hostname = "ahostname";
services.openssh.enable = true;
}
However where the values are very simple it will probably be much easier to just set them directly, e.g. just define networking.hostname in configuration.nix. This section of the manual re. merging and priorities may be helpful also [2].
Further discussion:
The value of _module.args is indeed applied to all imported configurations (though the value will only be used in modules that directly refer to it, such as the pkgs value, the ... represents all the values that aren't referenced).
For passing arguments to modules it seems a good approach to me, but from your comments perhaps a different approach might be more suitable.
Another solution could be to flip the relationship in the imports: rather than a single common config that passes multiple different arguments instead multiple different configs import the common configuration. E.g.
$cat ./common.nix
{ services.openssh.enable = true; }
$cat ./ahostname.nix
{ imports = [ ./common.nix ]; networking.hostname = "ahostname"; }
The NixOS config in this Reddit comment looks like it uses this approach. There are quite a few other NixOS configurations that people have shared publicly online so you might find some useful ideas there. The points in the answer from Robert Hensing are very useful to bear in mind as well.
However it's hard to say what might be a better solution in your case without knowing a bit more about the context in which you want to use it. You could create a new SO question with some more information on that which might make it easier to see a more appropriate solution.

Common php functions in hack

I decided to start a new project to get into hacklang, and after fixing some if the problems I initially ran into transitioning from php habits, I ran into the following errors:
Unbound name: str_replace
Unbound name: empty
Doing some research I found that this is due to using 'legacy' php which isn't typechecked, and will error with //strict.
That's fine and all, empty() was easy enough to replace, however str_replace() is a bit more difficult.
Is there an equivalent function that will work with //strict? Or at least something similar.
I'm aware that I could use //decl but I feel like that defeats the purpose in my case.
Is there at least any way to tell which functions are implemented in hack and which are not in the documentation as I couldn't find one?
For reference (though it isn't too relevant to the question itself), here is the code:
<?hh //strict
class HackMarkdown {
public function parse(string $content) : string {
if($content===null){
throw new RuntimeException('Empty Content');
}
$prepared = $this->prepare($content);
}
private function prepare(string $contentpre) : Vector<string>{
$contentpre = str_replace(array("\r\n","\r"),"\n",$contentpre);
//probably need more in here
$prepared = Vector::fromArray(explode($contentpre,"\n"));
//and here
return $prepared;
}
}
You don't need to change your code at all. You just need to tell the Hack tools about all the inbuilt PHP functions.
The easiest way to do this is to download this folder and put it somewhere in your project. I put it in a hhi folder in the base of my project. The files in there tell Hack about all the inbuilt PHP functions.
Most of them don't have type hints, which can lead to Hack thinking the return type of everything is mixed instead of the actual return, that is actually correct in most cases as, for example, str_replace can return either a string or a bool. However, it does stop the "unbound name" errors, which is the main reason for adding them.

How to iterate over an array in Puppet

I would like to iterate over an array that is stored as a Facter fact, and for each element of the array create a new system user and a directory, and finally make API calls to AWS.
Example of the fact: my_env => [shared1,shared2,shared3]
How can I iterate over an array in Puppet?
This might work, depending on what you are doing
# Assuming fact my_env => [ shared1, shared2, shared3 ]
define my_resource {
file { "/var/tmp/$name":
ensure => directory,
mode => '0600',
}
user { $name:
ensure => present,
}
}
my_resource { $my_env: }
It will work if your requirements are simple, if not, Puppet makes this very hard to do. The Puppet developers have irrational prejudices against iteration based on a misunderstanding about how declarative languages work.
If this kind of resource doesn't work for you, perhaps you could give a better idea of which resource properties you are trying to set from your array?
EDIT:
With Puppet 4, this lamentable flaw was finally fixed. Current state of affairs documented here. As the documentation says, you'll find examples of the above solution in a lot of old code.
As of puppet 3.2 this is possible using the "future" parser like so:
$my_env = [ 'shared1', 'shared2', 'shared3', ]
each($my_env) |$value| {
file { "/var/tmp/$value":
ensure => directory,
mode => 0600,
}
user { $value:
ensure -> present,
}
}
See also: http://docs.puppetlabs.com/puppet/3/reference/lang_experimental_3_2.html#background-the-puppet-future-parser
Puppet 3.7 released earlier this month have the new DSL, which one feature is the iteration, check the following URL https://docs.puppetlabs.com/puppet/latest/reference/experiments_lambdas.html#enabling-lambdas-and-iteration
these new features can be enabled with the :
Setting parser = future in your puppet.conf file
or adding the command line switch --parser=future
hope that helps
As of latest Puppet (6.4.2), and since Puppet 4, iteration over arrays is supported in a few ways:
$my_arr = ['foo', 'bar', 'baz']
Each function:
$my_arr.each |$v| {
notice($v)
}
Each function alternative syntax:
each($my_arr) |$v| {
notice($v)
}
To get the index:
Pass a second argument to each:
$my_arr.each |$i, $v| {
notice("Index: $i, value: $v")
}
Comparison with Ruby:
Note that this grammar is inspired by Ruby but slightly different, and it's useful to show the two side by side to avoid confusion. Ruby would allow:
my_arr.each do |v|
notice(v)
end
Or:
my_arr.each { |v|
notice(v)
}
Other iteration functions:
Note that Puppet provides a number of other iteration functions:
each - Repeats a block of code a number of times, using a collection of values to provide different parameters each time.
slice - Repeats a block of code a number of times, using groups of values from a collection as parameters.
filter - Uses a block of code to transform a data structure by removing non-matching elements.
map - Uses a block of code to transform every value in a data structure.
reduce - Uses a block of code to create a new value, or data structure, by combining values from a provided data structure.
with - Evaluates a block of code once, isolating it in its own local scope. It doesn’t iterate, but has a family resemblance to the iteration functions.
Puppet 3 and earlier:
If you have inherited old code still using Puppet 3, the accepted answer is still correct:
define my_type {
notice($name)
}
my_type { $my_arr: }
Note however that this is usually considered bad style in modern Puppet.
itsbruce's answer is probably the best for now, but there is an iteration proposal going through puppetlabs' armatures process for possible implementation in future.
There is a "create_resources()" function in puppet. that will be very helpful while iterating over the list of itmes

How can I access the scenario and example names in Cucumber?

I'm using cucumber to generate test scripts that can be executed by a tool or human... so not the standard use.
However I would like to pass through the scenario and example names through to my output.
Is this possible?
Found it.. (with some help from Tim Walker)
Before do |scenario|
puts "Before Scenario: #{scenario.to_sexp[2]}"
.
.
.
end
Your SExpression may differ, so it's worth doing a scenario.to_sexp.inspect to see what that tree is.
Aslak is keen to avoid exposing properties on his classes (which is a decision I happen to agree with, so I'm happy to do this work around).
A more serious answer (or at least, suggestion): make use of ruby's reflection to try to find what you are looking for. Grab likely objects, find out what methods they have, and see if you can find it. For example:
File.open('happy_hunting.log','a') { |f|
f.print "Scenario supports: #{(scenario.methods - Object.methods).inspect}\n"
}
and then repeat it to figure out whats where.
Another suggestion, look at the source.
I did something scrappy. As I use this info for only debugging, this will work for now, until I find something better.
#Before
public void printTestInfoBeforeScenario(Scenario scenario) {
LOGGER.info("Upcoming Test: "+scenario.getSourceTagNames());
}
#After
public void printTestInfoAfterScenario(Scenario scenario) {
LOGGER.info("Test Complete: " + scenario.getSourceTagNames() + " Status: " + scenario.getStatus());
}

Resources