Hi Andy,

thanks for the great explanation.

I really need to get my Dev skills above zero :)

I will post a link to this function and write some step by step little guide ....


grts

johan



On 25/07/14 19:47, Andy Parker wrote:
Hi Johan,

On Fri, Jul 25, 2014 at 5:08 AM, Johan De Wit <jo...@open-future.be <mailto: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
    <tel:%2B32%20%280%292%2F255%2070%2070>
    Zavelstraat 72              Fax +32 (0)2/255 70 71
    <tel:%2B32%20%280%292%2F255%2070%2071>
    3071 KORTENBERG             Mobile +32 (0)474/42 40 73
    <tel:%2B32%20%280%29474%2F42%2040%2073>
    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
    <mailto:puppet-dev%2bunsubscr...@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 <mailto: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 <mailto: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 <https://groups.google.com/d/msgid/puppet-dev/CANhgQXtapXGjYun92fLqkMZm%2B2OOVqdKpDDUpR5NQqj%2BroYRRA%40mail.gmail.com?utm_medium=email&utm_source=footer>.
For more options, visit https://groups.google.com/d/optout.


--
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/53D3B180.6090804%40open-future.be.
For more options, visit https://groups.google.com/d/optout.

Reply via email to