Hi Johan,

On Fri, Jul 25, 2014 at 5:08 AM, Johan De Wit <jo...@open-future.be> wrote:

> Hi,
>
> Does someone knows more rspec code examples for working with files ?
>
> I stumbled across https://github.com/puppetlabs/puppetlabs-inifile/blob/
> master/spec/unit/puppet/provider/ini_setting/ruby_spec.rb ,
>
> but cannot find more examples, and struggling a bit in writing good rspec
> tests for the following code snippet :
>
>
You essentially have two choices when doing this kind of thing: use a real
filesystem or stub it out in some way. The code that you pointed to looks
to be using a real filesystem. In that case what is often a good practice
is to create a temp directory in a setup step (before :each) and delete it
in a teardown (after :each). Then you do whatever is needed to have your
code read from that directory. In your case it looks like you should also
set Puppet[:config] to be some fake file in that directory. Then write out
the files that you need for your check (or don't write out the file if you
want to test the File.exist? == false paths).

If you are going to go down the stubbing route you'll have a much harder
time. You can use something like fakefs (a ruby gem for testing against
filesystems), but since you are pulling in all of puppet for this you might
encounter a lot of problems as it tries to read things that you don't care
about at all. If you are going to head down that path, then I suggest
extracting your functionality out of the puppet function, test it in
isolation, and then make the puppet function a very small adapter to the
other code (essentially just a single call). Then you can test your logic
without any ties to puppet.


> (intention is to read the uid from a yaml file for users)
>
> require 'yaml'
> module Puppet::Parser::Functions
>   newfunction(:lookup_uid, :type => :rvalue ) do |args|
>
>     # read the configuration file from puppets configuration dir
>     configfile = File.join([File.dirname(Puppet.settings[:config]),
> 'lookup_uid.yaml'])
>     raise(Puppet::ParseError, "lookup_uid configfile not readable") unless
> File.exist?(configfile)
>     config = YAML.load_file(configfile)
>
>     # read the user yaml file
>     raise(Puppet::ParseError, "Could not load user mapping file
> (#{config['user_file']}") unless File.exists?(config['user_file'])
>
>     # Lookup the uid, and convert it to an integer
>     users = YAML.load_file(config['user_file'])
>     uid = users.fetch(args[0], ifnone = nil)
>     raise(Puppet::ParseError, "#{args[0]} user not found in
> #{config['user_file']}") unless uid
>     uid.to_int
>   end
> end
>
>
In the code itself there are a few things that caught my eye. Your tests
might have uncovered some of these.

require 'yaml'
# no need to open the module, just call the function
# you can use arity to have it do some parameter checks for you (assuming
it'll be used on a new enough puppet)
Puppet::Parser::Functions.newfunction(:lookup_uid, :type => :rvalue, :arity
=> 1) do |args|
  # give the parameter a meaningful name as soon as possible
  username = args[0]

  # don't need to construct an array in the join() call
  # also, why :config and not :confdir?
  # Settings can be accessed by just using Puppet[:settingname] instead of
Puppet.settings[:settingname]
  configfile = File.join(File.dirname(Puppet[:config]), 'lookup_uid.yaml')

  # I always prefer stating things in the positive and using a full if ...
else ... end. I find that it makes the various code paths and error cases
much more visible.
  if File.exist?(configfile)
    # this can raise errors, you might consider dealing with them here and
providing some context to the user in the error message, just don't lose
the original error!
    config = YAML.load_file(configfile)

    # once again, prefer positive statements
    # config could be nil, and 'user_file' could be nil (or not a string)
    # there are actually more ways that this could be validated...isn't
input validation fun?
    if config.is_a?(Hash) && config['user_file'].is_a?(String) &&
File.exists?(config['user_file'])
      users = YAML.load_file(config['user_file'])
      # passing nil in the second position to fetch() is the same as just
fetching and getting nothing (since it is the default)
      uid = users[username]
      if uid
        # adding some error checking around this might be good. It is
possible that it can't be converted to an int
        uid.to_int
      else
        raise(Puppet::ParseError, "#{username} user not found in
#{config['user_file']}")
      end
    else
      # with all of the extra validation above, it is clear that this isn't
enough of an error message, in fact the validation might be something to do
as a separate step and be able to signal each possible error individually
      raise(Puppet::ParseError, "Could not load user mapping file
(#{config['user_file']}")
    end
  else
    # In errors be as precise and convey as much information as possible.
In this case, what file did it look for. Also, the check was for existence,
so you can only inform the user about that state of things.
    raise(Puppet::ParseError, "lookup_uid configfile #{configfile} does not
exist")
  end
end


> Thxs
>
> johan
>
> --
> Johan De Wit
>
> Open Source Consultant
>
> Red Hat Certified Engineer              (805008667232363)
> Puppet Certified Professional 2013/2014 (PCP0000006)
> _________________________________________________________
>  Open-Future                 Phone     +32 (0)2/255 70 70
> Zavelstraat 72              Fax       +32 (0)2/255 70 71
> 3071 KORTENBERG             Mobile    +32 (0)474/42 40 73
> BELGIUM                     http://www.open-future.be
> _________________________________________________________
>
> Next Events:
> Linux Training | https://www.open-future.be/linux-training-8-till-12th-
> september
> Puppet Introduction Course | https://www.open-future.be/
> puppet-introduction-course-15th-september
> Puppet Fundamentals Training | https://www.open-future.be/
> puppet-fundamentals-training-16-till-18th-september Zabbix Certified
> Specialist | https://www.open-future.be/zabbix-certified-
> specialisttraining-22-till-24th-september
> Zabbix Certified Professional | https://www.open-future.be/
> zabbix-certified-professional-training-25-till-26th-september
> Subscribe to our newsletter | http://eepurl.com/BUG8H
>
> --
> You received this message because you are subscribed to the Google Groups
> "Puppet Developers" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to puppet-dev+unsubscr...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/
> msgid/puppet-dev/53D248D8.9020304%40open-future.be.
> For more options, visit https://groups.google.com/d/optout.
>



-- 
Andrew Parker
a...@puppetlabs.com
Freenode: zaphod42
Twitter: @aparker42
Software Developer

*Join us at PuppetConf 2014 <http://www.puppetconf.com/>, September
22-24 in San Francisco*
*Register by May 30th to take advantage of the Early Adopter discount
<http://links.puppetlabs.com/puppetconf-early-adopter> **—**save $349!*

-- 
You received this message because you are subscribed to the Google Groups 
"Puppet Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to puppet-dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/puppet-dev/CANhgQXtapXGjYun92fLqkMZm%2B2OOVqdKpDDUpR5NQqj%2BroYRRA%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to