Class: ChefVault::TestFixtures

Inherits:
Object
  • Object
show all
Defined in:
lib/chef-vault/test_fixtures.rb

Overview

dynamic RSpec contexts for cookbooks that use chef-vault

Constant Summary collapse

VERSION =

the version of the gem

"0.5.2"

Class Method Summary collapse

Class Method Details

.rspec_shared_context(stub_encrypted_data = false) ⇒ Module

created a shared RSpec context that stubs calls to ChefVault::Item.load

Parameters:

  • stub_encrypted_data (Boolean) (defaults to: false)

    whether to also stub calls to Chef::DataBagItem.load

Returns:

  • (Module)

    a shared context to include in your example groups



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/chef-vault/test_fixtures.rb', line 28

def rspec_shared_context(stub_encrypted_data = false)
  @context ||= begin
    Module.new do
      extend RSpec::Core::SharedContext

      before { find_vaults(stub_encrypted_data) }

      private

      # finds all the directories in test/integration/data_bags, stubbing
      # each as a vault
      # @param stub_encrypted_data [Boolean] whether to also stub calls to
      #   Chef::DataBagItem.load
      # return [void]
      # @api private
      def find_vaults(stub_encrypted_data)
        dbdir = Pathname.new("test") + "integration" + "data_bags"
        dbdir.each_child do |vault|
          next unless vault.directory?
          stub_vault(stub_encrypted_data, vault)
        end
      end

      # stubs a vault with the contents of JSON files in a directory.
      # Finds all files in the vault path ending in .json and stubs
      # each as a vault item.
      # @param stub_encrypted_data [Boolean] whether to also stub calls to
      #   Chef::DataBagItem.load
      # @param vault [Pathname] the path to the directory that will be
      #   stubbed as a vault
      # @return [void]
      # @api private
      def stub_vault(stub_encrypted_data, vault)
        db = {}
        vault.each_child do |e|
          next unless e.file?
          m = e.basename.to_s.downcase.match(/(.+)\.json/i)
          next unless m
          content = JSON.parse(e.read)
          vaultname = vault.basename.to_s
          stub_vault_item(vaultname, m[1], content, db)
          if stub_encrypted_data
            stub_vault_item_encrypted_data(vaultname, m[1], content)
          end
        end
      end

      # stubs a vault item with the contents of a parsed JSON string.
      # If the class-level setting `encrypted_data_stub` is true, then
      # Chef::DataBagItem.load
      # @param vault [String] the name of the vault data bag
      # @param item [String] the name of the vault item
      # @param content [String] the JSON-encoded contents to populate the
      #   fake vault with
      # @param db [Hash] the fake data bag item that contains the item
      # @return [void]
      # @api private
      def stub_vault_item(vault, item, content, db)
        db["#{item}_keys"] = true
        vi = make_fakevault(vault, item)

        # stub vault lookup of each of the vault item keys
        content.each do |k, v|
          next if "id" == k
          allow(vi).to receive(:[]).with(k).and_return(v)
        end

        # stub ChefVault and Chef::DataBag to return the doubles
        # via both symbol and string forms of the data bag name
        [vault, vault.to_sym].each do |dbname|
          allow(ChefVault::Item).to(
            receive(:vault?).with(dbname, item).and_return(true)
          )

          allow(ChefVault::Item).to(
            receive(:load)
            .with(dbname, item)
            .and_return(vi)
          )
          allow(Chef::DataBag).to(
            receive(:load)
            .with(dbname)
            .and_return(db)
          )
        end
      end

      # stubs Chef::DataBagItem.load to return a fake hash in which
      # each key of the content returns a hash with single
      # `encrypted_data` key, which fools some attempts to determine
      # whether a data bag is a vault
      # @param vault [String] the name of the vault data bag
      # @param item [String] the name of the vault item
      # @param content [String] the JSON-encoded contents to populate the
      #   fake vault with
      # @return [void]
      # @api private
      def stub_vault_item_encrypted_data(vault, item, content)
        # stub data bag lookup of each of the vault item keys
        dbi = ChefVault::TestFixtureDataBagItem.new
        dbi["raw_data"] = content
        content.each_key do |k|
          next if "id" == k
          dbi[k] = { "encrypted_data" => "..." }
        end

        [vault, vault.to_sym].each do |dbname|
          allow(Chef::DataBagItem).to(
            receive(:load).with(dbname, item).and_return(dbi)
          )
        end
      end

      # returns an RSpec double that acts like a vault item
      # @param vault [String] the name of the vault data bag
      # @param item [String] the name of the vault item
      # @return [RSpec::Mocks::Double] the vault double
      # @api private
      def make_fakevault(vault, item)
        fakevault = double "vault item #{vault}/#{item}"
        allow(fakevault).to receive(:[]=).with(String, Object)
        allow(fakevault).to receive(:clients).with(String)
        allow(fakevault).to receive(:save)
        fakevault
      end
    end
  end
end