diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 064443f..8424781 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,65 +1,65 @@ name: "release" on: push: branches: - 'release' jobs: LitmusAcceptancePuppet5: env: HONEYCOMB_WRITEKEY: 7f3c63a70eecc61d635917de46bea4e6 HONEYCOMB_DATASET: litmus tests runs-on: self-hosted strategy: matrix: ruby_version: [2.5.x] puppet_gem_version: [~> 6.0] platform: [release_checks_5] agent_family: ['puppet5'] steps: - uses: actions/checkout@v1 - name: Litmus Parallel - uses: puppetlabs/action-litmus_parallel@master + uses: puppetlabs/action-litmus_parallel@main with: platform: ${{ matrix.platform }} agent_family: ${{ matrix.agent_family }} LitmusAcceptancePuppet6: env: HONEYCOMB_WRITEKEY: 7f3c63a70eecc61d635917de46bea4e6 HONEYCOMB_DATASET: litmus tests runs-on: self-hosted strategy: matrix: ruby_version: [2.5.x] puppet_gem_version: [~> 6.0] platform: [release_checks_6] agent_family: ['puppet6'] steps: - uses: actions/checkout@v1 - name: Litmus Parallel - uses: puppetlabs/action-litmus_parallel@master + uses: puppetlabs/action-litmus_parallel@main with: platform: ${{ matrix.platform }} agent_family: ${{ matrix.agent_family }} Spec: runs-on: self-hosted strategy: matrix: check: [parallel_spec, 'syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop'] ruby_version: [2.5.x] puppet_gem_version: [~> 5.0, ~> 6.0] exclude: - puppet_gem_version: ~> 5.0 check: 'syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop' - ruby_version: 2.5.x puppet_gem_version: ~> 5.0 steps: - uses: actions/checkout@v1 - name: Spec Tests - uses: puppetlabs/action-litmus_spec@master + uses: puppetlabs/action-litmus_spec@main with: puppet_gem_version: ${{ matrix.puppet_gem_version }} check: ${{ matrix.check }} diff --git a/.github/workflows/weekly.yml b/.github/workflows/weekly.yml index f6b48df..7ca532a 100644 --- a/.github/workflows/weekly.yml +++ b/.github/workflows/weekly.yml @@ -1,64 +1,64 @@ name: "weekly" on: schedule: - cron: '0 3 * * 5' jobs: LitmusAcceptancePuppet5: env: HONEYCOMB_WRITEKEY: 7f3c63a70eecc61d635917de46bea4e6 HONEYCOMB_DATASET: litmus tests runs-on: self-hosted strategy: matrix: ruby_version: [2.5.x] puppet_gem_version: [~> 6.0] platform: [release_checks_5] agent_family: ['puppet5'] steps: - uses: actions/checkout@v1 - name: Litmus Parallel - uses: puppetlabs/action-litmus_parallel@master + uses: puppetlabs/action-litmus_parallel@main with: platform: ${{ matrix.platform }} agent_family: ${{ matrix.agent_family }} LitmusAcceptancePuppet6: env: HONEYCOMB_WRITEKEY: 7f3c63a70eecc61d635917de46bea4e6 HONEYCOMB_DATASET: litmus tests runs-on: self-hosted strategy: matrix: ruby_version: [2.5.x] puppet_gem_version: [~> 6.0] platform: [release_checks_6] agent_family: ['puppet6'] steps: - uses: actions/checkout@v1 - name: Litmus Parallel - uses: puppetlabs/action-litmus_parallel@master + uses: puppetlabs/action-litmus_parallel@main with: platform: ${{ matrix.platform }} agent_family: ${{ matrix.agent_family }} Spec: runs-on: self-hosted strategy: matrix: check: [parallel_spec, 'syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop'] ruby_version: [2.5.x] puppet_gem_version: [~> 5.0, ~> 6.0] exclude: - puppet_gem_version: ~> 5.0 check: 'syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop' - ruby_version: 2.5.x puppet_gem_version: ~> 5.0 steps: - uses: actions/checkout@v1 - name: Spec Tests - uses: puppetlabs/action-litmus_spec@master + uses: puppetlabs/action-litmus_spec@main with: puppet_gem_version: ${{ matrix.puppet_gem_version }} check: ${{ matrix.check }} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1a9fb3a..9c171f9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,271 +1,271 @@ # Contributing to Puppet modules So you want to contribute to a Puppet module: Great! Below are some instructions to get you started doing that very thing while setting expectations around code quality as well as a few tips for making the process as easy as possible. ### Table of Contents 1. [Getting Started](#getting-started) 1. [Commit Checklist](#commit-checklist) 1. [Submission](#submission) 1. [More about commits](#more-about-commits) 1. [Testing](#testing) - [Running Tests](#running-tests) - [Writing Tests](#writing-tests) 1. [Get Help](#get-help) ## Getting Started - Fork the module repository on GitHub and clone to your workspace - Make your changes! ## Commit Checklist ### The Basics - [x] my commit is a single logical unit of work - [x] I have checked for unnecessary whitespace with "git diff --check" - [x] my commit does not include commented out code or unneeded files ### The Content - [x] my commit includes tests for the bug I fixed or feature I added - [x] my commit includes appropriate documentation changes if it is introducing a new feature or changing existing functionality - [x] my code passes existing test suites ### The Commit Message - [x] the first line of my commit message includes: - [x] an issue number (if applicable), e.g. "(MODULES-xxxx) This is the first line" - [x] a short description (50 characters is the soft limit, excluding ticket number(s)) - [x] the body of my commit message: - [x] is meaningful - [x] uses the imperative, present tense: "change", not "changed" or "changes" - [x] includes motivation for the change, and contrasts its implementation with the previous behavior ## Submission ### Pre-requisites - Make sure you have a [GitHub account](https://github.com/join) - [Create a ticket](https://tickets.puppet.com/secure/CreateIssue!default.jspa), or [watch the ticket](https://tickets.puppet.com/browse/) you are patching for. ### Push and PR - Push your changes to your fork - [Open a Pull Request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/) against the repository in the puppetlabs organization ## More about commits 1. Make separate commits for logically separate changes. Please break your commits down into logically consistent units which include new or changed tests relevant to the rest of the change. The goal of doing this is to make the diff easier to read for whoever is reviewing your code. In general, the easier your diff is to read, the more likely someone will be happy to review it and get it into the code base. If you are going to refactor a piece of code, please do so as a separate commit from your feature or bug fix changes. We also really appreciate changes that include tests to make sure the bug is not re-introduced, and that the feature is not accidentally broken. Describe the technical detail of the change(s). If your description starts to get too long, that is a good sign that you probably need to split up your commit into more finely grained pieces. Commits which plainly describe the things which help reviewers check the patch and future developers understand the code are much more likely to be merged in with a minimum of bike-shedding or requested changes. Ideally, the commit message would include information, and be in a form suitable for inclusion in the release notes for the version of Puppet that includes them. Please also check that you are not introducing any trailing whitespace or other "whitespace errors". You can do this by running "git diff --check" on your changes before you commit. 2. Sending your patches To submit your changes via a GitHub pull request, we _highly_ recommend that you have them on a topic branch, instead of - directly on "master". + directly on "main". It makes things much easier to keep track of, especially if you decide to work on another thing before your first change is merged in. GitHub has some pretty good [general documentation](http://help.github.com/) on using their site. They also have documentation on [creating pull requests](https://help.github.com/articles/creating-a-pull-request-from-a-fork/). In general, after pushing your topic branch up to your repository on GitHub, you can switch to the branch in the GitHub UI and click "Pull Request" towards the top of the page in order to open a pull request. 3. Update the related JIRA issue. If there is a JIRA issue associated with the change you submitted, then you should update the ticket to include the location of your branch, along with any other commentary you may wish to make. # Testing ## Getting Started Our Puppet modules provide [`Gemfile`](./Gemfile)s, which can tell a Ruby package manager such as [bundler](http://bundler.io/) what Ruby packages, or Gems, are required to build, develop, and test this software. Please make sure you have [bundler installed](http://bundler.io/#getting-started) on your system, and then use it to install all dependencies needed for this project in the project root by running ```shell % bundle install --path .bundle/gems Fetching gem metadata from https://rubygems.org/........ Fetching gem metadata from https://rubygems.org/.. Using rake (10.1.0) Using builder (3.2.2) -- 8><-- many more --><8 -- Using rspec-system-puppet (2.2.0) Using serverspec (0.6.3) Using rspec-system-serverspec (1.0.0) Using bundler (1.3.5) Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed. ``` NOTE: some systems may require you to run this command with sudo. If you already have those gems installed, make sure they are up-to-date: ```shell % bundle update ``` ## Running Tests With all dependencies in place and up-to-date, run the tests: ### Unit Tests ```shell % bundle exec rake spec ``` This executes all the [rspec tests](http://rspec-puppet.com/) in the directories defined [here](https://github.com/puppetlabs/puppetlabs_spec_helper/blob/699d9fbca1d2489bff1736bb254bb7b7edb32c74/lib/puppetlabs_spec_helper/rake_tasks.rb#L17) and so on. rspec tests may have the same kind of dependencies as the module they are testing. Although the module defines these dependencies in its [metadata.json](./metadata.json), rspec tests define them in [.fixtures.yml](./fixtures.yml). ### Acceptance Tests Some Puppet modules also come with acceptance tests, which use [beaker][]. These tests spin up a virtual machine under [VirtualBox](https://www.virtualbox.org/), controlled with [Vagrant](http://www.vagrantup.com/), to simulate scripted test scenarios. In order to run these, you need both Virtualbox and Vagrant installed on your system. Run the tests by issuing the following command ```shell % bundle exec rake spec_clean % bundle exec rspec spec/acceptance ``` This will now download a pre-fabricated image configured in the [default node-set](./spec/acceptance/nodesets/default.yml), install Puppet, copy this module, and install its dependencies per [spec/spec_helper_acceptance.rb](./spec/spec_helper_acceptance.rb) and then run all the tests under [spec/acceptance](./spec/acceptance). ## Writing Tests ### Unit Tests When writing unit tests for Puppet, [rspec-puppet][] is your best friend. It provides tons of helper methods for testing your manifests against a catalog (e.g. contain_file, contain_package, with_params, etc). It would be ridiculous to try and top rspec-puppet's [documentation][rspec-puppet_docs] but here's a tiny sample: Sample manifest: ```puppet file { "a test file": ensure => present, path => "/etc/sample", } ``` Sample test: ```ruby it 'does a thing' do expect(subject).to contain_file("a test file").with({:path => "/etc/sample"}) end ``` ### Acceptance Tests Writing acceptance tests for Puppet involves [beaker][] and its cousin [beaker-rspec][]. A common pattern for acceptance tests is to create a test manifest, apply it twice to check for idempotency or errors, then run expectations. ```ruby it 'does an end-to-end thing' do pp = <<-EOF file { 'a test file': ensure => present, path => "/etc/sample", content => "test string", } apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) end describe file("/etc/sample") do it { is_expected.to contain "test string" } end ``` # If you have commit access to the repository Even if you have commit access to the repository, you still need to go through the process above, and have someone else review and merge in your changes. The rule is that **all changes must be reviewed by a project developer that did not write the code to ensure that all changes go through a code review process.** The record of someone performing the merge is the record that they performed the code review. Again, this should be someone other than the author of the topic branch. # Get Help ### On the web * [Puppet help messageboard](http://puppet.com/community/get-help) * [Writing tests](https://docs.puppet.com/guides/module_guides/bgtm.html#step-three-module-testing) * [General GitHub documentation](http://help.github.com/) * [GitHub pull request documentation](http://help.github.com/send-pull-requests/) ### On chat * Slack (slack.puppet.com) #forge-modules, #puppet-dev, #windows, #voxpupuli * IRC (freenode) #puppet-dev, #voxpupuli [rspec-puppet]: http://rspec-puppet.com/ [rspec-puppet_docs]: http://rspec-puppet.com/documentation/ [beaker]: https://github.com/puppetlabs/beaker [beaker-rspec]: https://github.com/puppetlabs/beaker-rspec diff --git a/README.md b/README.md index 5c44cf0..3d85fd5 100644 --- a/README.md +++ b/README.md @@ -1,315 +1,315 @@ # inifile -[![Build Status](https://travis-ci.org/puppetlabs/puppetlabs-inifile.png?branch=master)](https://travis-ci.org/puppetlabs/puppetlabs-inifile) +[![Build Status](https://travis-ci.org/puppetlabs/puppetlabs-inifile.png?branch=main)](https://travis-ci.org/puppetlabs/puppetlabs-inifile) #### Table of Contents 1. [Overview](#overview) 1. [Module Description - What the module does and why it is useful](#module-description) 1. [Setup - The basics of getting started with inifile module](#setup) 1. [Usage - Configuration options and additional functionality](#usage) 1. [Reference - An under-the-hood peek at what the module is doing and how](#reference) 1. [Limitations - OS compatibility, etc.](#limitations) 1. [Development - Guide for contributing to the module](#development) ## Overview The inifile module lets Puppet manage settings stored in INI-style configuration files. ## Module Description Many applications use INI-style configuration files to store their settings. This module supplies two custom resource types to let you manage those settings through Puppet. ## Setup ### Beginning with inifile To manage a single setting in an INI file, add the `ini_setting` type to a class: ~~~puppet ini_setting { "sample setting": ensure => present, path => '/tmp/foo.ini', section => 'bar', setting => 'baz', value => 'quux', } ~~~ ## Usage The inifile module is used to: * Support comments starting with either '#' or ';'. * Support either whitespace or no whitespace around '='. * Add any missing sections to the INI file. It does not manipulate your file any more than it needs to. In most cases, it doesn't affect the original whitespace, comments, or ordering. See the common usages below for examples. ### Manage multiple values in a setting Use the `ini_subsetting` type: ~~~puppet ini_subsetting {'sample subsetting': ensure => present, section => '', key_val_separator => '=', path => '/etc/default/pe-puppetdb', setting => 'JAVA_ARGS', subsetting => '-Xmx', value => '512m', } ~~~ Results in managing this `-Xmx` subsetting: ~~~puppet JAVA_ARGS="-Xmx512m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/pe-puppetdb/puppetdb-oom.hprof" ~~~ ### Use a non-standard section header ~~~puppet ini_setting { 'default minage': ensure => present, path => '/etc/security/users', section => 'default', setting => 'minage', value => '1', section_prefix => '', section_suffix => ':', } ~~~ Results in: ~~~puppet default: minage = 1 ~~~ ### Use a non-standard indent character To use a non-standard indent character or string for added settings, set the `indent_char` and the `indent_width` parameters. The `indent_width` parameter controls how many `indent_char` appear in the indent. ~~~puppet ini_setting { 'procedure cache size': ensure => present, path => '/var/lib/ase/config/ASE-16_0/SYBASE.cfg', section => 'SQL Server Administration', setting => 'procedure cache size', value => '15000', indent_char => "\t", indent_width => 2, } ~~~ Results in: ~~~puppet [SQL Server Administration] procedure cache size = 15000 ~~~ ### Implement child providers You might want to create child providers that inherit the `ini_setting` provider for one of the following reasons: * To make a custom resource to manage an application that stores its settings in INI files, without recreating the code to manage the files themselves. * To [purge all unmanaged settings](https://docs.puppetlabs.com/references/latest/type.html#resources-attribute-purge) from a managed INI file. To implement child providers, first specify a custom type. Have it implement a namevar called `name` and a property called `value`: ~~~ruby #my_module/lib/puppet/type/glance_api_config.rb Puppet::Type.newtype(:glance_api_config) do ensurable newparam(:name, :namevar => true) do desc 'Section/setting name to manage from glance-api.conf' # namevar should be of the form section/setting newvalues(/\S+\/\S+/) end newproperty(:value) do desc 'The value of the setting to define' munge do |v| v.to_s.strip end end end ~~~ Your type also needs a provider that uses the `ini_setting` provider as its parent: ~~~ruby # my_module/lib/puppet/provider/glance_api_config/ini_setting.rb Puppet::Type.type(:glance_api_config).provide( :ini_setting, # set ini_setting as the parent provider :parent => Puppet::Type.type(:ini_setting).provider(:ruby) ) do # implement section as the first part of the namevar def section resource[:name].split('/', 2).first end def setting # implement setting as the second part of the namevar resource[:name].split('/', 2).last end # hard code the file path (this allows purging) def self.file_path '/etc/glance/glance-api.conf' end end ~~~ Now you can manage the settings in the `/etc/glance/glance-api.conf` file as individual resources: ~~~puppet glance_api_config { 'HEADER/important_config': value => 'secret_value', } ~~~ If you've implemented `self.file_path`, you can have Puppet purge the file of the all lines that aren't implemented as Puppet resources: ~~~puppet resources { 'glance_api_config': purge => true, } ~~~ ### Manage multiple ini_settings To manage multiple `ini_settings`, use the [`inifile::create_ini_settings`](REFERENCE.md#inifilecreate_ini_settings) function. ~~~puppet $defaults = { 'path' => '/tmp/foo.ini' } $example = { 'section1' => { 'setting1' => 'value1' } } inifile::create_ini_settings($example, $defaults) ~~~ Results in: ~~~puppet ini_setting { '[section1] setting1': ensure => present, section => 'section1', setting => 'setting1', value => 'value1', path => '/tmp/foo.ini', } ~~~ To include special parameters, use the following code: ~~~puppet $defaults = { 'path' => '/tmp/foo.ini' } $example = { 'section1' => { 'setting1' => 'value1', 'settings2' => { 'ensure' => 'absent' } } } inifile::create_ini_settings($example, $defaults) ~~~ Results in: ~~~puppet ini_setting { '[section1] setting1': ensure => present, section => 'section1', setting => 'setting1', value => 'value1', path => '/tmp/foo.ini', } ini_setting { '[section1] setting2': ensure => absent, section => 'section1', setting => 'setting2', path => '/tmp/foo.ini', } ~~~ #### Manage multiple ini_settings with Hiera For the profile `example`: ~~~puppet class profile::example ( Hash $settings, ) { $defaults = { 'path' => '/tmp/foo.ini' } inifile::create_ini_settings($settings, $defaults) } ~~~ Provide this in your Hiera data: ~~~puppet profile::example::settings: section1: setting1: value1 setting2: value2 setting3: ensure: absent ~~~ Results in: ~~~puppet ini_setting { '[section1] setting1': ensure => present, section => 'section1', setting => 'setting1', value => 'value1', path => '/tmp/foo.ini', } ini_setting { '[section1] setting2': ensure => present, section => 'section1', setting => 'setting2', value => 'value2', path => '/tmp/foo.ini', } ini_setting { '[section1] setting3': ensure => absent, section => 'section1', setting => 'setting3', path => '/tmp/foo.ini', } ~~~ ## Reference -See [REFERENCE.md](https://github.com/puppetlabs/puppetlabs-inifile/blob/master/REFERENCE.md) +See [REFERENCE.md](https://github.com/puppetlabs/puppetlabs-inifile/blob/main/REFERENCE.md) ## Limitations -For an extensive list of supported operating systems, see [metadata.json](https://github.com/puppetlabs/puppetlabs-inifile/blob/master/metadata.json) +For an extensive list of supported operating systems, see [metadata.json](https://github.com/puppetlabs/puppetlabs-inifile/blob/main/metadata.json) ## Development We are experimenting with a new tool for running acceptance tests. It's name is [puppet_litmus](https://github.com/puppetlabs/puppet_litmus) this replaces beaker as the test runner. To run the acceptance tests follow the instructions [here](https://github.com/puppetlabs/puppet_litmus/wiki/Tutorial:-use-Litmus-to-execute-acceptance-tests-with-a-sample-module-(MoTD)#install-the-necessary-gems-for-the-module). Puppet Labs modules on the Puppet Forge are open projects, and community contributions are essential for keeping them great. We can't access the huge number of platforms and myriad of hardware, software, and deployment configurations that Puppet is intended to serve. We want to keep it as easy as possible to contribute changes so that our modules work in your environment. There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things. For more information, see our [module contribution guide.](https://puppet.com/docs/puppet/latest/contributing.html) ### Contributors To see who's already involved, see the [list of contributors.](https://github.com/puppetlabs/puppetlabs-inifile/graphs/contributors) diff --git a/metadata.json b/metadata.json index e926c69..1218b9f 100644 --- a/metadata.json +++ b/metadata.json @@ -1,114 +1,114 @@ { "name": "puppetlabs-inifile", "version": "4.3.0", "author": "puppetlabs", "summary": "Resource types for managing settings in INI files", "license": "Apache-2.0", "source": "https://github.com/puppetlabs/puppetlabs-inifile", "project_page": "https://github.com/puppetlabs/puppetlabs-inifile", "issues_url": "https://tickets.puppetlabs.com/browse/MODULES", "dependencies": [ { "name": "puppetlabs/translate", "version_requirement": ">= 1.0.0 < 3.0.0" }, { "name": "puppetlabs/stdlib", "version_requirement": ">= 4.13.0 < 7.0.0" } ], "operatingsystem_support": [ { "operatingsystem": "RedHat", "operatingsystemrelease": [ "5", "6", "7", "8" ] }, { "operatingsystem": "CentOS", "operatingsystemrelease": [ "5", "6", "7", "8" ] }, { "operatingsystem": "OracleLinux", "operatingsystemrelease": [ "5", "6", "7" ] }, { "operatingsystem": "Scientific", "operatingsystemrelease": [ "6", "7" ] }, { "operatingsystem": "SLES", "operatingsystemrelease": [ "11 SP1", "12", "15" ] }, { "operatingsystem": "Debian", "operatingsystemrelease": [ "8", "9", "10" ] }, { "operatingsystem": "Ubuntu", "operatingsystemrelease": [ "14.04", "16.04", "18.04", "20.04" ] }, { "operatingsystem": "Solaris", "operatingsystemrelease": [ "10", "11" ] }, { "operatingsystem": "Windows", "operatingsystemrelease": [ "2008 R2", "2012 R2", "2016", "2019", "10" ] }, { "operatingsystem": "AIX", "operatingsystemrelease": [ "5.3", "6.1", "7.1" ] } ], "requirements": [ { "name": "puppet", "version_requirement": ">= 5.5.10 < 7.0.0" } ], - "template-url": "https://github.com/puppetlabs/pdk-templates#master", - "template-ref": "heads/master-0-gd610ead", + "template-url": "https://github.com/puppetlabs/pdk-templates#main", + "template-ref": "heads/main-0-gd610ead", "pdk-version": "1.18.1" } diff --git a/spec/unit/puppet/provider/ini_setting/ruby_spec.rb b/spec/unit/puppet/provider/ini_setting/ruby_spec.rb index 0e8a938..414eb85 100644 --- a/spec/unit/puppet/provider/ini_setting/ruby_spec.rb +++ b/spec/unit/puppet/provider/ini_setting/ruby_spec.rb @@ -1,1588 +1,1588 @@ require 'spec_helper' require 'puppet' provider_class = Puppet::Type.type(:ini_setting).provider(:ruby) describe provider_class do include PuppetlabsSpec::Files let(:tmpfile) { tmpfilename('ini_setting_test') } let(:emptyfile) { tmpfilename('ini_setting_test_empty') } let(:common_params) do { title: 'ini_setting_ensure_present_test', path: tmpfile, section: 'section2', } end def validate_file(expected_content, tmpfile) expect(File.read(tmpfile)).to eq(expected_content) end before :each do File.open(tmpfile, 'w') do |fh| fh.write(orig_content) end File.open(emptyfile, 'w') do |fh| fh.write('') end end context 'when calling instances' do let :orig_content do '' end it 'fails when file path is not set' do expect { provider_class.instances }.to raise_error(Puppet::Error, 'Ini_settings only support collecting instances when a file path is hard coded') end context 'when file path is set by a child class' do child_one = Class.new(provider_class) do def self.file_path emptyfile end end it 'returns [] when file is empty' do expect(child_one).to receive(:file_path).and_return(emptyfile) expect(child_one.instances).to eq([]) end child_two = Class.new(provider_class) do def self.file_path '/some/file/path' end end it 'overrides the provider instances file_path' do resource = Puppet::Type::Ini_setting.new(common_params) provider = child_two.new(resource) expect(provider.file_path).to eq('/some/file/path') end end context 'when file has contecnts' do let(:orig_content) do <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue - master = true + main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section:sub] subby=bar #another comment ; yet another comment EOS end it 'is able to parse the results' do child_three = Class.new(provider_class) do def self.file_path '/some/file/path' end end expect(child_three).to receive(:file_path).exactly(2).times.and_return(tmpfile) expect(child_three.instances.size).to eq(7) expected_array = [ { name: 'section1/foo', value: 'foovalue' }, { name: 'section1/bar', value: 'barvalue' }, - { name: 'section1/master', value: 'true' }, + { name: 'section1/main', value: 'true' }, { name: 'section2/foo', value: 'foovalue2' }, { name: 'section2/baz', value: 'bazvalue' }, { name: 'section2/url', value: 'http://192.168.1.1:8080' }, { name: 'section:sub/subby', value: 'bar' }, ] real_array = [] ensure_array = [] child_three.instances.each do |x| prop_hash = x.instance_variable_get(:@property_hash) ensure_value = prop_hash.delete(:ensure) ensure_array.push(ensure_value) real_array.push(prop_hash) end expect(ensure_array.uniq).to eq([:present]) expect((real_array - expected_array) && (expected_array - real_array)).to eq([]) end # rubocop:enable RSpec/ExampleLength # rubocop:enable RSpec/MultipleExpectations end end context 'when ensuring that a setting is present' do let(:orig_content) do <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue -master = true +main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section:sub] subby=bar #another comment ; yet another comment -nonstandard- shoes = purple EOS end expected_content_one = <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue -master = true +main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 yahoo = yippee [section:sub] subby=bar #another comment ; yet another comment -nonstandard- shoes = purple EOS it 'adds a missing setting to the correct section' do resource = Puppet::Type::Ini_setting.new(common_params.merge(setting: 'yahoo', value: 'yippee')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(expected_content_one, tmpfile) end expected_content_two = <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue -master = true +main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section:sub] subby=bar #another comment ; yet another comment -nonstandard- shoes = purple yahoo = yippee EOS it 'adds a missing setting to the correct section with pre/suffix' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'nonstandard', setting: 'yahoo', value: 'yippee', section_prefix: '-', section_suffix: '-')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(expected_content_two, tmpfile) end expected_content_three = <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue -master = true +main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section:sub] subby=bar #another comment ; yet another comment -nonstandard- shoes = purple indented = weirdly EOS it 'adds a missing setting to the correct section with indent_char' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'nonstandard', setting: 'indented', value: 'weirdly', section_prefix: '-', section_suffix: '-', indent_char: "\t")) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(expected_content_three, tmpfile) end expected_content_four = <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue -master = true +main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section:sub] subby=bar #another comment ; yet another comment -nonstandard- shoes = purple indented = weirdly EOS it 'adds a missing setting to the correct section indented by indent_char * indent_width' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'nonstandard', setting: 'indented', value: 'weirdly', section_prefix: '-', section_suffix: '-', indent_char: "\t", indent_width: 4)) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(expected_content_four, tmpfile) end expected_content_five = <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue -master = true +main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section:sub] subby=bar #another comment ; yet another comment -nonstandard- shoes = purple indented = weirdly EOS it 'treats a string indent_width as an integer' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'nonstandard', setting: 'indented', value: 'weirdly', section_prefix: '-', section_suffix: '-', indent_char: "\t", indent_width: '4')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(expected_content_five, tmpfile) end expected_content_six = <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue -master = true +main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section:sub] subby=bar #another comment ; yet another comment -nonstandard- shoes = purple yahoo = yippee EOS it 'adds a missing setting to the correct section with colon' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section:sub', setting: 'yahoo', value: 'yippee')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(expected_content_six, tmpfile) end expected_content_seven = <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue -master = true +main = true [section2] foo= foovalue2 baz=bazvalue2 url = http://192.168.1.1:8080 [section:sub] subby=bar #another comment ; yet another comment -nonstandard- shoes = purple EOS it 'modifies an existing setting with a different value' do resource = Puppet::Type::Ini_setting.new(common_params.merge(setting: 'baz', value: 'bazvalue2')) provider = described_class.new(resource) expect(provider).to be_exists provider.value = 'bazvalue2' validate_file(expected_content_seven, tmpfile) end expected_content_eight = <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue -master = false +main = false [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section:sub] subby=bar #another comment ; yet another comment -nonstandard- shoes = purple EOS it 'modifies an existing setting with a different boolean value' do - resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section1', setting: 'master', value: false)) + resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section1', setting: 'main', value: false)) provider = described_class.new(resource) expect(provider.exists?).to be true transaction = instance_double('transaction', persistence: true) expect(Puppet::Transaction::ResourceHarness.new(transaction).evaluate(provider.resource).out_of_sync).to eq(true) validate_file(expected_content_eight, tmpfile) end # rubocop:enable RSpec/MultipleExpectations : Unable to reduce without altering test expected_content_nine = <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue -master = true +main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section:sub] subby=bar #another comment ; yet another comment -nonstandard- shoes = orange EOS it 'modifies an existing setting with pre/suffix with a different value' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'nonstandard', setting: 'shoes', value: 'orange', section_prefix: '-', section_suffix: '-')) provider = described_class.new(resource) expect(provider.exists?).to be true provider.value = 'orange' validate_file(expected_content_nine, tmpfile) end expected_content_ten = <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue -master = true +main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section:sub] subby=foo #another comment ; yet another comment -nonstandard- shoes = purple EOS it 'modifies an existing setting with a different value - with colon in section' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section:sub', setting: 'subby', value: 'foo')) provider = described_class.new(resource) expect(provider.value).to eq('bar') provider.value = 'foo' validate_file(expected_content_ten, tmpfile) end expected_content_eleven = <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue -master = true +main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.0.1:8080 [section:sub] subby=bar #another comment ; yet another comment -nonstandard- shoes = purple EOS it 'is able to handle settings with non alphanumbering settings' do resource = Puppet::Type::Ini_setting.new(common_params.merge(setting: 'url', value: 'http://192.168.0.1:8080')) provider = described_class.new(resource) expect(provider.value).to eq('http://192.168.1.1:8080') provider.value = 'http://192.168.0.1:8080' validate_file(expected_content_eleven, tmpfile) end expected_content_twelve = <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue -master = true +main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section:sub] subby=bar #another comment ; yet another comment -nonstandard- shoes = http://192.168.0.1:8080 EOS it 'is able to handle settings with pre/suffix with non alphanumbering settings' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'nonstandard', setting: 'shoes', value: 'http://192.168.0.1:8080', section_prefix: '-', section_suffix: '-')) provider = described_class.new(resource) expect(provider.value).to eq('purple') provider.value = 'http://192.168.0.1:8080' validate_file(expected_content_twelve, tmpfile) end it 'recognizes an existing setting with the specified value' do resource = Puppet::Type::Ini_setting.new(common_params.merge(setting: 'baz', value: 'bazvalue')) provider = described_class.new(resource) expect(provider.exists?).to be true end it 'recognizes an existing setting with pre/suffix with the specified value' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'nonstandard', setting: 'shoes', value: 'purple', section_prefix: '-', section_suffix: '-')) provider = described_class.new(resource) expect(provider.exists?).to be true end expected_content_thirteen = <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue -master = true +main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section:sub] subby=bar #another comment ; yet another comment -nonstandard- shoes = purple [section3] huzzah = shazaam EOS it 'adds a new section if the section does not exist' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section3', setting: 'huzzah', value: 'shazaam')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(expected_content_thirteen, tmpfile) end expected_content_fourteen = <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue -master = true +main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section:sub] subby=bar #another comment ; yet another comment -nonstandard- shoes = purple -section3- huzzah = shazaam EOS it 'adds a new section with pre/suffix if the section does not exist' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section3', setting: 'huzzah', value: 'shazaam', section_prefix: '-', section_suffix: '-')) provider = described_class.new(resource) expect(provider).not_to be_exists provider.create validate_file(expected_content_fourteen, tmpfile) end expected_content_fifteen = <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue -master = true +main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section:sub] subby=bar #another comment ; yet another comment -nonstandard- shoes = purple [section:subsection] huzzah = shazaam EOS it 'adds a new section if the section does not exist - with colon' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section:subsection', setting: 'huzzah', value: 'shazaam')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(expected_content_fifteen, tmpfile) end expected_content_sixteen = <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue -master = true +main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section:sub] subby=bar #another comment ; yet another comment -nonstandard- shoes = purple -section:subsection- huzzah = shazaam EOS it 'adds a new section with pre/suffix if the section does not exist - with colon' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section:subsection', setting: 'huzzah', value: 'shazaam', section_prefix: '-', section_suffix: '-')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(expected_content_sixteen, tmpfile) end it 'adds a new empty section' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(orig_content + "\n[section]\n", tmpfile) end it 'is able to handle variables of any type' do - resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section1', setting: 'master', value: true)) + resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section1', setting: 'main', value: true)) provider = described_class.new(resource) expect(provider.value).to eq('true') end end context 'when no sections exist' do let(:orig_content) do '' end validate_zero = "[section]\n" it 'adds an empty section' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section', path: emptyfile)) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(validate_zero, emptyfile) end validate_one = '[section1] setting1 = hellowworld ' it 'adds a new section' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section1', setting: 'setting1', value: 'hellowworld', path: emptyfile)) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(validate_one, emptyfile) end validate_two = '-section1- setting1 = hellowworld ' it 'adds a new section with pre/suffix' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section1', setting: 'setting1', value: 'hellowworld', path: emptyfile, section_prefix: '-', section_suffix: '-')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(validate_two, emptyfile) end validate_three = '[section:subsection] setting1 = hellowworld ' it 'adds a new section with colon' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section:subsection', setting: 'setting1', value: 'hellowworld', path: emptyfile)) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(validate_three, emptyfile) end validate_four = '-section:subsection- setting1 = hellowworld ' it 'adds a new section with pre/suffix with colon' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section:subsection', setting: 'setting1', value: 'hellowworld', path: emptyfile, section_prefix: '-', section_suffix: '-')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(validate_four, emptyfile) end end context 'when only an empty section exists' do let(:orig_content) do "[section]\n" end it 'adds a new setting' do expected = orig_content { 'section' => { 'first' => 1 } }.each_pair do |section, settings| settings.each_pair do |setting, value| resource = Puppet::Type::Ini_setting.new(common_params.merge(section: section, setting: setting, value: value)) provider = described_class.new(resource) expect(provider.exists?).to be false # byebug provider.create expected += "#{setting} = #{value}\n" end end validate_file(expected, tmpfile) end end context 'when dealing with a global section' do let(:orig_content) do <<-EOS # This is a comment foo=blah [section2] foo = http://192.168.1.1:8080 ; yet another comment EOS end expected_content_one = <<-EOS # This is a comment foo=blah bar = yippee [section2] foo = http://192.168.1.1:8080 ; yet another comment EOS it "adds a missing setting if it doesn't exist" do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: '', setting: 'bar', value: 'yippee')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(expected_content_one, tmpfile) end expected_content_two = <<-EOS # This is a comment foo=yippee [section2] foo = http://192.168.1.1:8080 ; yet another comment EOS it 'modifies an existing setting with a different value' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: '', setting: 'foo', value: 'yippee')) provider = described_class.new(resource) expect(provider.value).to eq('blah') provider.value = 'yippee' validate_file(expected_content_two, tmpfile) end it 'recognizes an existing setting with the specified value' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: '', setting: 'foo', value: 'blah')) provider = described_class.new(resource) expect(provider.exists?).to be true end end context 'when the first line of the file is a section' do let(:orig_content) do <<-EOS [section2] foo = http://192.168.1.1:8080 EOS end expected_content_one = <<-EOS foo = yippee [section2] foo = http://192.168.1.1:8080 EOS it 'is able to add a global setting' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: '', setting: 'foo', value: 'yippee')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(expected_content_one, tmpfile) end expected_content_two = <<-EOS [section2] foo = yippee EOS it 'modifies an existing setting' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section2', setting: 'foo', value: 'yippee')) provider = described_class.new(resource) expect(provider.value).to eq('http://192.168.1.1:8080') provider.value = 'yippee' validate_file(expected_content_two, tmpfile) end expected_content_three = <<-EOS [section2] foo = http://192.168.1.1:8080 bar = baz EOS it 'adds a new setting' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section2', setting: 'bar', value: 'baz')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(expected_content_three, tmpfile) end end context 'when overriding the separator' do let(:orig_content) do <<-EOS [section2] foo=bar EOS end expected_content_one = <<-EOS [section2] foo=yippee EOS it 'modifies an existing setting' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section2', setting: 'foo', value: 'yippee', key_val_separator: '=')) provider = described_class.new(resource) expect(provider.value).to eq('bar') provider.value = 'yippee' validate_file(expected_content_one, tmpfile) end end context 'when overriding the separator to something other than =' do let(:orig_content) do <<-EOS [section2] foo: bar EOS end expected_content_one = <<-EOS [section2] foo: yippee EOS it 'modifies an existing setting' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section2', setting: 'foo', value: 'yippee', key_val_separator: ': ')) provider = described_class.new(resource) expect(provider.value).to eq('bar') provider.value = 'yippee' validate_file(expected_content_one, tmpfile) end expected_content_two = <<-EOS [section2] foo: bar bar: baz EOS it 'adds a new setting' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section2', setting: 'bar', value: 'baz', key_val_separator: ': ')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(expected_content_two, tmpfile) end end context 'when overriding the separator to a space' do let(:orig_content) do <<-EOS [section2] foo bar EOS end expected_content_one = <<-EOS [section2] foo yippee EOS it 'modifies an existing setting' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section2', setting: 'foo', value: 'yippee', key_val_separator: ' ')) provider = described_class.new(resource) expect(provider.value).to eq('bar') provider.value = 'yippee' validate_file(expected_content_one, tmpfile) end expected_content_two = <<-EOS [section2] foo bar bar baz EOS it 'adds a new setting' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section2', setting: 'bar', value: 'baz', key_val_separator: ' ')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(expected_content_two, tmpfile) end end context 'when ensuring that a setting is absent' do let(:orig_content) do <<-EOS [section1] ; This is also a comment foo=foovalue bar = barvalue -master = true +main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section3] # com = ment uncom = ment [section4] uncom = ment [section:sub] subby=bar #another comment ; yet another comment -nonstandard- shoes = purple EOS end expected_content_one = <<-EOS [section1] ; This is also a comment bar = barvalue -master = true +main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section3] # com = ment uncom = ment [section4] uncom = ment [section:sub] subby=bar #another comment ; yet another comment -nonstandard- shoes = purple EOS it 'removes a setting that exists' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section1', setting: 'foo', ensure: 'absent')) provider = described_class.new(resource) expect(provider.exists?).to be true provider.destroy validate_file(expected_content_one, tmpfile) end expected_content_two = <<-EOS [section1] ; This is also a comment foo=foovalue bar = barvalue -master = true +main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section3] # com = ment uncom = ment [section4] uncom = ment [section:sub] subby=bar #another comment ; yet another comment EOS it 'removes a setting with pre/suffix that exists' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'nonstandard', setting: 'shoes', ensure: 'absent', section_prefix: '-', section_suffix: '-')) provider = described_class.new(resource) expect(provider.exists?).to be true provider.destroy validate_file(expected_content_two, tmpfile) end expected_content_three = <<-EOS [section1] ; This is also a comment foo=foovalue bar = barvalue -master = true +main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section3] # com = ment uncom = ment [section4] uncom = ment [section:sub] subby=bar #another comment ; yet another comment -nonstandard- shoes = purple EOS it 'does nothing for a setting that does not exist' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section:sub', setting: 'foo', ensure: 'absent')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.destroy validate_file(expected_content_three, tmpfile) end expected_content_four = <<-EOS [section1] ; This is also a comment foo=foovalue bar = barvalue -master = true +main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section3] # com = ment uncom = ment [section4] uncom = ment [section:sub] subby=bar #another comment ; yet another comment -nonstandard- shoes = purple EOS it 'does nothing for a setting with pre/suffix that does not exist' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'nonstandard', setting: 'foo', ensure: 'absent', section_prefix: '-', section_suffix: '-')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.destroy validate_file(expected_content_four, tmpfile) end expected_content_five = <<-EOS [section1] ; This is also a comment foo=foovalue bar = barvalue -master = true +main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section3] # com = ment [section4] uncom = ment [section:sub] subby=bar #another comment ; yet another comment -nonstandard- shoes = purple EOS it 'does not remove a section when the last uncommented setting is removed if there are comments' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section3', setting: 'uncom', ensure: 'absent')) provider = described_class.new(resource) expect(provider.exists?).to be true provider.destroy validate_file(expected_content_five, tmpfile) end expected_content_six = <<-EOS [section1] ; This is also a comment foo=foovalue bar = barvalue -master = true +main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section3] # com = ment uncom = ment [section:sub] subby=bar #another comment ; yet another comment -nonstandard- shoes = purple EOS it 'removes the section when removing the last line in the section' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section4', setting: 'uncom', ensure: 'absent')) provider = described_class.new(resource) expect(provider.exists?).to be true provider.destroy validate_file(expected_content_six, tmpfile) end end context 'when dealing with indentation in sections' do let(:orig_content) do <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue - master = true + main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section:sub] subby=bar #another comment fleezy = flam ; yet another comment EOS end expected_content_one = <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue - master = true + main = true yahoo = yippee [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section:sub] subby=bar #another comment fleezy = flam ; yet another comment EOS it 'adds a missing setting at the correct indentation when the header is aligned' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section1', setting: 'yahoo', value: 'yippee')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(expected_content_one, tmpfile) end expected_content_two = <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue2 - master = true + main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section:sub] subby=bar #another comment fleezy = flam ; yet another comment EOS it 'updates an existing setting at the correct indentation when the header is aligned' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section1', setting: 'bar', value: 'barvalue2')) provider = described_class.new(resource) expect(provider.exists?).to be true provider.create validate_file(expected_content_two, tmpfile) end expected_content_three = <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue - master = true + main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 yahoo = yippee [section:sub] subby=bar #another comment fleezy = flam ; yet another comment EOS it 'adds a missing setting at the correct indentation when the header is not aligned' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section2', setting: 'yahoo', value: 'yippee')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(expected_content_three, tmpfile) end expected_content_four = <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue - master = true + main = true [section2] foo= foovalue2 baz=bazvalue2 url = http://192.168.1.1:8080 [section:sub] subby=bar #another comment fleezy = flam ; yet another comment EOS it 'updates an existing setting at the correct indentation when the header is not aligned' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section2', setting: 'baz', value: 'bazvalue2')) provider = described_class.new(resource) expect(provider.exists?).to be true provider.create validate_file(expected_content_four, tmpfile) end expected_content_five = <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue - master = true + main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section:sub] subby=bar #another comment fleezy = flam ; yet another comment yahoo = yippee EOS it 'adds a missing setting at the min indentation when the section is not aligned' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section:sub', setting: 'yahoo', value: 'yippee')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(expected_content_five, tmpfile) end expected_content_six = <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue - master = true + main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section:sub] subby=bar #another comment fleezy = flam2 ; yet another comment EOS it 'updates an existing setting at the previous indentation when the section is not aligned' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section:sub', setting: 'fleezy', value: 'flam2')) provider = described_class.new(resource) expect(provider.exists?).to be true provider.create validate_file(expected_content_six, tmpfile) end expected_content_seven = <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue - master = true + main = true [section2] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section:sub] subby=bar #another comment fleezy = flam2 ; yet another comment EOS it 'updates an existing setting at the previous indentation regardless of indent_char and indent_width settings' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section:sub', setting: 'fleezy', value: 'flam2', indent_char: 'ignore this', indent_width: 10)) provider = described_class.new(resource) expect(provider.exists?).to be true provider.create validate_file(expected_content_seven, tmpfile) end end context 'when dealing settings that have a commented version present' do let(:orig_content) do <<-EOS [section1] # foo=foovalue bar=barvalue foo = foovalue2 [section2] # foo = foovalue ;bar=barvalue blah = blah #baz= EOS end expected_content_eight = <<-EOS [section1] # foo=foovalue bar=barvalue foo = foovalue2 [section2] # foo = foovalue foo = foo3 ;bar=barvalue blah = blah #baz= EOS it 'adds a new setting below a commented version of that setting' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section2', setting: 'foo', value: 'foo3')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(expected_content_eight, tmpfile) end expected_content_nine = <<-EOS [section1] # foo=foovalue bar=barvalue foo = foo3 [section2] # foo = foovalue ;bar=barvalue blah = blah #baz= EOS it 'updates an existing setting in place, even if there is a commented version of that setting' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section1', setting: 'foo', value: 'foo3')) provider = described_class.new(resource) expect(provider.exists?).to be true provider.create validate_file(expected_content_nine, tmpfile) end expected_content_ten = <<-EOS [section1] # foo=foovalue bar=barvalue foo = foovalue2 [section2] # foo = foovalue ;bar=barvalue bar = bar3 blah = blah #baz= EOS it 'adds a new setting below a commented version of that setting, respecting semicolons as comments' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section2', setting: 'bar', value: 'bar3')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(expected_content_ten, tmpfile) end expected_content_four = <<-EOS [section1] # foo=foovalue bar=barvalue foo = foovalue2 [section2] # foo = foovalue ;bar=barvalue blah = blah #baz= baz = bazvalue EOS it 'adds a new setting below an empty commented version of that setting' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section2', setting: 'baz', value: 'bazvalue')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(expected_content_four, tmpfile) end context 'when a section only contains comments' do let(:orig_content) do <<-EOS [section1] # foo=foovalue # bar=bar2 EOS end expected_content_one = <<-EOS [section1] # foo=foovalue foo = foovalue2 # bar=bar2 EOS it 'is able to add a new setting when a section contains only comments' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section1', setting: 'foo', value: 'foovalue2')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(expected_content_one, tmpfile) end expected_content_two = <<-EOS [section1] # foo=foovalue # bar=bar2 bar = barvalue2 EOS it 'is able to add a new setting when it matches a commented out line other than the first one' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section1', setting: 'bar', value: 'barvalue2')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(expected_content_two, tmpfile) end end context 'when sections have spaces and dashes' do let(:orig_content) do <<-EOS # This is a comment [section - one] ; This is also a comment foo=foovalue bar = barvalue -master = true +main = true [section - two] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 [section:sub] subby=bar #another comment ; yet another comment EOS end expected_content_one = <<-EOS # This is a comment [section - one] ; This is also a comment foo=foovalue bar = barvalue -master = true +main = true [section - two] foo= foovalue2 baz=bazvalue url = http://192.168.1.1:8080 yahoo = yippee [section:sub] subby=bar #another comment ; yet another comment EOS it 'adds a missing setting to the correct section' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'section - two', setting: 'yahoo', value: 'yippee')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(expected_content_one, tmpfile) end end end context 'when sections have spaces and quotations' do let(:orig_content) do <<-EOS -[branch "master"] +[branch "main"] remote = origin - merge = refs/heads/master + merge = refs/heads/main [alias] -to-deploy = log --merges --grep='pull request' --format='%s (%cN)' origin/production..origin/master +to-deploy = log --merges --grep='pull request' --format='%s (%cN)' origin/production..origin/main [branch "production"] remote = origin merge = refs/heads/production EOS end expected_content_one = <<-EOS -[branch "master"] +[branch "main"] remote = origin - merge = refs/heads/master + merge = refs/heads/main [alias] -to-deploy = log --merges --grep='pull request' --format='%s (%cN)' origin/production..origin/master +to-deploy = log --merges --grep='pull request' --format='%s (%cN)' origin/production..origin/main foo = bar [branch "production"] remote = origin merge = refs/heads/production EOS it 'adds a missing setting to the correct section' do resource = Puppet::Type::Ini_setting.new(common_params.merge(section: 'alias', setting: 'foo', value: 'bar')) provider = described_class.new(resource) expect(provider.exists?).to be false provider.create validate_file(expected_content_one, tmpfile) end end # rubocop:enable Layout/IndentHeredoc end diff --git a/spec/unit/puppet/provider/ini_subsetting/ruby_spec.rb b/spec/unit/puppet/provider/ini_subsetting/ruby_spec.rb index d7a6986..18f22f7 100644 --- a/spec/unit/puppet/provider/ini_subsetting/ruby_spec.rb +++ b/spec/unit/puppet/provider/ini_subsetting/ruby_spec.rb @@ -1,361 +1,361 @@ require 'spec_helper' require 'puppet' provider_class = Puppet::Type.type(:ini_subsetting).provider(:ruby) describe provider_class do include PuppetlabsSpec::Files let(:tmpfile) { tmpfilename('ini_setting_test') } def validate_file(expected_content, tmpfile) expect(File.read(tmpfile)).to eq expected_content end before :each do File.open(tmpfile, 'w') do |fh| fh.write(orig_content) end end context 'when ensuring that a subsetting is present' do let(:common_params) do { title: 'ini_setting_ensure_present_test', path: tmpfile, section: '', key_val_separator: '=', setting: 'JAVA_ARGS', } end let(:orig_content) do <<-EOS JAVA_ARGS="-Xmx192m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/pe-puppetdb/puppetdb-oom.hprof" EOS end expected_content_one = <<-EOS JAVA_ARGS="-Xmx192m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/pe-puppetdb/puppetdb-oom.hprof -Xms128m" EOS it 'adds a missing subsetting' do resource = Puppet::Type::Ini_subsetting.new(common_params.merge(subsetting: '-Xms', value: '128m')) provider = described_class.new(resource) expect(provider.exists?).to be_nil provider.create validate_file(expected_content_one, tmpfile) end expected_content_two = <<-EOS JAVA_ARGS="-Xms128m -Xmx192m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/pe-puppetdb/puppetdb-oom.hprof" EOS it 'adds a missing subsetting element at the beginning of the line' do resource = Puppet::Type::Ini_subsetting.new(common_params.merge(subsetting: '-Xms', value: '128m', insert_type: :start)) provider = described_class.new(resource) expect(provider.exists?).to be_nil provider.create validate_file(expected_content_two, tmpfile) end expected_content_three = <<-EOS JAVA_ARGS="-Xmx192m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/pe-puppetdb/puppetdb-oom.hprof -Xms128m" EOS it 'adds a missing subsetting element at the end of the line' do resource = Puppet::Type::Ini_subsetting.new(common_params.merge(subsetting: '-Xms', value: '128m', insert_type: :end)) provider = described_class.new(resource) expect(provider.exists?).to be_nil provider.create validate_file(expected_content_three, tmpfile) end expected_content_four = <<-EOS JAVA_ARGS="-Xmx192m -Xms128m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/pe-puppetdb/puppetdb-oom.hprof" EOS it 'adds a missing subsetting element after the given item' do resource = Puppet::Type::Ini_subsetting.new(common_params.merge(subsetting: '-Xms', value: '128m', insert_type: :after, insert_value: '-Xmx')) provider = described_class.new(resource) expect(provider.exists?).to be_nil provider.create validate_file(expected_content_four, tmpfile) end expected_content_five = <<-EOS JAVA_ARGS="-Xms128m -Xmx192m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/pe-puppetdb/puppetdb-oom.hprof" EOS it 'adds a missing subsetting element before the given item' do resource = Puppet::Type::Ini_subsetting.new(common_params.merge(subsetting: '-Xms', value: '128m', insert_type: :before, insert_value: '-Xmx')) provider = described_class.new(resource) expect(provider.exists?).to be_nil provider.create validate_file(expected_content_five, tmpfile) end expected_content_six = <<-EOS JAVA_ARGS="-Xmx192m -Xms128m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/pe-puppetdb/puppetdb-oom.hprof" EOS it 'adds a missing subsetting element at the given index' do resource = Puppet::Type::Ini_subsetting.new(common_params.merge(subsetting: '-Xms', value: '128m', insert_type: :index, insert_value: '1')) provider = described_class.new(resource) expect(provider.exists?).to be_nil provider.create validate_file(expected_content_six, tmpfile) end expected_content_seven = <<-EOS JAVA_ARGS="-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/pe-puppetdb/puppetdb-oom.hprof" EOS it 'removes an existing subsetting' do resource = Puppet::Type::Ini_subsetting.new(common_params.merge(subsetting: '-Xmx')) provider = described_class.new(resource) expect(provider.exists?).to eq '192m' provider.destroy validate_file(expected_content_seven, tmpfile) end expected_content_eight = <<-EOS JAVA_ARGS="-Xmx192m" EOS it 'is able to remove several subsettings with the same name' do resource = Puppet::Type::Ini_subsetting.new(common_params.merge(subsetting: '-XX')) provider = described_class.new(resource) expect(provider.exists?).to eq ':+HeapDumpOnOutOfMemoryError' provider.destroy validate_file(expected_content_eight, tmpfile) end expected_content_nine = <<-EOS JAVA_ARGS="-Xmx256m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/pe-puppetdb/puppetdb-oom.hprof" EOS it 'modifies an existing subsetting' do resource = Puppet::Type::Ini_subsetting.new(common_params.merge(subsetting: '-Xmx', value: '256m')) provider = described_class.new(resource) expect(provider.exists?).to eq '192m' provider.value = '256m' validate_file(expected_content_nine, tmpfile) end expected_content_ten = <<-EOS JAVA_ARGS="-Xmx192m -XXtest -XXtest" EOS it 'is able to modify several subsettings with the same name' do resource = Puppet::Type::Ini_subsetting.new(common_params.merge(subsetting: '-XX', value: 'test')) provider = described_class.new(resource) expect(provider.exists?).to eq ':+HeapDumpOnOutOfMemoryError' provider.value = 'test' validate_file(expected_content_ten, tmpfile) end end context 'when working with subsettings in files with unquoted settings values' do let(:common_params) do { title: 'ini_setting_ensure_present_test', path: tmpfile, - section: 'master', + section: 'main', setting: 'reports', } end let(:orig_content) do <<-EOS - [master] + [main] reports = http,foo EOS end expected_content_one = <<-EOS - [master] + [main] reports = foo EOS it 'removes an existing subsetting' do resource = Puppet::Type::Ini_subsetting.new(common_params.merge(subsetting: 'http', subsetting_separator: ',')) provider = described_class.new(resource) expect(provider.exists?).to eq '' provider.destroy validate_file(expected_content_one, tmpfile) end expected_content_two = <<-EOS - [master] + [main] reports = http,foo,puppetdb EOS it "adds a new subsetting when the 'parent' setting already exists" do resource = Puppet::Type::Ini_subsetting.new(common_params.merge(subsetting: 'puppetdb', subsetting_separator: ',')) provider = described_class.new(resource) expect(provider.exists?).to be_nil provider.value = '' validate_file(expected_content_two, tmpfile) end expected_content_three = <<-EOS - [master] + [main] reports = http,foo somenewsetting = puppetdb EOS it "adds a new subsetting when the 'parent' setting does not already exist" do resource = Puppet::Type::Ini_subsetting.new(common_params.merge(setting: 'somenewsetting', subsetting: 'puppetdb', subsetting_separator: ',')) provider = described_class.new(resource) expect(provider.exists?).to be_nil provider.value = '' validate_file(expected_content_three, tmpfile) end end context 'when working with subsettings in files with use_exact_match' do let(:common_params) do { title: 'ini_setting_ensure_present_test', path: tmpfile, - section: 'master', + section: 'main', setting: 'reports', use_exact_match: true, } end let(:orig_content) do <<-EOS - [master] + [main] reports = http,foo EOS end expected_content_one = <<-EOS - [master] + [main] reports = http,foo,fo EOS it "adds a new subsetting when the 'parent' setting already exists" do resource = Puppet::Type::Ini_subsetting.new(common_params.merge(subsetting: 'fo', subsetting_separator: ',')) provider = described_class.new(resource) provider.value = '' validate_file(expected_content_one, tmpfile) end expected_content_two = <<-EOS - [master] + [main] reports = http,foo EOS it 'does not remove substring subsettings' do resource = Puppet::Type::Ini_subsetting.new(common_params.merge(subsetting: 'fo', subsetting_separator: ',')) provider = described_class.new(resource) provider.value = '' provider.destroy validate_file(expected_content_two, tmpfile) end end context 'when working with subsettings in files with subsetting_key_val_separator' do let(:common_params) do { title: 'ini_setting_ensure_present_test', path: tmpfile, - section: 'master', + section: 'main', setting: 'reports', subsetting_separator: ',', subsetting_key_val_separator: ':', } end let(:orig_content) do <<-EOS - [master] + [main] reports = a:1,b:2 EOS end expected_content_one = <<-EOS - [master] + [main] reports = a:1,b:2,c:3 EOS it "adds a new subsetting when the 'parent' setting already exists" do resource = Puppet::Type::Ini_subsetting.new(common_params.merge(subsetting: 'c', value: '3')) provider = described_class.new(resource) provider.value = '3' validate_file(expected_content_one, tmpfile) end expected_content_two = <<-EOS - [master] + [main] reports = a:1,b:2 somenewsetting = c:3 EOS it "adds a new subsetting when the 'parent' setting does not already exist" do resource = Puppet::Type::Ini_subsetting.new(common_params.merge(subsetting: 'c', value: '3', setting: 'somenewsetting')) provider = described_class.new(resource) expect(provider.exists?).to be_nil provider.value = '3' validate_file(expected_content_two, tmpfile) end expected_content_three = <<-EOS - [master] + [main] reports = a:1 EOS it 'is able to remove the existing subsetting' do resource = Puppet::Type::Ini_subsetting.new(common_params.merge(subsetting: 'b')) provider = described_class.new(resource) expect(provider.exists?).to eq '2' provider.destroy validate_file(expected_content_three, tmpfile) end expected_content_four = <<-EOS - [master] + [main] reports = a:1,b:5 EOS it 'is able to modify the existing subsetting' do resource = Puppet::Type::Ini_subsetting.new(common_params.merge(subsetting: 'b', value: '5')) provider = described_class.new(resource) expect(provider.exists?).to eq '2' provider.value = '5' validate_file(expected_content_four, tmpfile) end end context 'when delete_if_empty is toggled to true' do let(:common_params) do { title: 'ini_setting_delete_if_empty_test', path: tmpfile, - section: 'master', + section: 'main', delete_if_empty: true, } end let(:orig_content) do <<-EOS - [master] + [main] reports = http something = else EOS end expected_content_one = <<-EOS - [master] + [main] something = else EOS expected_content_two = '' it 'removes the subsetting when the it is empty' do resource = Puppet::Type::Ini_subsetting.new(common_params.merge(setting: 'reports', subsetting: 'http', subsetting_separator: ',')) provider = described_class.new(resource) provider.destroy validate_file(expected_content_one, tmpfile) resource = Puppet::Type::Ini_subsetting.new(common_params.merge(setting: 'something', subsetting: 'else', subsetting_separator: ',')) provider = described_class.new(resource) provider.destroy validate_file(expected_content_two, tmpfile) end end end diff --git a/spec/unit/puppet/util/ini_file_spec.rb b/spec/unit/puppet/util/ini_file_spec.rb index 2f284d3..bb4ceda 100644 --- a/spec/unit/puppet/util/ini_file_spec.rb +++ b/spec/unit/puppet/util/ini_file_spec.rb @@ -1,316 +1,316 @@ require 'spec_helper' require 'stringio' require 'puppet/util/ini_file' describe Puppet::Util::IniFile do subject(:ini_sub) { described_class.new('/my/ini/file/path') } before :each do allow(File).to receive(:file?).with('/my/ini/file/path') { true } allow(described_class).to receive(:readlines).once.with('/my/ini/file/path') do sample_content end end context 'when parsing a file' do let(:sample_content) do template = <<-EOS # This is a comment [section1] ; This is also a comment foo=foovalue bar = barvalue baz = [section2] foo= foovalue2 baz=bazvalue ; commented = out setting #another comment ; yet another comment zot = multi word value xyzzy['thing1']['thing2']=xyzzyvalue l=git log EOS template.split("\n") end it 'parses the correct number of sections' do # there is always a "global" section, so our count should be 3. expect(ini_sub.section_names.length).to eq(3) end it 'parses the correct section_names' do # there should always be a "global" section named "" at the beginning of the list expect(ini_sub.section_names).to eq(['', 'section1', 'section2']) end it 'exposes settings for sections #section1' do expect(ini_sub.get_settings('section1')).to eq('bar' => 'barvalue', 'baz' => '', 'foo' => 'foovalue') end it 'exposes settings for sections #section2' do expect(ini_sub.get_settings('section2')).to eq('baz' => 'bazvalue', 'foo' => 'foovalue2', 'l' => 'git log', "xyzzy['thing1']['thing2']" => 'xyzzyvalue', 'zot' => 'multi word value') end end context 'when parsing a file whose first line is a section' do let(:sample_content) do template = <<-EOS [section1] ; This is a comment foo=foovalue EOS template.split("\n") end it 'parses the correct number of sections' do # there is always a "global" section, so our count should be 2. expect(ini_sub.section_names.length).to eq(2) end it 'parses the correct section_names' do # there should always be a "global" section named "" at the beginning of the list expect(ini_sub.section_names).to eq(['', 'section1']) end it 'exposes settings for sections' do expect(ini_sub.get_value('section1', 'foo')).to eq('foovalue') end end context "when parsing a file with a 'global' section" do let(:sample_content) do template = <<-EOS foo = bar [section1] ; This is a comment foo=foovalue EOS template.split("\n") end it 'parses the correct number of sections' do # there is always a "global" section, so our count should be 2. expect(ini_sub.section_names.length).to eq(2) end it 'parses the correct section_names' do # there should always be a "global" section named "" at the beginning of the list expect(ini_sub.section_names).to eq(['', 'section1']) end it 'exposes settings for sections #bar' do expect(ini_sub.get_value('', 'foo')).to eq('bar') end it 'exposes settings for sections #foovalue' do expect(ini_sub.get_value('section1', 'foo')).to eq('foovalue') end end context 'when updating a file with existing empty values' do let(:sample_content) do template = <<-EOS [section1] foo= #bar= #xyzzy['thing1']['thing2']='xyzzyvalue' EOS template.split("\n") end # rubocop:disable RSpec/ExpectInHook before :each do expect(ini_sub.get_value('section1', 'far')).to eq(nil) expect(ini_sub.get_value('section1', 'bar')).to eq(nil) expect(ini_sub.get_value('section1', "xyzzy['thing1']['thing2']")).to eq(nil) end # rubocop:enable RSpec/ExpectInHook it 'properlies update uncommented values' do ini_sub.set_value('section1', 'foo', ' = ', 'foovalue') expect(ini_sub.get_value('section1', 'foo')).to eq('foovalue') end it 'properlies update uncommented values without separator' do ini_sub.set_value('section1', 'foo', 'foovalue') expect(ini_sub.get_value('section1', 'foo')).to eq('foovalue') end it 'properlies update commented value' do ini_sub.set_value('section1', 'bar', ' = ', 'barvalue') expect(ini_sub.get_value('section1', 'bar')).to eq('barvalue') end it 'properlies update commented values' do ini_sub.set_value('section1', "xyzzy['thing1']['thing2']", ' = ', 'xyzzyvalue') expect(ini_sub.get_value('section1', "xyzzy['thing1']['thing2']")).to eq('xyzzyvalue') end it 'properlies update commented value without separator' do ini_sub.set_value('section1', 'bar', 'barvalue') expect(ini_sub.get_value('section1', 'bar')).to eq('barvalue') end it 'properlies update commented values without separator' do ini_sub.set_value('section1', "xyzzy['thing1']['thing2']", 'xyzzyvalue') expect(ini_sub.get_value('section1', "xyzzy['thing1']['thing2']")).to eq('xyzzyvalue') end it 'properlies add new empty values' do ini_sub.set_value('section1', 'baz', ' = ', 'bazvalue') expect(ini_sub.get_value('section1', 'baz')).to eq('bazvalue') end it 'adds new empty values without separator' do ini_sub.set_value('section1', 'baz', 'bazvalue') expect(ini_sub.get_value('section1', 'baz')).to eq('bazvalue') end end context 'the file has quotation marks in its section names' do let(:sample_content) do template = <<-EOS - [branch "master"] + [branch "main"] remote = origin - merge = refs/heads/master + merge = refs/heads/main [alias] - to-deploy = log --merges --grep='pull request' --format='%s (%cN)' origin/production..origin/master + to-deploy = log --merges --grep='pull request' --format='%s (%cN)' origin/production..origin/main [branch "production"] remote = origin merge = refs/heads/production EOS template.split("\n") end it 'parses the sections' do expect(ini_sub.section_names).to match_array ['', - 'branch "master"', + 'branch "main"', 'alias', 'branch "production"'] end end context 'Samba INI file with dollars in section names' do let(:sample_content) do template = <<-EOS [global] workgroup = FELLOWSHIP ; ... idmap config * : backend = tdb [printers] comment = All Printers ; ... browseable = No [print$] comment = Printer Drivers path = /var/lib/samba/printers [Shares] path = /home/shares read only = No guest ok = Yes EOS template.split("\n") end it 'parses the correct section_names' do expect(ini_sub.section_names).to match_array ['', 'global', 'printers', 'print$', 'Shares'] end end context 'section names with forward slashes in them' do let(:sample_content) do template = <<-EOS [monitor:///var/log/*.log] disabled = test_value EOS template.split("\n") end it 'parses the correct section_names' do expect(ini_sub.section_names).to match_array [ '', 'monitor:///var/log/*.log', ] end end context 'KDE Configuration with braces in setting names' do let(:sample_content) do template = <<-EOS [khotkeys] _k_friendly_name=khotkeys {5465e8c7-d608-4493-a48f-b99d99fdb508}=Print,none,PrintScreen {d03619b6-9b3c-48cc-9d9c-a2aadb485550}=Search,none,Search EOS template.split("\n") end it 'exposes settings for sections #print' do expect(ini_sub.get_value('khotkeys', '{5465e8c7-d608-4493-a48f-b99d99fdb508}')).to eq('Print,none,PrintScreen') end it 'exposes settings for sections #search' do expect(ini_sub.get_value('khotkeys', '{d03619b6-9b3c-48cc-9d9c-a2aadb485550}')).to eq('Search,none,Search') end end context 'Configuration with colons in setting names' do let(:sample_content) do template = <<-EOS [Drive names] A:=5.25" Floppy B:=3.5" Floppy C:=Winchester EOS template.split("\n") end it 'exposes settings for sections #A' do expect(ini_sub.get_value('Drive names', 'A:')).to eq '5.25" Floppy' end it 'exposes settings for sections #B' do expect(ini_sub.get_value('Drive names', 'B:')).to eq '3.5" Floppy' end it 'exposes settings for sections #C' do expect(ini_sub.get_value('Drive names', 'C:')).to eq 'Winchester' end end context 'Configuration with spaces in setting names' do let(:sample_content) do template = <<-EOS [global] # log files split per-machine: log file = /var/log/samba/log.%m kerberos method = system keytab passdb backend = tdbsam security = ads EOS template.split("\n") end it 'exposes settings for sections #log' do expect(ini_sub.get_value('global', 'log file')).to eq '/var/log/samba/log.%m' end it 'exposes settings for sections #kerberos' do expect(ini_sub.get_value('global', 'kerberos method')).to eq 'system keytab' end it 'exposes settings for sections #passdb' do expect(ini_sub.get_value('global', 'passdb backend')).to eq 'tdbsam' end it 'exposes settings for sections #security' do expect(ini_sub.get_value('global', 'security')).to eq 'ads' end end end