diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 00d9a52..eca7bf6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -353,9 +353,30 @@ pup6.pe: pup6.pe-fips: <<: *pup_6_pe <<: *acceptance_base + <<: *with_SIMP_ACCEPTANCE_MATRIX_LEVEL_3 script: - 'BEAKER_fips=yes bundle exec rake beaker:suites[default,default]' +pup6.x.centos7: + <<: *pup_6_x + <<: *acceptance_base + script: + - 'bundle exec rake beaker:suites[default,centos7]' + +pup6.x.centos7-fips: + <<: *pup_6_x + <<: *acceptance_base + <<: *with_SIMP_ACCEPTANCE_MATRIX_LEVEL_3 + script: + - 'BEAKER_fips=yes bundle exec rake beaker:suites[default,centos7]' + +pup6.pe.centos7: + <<: *pup_6_pe + <<: *acceptance_base + <<: *with_SIMP_ACCEPTANCE_MATRIX_LEVEL_3 + script: + - 'bundle exec rake beaker:suites[default,centos7]' + pup6.pe-oel: <<: *pup_6_pe <<: *acceptance_base @@ -369,8 +390,29 @@ pup6.pe-oel-fips: script: - 'BEAKER_fips=yes bundle exec rake beaker:suites[default,oel]' +pup6.pe.centos7-oel: + <<: *pup_6_pe + <<: *acceptance_base + <<: *with_SIMP_ACCEPTANCE_MATRIX_LEVEL_3 + script: + - 'bundle exec rake beaker:suites[default,oel7]' + +pup6.pe.centos7-oel-fips: + <<: *pup_6_pe + <<: *acceptance_base + <<: *with_SIMP_ACCEPTANCE_MATRIX_LEVEL_3 + script: + - 'BEAKER_fips=yes bundle exec rake beaker:suites[default,oel7]' + pup7.x: <<: *pup_7_x <<: *acceptance_base script: - 'bundle exec rake beaker:suites[default,default]' + +pup7.x.centos7: + <<: *pup_7_x + <<: *acceptance_base + <<: *with_SIMP_ACCEPTANCE_MATRIX_LEVEL_3 + script: + - 'bundle exec rake beaker:suites[default,centos7]' diff --git a/README.md b/README.md index 52eb5c4..e57a934 100644 --- a/README.md +++ b/README.md @@ -506,9 +506,10 @@ To create your own plugin test shows you how to instantiate an object of your plugin for testing purposes. * Write acceptance tests for your plugin, using the acceptance tests for - simpkv's file plugin, `spec/acceptances/suites/default/file_plugin_spec.rb`, - as an example. That test uses a test module, `spec/support/simpkv_test` to - exercise the the simpkv API and verify its operation. + simpkv's file plugin in `spec/acceptances/suites/default/`, + as an example. That test uses a test module, `spec/support/simpkv_test` + and a plugin-specific validator to exercise the the simpkv API and verify its + operation with the file plugin. * Document your plugin's type and configuration parameters in the README.md for your store plugin module. diff --git a/spec/acceptance/helpers.rb b/spec/acceptance/helpers.rb new file mode 100644 index 0000000..7ab878a --- /dev/null +++ b/spec/acceptance/helpers.rb @@ -0,0 +1,2 @@ +rb_files = File.expand_path( 'helpers/**/*.rb', __dir__) +Dir.glob( rb_files ).sort_by(&:to_s).each { |file| require file } diff --git a/spec/acceptance/helpers/files/initial_key_info.erb b/spec/acceptance/helpers/files/initial_key_info.erb new file mode 100644 index 0000000..603ddc8 --- /dev/null +++ b/spec/acceptance/helpers/files/initial_key_info.erb @@ -0,0 +1,119 @@ +--- +# NOTES FOR TEST MAINTAINERS: +# This file specifies test key information in a data structure corresponding to +# the Simpkv_test::KeyInfo type alias. This data or data derived from it will be +# used to stimulate simpkv_test manifests to test simpkv functions. +# +# ** Please take time to understand how the simpkv_test module works! ** +# +# Important details about this key information are as follows: +# * The keys are designed to cover a wide variety of keys types a user could +# specify. This includes: +# - Keys with simple values (Boolean, Integer, Float, String) +# - Keys with complex values (Hash, Array) +# - Keys that have to be handled with special Puppet code (Binary values) +# - Puppet-environment-specific keys +# - Global keys +# - Keys with/without metadata +# - Keys with/without path elements in their key names +# * The keys are explicitly designed to test that key uniqueness is +# appropriately handled. +# - Keys are supposed to be uniquely specified by their +# {key path, global status, and backend} triples. +# - This data and the tests **ASSUME** a one-to-one mapping of app_id +# to backend, and so a key is uniquely specified by its +# {key path, global status, and app_id} triple. +# - This file contains multiple keys with the same key path, but different +# content and different combinations of app_id and global status. +# * The key info is also designed to test different folder configurations +# - Folders with keys and sub-folders +# - Folders with only keys +# - Folders with only sub-folders +# +# Also of note: +# - This file currently only supports 3 different app_ids. +# - Binary data is loaded with the Puppet binary_file() method, so the +# 'file' specification must match what that function requires. +# - Validation logic elsewhere assumes the Binary value of a key will be found +# in a file in the simpkv_test module. +# +"<%= appid1 %>": + env: + boolean: + value: true + integer: + value: 1234567890 + metadata: + verified: true + float: + value: 0.123 + string: + value: "test string1" + metadata: + author: "Sally Smith" + complex/array_integers: + value: + - 8 + - 9 + - 10 + metadata: + normalized: true + complex/array_strings: + value: + - 'test string2' + complex/hash: + value: + attr1: "test string2" + attr2: 11.0 + attr3: false + attr4: + part1: "test string3" + part2: true + part3: + - 12 + - 13 + empty/string: + value: "" + empty/complex/array: + value: [] + empty/complex/hash: + value: {} + global: + boolean: + value: false + string: + value: "global test string1" + metadata: + auditor: "Jill Jones" + binary/keytabs/test_krb5.keytab: + file: "simpkv_test/test_krb5.keytab" + metadata: + comment: "from simp/krb5 test" +"<%= appid2 %>": + # list will have no sub-folders + env: + integer: + value: 123 + float: + value: 45.678 + metadata: + origin: sensor + version: 3 + global: + integer: + value: 901 + metadata: + truncated: true + string: + value: "global test string2" + +"<%= appid3 %>": + env: + # list will have only sub-folders + complex/hash: + value: + location: rack1 + slot: 10 + metadata: + last_reviewed: "2021-08-30" + # global list will be empty diff --git a/spec/acceptance/helpers/manifest_utils.rb b/spec/acceptance/helpers/manifest_utils.rb new file mode 100644 index 0000000..119c6b6 --- /dev/null +++ b/spec/acceptance/helpers/manifest_utils.rb @@ -0,0 +1,25 @@ +module Acceptance + module Helpers + module ManifestUtils + + def print_test_config(hieradata, manifest) + puts '>'*80 + if hieradata.is_a?(Hash) + puts "Hieradata:\n#{hieradata.to_yaml}" + else + puts "Hieradata:\n#{hieradata}" + end + puts '-'*80 + puts "Manifest:\n#{manifest}" + puts '<'*80 + end + + def set_hiera_and_apply_on(host, hieradata, manifest, apply_opts = {}, verbose = true ) + print_test_config(hieradata, manifest) if verbose + set_hieradata_on(host, hieradata) + apply_manifest_on(host, manifest, apply_opts) + end + + end + end +end diff --git a/spec/acceptance/helpers/test_data.rb b/spec/acceptance/helpers/test_data.rb new file mode 100644 index 0000000..f0b19f0 --- /dev/null +++ b/spec/acceptance/helpers/test_data.rb @@ -0,0 +1,482 @@ +require 'erb' +require 'pathname' +require 'set' +require 'yaml' + +module Acceptance; end +module Acceptance::Helpers; end + +# Methods to create simpkv backend hieradata and simpkv_test module hieradata +# to exercise and verify simpkv functions. +# +# - See the simpkv module README.md for a description of simpkv backend +# hieradata +# - See the simpkv_test module documentation for descriptions of the +# type aliases corresponding to the Hashes used in the data +# generation/transformation methods. + +module Acceptance::Helpers::TestData + + # @return simpkv::options hieradata with aliases to backend configuration + # derived from backend_configs + # + # @param backend_configs Hash of backend configuration + # - Key is the name of the backend and its value is its backend + # configuration Hash. + # - One of the backend names must be 'default'. + # - Each backend configuration Hash must have 'type' specifying the plugin + # type and any other plugin-specific configuration required in order for + # the plugin to connect to its keystore. + # - This method will set the required backend config 'id' attribute for + # each backend configuration in the hieradata. + # - 'id' will be set to the backend's name. + # - Backends are *not* required to be of the same 'type'. + # + # @raise RuntimeError if 'default' is not one of the backend config names or + # if any backend configuration is missing the required 'type' attribute + # + def generate_backend_hiera(backend_configs) + errors = [] + unless backend_configs.keys.include?('default') + errors << "'default' backend missing from backend config: #{backend_configs}" + end + + backend_configs.each do |name, config| + unless config.include?('type') + errors << "'#{name}' backend config missing 'type': #{config}" + end + end + + unless errors.empty? + raise("ERROR: Invalid backend configuration:\n#{errors.join("\n")}") + end + + hiera = {} + backends = {} + backend_configs.each do |name, config| + backend_tag = "simpkv::backend::#{name}" + hiera[backend_tag] = config + hiera[backend_tag]['id'] = name + backends[name]= "%{alias('#{backend_tag}')}" + end + + hiera['simpkv::options'] = { + 'environment' => '%{server_facts.environment}', + 'softfail' => false, + 'backends' => backends + } + + hiera + end + + # Generates a Hash of key information for 3 app ids + # + # >> See the comment block in initial_key_info.erb for important details! << + # + # Note that this method will map 'default' to '', in order to test the + # behavior of the simpkv functions when there is no `app_id` attribute in + # the `simpkv_options` parameter in a simpkv function call. + # + # @param app_id1 First app_id; expected to map uniquely to a backend + # @param app_id2 Second app_id; expected to map uniquely a backend + # @param app_id3 Third app_id; expected to map uniquely a backend + # + # @return Hash of key information whose format corresponds to the + # Simpkv_test::KeyInfo type alias + # + # @raise RuntimeError if the 3 app ids are not unique + # + def generate_initial_key_info(app_id1, app_id2, app_id3) + ids = [ app_id1, app_id2, app_id3 ].uniq + unless ids.size == 3 + raise("ERROR: App ids must be unique: <#{app_id1}, #{app_id2}, #{app_id3}>") + end + + data_template = File.join(__dir__, 'files', 'initial_key_info.erb') + appid1 = (app_id1 == 'default') ? '' : app_id1 + appid2 = (app_id2 == 'default') ? '' : app_id2 + appid3 = (app_id3 == 'default') ? '' : app_id3 + + data_yaml = ERB.new(File.read(data_template)).result(binding) + YAML.load(data_yaml) + end + + # @return transformed copy of original_key_info in which the key values and/or + # metadata have been modified + # + # TODO Change the 'file' attribute of a key specification for keys + # with Binary values. Currently only modifies all non-binary values, + # i.e., keys whose specification has a 'value' attribute. + # + # @param original_key_info Hash of key info whose format corresponds to + # the Simpkv_test::KeyInfo type alias + # + def modify_key_data(original_key_info) + updated_key_info = Marshal.load(Marshal.dump(original_key_info)) + updated_key_info.each do |app_id, key_struct| + key_struct.each do |key_type, keys| + keys.each do |key, key_data| + # modify non-binary values + if key_data.key?('value') + if key_data['value'].is_a?(Array) || key_data['value'].is_a?(String) + key_data['value'] = key_data['value'] + key_data['value'] + end + + if key_data['value'].is_a?(TrueClass) || key_data['value'].is_a?(FalseClass) + key_data['value'] = ! key_data['value'] + end + + if key_data['value'].is_a?(Hash) + key_data['value']['new_key'] = 'new string elem' + end + + if key_data['value'].is_a?(Numeric) + key_data['value'] *= 10 + end + end + + #TODO modify binary values specified by a 'file' attribute + + # modify metadata + if key_data.key?('metadata') + key_data.delete('metadata') + else + key_data['metadata'] = { 'version' => 2 } + end + end + end + end + + updated_key_info + end + + # @return transformed copy of original_folder_info in which each folder + # listed has suffix appended to its name + # + # @param original_folder_info Hash of folder name info whose format + # corresponds to the Simpkv_test::FolderInfo type alias + # + # @param suffix Suffix to be appended to each original folder name + # + def rename_folders_in_folder_info(original_folder_info, suffix='new') + new_info = {} + original_folder_info.each do |app_id,folder_struct| + new_info[app_id] = {} + folder_struct.each do |folder_type,folders| + new_info[app_id][folder_type] = {} + folders.each do |folder,folder_data| + new_info[app_id][folder_type]["#{folder}#{suffix}"] = folder_data + end + end + end + + new_info + end + + # @return transformed copy of original_foldername_info in which each folder + # listed has suffix appended to its name + # + # @param original_foldername_info Hash of folder name info whose format + # corresponds to the Simpkv_test::NameInfo type alias + # + # @param suffix Suffix to be appended to each original folder name + # + def rename_folders_in_name_info(original_foldername_info, suffix='new') + new_info = Marshal.load(Marshal.dump(original_foldername_info)) + new_info.each do |app_id,folder_struct| + folder_struct.each do |folder_type, folder_names| + folder_struct[folder_type] = folder_names.map { |folder| "#{folder}#{suffix}" } + end + end + + new_info + end + + # @return transformed copy of original_key_info in which the key names have been + # modified by suffix + # + # @param original_key_info Hash of key info whose format corresponds to + # the Simpkv_test::KeyInfo type alias + # + # @param suffix String to be appended to original key names + # + def rename_keys_in_key_info(original_key_info, suffix='new') + key_info = {} + original_key_info.each do |app_id, key_struct| + key_info[app_id] = {} + key_struct.each do |key_type, keys| + key_info[app_id][key_type] = {} + keys.each do |key, key_data| + new_key = key + suffix + key_info[app_id][key_type][new_key] = key_data + end + end + end + + key_info + end + + # Returns Hash of root folder names info for any non-empty root folders + # corresponding to the key data specified in key_info + # + # @param key_info Hash of key info whose format corresponds to the + # Simpkv_test::KeyInfo type alias + # + # @return Hash with root name info whose format corresponds to the + # Simpkv_test::NameInfo type alias or {} if no non-empty root directories are + # found + # + def root_foldername_info(key_info) + foldername_info = {} + full_foldername_info = to_foldername_info(key_info) + full_foldername_info.each do |app_id,folder_struct| + folder_struct.each do |folder_type, folder_names| + if folder_names.include?('/') + foldername_info[app_id] = {} unless foldername_info.key?(app_id) + foldername_info[app_id][folder_type] = [ '/' ] + end + end + end + + foldername_info + end + + # Creates a Hash of folder name info that is subset of subfolders in + # original_foldername_name + # + # NOTE: No child folders beneath a selected subfolder will be included in + # the returned result. + # + # @param original_foldername_info Hash with folder name info whose format + # corresponds to the Simpkv_test::NameInfo type alias + # + # @return Hash with subfolder name info whose format corresponds to the + # Simpkv_test::NameInfo type alias or {} if no subfolders are found + # + def select_subfolders_subset(original_foldername_info) + subset_info = {} + original_foldername_info.each do |app_id,folder_struct| + folder_struct.each do |folder_type, folder_names| + count = 0 + selected = [] + folder_names.sort.each do |folder| + next if folder == '/' + + within_selected_folder = false + selected.each do |subfolder| + if folder.start_with?("#{subfolder}/") + within_selected_folder = true + break + end + end + + if !within_selected_folder && ( (count % 2) == 0) + selected << folder + count += 1 + end + end + + unless selected.empty? + subset_info[app_id] = {} unless subset_info.key?(app_id) + subset_info[app_id][folder_type] = selected + end + end + end + + subset_info + end + + # Based on subfolder deletions specified in delete_foldernames_info, separate + # original_key_info into a pair of Hashes: one for retained keys and one + # for deleted keys + # + # @param original_key_info Hash of key info whose format corresponds to + # the Simpkv_test::KeyInfo type alias + # + # @param delete_foldernames_info Hash specifying the subfolders that have + # been deleted whose format corresponds to the Simpkv_test::NameInfo data + # type + # + # @param [ , ], where each is a Hash of key info + # whose format corresponds to the Simpkv_test::KeyInfo type alias + # + def split_key_info_per_subfolder_deletes(original_key_info, delete_foldernames_info) + retain_index = 0 + remove_index = 1 + key_infos = [ Hash.new, Hash.new ] + original_key_info.each do |app_id, key_struct| + key_struct.each do |key_type, keys| + keys.each do |key, key_data| + type = retain_index + if delete_foldernames_info.key?(app_id) && + delete_foldernames_info[app_id].key?(key_type) + delete_foldernames_info[app_id][key_type].each do |folder| + if key.start_with?("#{folder}/") + type = remove_index + break + end + end + end + + key_infos[type][app_id] = {} unless key_infos[type].key?(app_id) + key_infos[type][app_id][key_type] = {} unless key_infos[type][app_id].key?(key_type) + key_infos[type][app_id][key_type][key] = key_data + end + end + end + + key_infos + end + + # Split original_key_info into an Array of key info objects + # + # Input key data is assigned to an output Hash in a round-robin + # fashion per key type ('env' or 'global'). + # + # @param original_key_info Hash of key info whose format corresponds to + # the Simpkv_test::KeyInfo type alias + # + # @param split_size Number of key info hashes to create from original_key_info + # + # @return Array of key info hashes, each of which whose format corresponds to + # the Simpkv_test::KeyInfo type alias or is empty, if input key info hash is + # too sparse to support the split size specified. + # + def split_key_info(original_key_info, split_size=2) + key_infos = Array.new(split_size) { Hash.new } + + original_key_info.each do |app_id, key_struct| + key_infos.each { |key_info| key_info[app_id] = Hash.new } + key_struct.each do |key_type, keys| + key_infos.each { |key_info| key_info[app_id][key_type] = Hash.new } + + count = 0 + keys.each do |key, key_data| + key_infos[ count % split_size ][app_id][key_type][key] = key_data + count += 1 + end + + key_infos.each do |key_info| + if key_info[app_id][key_type].empty? + key_info[app_id].delete(key_type) + end + end + end + + key_infos.each do |key_info| + if key_info[app_id].empty? + key_info.delete(app_id) + end + end + end + + key_infos + end + + # @return Hash with full folder info derived from key_info and whose format + # corresponds to the Simpkv_test::FolderInfo type alias + # + # FIXME This method excludes any folders with binary key values in its + # output, because simpkv_test::retrieve_and_verify_folders doesn't yet handle + # verification of binary key data in simpk::list results + # + # @param key_info Hash of key information whose format corresponds to the + # Simpkv_test::KeyInfo type alias + # + # @param exclude_root_folder Whether to exclude the root folder from the returned + # listing + # + def to_folder_info(key_info, exclude_root_folder=false) + folder_info = {} + key_info.each do |app_id, key_struct| + folder_info[app_id] = {} + key_struct.each do |key_type, keys| + folder_info[app_id][key_type] = {} + keys.each do |key, key_data| + keypath = Pathname.new(key) + keypath.descend do |path| + parent = (path.dirname.to_s == '.') ? '/' : path.dirname.to_s + next if (parent == '/') && exclude_root_folder + + unless folder_info[app_id][key_type].key?(parent) + folder_info[app_id][key_type][parent] = { 'keys' => {}, 'folders' => [] } + end + if path.to_s == key + folder_info[app_id][key_type][parent]['keys'][path.basename.to_s] = key_data + else + unless folder_info[app_id][key_type][parent]['folders'].include?(path.basename.to_s) + folder_info[app_id][key_type][parent]['folders'] << path.basename.to_s + end + end + end + end + end + end + + folder_info.each do |app_id, folder_struct| + folder_struct.each do |folder_type, folders| + folders.delete_if do |folder, folder_data| + binary_data = false + folder_data['keys'].each do |key, key_data| + if key_data.key?('file') + binary_data = true + break + end + end + + binary_data + end + end + end + + folder_info + end + + # @return Hash with folder name info derived from key_info and whose format + # corresponds to the Simpkv_test::NameInfo type alias + # + # @param key_info Hash of key information whose format corresponds to the + # Simpkv_test::KeyInfo type alias + # + def to_foldername_info(key_info) + foldername_info = {} + key_info.each do |app_id, key_struct| + foldername_info[app_id] = {} + key_struct.each do |key_type, keys| + foldername_info[app_id][key_type] = Set.new + foldername_info[app_id][key_type] << '/' + keys.each do |key, key_data| + path = File.dirname(key) + unless path == '.' + Pathname.new(path).descend do |folder| + foldername_info[app_id][key_type] << folder.to_s + end + end + end + + foldername_info[app_id][key_type] = foldername_info[app_id][key_type].to_a.sort + end + end + + foldername_info + end + + # @return Hash with key name info derived from key_info and whose format + # corresponds to the Simpkv_test::NameInfo type alias + # + # @param key_info Hash of key information whose format corresponds to the + # Simpkv_test::KeyInfo type alias + # + def to_keyname_info(key_info) + keyname_info = {} + key_info.each do |app_id, key_struct| + keyname_info[app_id] = {} + key_struct.each do |key_type, keys| + keyname_info[app_id][key_type] = keys.keys + end + end + + keyname_info + end +end + diff --git a/spec/acceptance/helpers/utils.rb b/spec/acceptance/helpers/utils.rb new file mode 100644 index 0000000..08afe0d --- /dev/null +++ b/spec/acceptance/helpers/utils.rb @@ -0,0 +1,40 @@ +require 'json' +require 'base64' + +module Acceptance; end +module Acceptance::Helpers; end + +module Acceptance::Helpers::Utils + + # @return key string persisted to the backend for the key_data + # + # FIXME: If the data is binary and specified by the 'file' attribute, + # this method ASSUMES the file is in the simpkv_test module + # + # @param key_data + def key_data_string(key_data) + key_hash = {} + if key_data.key?('value') + key_hash['value'] = key_data['value'] + elsif key_data.key?('file') + simpkv_test_files = File.join(__dir__, '../../support/modules/simpkv_test/files') + value = IO.read( key_data['file'].gsub('simpkv_test', "#{simpkv_test_files}") ) + value.force_encoding('ASCII-8BIT') + + encoded_value = Base64.strict_encode64(value) + key_hash['value'] = encoded_value + key_hash['encoding'] = 'base64' + key_hash['original_encoding'] = 'ASCII-8BIT' + end + + if key_data.key?('metadata') + key_hash['metadata'] = key_data['metadata'] + else + key_hash['metadata'] = {} + end + + key_hash.to_json + end + +end + diff --git a/spec/acceptance/nodesets/centos7.yml b/spec/acceptance/nodesets/centos7.yml new file mode 100644 index 0000000..3537fb1 --- /dev/null +++ b/spec/acceptance/nodesets/centos7.yml @@ -0,0 +1,23 @@ +<% + if ENV['BEAKER_HYPERVISOR'] + hypervisor = ENV['BEAKER_HYPERVISOR'] + else + hypervisor = 'vagrant' + end +-%> +HOSTS: + el7: + roles: + - default + platform: el-7-x86_64 + box: centos/7 + hypervisor: <%= hypervisor %> + +CONFIG: + log_level: verbose + synced_folder : disabled + type: aio + vagrant_memsize: 256 +<% if ENV['BEAKER_PUPPET_COLLECTION'] -%> + puppet_collection: <%= ENV['BEAKER_PUPPET_COLLECTION'] %> +<% end -%> diff --git a/spec/acceptance/nodesets/default.yml b/spec/acceptance/nodesets/default.yml index 38453b7..0f2c175 100644 --- a/spec/acceptance/nodesets/default.yml +++ b/spec/acceptance/nodesets/default.yml @@ -8,19 +8,11 @@ HOSTS: el8: roles: - - server - default - - master - - client platform: el-8-x86_64 box: generic/centos8 hypervisor: <%= hypervisor %> - el7: - roles: - - client - platform: el-7-x86_64 - box: centos/7 - hypervisor: <%= hypervisor %> + CONFIG: log_level: verbose synced_folder : disabled diff --git a/spec/acceptance/nodesets/oel.yml b/spec/acceptance/nodesets/oel.yml index acc3f24..101da67 100644 --- a/spec/acceptance/nodesets/oel.yml +++ b/spec/acceptance/nodesets/oel.yml @@ -6,21 +6,13 @@ end -%> HOSTS: - oel8: - roles: - - server - - default - - master - - client - platform: el-8-x86_64 - box: generic/oracle8 - hypervisor: <%= hypervisor %> oel7: roles: - - client + - default platform: el-7-x86_64 box: generic/oracle7 hypervisor: <%= hypervisor %> + CONFIG: log_level: verbose synced_folder : disabled diff --git a/spec/acceptance/nodesets/oel7.yml b/spec/acceptance/nodesets/oel7.yml new file mode 100644 index 0000000..5d06091 --- /dev/null +++ b/spec/acceptance/nodesets/oel7.yml @@ -0,0 +1,23 @@ +<% + if ENV['BEAKER_HYPERVISOR'] + hypervisor = ENV['BEAKER_HYPERVISOR'] + else + hypervisor = 'vagrant' + end +-%> +HOSTS: + oel8: + roles: + - default + platform: el-8-x86_64 + box: generic/oracle8 + hypervisor: <%= hypervisor %> + +CONFIG: + log_level: verbose + synced_folder : disabled + type: aio + vagrant_memsize: 256 +<% if ENV['BEAKER_PUPPET_COLLECTION'] -%> + puppet_collection: <%= ENV['BEAKER_PUPPET_COLLECTION'] %> +<% end -%> diff --git a/spec/acceptance/shared_examples.rb b/spec/acceptance/shared_examples.rb new file mode 100644 index 0000000..b689f67 --- /dev/null +++ b/spec/acceptance/shared_examples.rb @@ -0,0 +1,2 @@ +rb_files = File.expand_path( 'shared_examples/**/*.rb', __dir__) +Dir.glob( rb_files ).sort_by(&:to_s).each { |file| require file } diff --git a/spec/acceptance/shared_examples/pre_populate_keystores.rb b/spec/acceptance/shared_examples/pre_populate_keystores.rb new file mode 100644 index 0000000..5ec8283 --- /dev/null +++ b/spec/acceptance/shared_examples/pre_populate_keystores.rb @@ -0,0 +1,35 @@ +# Execute simpkv::put operations via simpkv_test::store_keys to pre-populate key +# stores in the configured backend plugin. +# +# ASSUMED CONTEXT: +# The following are assumed to be available within this shared_examples context: +# * `clear_data_cmd`: Command string to be executed on the host to clear out +# all stored key data in the configured backends: +# - Must work from the host being tested, even when the keystore is not +# co-resident. +# +# * `backend_hiera`: 'simpkv::options' hash specifying backend configuration +# - One of the backends must be named 'default' +# +# * `initial_key_info`: Hash specifying key data to be initially stored in +# the backends: +# +shared_examples 'pre-populate keystores' do |host| + context "ensure keystores are pre-populated with initial keys on #{host}" do + let(:hieradata) { + backend_hiera.merge( { + 'simpkv_test::store_keys::key_info' => initial_key_info + } ) + } + + let(:manifest) { 'include simpkv_test::store_keys' } + + it 'should remove all backend instance data' do + on(host, clear_data_cmd, :accept_all_exit_codes => true) + end + + it 'should store keys' do + set_hiera_and_apply_on(host, hieradata, manifest, { :catch_failures => true }) + end + end +end diff --git a/spec/acceptance/shared_examples/simpkv_delete.rb b/spec/acceptance/shared_examples/simpkv_delete.rb new file mode 100644 index 0000000..59847b4 --- /dev/null +++ b/spec/acceptance/shared_examples/simpkv_delete.rb @@ -0,0 +1,97 @@ +# Execute and verify simpkv::delete using the configured backend plugins. +# +# ASSUMED CONTEXT: +# The following are assumed to be available within this shared_examples context: +# * `clear_data_cmd`: Command string to be executed on the host to clear out +# all stored key data in the configured backends: +# - Must work from the host being tested, even when the keystore is not +# co-resident. +# +# * `backend_hiera`: 'simpkv::options' hash specifying backend configuration +# - One of the backends must be named 'default' +# +# * `initial_key_info`: Hash specifying key data to be initially stored in +# the backends: +# - Format corresponds to the Simpkv_test::KeyInfo type alias +# - **Must** have app_ids that correspond to the backends named in +# backend_hiera +# +# * `validator`: Method object that can be called to independently validate +# backend state: +# - Method will be called to validate whether keys are present or absent in +# their corresponding backends, and when they are expected to be present, +# the stored key data is correct. +# - Method must return a Boolean indicating validation success +# - Method should log details of validation failures for debug +# - Method should attempt all validations before reporting failure +# - Method must have the following parameter list +# - Parameter 1: Hash of key information whose format corresponds to the +# Simpkv_test::KeyInfo type alias +# - Parameter 2: Whether keys should exist +# true = verify keys are present with correct stored data +# false = verify keys are absent +# - Parameter 3: Hash of backend configuration ('simpkv::options' Hash) +# - Parameter 4: Host object on which the validator will execute commands; +# Is the host under test, which may not be the host on which +# the keystore resides. +# +shared_examples 'simpkv::delete tests' do |host| + include_examples('pre-populate keystores', host) + + context "simpkv::delete operation on #{host}" do + # Hash with two keys: + # - :remove = Key info Hash of keys to remove + # - :retain = Key info Hash of keys to retain + # + # Hashes are subsets of initial_key_info + # + let(:test_key_infos) { + key_infos = split_key_info(initial_key_info, 2) + + if key_infos[0].empty? or key_infos[1].empty? + raise("Unable to split the initial_key_info into two non-empty Hashes. Data provided is too sparse") + end + + { + :remove => key_infos[0], + :retain => key_infos[1] + } + } + + let(:remove_manifest) { 'include simpkv_test::remove_keys' } + let(:remove_hieradata) { + backend_hiera.merge( { + 'simpkv_test::remove_keys::keyname_info' => to_keyname_info(test_key_infos[:remove]) + } ) + } + + let(:verify_manifest) { 'include simpkv_test::retrieve_and_verify_keys' } + let(:verify_hieradata) { + backend_hiera.merge( { + 'simpkv_test::retrieve_and_verify_keys::valid_key_info' => test_key_infos[:retain], + 'simpkv_test::retrieve_and_verify_keys::invalid_key_info' => test_key_infos[:remove] + } ) + } + + it 'should call simpkv::delete with valid keys without errors' do + set_hiera_and_apply_on(host, remove_hieradata, remove_manifest, + { :catch_failures => true }) + end + + it 'should retain only untouched keys in backends' do + expect( validator.call(test_key_infos[:retain], true, backend_hiera, host) ).to be true + expect( validator.call(test_key_infos[:remove], false, backend_hiera, host) ).to be true + end + + it 'should only be able to retrieve untouched keys via simpkv::get' do + set_hiera_and_apply_on(host, verify_hieradata, verify_manifest, + { :catch_failures => true }) + end + + it 'should call simpkv::delete with invalid keys without errors' do + set_hiera_and_apply_on(host, remove_hieradata, remove_manifest, + { :catch_failures => true }) + end + end +end + diff --git a/spec/acceptance/shared_examples/simpkv_deletetree.rb b/spec/acceptance/shared_examples/simpkv_deletetree.rb new file mode 100644 index 0000000..602cc43 --- /dev/null +++ b/spec/acceptance/shared_examples/simpkv_deletetree.rb @@ -0,0 +1,145 @@ +# Execute and verify simpkv::deletetree using the configured backend plugins. +# +# ASSUMED CONTEXT: +# The following are assumed to be available within this shared_examples context: +# * `clear_data_cmd`: Command string to be executed on the host to clear out +# all stored key data in the configured backends: +# - Must work from the host being tested, even when the keystore is not +# co-resident. +# +# * `backend_hiera`: 'simpkv::options' hash specifying backend configuration +# - One of the backends must be named 'default' +# +# * `initial_key_info`: Hash specifying key data to be initially stored in +# the backends: +# - Format corresponds to the Simpkv_test::KeyInfo type alias +# - **Must** have app_ids that correspond to the backends named in +# backend_hiera +# +# * `validator`: Method object that can be called to independently validate +# backend state: +# - Method will be called to validate whether keys are present or absent in +# their corresponding backends, and when they are expected to be present, +# the stored key data is correct. +# - Method must return a Boolean indicating validation success +# - Method should log details of validation failures for debug +# - Method should attempt all validations before reporting failure +# - Method must have the following parameter list +# - Parameter 1: Hash of key information whose format corresponds to the +# Simpkv_test::KeyInfo type alias +# - Parameter 2: Whether keys should exist +# true = verify keys are present with correct stored data +# false = verify keys are absent +# - Parameter 3: Hash of backend configuration ('simpkv::options' Hash) +# - Parameter 4: Host object on which the validator will execute commands; +# Is the host under test, which may not be the host on which +# the keystore resides. +# +shared_examples 'simpkv::deletetree tests' do |host| + include_examples('pre-populate keystores', host) + + context "simpkv::deletetree operation on #{host}" do + let(:initial_foldername_info) { to_foldername_info(initial_key_info) } + let(:subfolders_to_delete) { + subfolders = select_subfolders_subset(initial_foldername_info) + if subfolders.empty? + raise('No subfolders from initial_key_info selected for deletion: data too sparse') + end + + subfolders + } + + let(:test_key_infos_after_subfolder_delete) { + key_infos = split_key_info_per_subfolder_deletes(initial_key_info, subfolders_to_delete) + { :retain => key_infos[0], :remove => key_infos[1] } + } + + # Any root folder that originally had key data. + let(:root_folders) { + foldername_info = root_foldername_info(initial_key_info) + if foldername_info.empty? + raise('All root folders found in initial_key_info are empty: No keys!') + end + + foldername_info + } + + let(:remove_manifest) { 'include simpkv_test::remove_folders' } + let(:remove_subfolders_hieradata) { + backend_hiera.merge( { + 'simpkv_test::remove_folders::foldername_info' => subfolders_to_delete + } ) + } + + let(:remove_root_folders_hieradata) { + backend_hiera.merge( { + 'simpkv_test::remove_folders::foldername_info' => root_folders + } ) + } + + let(:verify_manifest) { 'include simpkv_test::retrieve_and_verify_folders' } + let(:verify_hieradata_after_subfolders_delete) { + backend_hiera.merge( { + 'simpkv_test::retrieve_and_verify_folders::valid_folder_info' => to_folder_info(test_key_infos_after_subfolder_delete[:retain]), + 'simpkv_test::retrieve_and_verify_folders::invalid_folder_info' => to_folder_info(test_key_infos_after_subfolder_delete[:remove], true) + } ) + } + + let(:verify_empty_backend_folders_hieradata) { + # Expected results after root directories have been removed: + # - The root folder for the Puppet environment in each backend will no + # longer exist, and so a listing of if will fail. + # - The 'globals' root folder in each backend will exist ('globals' + # folder is part of the infrastructure maintained by each plugin and + # not deletable via the simpkv functions API), but it will be empty. + # + env_folder_info = {} + global_folder_info = {} + empty_folders = { '/' => { 'keys' => {}, 'folders' => [] } } + initial_key_info.keys.each do |app_id| + env_folder_info[app_id] = { 'env' => Marshal.load(Marshal.dump(empty_folders)) } + global_folder_info[app_id] = { 'global' => Marshal.load(Marshal.dump(empty_folders)) } + end + + backend_hiera.merge( { + 'simpkv_test::retrieve_and_verify_folders::valid_folder_info' => global_folder_info, + 'simpkv_test::retrieve_and_verify_folders::invalid_folder_info' => env_folder_info + } ) + } + + it 'should call simpkv::deletetree with valid sub-folders without errors' do + set_hiera_and_apply_on(host, remove_subfolders_hieradata, remove_manifest, + { :catch_failures => true }) + end + + it 'should retain only untouched keys/folders in backends' do + set_hiera_and_apply_on(host, verify_hieradata_after_subfolders_delete, + verify_manifest, { :catch_failures => true }) + end + + it 'should call simpkv::deletetree with root folders without errors' do + set_hiera_and_apply_on(host, remove_root_folders_hieradata, + remove_manifest, { :catch_failures => true }) + end + + it 'should retain no key data in the backends' do + # This makes sure there is no key data, but does not verify that the + # directory tree is absent. That verification is done by the next test + # example. + expect( validator.call(initial_key_info, false, backend_hiera, host) ).to be true + end + + it 'should retrieve non-existent or empty root dir list results from the backends' do + # non-existent: Puppet environment root dirs + # empty: global root dirs + set_hiera_and_apply_on(host, verify_empty_backend_folders_hieradata, + verify_manifest, { :catch_failures => true }) + end + + it 'should call simpkv::deletetree with invalid folders without errors' do + set_hiera_and_apply_on(host, remove_subfolders_hieradata, + remove_manifest, { :catch_failures => true }) + end + end +end + diff --git a/spec/acceptance/shared_examples/simpkv_exists.rb b/spec/acceptance/shared_examples/simpkv_exists.rb new file mode 100644 index 0000000..9c71b38 --- /dev/null +++ b/spec/acceptance/shared_examples/simpkv_exists.rb @@ -0,0 +1,84 @@ +# Execute and verify simpkv::exists using the configured backend plugins. +# +# ASSUMED CONTEXT: +# The following are assumed to be available within this shared_examples context: +# * `clear_data_cmd`: Command string to be executed on the host to clear out +# all stored key data in the configured backends: +# - Must work from the host being tested, even when the keystore is not +# co-resident. +# +# * `backend_hiera`: 'simpkv::options' hash specifying backend configuration +# +# * `initial_key_info`: Hash specifying key data to be initially stored in +# the backends: +# - Format corresponds to the Simpkv_test::KeyInfo type alias +# - **Must** have app_ids that correspond to the backends named in +# backend_hiera +# +shared_examples 'simpkv::exists tests' do |host| + include_examples('pre-populate keystores', host) + + context "simpkv::exists operation for keys on #{host}" do + let(:initial_keyname_info) { to_keyname_info(initial_key_info) } + let(:hieradata_with_valid_keys) { + backend_hiera.merge( { + 'simpkv_test::verify_keys_exist::valid_keyname_info' => initial_keyname_info, + 'simpkv_test::verify_keys_exist::invalid_keyname_info' => {} + } ) + } + + # copy of initial_key_info for which all key names have been modified + let(:new_key_info) { rename_keys_in_key_info(initial_key_info) } + let(:new_keyname_info) { to_keyname_info(new_key_info) } + + let(:hieradata_with_invalid_keys) { + backend_hiera.merge( { + 'simpkv_test::verify_keys_exist::valid_keyname_info' => {}, + 'simpkv_test::verify_keys_exist::invalid_keyname_info' => new_keyname_info + } ) + } + + let(:manifest) { 'include simpkv_test::verify_keys_exist' } + + it 'should call simpkv::exists for valid keys and return true' do + set_hiera_and_apply_on(host, hieradata_with_valid_keys, manifest, + { :catch_failures => true }) + end + + it 'should call simpkv::exists for invalid keys and return false' do + set_hiera_and_apply_on(host, hieradata_with_invalid_keys, manifest, + { :catch_failures => true }) + end + end + + context "simpkv::exists operation for folders on #{host}" do + let(:initial_foldername_info) { to_foldername_info(initial_key_info) } + let(:hieradata_with_valid_folders) { + backend_hiera.merge( { + 'simpkv_test::verify_folders_exist::valid_foldername_info' => initial_foldername_info, + 'simpkv_test::verify_folders_exist::invalid_foldername_info' => {} + } ) + } + + # copy of inital_foldername_info for which all folder names have been modified + let(:new_foldername_info) { rename_folders_in_name_info(initial_foldername_info) } + let(:hieradata_with_invalid_folders) { + backend_hiera.merge( { + 'simpkv_test::verify_folders_exist::valid_foldername_info' => {}, + 'simpkv_test::verify_folders_exist::invalid_foldername_info' => new_foldername_info + } ) + } + + let(:manifest) { 'include simpkv_test::verify_folders_exist' } + + it 'should call simpkv::exists for valid folders and return true' do + set_hiera_and_apply_on(host, hieradata_with_valid_folders, manifest, + { :catch_failures => true }) + end + + it 'should call simpkv::exists for invalid folders and return false' do + set_hiera_and_apply_on(host, hieradata_with_invalid_folders, manifest, + { :catch_failures => true }) + end + end +end diff --git a/spec/acceptance/shared_examples/simpkv_get.rb b/spec/acceptance/shared_examples/simpkv_get.rb new file mode 100644 index 0000000..42eebfb --- /dev/null +++ b/spec/acceptance/shared_examples/simpkv_get.rb @@ -0,0 +1,52 @@ +# Execute and verify simpkv::get using the configured backend plugins. +# +# ASSUMED CONTEXT: +# The following are assumed to be available within this shared_examples context: +# * `clear_data_cmd`: Command string to be executed on the host to clear out +# all stored key data in the configured backends: +# - Must work from the host being tested, even when the keystore is not +# co-resident. +# +# * `backend_hiera`: 'simpkv::options' hash specifying backend configuration +# - One of the backends must be named 'default' +# +# * `initial_key_info`: Hash specifying key data to be initially stored in +# the backends: +# - Format corresponds to the Simpkv_test::KeyInfo type alias +# - **Must** have app_ids that correspond to the backends named in +# backend_hiera +# +shared_examples 'simpkv::get tests' do |host| + include_examples('pre-populate keystores', host) + + context "simpkv::get operation on #{host}" do + let(:hieradata_with_valid_keys) { + backend_hiera.merge( { + 'simpkv_test::retrieve_and_verify_keys::valid_key_info' => initial_key_info, + 'simpkv_test::retrieve_and_verify_keys::invalid_key_info' => {} + } ) + } + + # copy of initial_key_info for which all key names have been modified + let(:new_key_info) { rename_keys_in_key_info(initial_key_info) } + + let(:hieradata_with_invalid_keys) { + backend_hiera.merge( { + 'simpkv_test::retrieve_and_verify_keys::valid_key_info' => {}, + 'simpkv_test::retrieve_and_verify_keys::invalid_key_info' => new_key_info + } ) + } + + let(:manifest) { 'include simpkv_test::retrieve_and_verify_keys' } + + it 'should call simpkv::get for valid keys without errors and verify retrieved info' do + set_hieradata_on(host, hieradata_with_valid_keys) + apply_manifest_on(host, manifest, :catch_failures => true) + end + + it 'should call simpkv::get with softfail=true for invalid keys without errors and verify nothing is retrieved' do + set_hieradata_on(host, hieradata_with_invalid_keys) + apply_manifest_on(host, manifest, :catch_failures => true) + end + end +end diff --git a/spec/acceptance/shared_examples/simpkv_list.rb b/spec/acceptance/shared_examples/simpkv_list.rb new file mode 100644 index 0000000..2e1318a --- /dev/null +++ b/spec/acceptance/shared_examples/simpkv_list.rb @@ -0,0 +1,52 @@ +# Execute and verify simpkv::list using the configured backend plugins. +# +# ASSUMED CONTEXT: +# The following are assumed to be available within this shared_examples context: +# * `clear_data_cmd`: Command string to be executed on the host to clear out +# all stored key data in the configured backends: +# - Must work from the host being tested, even when the keystore is not +# co-resident. +# +# * `backend_hiera`: 'simpkv::options' hash specifying backend configuration +# - One of the backends must be named 'default' +# +# * `initial_key_info`: Hash specifying key data to be initially stored in +# the backends: +# - Format corresponds to the Simpkv_test::KeyInfo type alias +# - **Must** have app_ids that correspond to the backends named in +# backend_hiera +# +shared_examples 'simpkv::list tests' do |host| + include_examples('pre-populate keystores', host) + + context "simpkv::list operation on #{host}" do + let(:initial_folder_info) { to_folder_info(initial_key_info) } + let(:hieradata_with_valid_folders) { + backend_hiera.merge( { + 'simpkv_test::retrieve_and_verify_folders::valid_folder_info' => initial_folder_info, + 'simpkv_test::retrieve_and_verify_folders::invalid_folder_info' => {} + } ) + } + + # copy of initial_folder_info for which all folder names have been modified + let(:new_folder_info) { rename_folders_in_folder_info(initial_folder_info) } + let(:hieradata_with_invalid_folders) { + backend_hiera.merge( { + 'simpkv_test::retrieve_and_verify_folders::valid_folder_info' => {}, + 'simpkv_test::retrieve_and_verify_folders::invalid_folder_info' => new_folder_info + } ) + } + + let(:manifest) { 'include simpkv_test::retrieve_and_verify_folders' } + + it 'should call simpkv::list for valid folders without errors and verify retrieved info' do + set_hiera_and_apply_on(host, hieradata_with_valid_folders, manifest, + { :catch_failures => true }) + end + + it 'should call simpkv::list with softfail=true for invalid folders without errors and verify nothing is retrieved' do + set_hiera_and_apply_on(host, hieradata_with_invalid_folders, manifest, + { :catch_failures => true }) + end + end +end diff --git a/spec/acceptance/shared_examples/simpkv_plugin.rb b/spec/acceptance/shared_examples/simpkv_plugin.rb new file mode 100644 index 0000000..b0fb56a --- /dev/null +++ b/spec/acceptance/shared_examples/simpkv_plugin.rb @@ -0,0 +1,128 @@ +# Execute and verify simpkv functions using the configured backend plugin(s). +# +# TEST OVERVIEW +# This test uses the following: +# - A set of backend instances to verify app_id-based backend selection. +# - The simpkv_test module to exercise the simpkv::* functions and to verify +# their operation, independent of the backend type used. +# - A backend-specific validator function provided by the plugin developer to +# independently verify keys are present/absent in the appropriate backend. +# - Initial key data and methods to transform that data into hieradata for all +# the simpkv_test manifests that affect key storage, removal, retrieval, and +# validation. +# +# TEST STRUCTURE +# This test includes specific shared_examples for each simpkv function. These +# examples are written to be self contained. In other words, each included +# share_example resets the keystores to a known state before executing any +# tests. This makes the tests much easier to understand. +# +# VERIFICATION DETAILS: +# This test uses 2 types of verification: +# - API-self-consistency verification via the simpkv_test module. +# - The simpkv_test module exclusively uses simpkv functions for +# storage/retrieval operations. +# - The simpkv_test module verifies the content of the retrieve operations: +# - true/false returned values for existence checks of present/absent +# keys and folders. +# - Key value and metadata verification for existing keys +# - Folder list contents for existing folders +# - Null results for keys/folders that are expected to be absent, when +# the 'softfail' simpkv option is used. +# - Backend-specific verification via a plugin-developer-provided validator +# function. +# - Validates data is stored appropriately when it is expected to be present. +# - Validates data is not stored when it is expected to be absent. +# - The only mechanism that ensures the data is stored where it is +# supposed to be stored! +# +# ASSUMED CONTEXT: +# The following are assumed to be available within this shared_examples context: +# * `clear_data_cmd`: Command string to be executed on the host to clear out +# all stored key data in the configured backends: +# - Must work from the host being tested, even when the keystore is not +# co-resident. +# +# * `backend_hiera`: 'simpkv::options' hash specifying backend configuration +# - One of the backends must be named 'default' +# +# * `initial_key_info`: Hash specifying key data to be initially stored in +# the backends: +# - Format corresponds to the Simpkv_test::KeyInfo type alias +# - **Must** have app_ids that correspond to the backends named in +# backend_hiera +# +# * `validator`: Method object that can be called to independently validate +# backend state: +# - Method will be called to validate whether keys are present or absent in +# their corresponding backends, and when they are expected to be present, +# the stored key data is correct. +# - Method must return a Boolean indicating validation success +# - Method should log details of validation failures for debug +# - Method should attempt all validations before reporting failure +# - Method must have the following parameter list +# - Parameter 1: Hash of key information whose format corresponds to the +# Simpkv_test::KeyInfo type alias +# - Parameter 2: Whether keys should exist +# true = verify keys are present with correct stored data +# false = verify keys are absent +# - Parameter 3: Hash of backend configuration ('simpkv::options' Hash) +# - Parameter 4: Host object on which the validator will execute commands; +# Is the host under test, which may not be the host on which +# the keystore resides. +# +# NOTE FOR MAINTAINERS +# Before updating this test, please take time to understand what the simpkv_test +# module does and how the Acceptance::Helpers::TestData methods are used to +# drive that module to exercise and validate simpkv functions. To aid +# understanding and debug +# * Each time a simpkv_test manifest is used, the hieradata and manifest are +# logged to the console. +# * The simpkv_test manifests log info-level, detailed messages to tell you +# what is happening during a catalog complile. This includes when a simpkv +# function is called, the parameters used in the function call, when results +# from a simpkv retrieval operation are being compared with expected values, +# and details about any comparison failures. +# +# @param host Host object on which the test manifests will be applied and +# independent verification commands executed +# +shared_examples 'a simpkv plugin test' do |host| + + # This is a very high level, test configuration sanity check, but will not + # detect all misconfiguration errors (especially ones that result in + # non-unique keys, e.g., when multiple app_ids unexpectedly end up in the + # same backend). + # + # Included examples may have more specific validation, especially WRT to + # whether initial_key_info has appropriate data for derived data used to + # stimulate the key/folder removal tests. + it 'should have basic test configuration' do + expect( backend_hiera.key?('simpkv::options')).to be true + expect( backend_hiera['simpkv::options'].key?('backends')).to be true + expect( backend_hiera['simpkv::options']['backends'].key?('default')).to be true + + expect(initial_key_info).to_not be_empty + initial_key_info.keys.each do |app_id| + appid = app_id.empty? ? 'default' : app_id + expect( backend_hiera['simpkv::options']['backends'].keys.include?(appid) ).to be true + end + end + + # All other simpkv function tests depend upon the keystores being populated + # by simpkv::put via simpkv_test manifests. So, make sure the simpkv::put + # operation is verified **first**. + include_examples('simpkv::put tests', host) + + include_examples('simpkv::exists tests', host) + include_examples('simpkv::get tests', host) + include_examples('simpkv::list tests', host) + + # The simpkv::delete and simpkv::deletetree tests will use simpkv::get and + # simpkv::list, respectively, as part of their removal verfication. So, make + # sure these tests come **after** the simpkv:get and simpkv::list operations + # are verified by their tests. + include_examples('simpkv::delete tests', host) + include_examples('simpkv::deletetree tests', host) +end + diff --git a/spec/acceptance/shared_examples/simpkv_put.rb b/spec/acceptance/shared_examples/simpkv_put.rb new file mode 100644 index 0000000..3086b0a --- /dev/null +++ b/spec/acceptance/shared_examples/simpkv_put.rb @@ -0,0 +1,86 @@ +# Execute and verify simpkv::put using the configured backend plugins. +# +# ASSUMED CONTEXT: +# The following are assumed to be available within this shared_examples context: +# * `clear_data_cmd`: Command string to be executed on the host to clear out +# all stored key data in the configured backends. +# - Must work from the host being tested, even when the keystore is not +# co-resident. +# +# * `backend_hiera`: 'simpkv::options' hash specifying backend configuration +# +# * `initial_key_info`: Hash specifying key data to be initially stored in +# the backends: +# - Format corresponds to the Simpkv_test::KeyInfo type alias +# - **Must** have app_ids that correspond to the backends named in +# backend_hiera +# +# * `validator`: Method object that can be called to independently validate +# backend state: +# - Method will be called to validate whether keys are present or absent in +# their corresponding backends, and when they are expected to be present, +# the stored key data is correct. +# - Method must return a Boolean indicating validation success +# - Method should log details of validation failures for debug +# - Method must have the following parameter list +# - Parameter 1: Hash of key information whose format corresponds to the +# Simpkv_test::KeyInfo type alias +# - Parameter 2: Whether keys should exist +# true = verify keys are present with correct stored data +# false = verify keys are absent +# - Parameter 3: Hash of backend configuration ('simpkv::options' Hash) +# - Parameter 4: Host object on which the validator will execute commands; +# Is the host under test, which may not be the host on which +# the keystore resides. +# +# @param host Host object on which the test manifests will be applied and +# independent verification commands executed +# +shared_examples 'simpkv::put tests' do |host| + context "ensure empty keystore(s) on #{host}" do + it 'should remove all backend instance data' do + on(host, clear_data_cmd, :accept_all_exit_codes => true) + end + end + + context "simpkv::put operation on #{host}" do + let(:hieradata) { + backend_hiera.merge( { + 'simpkv_test::store_keys::key_info' => initial_key_info + } ) + } + + let(:updated_key_info) { modify_key_data(initial_key_info) } + let(:updated_hieradata) { + backend_hiera.merge( { + 'simpkv_test::store_keys::key_info' => updated_key_info + } ) + } + + let(:manifest) { 'include simpkv_test::store_keys' } + + it 'should call simpkv::put without errors' do + set_hiera_and_apply_on(host, hieradata, manifest, { :catch_failures => true }) + end + + it 'should store the keys in the configured backends' do + expect( validator.call(initial_key_info, true, backend_hiera, host) ).to be true + end + + it 'should call simpkv::put without errors when keys already exist with same value' do + apply_manifest_on(host, manifest, :catch_failures => true) + end + + it 'should retain the keys in the configured backends' do + expect( validator.call(initial_key_info, true, backend_hiera, host) ).to be true + end + + it 'should call simpkv::put without errors when keys already exist with different values' do + set_hiera_and_apply_on(host, updated_hieradata, manifest, { :catch_failures => true }) + end + + it 'should update the keys in the configured backends' do + expect( validator.call(updated_key_info, true, backend_hiera, host) ).to be true + end + end +end diff --git a/spec/acceptance/suites/default/00_file_plugin_setup_spec.rb b/spec/acceptance/suites/default/00_file_plugin_setup_spec.rb new file mode 100644 index 0000000..d9debf7 --- /dev/null +++ b/spec/acceptance/suites/default/00_file_plugin_setup_spec.rb @@ -0,0 +1,18 @@ +require 'spec_helper_acceptance' + +test_name 'simpkv file plugin setup' + +describe 'simpkv file plugin setup' do + # Ensure /var/simp/simpkv already exists + let(:manifest) { <<~EOM + file {'/var/simp': ensure => directory } + file {'/var/simp/simpkv': ensure => directory } + EOM + } + + hosts.each do |host| + it "should create /var/simp/simpkv on #{host}" do + apply_manifest_on(host, manifest, :catch_failures => true) + end + end +end diff --git a/spec/acceptance/suites/default/10_configured_file_plugin_spec.rb b/spec/acceptance/suites/default/10_configured_file_plugin_spec.rb new file mode 100644 index 0000000..5b82118 --- /dev/null +++ b/spec/acceptance/suites/default/10_configured_file_plugin_spec.rb @@ -0,0 +1,69 @@ +require_relative 'validate_file_entries' +require 'spec_helper_acceptance' + +test_name 'simpkv configured file plugin' + +describe 'simpkv configured file plugin' do + # Method object to validate key file entries in an file instance. + # - Conforms to the API specified in 'a simpkv plugin test' shared_examples + let(:validator) { method(:validate_file_entries) } + + # Command to run on the test host to clear out all stored key data. + # - Since the file plugin has to be on the same host as the file keystore, + # a local filesystem command is appropriate. + let(:clear_data_cmd) { 'rm -rf /var/simp/simpkv/file' } + + + # The ids below are the backend/app_id names used in the test: + # - One must be 'default' or simpkv::options validation will fail. + # - 'a simpkv plugin test' shared_examples assumes there is a one-to-one + # mapping of the app_ids in the input key data to the backend names. + # Although simpkv supports fuzzy logic for that mapping, we set the + # backend names/app_ids to the same values, here, for simplicity. The + # fuzzy mapping logic is tested in the unit test. + # - The input-data-generator currently supports exactly 3 app_ids. + # - 'default' app_id is mapped to '' in the generated input key data, which, in + # turn causes simpkv functions to be called in the test manifests without + # an app_id set. In other words, 'default' maps to the expected, normal + # usage of simpkv functions. + # + let(:id1) { 'default' } + let(:id2) { 'custom' } + let(:id3) { 'custom_snowflake' } + + # simpkv::options hieradata for 3 distinct backends, one of which must + # be 'default' + let(:backend_hiera) { + backend_configs = { + id1 => { + 'type' => 'file', + 'root_path' => "/var/simp/simpkv/file/#{id1}" + }, + id2 => { + 'type' => 'file', + 'root_path' => "/var/simp/simpkv/file/#{id2}" + }, + id3 => { + 'type' => 'file', + 'root_path' => "/var/simp/simpkv/file/#{id3}" + } + } + + generate_backend_hiera(backend_configs) + } + + # Hash of initial key information for the 3 test backends/app_ids. + # + # 'a simpkv plugin test' uses this data to test key storage operations + # and then transform the data into subsets that it uses to test key/folder + # existence, folder lists, and key and folder delete operations. + let(:initial_key_info) { + generate_initial_key_info(id1, id2, id3) + } + + hosts.each do |host| + context "configured simpkv file plugin on #{host}" do + it_behaves_like 'a simpkv plugin test', host + end + end +end diff --git a/spec/acceptance/suites/default/20_auto_default_file_plugin_spec.rb b/spec/acceptance/suites/default/20_auto_default_file_plugin_spec.rb new file mode 100644 index 0000000..e6f0692 --- /dev/null +++ b/spec/acceptance/suites/default/20_auto_default_file_plugin_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper_acceptance' + +test_name 'simpkv auto-default file plugin' + +# This test will not configure any backend in hieradata, store a few +# keys and verify they go to the auto-default file backend. +# +# Because /var/simp exists, the auto-default file backend will +# store its data within /var/simp/simpkv/file/auto_file +# +describe 'simpkv auto-default file plugin' do + let(:clean_data_cmd) { 'rm -rf /var/simp/simpkv/file' } + + # No backend configuration in hieradata + let(:hieradata) {{ }} + + # Store a few keys so we can spot check that the keys are being stored + # in the auto-default backend + let(:manifest) { + <<~EOS + simpkv::put('key1', 'environment key value1') + simpkv::put('global1', 'global key value 1', {'version' => 10}, {'global' => true}) + EOS + } + + hosts.each do |host| + context "without simpkv configuration on #{host}" do + it 'should start with no backend data' do + on(host, clean_data_cmd) + end + + it 'should call simpkv::put with no errors' do + set_hiera_and_apply_on(host, hieradata, manifest, + {:catch_failures => true} ) + end + + it 'should store keys in auto-default backend' do + [ + '/var/simp/simpkv/file/auto_default/environments/production/key1', + '/var/simp/simpkv/file/auto_default/globals/global1' + ].each do |file| + expect( file_exists_on(host, file) ).to be true + end + end + end + end +end diff --git a/spec/acceptance/suites/default/file_plugin_spec.rb b/spec/acceptance/suites/default/file_plugin_spec.rb deleted file mode 100644 index 444a3cc..0000000 --- a/spec/acceptance/suites/default/file_plugin_spec.rb +++ /dev/null @@ -1,301 +0,0 @@ -require 'spec_helper_acceptance' - -test_name 'simpkv file plugin' - -describe 'simpkv file plugin' do - - let(:hieradata) {{ - - 'simpkv::backend::file_class' => { - 'type' => 'file', - 'id' => 'class', - 'root_path' => '/var/simp/simpkv/file/class' - }, - - 'simpkv::backend::file_define_instance' => { - 'type' => 'file', - 'id' => 'define_instance', - 'root_path' => '/var/simp/simpkv/file/define_instance' - }, - - 'simpkv::backend::file_define_type' => { - 'type' => 'file', - 'id' => 'define_type', - 'root_path' => '/var/simp/simpkv/file/define_type' - }, - - 'simpkv::backend::file_default' => { - 'type' => 'file', - 'id' => 'default', - 'root_path' => '/var/simp/simpkv/file/default' - }, - - 'simpkv::options' => { - 'environment' => '%{server_facts.environment}', - 'softfail' => false, - 'backends' => { - 'simpkv_test_class' => "%{alias('simpkv::backend::file_class')}", - 'Simpkv_test::Defines::Put[define2]' => "%{alias('simpkv::backend::file_define_instance')}", - 'Simpkv_test::Defines::Put' => "%{alias('simpkv::backend::file_define_type')}", - 'default' => "%{alias('simpkv::backend::file_default')}", - } - - } - - }} - - hosts.each do |host| - context 'with simpkv configuration via simpkv::options' do - - context 'simpkv put operation' do - let(:manifest) { - <<-EOS - file {'/var/simp/simpkv': - ensure => directory - } - - # Calls simpkv::put directly and via a Puppet-language function - # * Stores values of different types. Binary content is handled - # via a separate test. - # * One of the calls to the Puppet-language function will go to the - # default backend - class { 'simpkv_test::put': } - - # These two defines call simpkv::put directly and via the Puppet-language - # function - # * The 'define1' put operations should use the 'file/define_instance' - # backend instance. - # * The 'define2' put operations should use the 'file/define_type' - simpkv_test::defines::put { 'define1': } - simpkv_test::defines::put { 'define2': } - EOS - } - - it 'should work with no errors' do - set_hieradata_on(host, hieradata) - apply_manifest_on(host, manifest, :catch_failures => true) - end - - [ - '/var/simp/simpkv/file/class/globals/from_class/boolean', - '/var/simp/simpkv/file/class/globals/from_class/string', - '/var/simp/simpkv/file/class/globals/from_class/integer', - '/var/simp/simpkv/file/class/globals/from_class/float', - '/var/simp/simpkv/file/class/globals/from_class/array_strings', - '/var/simp/simpkv/file/class/globals/from_class/array_integers', - '/var/simp/simpkv/file/class/globals/from_class/hash', - - '/var/simp/simpkv/file/class/environments/production/from_class/boolean', - '/var/simp/simpkv/file/class/environments/production/from_class/string', - '/var/simp/simpkv/file/class/environments/production/from_class/integer', - '/var/simp/simpkv/file/class/environments/production/from_class/float', - '/var/simp/simpkv/file/class/environments/production/from_class/array_strings', - '/var/simp/simpkv/file/class/environments/production/from_class/array_integers', - '/var/simp/simpkv/file/class/environments/production/from_class/hash', - - '/var/simp/simpkv/file/class/environments/production/from_class/boolean_with_meta', - '/var/simp/simpkv/file/class/environments/production/from_class/string_with_meta', - '/var/simp/simpkv/file/class/environments/production/from_class/integer_with_meta', - '/var/simp/simpkv/file/class/environments/production/from_class/float_with_meta', - '/var/simp/simpkv/file/class/environments/production/from_class/array_strings_with_meta', - '/var/simp/simpkv/file/class/environments/production/from_class/array_integers_with_meta', - '/var/simp/simpkv/file/class/environments/production/from_class/hash_with_meta', - - '/var/simp/simpkv/file/class/environments/production/from_class/boolean_from_pfunction', - '/var/simp/simpkv/file/default/environments/production/from_class/boolean_from_pfunction_no_app_id', - - '/var/simp/simpkv/file/define_instance/environments/production/from_define/define2/string', - '/var/simp/simpkv/file/define_instance/environments/production/from_define/define2/string_from_pfunction', - '/var/simp/simpkv/file/define_type/environments/production/from_define/define1/string', - '/var/simp/simpkv/file/define_type/environments/production/from_define/define1/string_from_pfunction' - ].each do |file| - # validation of content will be done in 'get' test - it "should create #{file}" do - expect( file_exists_on(host, file) ).to be true - end - end - end - - context 'simpkv exists operation' do - let(:manifest) { - <<-EOS - # class uses simpkv::exists to verify the existence of keys in - # the 'file/class' backend; fails compilation if any simpkv::exists - # result doesn't match expected - class { 'simpkv_test::exists': } - EOS - } - - it 'manifest should work with no errors' do - apply_manifest_on(host, manifest, :catch_failures => true) - end - end - - context 'simpkv get operation' do - let(:manifest) { - <<-EOS - # class uses simpkv::get to retrieve values with/without metadata for - # keys in the 'file/class' backend; fails compilation if any - # retrieved info does match expected - class { 'simpkv_test::get': } - EOS - } - - it 'manifest should work with no errors' do - apply_manifest_on(host, manifest, :catch_failures => true) - end - - end - - context 'simpkv list operation' do - let(:manifest) { - <<-EOS - # class uses simpkv::list to retrieve list of keys/values/metadata tuples - # for keys in the 'file/class' backend; fails compilation if the - # retrieved info does match expected - class { 'simpkv_test::list': } - EOS - } - - it 'manifest should work with no errors' do - apply_manifest_on(host, manifest, :catch_failures => true) - end - - end - - context 'simpkv delete operation' do - let(:manifest) { - <<-EOS - # class uses simpkv::delete to remove a subset of keys in the 'file/class' - # backend and the simpkv::exists to verify they are gone but the other keys - # are still present; fails compilation if any removed keys still exist or - # any preserved keys have been removed - class { 'simpkv_test::delete': } - EOS - } - - it 'manifest should work with no errors' do - apply_manifest_on(host, manifest, :catch_failures => true) - end - - [ - '/var/simp/simpkv/file/class/environments/production/from_class/boolean', - '/var/simp/simpkv/file/class/environments/production/from_class/string', - '/var/simp/simpkv/file/class/environments/production/from_class/integer', - '/var/simp/simpkv/file/class/environments/production/from_class/float', - '/var/simp/simpkv/file/class/environments/production/from_class/array_strings', - '/var/simp/simpkv/file/class/environments/production/from_class/array_integers', - '/var/simp/simpkv/file/class/environments/production/from_class/hash', - ].each do |file| - it "should remove #{file}" do - expect( file_exists_on(host, file) ).to be false - end - end - - - end - - context 'simpkv deletetree operation' do - let(:manifest) { - <<-EOS - # class uses simpkv::deletetree to remove the remaining Puppet env and - # global keys in the 'file/class' backend and the simpkv::exists to - # verify all keys are gone; fails compilation if any keys remain - class { 'simpkv_test::deletetree': } - EOS - } - - it 'manifest should work with no errors' do - apply_manifest_on(host, manifest, :catch_failures => true) - end - - it 'should remove specified folders' do - expect( file_exists_on(host, '/var/simp/simpkv/file/class/environments/production/from_class/') ).to be false - expect( file_exists_on(host, '/var/simp/simpkv/file/class/globals/from_class/') ).to be false - end - end - - context 'simpkv operations for binary data' do - context 'prep' do - it 'should create a binary file for test' do - on(host, 'mkdir /root/binary_data') - on(host, 'dd count=1 if=/dev/urandom of=/root/binary_data/input_data') - end - end - - context 'simpkv put operation for Binary type' do - let(:manifest) { - <<-EOS - # class uses simpkv::put to store binary data from binary_file() in - # a Binary type - class { 'simpkv_test::binary_put': } - EOS - } - - it 'manifest should work with no errors' do - apply_manifest_on(host, manifest, :catch_failures => true) - end - - [ - '/var/simp/simpkv/file/default/environments/production/from_class/binary', - '/var/simp/simpkv/file/default/environments/production/from_class/binary_with_meta' - ].each do |file| - it "should create #{file}" do - expect( file_exists_on(host, file) ).to be true - end - end - end - - context 'simpkv get operation for Binary type' do - let(:manifest) { - <<-EOS - # class uses simpkv::get to retrieve binary data for Binary type variables - # and to persist new files with binary content; fails compilation if any - # retrieved info does match expected - class { 'simpkv_test::binary_get': } - EOS - } - - it 'manifest should work with no errors' do - apply_manifest_on(host, manifest, :catch_failures => true) - end - - { - 'retrieved_data1' => 'retrieved from key without metadata', - 'retrieved_data2' => 'retrieved from key with metadata' - }.each do |output_file,summary| - it "should create binary file #{summary} that matches input binary file" do - on(host, "diff /root/binary_data/input_data /root/binary_data/#{output_file}") - end - end - end - end - end - - context 'without simpkv configuration' do - let(:manifest) { - <<-EOS - simpkv_test::defines::put { 'define1': } - simpkv_test::defines::put { 'define2': } - EOS - } - - it 'should work with no errors' do - # clear out hieradata that contained simpkv::options - set_hieradata_on(host, {}) - apply_manifest_on(host, manifest, :catch_failures => true) - end - - it 'should store keys in auto-default backend' do - [ - '/var/simp/simpkv/file/auto_default/environments/production/from_define/define2/string', - '/var/simp/simpkv/file/auto_default/environments/production/from_define/define2/string_from_pfunction', - '/var/simp/simpkv/file/auto_default/environments/production/from_define/define1/string', - '/var/simp/simpkv/file/auto_default/environments/production/from_define/define1/string_from_pfunction' - ].each do |file| - expect( file_exists_on(host, file) ).to be true - end - end - end - end -end diff --git a/spec/acceptance/suites/default/validate_file_entries.rb b/spec/acceptance/suites/default/validate_file_entries.rb new file mode 100644 index 0000000..c9e373b --- /dev/null +++ b/spec/acceptance/suites/default/validate_file_entries.rb @@ -0,0 +1,146 @@ +require 'acceptance/helpers/utils' +include Acceptance::Helpers::Utils + +# Validate file-plugin-managed keys on the local filesystem +# +# - Conforms to the API specified in 'a simpkv plugin test' shared_examples +# - Uses local filesystem commands, since the file plugin has to be on the +# same host as the file keystore +# +# @param key_info Hash of key information whose format corresponds to the +# Simpkv_test::KeyInfo type alias +# +# @param keys_should_exist Whether keys should exist +# - true = verify keys are present with correct stored data +# - false = verify keys are absent +# +# @param backend_hiera Hash of backend configuration ('simpkv::options' Hash) +# +# @param host Host object on which the validator will execute commands +# - Must be same host as file keystore +# +# @return Whether validation of keys succeeded +# +def validate_file_entries(key_info, keys_should_exist, backend_hiera, host) + if keys_should_exist + validate_file_entries_present(key_info, backend_hiera, host) + else + validate_file_entries_absent(key_info, backend_hiera, host) + end +end + +# Validate that file-plugin-managed keys exist on the local filesystem +# +# For each key specification, +# - Selects the backend whose name matches its 'app_id' or 'default', when +# no match is found +# - Checks for the existence of the appropriate file for the backend +# - Verifies the file content, when the file exists +# +# @param key_info Hash of key information whose format corresponds to the +# Simpkv_test::KeyInfo type alias +# +# @param backend_hiera Hash of backend configuration ('simpkv::options' Hash) +# +# @param host Host object on which the validator will execute commands +# - Must be same host as file file keystore +# +# @return Whether validation of keys succeeded +# +def validate_file_entries_present(key_info, backend_hiera, host) + errors = [] + key_info.each do |app_id, key_struct| + root_path = file_root_path_for_app_id(app_id, backend_hiera) + key_struct.each do |key_type, keys| + key_root_path = (key_type == 'global') ? "#{root_path}/globals" : "#{root_path}/environments/production" + keys.each do |key, key_data| + key_path = "#{key_root_path}/#{key}" + expected_key_string = key_data_string(key_data) + result = on(host, "cat #{key_path}", :accept_all_exit_codes => true) + if result.exit_code == 0 + if result.stdout.strip != expected_key_string + errors << [ + "Contents of #{key_path} did not match expected:", + " Expected: #{expected_key_string}", + " Actual: #{result.stdout}" + ].join("\n") + end + else + errors << "Validation of #{key_path} presence and data failed: #{result.stderr}" + end + end + end + end + + if errors.size == 0 + true + else + warn('Validation Failures:') + errors.each do |error| + warn(" #{error}") + end + + false + end +end + +# Validate that file-plugin-managed keys do not exist on the local filesystem +# +# For each key specification, +# - Selects the backend whose name matches its 'app_id' or 'default', when +# no match is found +# - Checks for the existence of the appropriate file for the backend +# +# @param key_info Hash of key information whose format corresponds to the +# Simpkv_test::KeyInfo type alias +# +# @param backend_hiera Hash of backend configuration ('simpkv::options' Hash) +# +# @param host Host object on which the validator will execute commands +# - Must be same host as file file keystore +# +# @return Whether validation of keys succeeded +# +def validate_file_entries_absent(key_info, backend_hiera, host) + errors = [] + key_info.each do |app_id, key_struct| + root_path = file_root_path_for_app_id(app_id, backend_hiera) + key_struct.each do |key_type, keys| + key_root_path = (key_type == 'global') ? "#{root_path}/globals" : "#{root_path}/environments/production" + keys.each do |key, key_data| + key_path = "#{key_root_path}/#{key}" + result = on(host, "ls -l #{key_path}", :accept_all_exit_codes => true) + if result.exit_code == 0 + errors << "Validation of #{key_path} absence failed: #{result.stdout}" + end + end + end + end + + if errors.size == 0 + true + else + warn('Validation Failures:') + errors.each do |error| + warn(" #{error}") + end + + false + end +end + +# @return Root path for the file backend that corresponds to the app_id +# +# @param app_id The app_id for a key or '', if none specified +# @param backend_hiera Hash of backend configuration ('simpkv::options' Hash) +# +def file_root_path_for_app_id(app_id, backend_hiera) + root_path = '' + if backend_hiera['simpkv::options']['backends'].keys.include?(app_id) + root_path = backend_hiera["simpkv::backend::#{app_id}"]['root_path'] + elsif backend_hiera['simpkv::options']['backends'].keys.include?('default') + root_path = backend_hiera['simpkv::backend::default']['root_path'] + end + + root_path +end diff --git a/spec/spec_helper_acceptance.rb b/spec/spec_helper_acceptance.rb index eac85b7..e1dcb84 100644 --- a/spec/spec_helper_acceptance.rb +++ b/spec/spec_helper_acceptance.rb @@ -1,11 +1,13 @@ require 'beaker-rspec' +require_relative 'acceptance/helpers' +require_relative 'acceptance/shared_examples' + require 'tmpdir' require 'yaml' require 'simp/beaker_helpers' include Simp::BeakerHelpers - -require 'data_helper' -include DataHelper +include Acceptance::Helpers::TestData +include Acceptance::Helpers::ManifestUtils unless ENV['BEAKER_provision'] == 'no' hosts.each do |host| @@ -26,6 +28,10 @@ # ensure that environment OS is ready on each host fix_errata_on hosts + # Detect cases in which no examples are executed (e.g., nodeset does not + # have hosts with required roles) + c.fail_if_no_examples = true + # Readable test descriptions c.formatter = :documentation diff --git a/spec/support/modules/simpkv_test/README.md b/spec/support/modules/simpkv_test/README.md new file mode 100644 index 0000000..42082ec --- /dev/null +++ b/spec/support/modules/simpkv_test/README.md @@ -0,0 +1,94 @@ +#### Table of Contents + + + +* [Module Description](#module-description) +* [Usage](#usage) +* [Limitations](#limitations) +* [Reference](#reference) + +## Module Description + +This is a module to test the simpkv function API. It uses Puppet manifests +to exercise all the simpkv functions and to verify the values stored in +each backend are correct. Specifically, it provides manifests that + +* store keys using `simpkv::put` +* remove keys using `simpkv::delete` +* remove folders using `simpkv::deletetree` +* verify the existence of key/folder names using `simpkv::exists` +* verify keys can be retrieved using `simpkv::get` and that the retrieved + key data is correct +* verify folder listings can be retrieved using `simpkv::list` and that the + retrieved list data is correct + +## Usage + +Usage of this module is fairly straight forward: + +* Include `simpkv_test::store_keys`, `simpkv_test::remove_keys`, or + `simpkv_test::remove_folders` to modify the state of one or more backends + + * These manifests use `simpkv::put`, `simpkv::delete`, and + `simpkv::deletetree`, respectively. + +* Include `simpkv_test::verify_keys_exist` and `simpkv_test::verify_folders_exist` + to verify that keys/folders are present or absent after the backend state + has been modified. + + * These manifests use `simpkv::exists`. + +* Include `simpkv_test::retrieve_and_verify_keys` and + `simpkv_test::retrieve_and_verify_folders` to retrieve and verify the + keys/folders information after the backend state has been modified. + + * These manifests use `simpkv::get` and `simpkv::list`, respectively. + +All key/folder information required by the manifests is driven by hieradata. + +For each key, this may include: + +* The key's name +* The key's value or a file containing its binary value +* The key's metadata +* The `app_id` to be used in the `simpkv::*` function calls for this key + or '' when no `app_id` is to be specified. +* Whether the keyis is a Puppet-environment key or a global key. + +For each folder, this may include: + +* The folder's name +* The key information for each key in the folder +* The list of subfolder names +* The `app_id` to be used in the `simpkv::*` function calls for this folder + or '' when no `app_id` is to be specified. +* Whether the folder is is a Puppet-environment folder or a global folder. + +IMPORTANT: +`simpkv::*` functions map `app_id` to the configured backend, or select the +'default' backend when no `app_id` is specified. To ensure uniqueness of test +keys, the data structures in this module are designed **assuming**, each +configured backend is uniquely mapped to the `app_id`. + +If your test setup violates this assumption, you use the same key name and +global status for different `app_ids`, and those `app_ids` map to the same +backend, the *last operation executed for that key name will determine its +state*. + +## Limitations + +* This test module verifies the simpkv function API is self-consistent, but + does not verify that the key data is actually stored in the correct location + in the desired backends. + + * The `simp-simpkv` module's acceptance test infrastructure uses + plugin-specific verification, in addition to the verifiction provided by + this module for full plugin verification! + +* This module only supports validation of Binary key data in `simpkv::get` + function call results. It does not support validation of Binary key data + in `simpkv::list` function call results. + +## Reference + +See [REFERENCE.md](./REFERENCE.md) for reference documentation. diff --git a/spec/support/modules/simpkv_test/REFERENCE.md b/spec/support/modules/simpkv_test/REFERENCE.md new file mode 100644 index 0000000..cb69c48 --- /dev/null +++ b/spec/support/modules/simpkv_test/REFERENCE.md @@ -0,0 +1,1002 @@ +# Reference + + + +## Table of Contents + +### Classes + +* [`simpkv_test::remove_folders`](#simpkv_testremove_folders): Remove folders using simpkv::deletetree +* [`simpkv_test::remove_keys`](#simpkv_testremove_keys): Remove keys using simpkv::delete +* [`simpkv_test::retrieve_and_verify_folders`](#simpkv_testretrieve_and_verify_folders): Retrieve folder lists with simpkv::list and verify the result +* [`simpkv_test::retrieve_and_verify_keys`](#simpkv_testretrieve_and_verify_keys): Retrieve keys with simpkv::get and verifies the results +* [`simpkv_test::store_keys`](#simpkv_teststore_keys): Store keys using simpkv::put +* [`simpkv_test::verify_folders_exist`](#simpkv_testverify_folders_exist): Check for the existence of folders using simpkv::exists +* [`simpkv_test::verify_keys_exist`](#simpkv_testverify_keys_exist): Check for the existence of keys using simpkv::exists + +### Defined types + +* [`simpkv_test::defines::remove_folder`](#simpkv_testdefinesremove_folder): Define that simply calls simpkv::deletetree +* [`simpkv_test::defines::remove_key`](#simpkv_testdefinesremove_key): Define that simply calls simpkv::delete +* [`simpkv_test::defines::retrieve_and_verify_folder`](#simpkv_testdefinesretrieve_and_verify_folder): Define that calls simpkv::list and validates its result +* [`simpkv_test::defines::retrieve_and_verify_key`](#simpkv_testdefinesretrieve_and_verify_key): Define that calls simpkv::get and validates its result +* [`simpkv_test::defines::store_key`](#simpkv_testdefinesstore_key): Define that simply calls simpkv::put +* [`simpkv_test::defines::verify_name_exists`](#simpkv_testdefinesverify_name_exists): Define that calls simpkv::exists and validates its result + +### Functions + +* [`simpkv_test::assert_equal`](#simpkv_testassert_equal): Compare 2 values and fail if they differ +* [`simpkv_test::code_source`](#simpkv_testcode_source): "Randomly" assigns the code source from which a simpkv function will +be called. +* [`simpkv_test::key_value`](#simpkv_testkey_value): Returns key value specified by `$key_data` +* [`simpkv_test::puppet_functions::remove_folder`](#simpkv_testpuppet_functionsremove_folder): Puppet language function that simply calls simpkv::deletetree +* [`simpkv_test::puppet_functions::remove_key`](#simpkv_testpuppet_functionsremove_key): Puppet language function that simply calls simpkv::delete +* [`simpkv_test::puppet_functions::retrieve_and_verify_folder`](#simpkv_testpuppet_functionsretrieve_and_verify_folder): Puppet language function that calls simpkv::list and validates its result +* [`simpkv_test::puppet_functions::retrieve_and_verify_key`](#simpkv_testpuppet_functionsretrieve_and_verify_key): Puppet language function that calls simpkv::get and validates +its result. +* [`simpkv_test::puppet_functions::store_key`](#simpkv_testpuppet_functionsstore_key): Puppet language function that simply calls simpkv::put +* [`simpkv_test::puppet_functions::verify_name_exists`](#simpkv_testpuppet_functionsverify_name_exists): Puppet language function that calls simpkv::exists and validates +its result. +* [`simpkv_test::simpkv_options`](#simpkv_testsimpkv_options): Generates simpkv_options Hash for use in simpkv function calls +* [`simpkv_test::verify_folder_data`](#simpkv_testverify_folder_data): Compare expected and actual folder contents and fail if they differ +* [`simpkv_test::verify_key_data`](#simpkv_testverify_key_data): Compare expected and actual key data and fail if they differ + +### Data types + +* [`Simpkv_test::AppId`](#simpkv_testappid): String used as the `app_id` attribute of the `simpkv_options` parameter in a simpkv function call +* [`Simpkv_test::FolderData`](#simpkv_testfolderdata): Information about an individual folder in a keystore +* [`Simpkv_test::FolderInfo`](#simpkv_testfolderinfo): Data structure specifying folder information Folders are unique based on 3 attributes: 1. The backend in which they are stored 2. Whether +* [`Simpkv_test::Folders`](#simpkv_testfolders): Data structure specifying folder listings +* [`Simpkv_test::Key`](#simpkv_testkey): Key or folder name The regex is not perfect (doesn't catch sequences that look like relative paths), but sufficient for this test module. +* [`Simpkv_test::KeyData`](#simpkv_testkeydata): Information about an individual key in a keystore +* [`Simpkv_test::KeyInfo`](#simpkv_testkeyinfo): Data structure specifying key information Keys are unique based on 3 attributes: 1. The backend in which they are stored 2. Whether they a +* [`Simpkv_test::Keys`](#simpkv_testkeys): Data structure specifying key/value pairs +* [`Simpkv_test::NameInfo`](#simpkv_testnameinfo): Data structure specifying simply key/folder names Key/folder names are unique based on 3 attributes: 1. The backend in which they are store +* [`Simpkv_test::NonBinaryKeyData`](#simpkv_testnonbinarykeydata): Information about an individual non-binary key in a keystore + +## Classes + +### `simpkv_test::remove_folders` + +Remove folders using simpkv::deletetree + +#### Parameters + +The following parameters are available in the `simpkv_test::remove_folders` class: + +* [`foldername_info`](#foldername_info) + +##### `foldername_info` + +Data type: `Simpkv_test::NameInfo` + +Info specifying the names of the folders to remove + +### `simpkv_test::remove_keys` + +Remove keys using simpkv::delete + +#### Parameters + +The following parameters are available in the `simpkv_test::remove_keys` class: + +* [`keyname_info`](#keyname_info) + +##### `keyname_info` + +Data type: `Simpkv_test::NameInfo` + +Info specifying the names of keys to remove + +### `simpkv_test::retrieve_and_verify_folders` + +Retrieve folder lists with simpkv::list and verify the result + +#### Parameters + +The following parameters are available in the `simpkv_test::retrieve_and_verify_folders` class: + +* [`valid_folder_info`](#valid_folder_info) +* [`invalid_folder_info`](#invalid_folder_info) + +##### `valid_folder_info` + +Data type: `Simpkv_test::FolderInfo` + +Info specifying folders that are expected to be present in the +keystore and their contents + +##### `invalid_folder_info` + +Data type: `Simpkv_test::FolderInfo` + +Info specifying folders that are not expected to be present in +the keystore + +### `simpkv_test::retrieve_and_verify_keys` + +Retrieve keys with simpkv::get and verifies the results + +#### Parameters + +The following parameters are available in the `simpkv_test::retrieve_and_verify_keys` class: + +* [`valid_key_info`](#valid_key_info) +* [`invalid_key_info`](#invalid_key_info) + +##### `valid_key_info` + +Data type: `Simpkv_test::KeyInfo` + +Info specifying keys that are expected to be present in the +keystore and their stored data + +##### `invalid_key_info` + +Data type: `Simpkv_test::KeyInfo` + +Info specifying keys that are not expected to be present in the +keystore + +### `simpkv_test::store_keys` + +Store keys using simpkv::put + +#### Parameters + +The following parameters are available in the `simpkv_test::store_keys` class: + +* [`key_info`](#key_info) + +##### `key_info` + +Data type: `Simpkv_test::KeyInfo` + +Info specifying the key names and data to be stored + +### `simpkv_test::verify_folders_exist` + +Check for the existence of folders using simpkv::exists + +#### Parameters + +The following parameters are available in the `simpkv_test::verify_folders_exist` class: + +* [`valid_foldername_info`](#valid_foldername_info) +* [`invalid_foldername_info`](#invalid_foldername_info) + +##### `valid_foldername_info` + +Data type: `Simpkv_test::NameInfo` + +Info specifying names of folder that are expected to be present in the +keystore + +##### `invalid_foldername_info` + +Data type: `Simpkv_test::NameInfo` + +Info specifying names of folder that are not expected to be present in +the keystore + +### `simpkv_test::verify_keys_exist` + +Check for the existence of keys using simpkv::exists + +#### Parameters + +The following parameters are available in the `simpkv_test::verify_keys_exist` class: + +* [`valid_keyname_info`](#valid_keyname_info) +* [`invalid_keyname_info`](#invalid_keyname_info) + +##### `valid_keyname_info` + +Data type: `Simpkv_test::NameInfo` + +Info specifying names of keys that are expected to be present in the +keystore + +##### `invalid_keyname_info` + +Data type: `Simpkv_test::NameInfo` + +Info specifying names of keys that are not expected to be present in +the keystore + +## Defined types + +### `simpkv_test::defines::remove_folder` + +Define that simply calls simpkv::deletetree + +#### Parameters + +The following parameters are available in the `simpkv_test::defines::remove_folder` defined type: + +* [`folder`](#folder) +* [`simpkv_options`](#simpkv_options) + +##### `folder` + +Data type: `Simpkv_test::Key` + +Name of the folder to remove + +##### `simpkv_options` + +Data type: `Hash` + +Value of the simpkv_options parameter to be used in the simpkv::deletetree +function call + +Default value: `{}` + +### `simpkv_test::defines::remove_key` + +Define that simply calls simpkv::delete + +#### Parameters + +The following parameters are available in the `simpkv_test::defines::remove_key` defined type: + +* [`key`](#key) +* [`simpkv_options`](#simpkv_options) + +##### `key` + +Data type: `Simpkv_test::Key` + +Name of the key to remove + +##### `simpkv_options` + +Data type: `Hash` + +Value of the simpkv_options parameter to be used in the simpkv::delete +function call + +Default value: `{}` + +### `simpkv_test::defines::retrieve_and_verify_folder` + +Fails if validation fails. + +#### Parameters + +The following parameters are available in the `simpkv_test::defines::retrieve_and_verify_folder` defined type: + +* [`folder`](#folder) +* [`expected_keys`](#expected_keys) +* [`expected_folders`](#expected_folders) +* [`simpkv_options`](#simpkv_options) + +##### `folder` + +Data type: `Simpkv_test::Key` + +Name of the folder to be listed + +##### `expected_keys` + +Data type: `Variant[Hash[Simpkv_test::Key,Simpkv_test::NonBinaryKeyData],Undef]` + +Expected key data + +##### `expected_folders` + +Data type: `Variant[Array[String[1]],Undef]` + +Expected folder data + +##### `simpkv_options` + +Data type: `Hash` + +Value of the simpkv_options parameter to be used in the simpkv::list +function call + +Default value: `{}` + +### `simpkv_test::defines::retrieve_and_verify_key` + +Fails if validation fails. + +#### Parameters + +The following parameters are available in the `simpkv_test::defines::retrieve_and_verify_key` defined type: + +* [`key`](#key) +* [`expected_value`](#expected_value) +* [`expected_metadata`](#expected_metadata) +* [`simpkv_options`](#simpkv_options) +* [`binary`](#binary) + +##### `key` + +Data type: `Simpkv_test::Key` + +Name of the key to be retrieved + +##### `expected_value` + +Data type: `Any` + +Expected key value + +##### `expected_metadata` + +Data type: `Variant[Hash,Undef]` + +Expected key metadata + +##### `simpkv_options` + +Data type: `Hash` + +Value of the simpkv_options parameter to be used in the simpkv::get +function call + +##### `binary` + +Data type: `Boolean` + +Whether the key has a binary value + +### `simpkv_test::defines::store_key` + +Define that simply calls simpkv::put + +#### Parameters + +The following parameters are available in the `simpkv_test::defines::store_key` defined type: + +* [`key`](#key) +* [`value`](#value) +* [`metadata`](#metadata) +* [`simpkv_options`](#simpkv_options) + +##### `key` + +Data type: `Simpkv_test::Key` + +Name of the key to store + +##### `value` + +Data type: `NotUndef` + +Value to store + +##### `metadata` + +Data type: `Hash` + +Metadata to store + +Default value: `{}` + +##### `simpkv_options` + +Data type: `Hash` + +Value of the simpkv_options parameter to be used in the simpkv::put +function call + +Default value: `{}` + +### `simpkv_test::defines::verify_name_exists` + +Fails if validation fails. + +#### Parameters + +The following parameters are available in the `simpkv_test::defines::verify_name_exists` defined type: + +* [`key`](#key) +* [`simpkv_options`](#simpkv_options) +* [`valid`](#valid) + +##### `key` + +Data type: `Simpkv_test::Key` + +Name of the key/folder whose existence is to be checked + +##### `simpkv_options` + +Data type: `Hash` + +Value of the simpkv_options parameter to be used in the simpkv::exists +function call + +Default value: `{}` + +##### `valid` + +Data type: `Boolean` + +Whether key/folder should exist + +## Functions + +### `simpkv_test::assert_equal` + +Type: Puppet Language + +Compare 2 values and fail if they differ + +#### `simpkv_test::assert_equal(Any $actual, Any $expected, String $message)` + +The simpkv_test::assert_equal function. + +Returns: `None` + +##### `actual` + +Data type: `Any` + +Actual value + +##### `expected` + +Data type: `Any` + +Expected value + +##### `message` + +Data type: `String` + +Explanatory text that is added to the failure message + +### `simpkv_test::code_source` + +Type: Puppet Language + +"Randomly" assigns the code source from which a simpkv function will +be called. + +#### `simpkv_test::code_source(String $id)` + +The simpkv_test::code_source function. + +Returns: `Enum['class', 'define', 'puppet_function']` + +##### `id` + +Data type: `String` + +Id of the key/folder used in the simpkv function + +- Used as the random generator seed + +### `simpkv_test::key_value` + +Type: Puppet Language + +Transforms to Binary as necessary, or undef if the value cannot be determined. + +#### `simpkv_test::key_value(Simpkv_test::KeyData $key_data)` + +Transforms to Binary as necessary, or undef if the value cannot be determined. + +Returns: `Any` + +##### `key_data` + +Data type: `Simpkv_test::KeyData` + +Key specification + +### `simpkv_test::puppet_functions::remove_folder` + +Type: Puppet Language + +Puppet language function that simply calls simpkv::deletetree + +#### `simpkv_test::puppet_functions::remove_folder(Simpkv_test::Key $folder, Hash $simpkv_options)` + +The simpkv_test::puppet_functions::remove_folder function. + +Returns: `None` + +##### `folder` + +Data type: `Simpkv_test::Key` + +Name of the folder to remove + +##### `simpkv_options` + +Data type: `Hash` + +Value of the simpkv_options parameter to be used in the simpkv::deletetree +function call + +### `simpkv_test::puppet_functions::remove_key` + +Type: Puppet Language + +Puppet language function that simply calls simpkv::delete + +#### `simpkv_test::puppet_functions::remove_key(Simpkv_test::Key $key, Hash $simpkv_options)` + +The simpkv_test::puppet_functions::remove_key function. + +Returns: `None` + +##### `key` + +Data type: `Simpkv_test::Key` + +Name of the key to remove + +##### `simpkv_options` + +Data type: `Hash` + +Value of the simpkv_options parameter to be used in the simpkv::delete +function call + +### `simpkv_test::puppet_functions::retrieve_and_verify_folder` + +Type: Puppet Language + +Fails if validation fails. + +#### `simpkv_test::puppet_functions::retrieve_and_verify_folder(Simpkv_test::Key $folder, Variant[Hash[Simpkv_test::Key,Simpkv_test::NonBinaryKeyData],Undef] $expected_keys, Variant[Array[String[1]],Undef] $expected_folders, Hash $simpkv_options = {})` + +Fails if validation fails. + +Returns: `None` + +##### `folder` + +Data type: `Simpkv_test::Key` + +Name of the folder to be listed + +##### `expected_keys` + +Data type: `Variant[Hash[Simpkv_test::Key,Simpkv_test::NonBinaryKeyData],Undef]` + +Expected key data + +##### `expected_folders` + +Data type: `Variant[Array[String[1]],Undef]` + +Expected folder data + +##### `simpkv_options` + +Data type: `Hash` + +Value of the simpkv_options parameter to be used in the simpkv::list +function call + +### `simpkv_test::puppet_functions::retrieve_and_verify_key` + +Type: Puppet Language + +Fails if validation fails. + +#### `simpkv_test::puppet_functions::retrieve_and_verify_key(Simpkv_test::Key $key, Any $expected_value, Variant[Hash,Undef] $expected_metadata, Hash $simpkv_options, Boolean $binary)` + +Fails if validation fails. + +Returns: `None` + +##### `key` + +Data type: `Simpkv_test::Key` + +Name of the key to be retrieved + +##### `expected_value` + +Data type: `Any` + +Expected key value + +##### `expected_metadata` + +Data type: `Variant[Hash,Undef]` + +Expected key metadata + +##### `simpkv_options` + +Data type: `Hash` + +Value of the simpkv_options parameter to be used in the simpkv::get +function call + +##### `binary` + +Data type: `Boolean` + +Whether the key has a binary value + +### `simpkv_test::puppet_functions::store_key` + +Type: Puppet Language + +Puppet language function that simply calls simpkv::put + +#### `simpkv_test::puppet_functions::store_key(Simpkv_test::Key $key, NotUndef $value, Hash $metadata, Hash $simpkv_options)` + +The simpkv_test::puppet_functions::store_key function. + +Returns: `None` + +##### `key` + +Data type: `Simpkv_test::Key` + +Name of the key to store + +##### `value` + +Data type: `NotUndef` + +Value to store + +##### `metadata` + +Data type: `Hash` + +Metadata to store + +##### `simpkv_options` + +Data type: `Hash` + +Value of the simpkv_options parameter to be used in the simpkv::put +function call + +### `simpkv_test::puppet_functions::verify_name_exists` + +Type: Puppet Language + +Fails if validation fails. + +#### `simpkv_test::puppet_functions::verify_name_exists(Simpkv_test::Key $key, Hash $simpkv_options, Boolean $valid)` + +Fails if validation fails. + +Returns: `None` + +##### `key` + +Data type: `Simpkv_test::Key` + +Name of the key/folder whose existence is to be checked + +##### `simpkv_options` + +Data type: `Hash` + +Value of the simpkv_options parameter to be used in the simpkv::exists +function call + +##### `valid` + +Data type: `Boolean` + +Whether key/folder should exist + +### `simpkv_test::simpkv_options` + +Type: Puppet Language + +Generates simpkv_options Hash for use in simpkv function calls + +#### `simpkv_test::simpkv_options(Simpkv_test::AppId $app_id, Enum['env', 'global'] $key_type, Hash $other_options = {})` + +The simpkv_test::simpkv_options function. + +Returns: `Hash` + +##### `app_id` + +Data type: `Simpkv_test::AppId` + +`app_id` to be set in the simpkv_options Hash + +- Ignored when an empty string + +##### `key_type` + +Data type: `Enum['env', 'global']` + +The key/folder type + +- 'env': key/folder is tied to a Puppet environment +- 'global': key/folder is global + +##### `other_options` + +Data type: `Hash` + +Other options to be set in the returned simpkv_options Hash + +### `simpkv_test::verify_folder_data` + +Type: Puppet Language + +Compare expected and actual folder contents and fail if they differ + +#### `simpkv_test::verify_folder_data(Variant[Hash,Undef] $list_result, Variant[Hash[Simpkv_test::Key,Simpkv_test::NonBinaryKeyData],Undef] $expected_keys, Variant[Array[String[1]],Undef] $expected_folders, String[1] $message)` + +The simpkv_test::verify_folder_data function. + +Returns: `None` + +##### `list_result` + +Data type: `Variant[Hash,Undef]` + +The actual `simpkv::list` result + +##### `expected_keys` + +Data type: `Variant[Hash[Simpkv_test::Key,Simpkv_test::NonBinaryKeyData],Undef]` + +Expected key data + +##### `expected_folders` + +Data type: `Variant[Array[String[1]],Undef]` + +Expected folder data + +##### `message` + +Data type: `String[1]` + +Explanatory text that is added to the failure message, if the comparison +fails + +### `simpkv_test::verify_key_data` + +Type: Puppet Language + +Compare expected and actual key data and fail if they differ + +#### `simpkv_test::verify_key_data(Variant[Hash,Undef] $get_result, Any $expected_value, Variant[Hash,Undef] $expected_metadata, Boolean $binary, String[1] $message)` + +The simpkv_test::verify_key_data function. + +Returns: `None` + +##### `get_result` + +Data type: `Variant[Hash,Undef]` + +The actual `simpkv::get` result + +##### `expected_value` + +Data type: `Any` + +Expected key value + +##### `expected_metadata` + +Data type: `Variant[Hash,Undef]` + +Expected key metadata + +##### `binary` + +Data type: `Boolean` + +Whether the key has a binary value + +##### `message` + +Data type: `String[1]` + +Explanatory text that is added to the failure message, if the comparison +fails + +## Data types + +### `Simpkv_test::AppId` + +String used as the `app_id` attribute of the `simpkv_options` parameter in +a simpkv function call + +Alias of + +```puppet +String +``` + +### `Simpkv_test::FolderData` + +Information about an individual folder in a keystore + +Alias of + +```puppet +Struct[{ + # Info about keys in the directory + # - Currently restricted to keys with non-binary data because of + # test manifest limitations + Optional[keys] => Hash[Simpkv_test::Key,Simpkv_test::NonBinaryKeyData], + + # List of subfolder names + Optional[folders] => Array[String[1]] +}] +``` + +### `Simpkv_test::FolderInfo` + +Data structure specifying folder information + +Folders are unique based on 3 attributes: + 1. The backend in which they are stored + 2. Whether they are tied to a Puppet environment or global + 3. The folder names (each of which may include a relative path) + +The grouping below was chosen to ensure uniqueness for test folders, +**ASSUMING**, backends are uniquely mapped to the `app_id` attribute that +will be used in the `simpkv_options` parameter of each simpkv function call. + +If you are mapping multiple `app_id` values to the same backend in a test, +be sure you don't have any folders that will resolve to the same storage +location! + +Alias of + +```puppet +Hash[Simpkv_test::AppId, Struct[{ + # - Any folder in 'env' is a folder tied to the Puppet environment. + # - Any folder in 'global' is a global folder. + # - For these folders, the 'global' attribute of the `simpkv_options` + # parameter of each simpkv function call will be automatically set + # to `true`. + Optional[env] => Simpkv_test::Folders, + Optional[global] => Simpkv_test::Folders + }]] +``` + +### `Simpkv_test::Folders` + +Data structure specifying folder listings + +Alias of + +```puppet +Hash[Simpkv_test::Key, Simpkv_test::FolderData] +``` + +### `Simpkv_test::Key` + +Key or folder name + +The regex is not perfect (doesn't catch sequences that look +like relative paths), but sufficient for this test module. + +Alias of + +```puppet +Pattern['^[a-z0-9._:\-\/]+$'] +``` + +### `Simpkv_test::KeyData` + +Information about an individual key in a keystore + +Alias of + +```puppet +Struct[{ + # Either 'value' or 'file' needs to be set. + # If both are set, 'value' will be used over 'file'. + # If neither are set, the Simpkv_test::KeyData instance will be skipped. + + # Non-binary value + Optional[value] => NotUndef, + + # File containing binary value + # - argument to binary_file, which is an absolute path or + # / string referencing a module file + Optional[file] => String[1], + + # Optional metadata stored with the value + Optional[metadata] => Hash +}] +``` + +### `Simpkv_test::KeyInfo` + +Data structure specifying key information + +Keys are unique based on 3 attributes: + 1. The backend in which they are stored + 2. Whether they are tied to a Puppet environment or global + 3. The key names (each of which may include a relative folder path) + +The grouping below was chosen to ensure uniqueness for test keys, +**ASSUMING**, backends are uniquely mapped to the `app_id` attribute that +will be used in the `simpkv_options` parameter of each simpkv function call. + +If you are mapping multiple `app_id` values to the same backend in a test, +be sure you don't have any keys that will resolve to the same storage +location! + +Alias of + +```puppet +Hash[Simpkv_test::AppId, Struct[{ + # - Any key in 'env' is a key tied to the Puppet environment. + # - Any key in 'global' is a global key. + # - For these keys, the 'global' attribute of the `simpkv_options` + # parameter of each simpkv function call will be automatically set + # to `true`. + Optional[env] => Simpkv_test::Keys, + Optional[global] => Simpkv_test::Keys + }]] +``` + +### `Simpkv_test::Keys` + +Data structure specifying key/value pairs + +Alias of + +```puppet +Hash[Simpkv_test::Key, Simpkv_test::KeyData] +``` + +### `Simpkv_test::NameInfo` + +Data structure specifying simply key/folder names + +Key/folder names are unique based on 3 attributes: + 1. The backend in which they are stored + 2. Whether they are tied to a Puppet environment or global + 3. The key/folder names (each of which may include a relative folder path) + +The grouping below was chosen to ensure uniqueness for test key/folder names, +**ASSUMING**, backends are uniquely mapped to the `app_id` attribute that +will be used in the `simpkv_options` parameter of each simpkv function call. + +If you are mapping multiple `app_id` values to the same backend in a test, +be sure you don't have any keys/folders that will resolve to the same storage +location! + +Alias of + +```puppet +Hash[Simpkv_test::AppId, Struct[{ + # - Any key/folder in 'env' is tied to the Puppet environment. + # - Any key/folder in 'global' is global + # - For these entities, the 'global' attribute of the `simpkv_options` + # parameter of each simpkv function call will be automatically set + # to `true`. + Optional[env] => Array[Simpkv_test::Key], + Optional[global] => Array[Simpkv_test::Key] + }]] +``` + +### `Simpkv_test::NonBinaryKeyData` + +Information about an individual non-binary key in a keystore + +Alias of + +```puppet +Struct[{ + # Non-binary value + value => NotUndef, + + # Optional metadata stored with the value + Optional[metadata] => Hash +}] +``` + diff --git a/spec/support/modules/simpkv_test/files/test_krb5.keytab b/spec/support/modules/simpkv_test/files/test_krb5.keytab new file mode 100644 index 0000000..c052185 Binary files /dev/null and b/spec/support/modules/simpkv_test/files/test_krb5.keytab differ diff --git a/spec/support/modules/simpkv_test/functions/assert_equal.pp b/spec/support/modules/simpkv_test/functions/assert_equal.pp index 940e8d3..b75cfb5 100644 --- a/spec/support/modules/simpkv_test/functions/assert_equal.pp +++ b/spec/support/modules/simpkv_test/functions/assert_equal.pp @@ -1,3 +1,16 @@ +# @summary Compare 2 values and fail if they differ +# +# @param actual +# Actual value +# +# @param expected +# Expected value +# +# @param message +# Explanatory text that is added to the failure message +# +# @return [None] +# function simpkv_test::assert_equal( Any $actual, Any $expected, @@ -6,7 +19,15 @@ function simpkv_test::assert_equal( info("Checking results for ${message}") - if ($actual != $expected) { + if ($actual == $expected) { + if $actual =~ Binary { + info("Actual binary results match expected") + } + else { + info("Actual results match expected '${expected}'") + } + } + else { fail("Expected '${expected}'; got '${actual}' for ${message}") } } diff --git a/spec/support/modules/simpkv_test/functions/code_source.pp b/spec/support/modules/simpkv_test/functions/code_source.pp new file mode 100644 index 0000000..1b9b6e0 --- /dev/null +++ b/spec/support/modules/simpkv_test/functions/code_source.pp @@ -0,0 +1,16 @@ +# @summary "Randomly" assigns the code source from which a simpkv function will +# be called. +# +# @param id +# Id of the key/folder used in the simpkv function +# +# - Used as the random generator seed +# +# @return [Enum['class', 'define', 'puppet_function']] +# +function simpkv_test::code_source(String $id) { + + $_values = [ 'class', 'define', 'puppet_function' ] + $_index = seeded_rand(3, $id) + $_values[$_index] +} diff --git a/spec/support/modules/simpkv_test/functions/key_value.pp b/spec/support/modules/simpkv_test/functions/key_value.pp new file mode 100644 index 0000000..4af7996 --- /dev/null +++ b/spec/support/modules/simpkv_test/functions/key_value.pp @@ -0,0 +1,23 @@ +# @summary Returns key value specified by `$key_data` +# +# Transforms to Binary as necessary, or undef if the value cannot be determined. +# +# @param key_data +# Key specification +# +# @return [Any] +# +function simpkv_test::key_value( + Simpkv_test::KeyData $key_data +) { + + if 'value' in $key_data { + $key_data['value'] + } + elsif 'file' in $key_data { + binary_file($key_data['file']) + } + else { + undef + } +} diff --git a/spec/support/modules/simpkv_test/functions/puppet_functions/remove_folder.pp b/spec/support/modules/simpkv_test/functions/puppet_functions/remove_folder.pp new file mode 100644 index 0000000..6736493 --- /dev/null +++ b/spec/support/modules/simpkv_test/functions/puppet_functions/remove_folder.pp @@ -0,0 +1,18 @@ +# @summary Puppet language function that simply calls simpkv::deletetree +# +# @param folder +# Name of the folder to remove +# +# @param simpkv_options +# Value of the simpkv_options parameter to be used in the simpkv::deletetree +# function call +# +# @return [None] +# +function simpkv_test::puppet_functions::remove_folder( + Simpkv_test::Key $folder, + Hash $simpkv_options +) { + info("Calling simpkv::deletetree('${folder}', ${simpkv_options})") + simpkv::deletetree($folder, $simpkv_options) +} diff --git a/spec/support/modules/simpkv_test/functions/puppet_functions/remove_key.pp b/spec/support/modules/simpkv_test/functions/puppet_functions/remove_key.pp new file mode 100644 index 0000000..243b8c9 --- /dev/null +++ b/spec/support/modules/simpkv_test/functions/puppet_functions/remove_key.pp @@ -0,0 +1,18 @@ +# @summary Puppet language function that simply calls simpkv::delete +# +# @param key +# Name of the key to remove +# +# @param simpkv_options +# Value of the simpkv_options parameter to be used in the simpkv::delete +# function call +# +# @return [None] +# +function simpkv_test::puppet_functions::remove_key( + Simpkv_test::Key $key, + Hash $simpkv_options +) { + info("Calling simpkv::delete('${key}', ${simpkv_options})") + simpkv::delete($key, $simpkv_options) +} diff --git a/spec/support/modules/simpkv_test/functions/puppet_functions/retrieve_and_verify_folder.pp b/spec/support/modules/simpkv_test/functions/puppet_functions/retrieve_and_verify_folder.pp new file mode 100644 index 0000000..83022c0 --- /dev/null +++ b/spec/support/modules/simpkv_test/functions/puppet_functions/retrieve_and_verify_folder.pp @@ -0,0 +1,32 @@ +# @summary Puppet language function that calls simpkv::list and validates its result +# +# Fails if validation fails. +# +# @param folder +# Name of the folder to be listed +# +# @param expected_keys +# Expected key data +# +# @param expected_folders +# Expected folder data +# +# @param simpkv_options +# Value of the simpkv_options parameter to be used in the simpkv::list +# function call +# +# @return [None] +# +function simpkv_test::puppet_functions::retrieve_and_verify_folder( + Simpkv_test::Key $folder, + Variant[Hash[Simpkv_test::Key,Simpkv_test::NonBinaryKeyData],Undef] $expected_keys, + Variant[Array[String[1]],Undef] $expected_folders, + Hash $simpkv_options = {} +) { + + $_message = "simpkv::list('${folder}', ${simpkv_options})" + info("Calling ${_message}") + + $_result = simpkv::list($folder, $simpkv_options) + simpkv_test::verify_folder_data($_result, $expected_keys, $expected_folders, $_message) +} diff --git a/spec/support/modules/simpkv_test/functions/puppet_functions/retrieve_and_verify_key.pp b/spec/support/modules/simpkv_test/functions/puppet_functions/retrieve_and_verify_key.pp new file mode 100644 index 0000000..87b9c03 --- /dev/null +++ b/spec/support/modules/simpkv_test/functions/puppet_functions/retrieve_and_verify_key.pp @@ -0,0 +1,38 @@ +# @summary Puppet language function that calls simpkv::get and validates +# its result. +# +# Fails if validation fails. +# +# @param key +# Name of the key to be retrieved +# +# @param expected_value +# Expected key value +# +# @param expected_metadata +# Expected key metadata +# +# @param simpkv_options +# Value of the simpkv_options parameter to be used in the simpkv::get +# function call +# +# @param binary +# Whether the key has a binary value +# +# @return [None] +# +function simpkv_test::puppet_functions::retrieve_and_verify_key( + Simpkv_test::Key $key, + Any $expected_value, + Variant[Hash,Undef] $expected_metadata, + Hash $simpkv_options, + Boolean $binary +) { + + $_message = "simpkv::get('${key}', ${simpkv_options})" + info("Calling ${_message}") + $_result = simpkv::get($key, $simpkv_options) + + simpkv_test::verify_key_data( $_result, $expected_value, + $expected_metadata, $binary, $_message) +} diff --git a/spec/support/modules/simpkv_test/functions/puppet_functions/store_key.pp b/spec/support/modules/simpkv_test/functions/puppet_functions/store_key.pp new file mode 100644 index 0000000..f9a2577 --- /dev/null +++ b/spec/support/modules/simpkv_test/functions/puppet_functions/store_key.pp @@ -0,0 +1,26 @@ +# @summary Puppet language function that simply calls simpkv::put +# +# @param key +# Name of the key to store +# +# @param value +# Value to store +# +# @param metadata +# Metadata to store +# +# @param simpkv_options +# Value of the simpkv_options parameter to be used in the simpkv::put +# function call +# +# @return [None] +# +function simpkv_test::puppet_functions::store_key( + Simpkv_test::Key $key, + NotUndef $value, + Hash $metadata, + Hash $simpkv_options +) { + info("Calling simpkv::put('${key}', ${value}, ${metadata}, ${simpkv_options})") + simpkv::put($key, $value, $metadata, $simpkv_options) +} diff --git a/spec/support/modules/simpkv_test/functions/puppet_functions/verify_name_exists.pp b/spec/support/modules/simpkv_test/functions/puppet_functions/verify_name_exists.pp new file mode 100644 index 0000000..b6f8d43 --- /dev/null +++ b/spec/support/modules/simpkv_test/functions/puppet_functions/verify_name_exists.pp @@ -0,0 +1,28 @@ +# @summary Puppet language function that calls simpkv::exists and validates +# its result. +# +# Fails if validation fails. +# +# @param key +# Name of the key/folder whose existence is to be checked +# +# @param simpkv_options +# Value of the simpkv_options parameter to be used in the simpkv::exists +# function call +# +# @param valid +# Whether key/folder should exist +# +# @return [None] +# +function simpkv_test::puppet_functions::verify_name_exists( + Simpkv_test::Key $key, + Hash $simpkv_options, + Boolean $valid +) { + + $_message = "simpkv::exists('${key}', ${simpkv_options})" + info("Calling ${_message}") + $_key_exists = simpkv::exists($key, $simpkv_options) + simpkv_test::assert_equal( $_key_exists, $valid, $_message) +} diff --git a/spec/support/modules/simpkv_test/functions/put_pwrapper.pp b/spec/support/modules/simpkv_test/functions/put_pwrapper.pp deleted file mode 100644 index 124aaa9..0000000 --- a/spec/support/modules/simpkv_test/functions/put_pwrapper.pp +++ /dev/null @@ -1,17 +0,0 @@ -# Puppet language wrapper function for simpkv::put -# -# We force the user to pass in options, so that simpkv::put -# doesn't always assume the backend in `default`! -function simpkv_test::put_pwrapper( - String $key, - Any $value, - Hash $options, - Hash $meta = {}, -) { - - # - # Insert application-specific work - # - - simpkv::put($key, $value, $meta, $options) -} diff --git a/spec/support/modules/simpkv_test/functions/simpkv_options.pp b/spec/support/modules/simpkv_test/functions/simpkv_options.pp new file mode 100644 index 0000000..57c2b22 --- /dev/null +++ b/spec/support/modules/simpkv_test/functions/simpkv_options.pp @@ -0,0 +1,45 @@ +# @summary Generates simpkv_options Hash for use in simpkv function calls +# +# @param app_id +# `app_id` to be set in the simpkv_options Hash +# +# - Ignored when an empty string +# +# @param key_type +# The key/folder type +# +# - 'env': key/folder is tied to a Puppet environment +# - 'global': key/folder is global +# +# @param other_options +# Other options to be set in the returned simpkv_options Hash +# +# @return [Hash] +# +function simpkv_test::simpkv_options( + Simpkv_test::AppId $app_id, + Enum['env', 'global'] $key_type, + Hash $other_options = {} +) { + if empty($app_id) { + if $key_type == 'env' { + $_simpkv_options = $other_options + } + else { + $_simpkv_options = $other_options.merge({ 'global' => true }) + } + } + else { + if $key_type == 'env' { + $_simpkv_options = $other_options.merge({ 'app_id' => $app_id }) + } + else { + $_simpkv_options = $other_options.merge({ + 'app_id' => $app_id, + 'global' => true + }) + } + } + + $_simpkv_options +} diff --git a/spec/support/modules/simpkv_test/functions/verify_folder_data.pp b/spec/support/modules/simpkv_test/functions/verify_folder_data.pp new file mode 100644 index 0000000..a725642 --- /dev/null +++ b/spec/support/modules/simpkv_test/functions/verify_folder_data.pp @@ -0,0 +1,42 @@ +# @summary Compare expected and actual folder contents and fail if they differ +# +# @param list_result +# The actual `simpkv::list` result +# +# @param expected_keys +# Expected key data +# +# @param expected_folders +# Expected folder data +# +# @param message +# Explanatory text that is added to the failure message, if the comparison +# fails +# +# @return [None] +# +function simpkv_test::verify_folder_data( + Variant[Hash,Undef] $list_result, + Variant[Hash[Simpkv_test::Key,Simpkv_test::NonBinaryKeyData],Undef] $expected_keys, + Variant[Array[String[1]],Undef] $expected_folders, + String[1] $message +) { + + info("Verifying list data for ${message}") + + if ($expected_keys =~ Undef) or ($expected_folders =~ Undef) { + simpkv_test::assert_equal($list_result, $expected_keys, $message) + } + elsif ($list_result =~ Undef) or !('keys' in $list_result) or !('folders' in $list_result) + { + fail("${message} returned invalid value << ${list_result} >>") + } + else { + $_expected_result = { + 'keys' => $expected_keys, + 'folders' => $expected_folders + } + + simpkv_test::assert_equal($list_result, $_expected_result, $message) + } +} diff --git a/spec/support/modules/simpkv_test/functions/verify_key_data.pp b/spec/support/modules/simpkv_test/functions/verify_key_data.pp new file mode 100644 index 0000000..6d3787a --- /dev/null +++ b/spec/support/modules/simpkv_test/functions/verify_key_data.pp @@ -0,0 +1,59 @@ +# @summary Compare expected and actual key data and fail if they differ +# +# @param get_result +# The actual `simpkv::get` result +# +# @param expected_value +# Expected key value +# +# @param expected_metadata +# Expected key metadata +# +# @param binary +# Whether the key has a binary value +# +# @param message +# Explanatory text that is added to the failure message, if the comparison +# fails +# +# @return [None] +# +function simpkv_test::verify_key_data( + Variant[Hash,Undef] $get_result, + Any $expected_value, + Variant[Hash,Undef] $expected_metadata, + Boolean $binary, + String[1] $message +) { + + info("Verifying key data for ${message}") + + if $expected_value =~ Undef { + simpkv_test::assert_equal($get_result, $expected_value, $message) + } + elsif ($get_result =~ Undef) or !('value' in $get_result) { + fail("${message} returned invalid value << ${get_result} >>") + } + elsif $binary { + $_value_binary = Binary.new($get_result['value'], '%r') + simpkv_test::assert_equal($_value_binary, $expected_value, + "${message} content") + + simpkv_test::assert_equal($get_result['metadata'], $expected_metadata, + "${message} metadata") + } + else { + if $expected_metadata { + $_expected_result = { + 'value' => $expected_value, + 'metadata' => $expected_metadata + } + } + else + { + $_expected_result = { 'value' => $expected_value } + } + + simpkv_test::assert_equal( $get_result, $_expected_result, $message) + } +} diff --git a/spec/support/modules/simpkv_test/manifests/binary_get.pp b/spec/support/modules/simpkv_test/manifests/binary_get.pp deleted file mode 100644 index df095a2..0000000 --- a/spec/support/modules/simpkv_test/manifests/binary_get.pp +++ /dev/null @@ -1,25 +0,0 @@ -class simpkv_test::binary_get( - Binary $test_binary = binary_file('/root/binary_data/input_data'), - Hash $test_meta = { 'some' => 'metadata for binary' } -) { - # Retrieving binary content requires careful handling, as the - # retrieved value is a String encoded in ASCII-8BIT - $_result1 = simpkv::get('from_class/binary') - $_value_binary1 = Binary.new($_result1['value'], '%r') - simpkv_test::assert_equal($_value_binary1, $test_binary, "simpkv::get('from_class/binary') content") - - $_result2 = simpkv::get('from_class/binary_with_meta') - $_value_binary2 = Binary.new($_result2['value'], '%r') - $_meta_binary2 = $_result2['metadata'] - simpkv_test::assert_equal($_value_binary2, $test_binary, "simpkv::get('from_class/binary_with_meta') content") - simpkv_test::assert_equal($_meta_binary2, $test_meta, "simpkv::get('from_class/binary_with_meta' metadata)") - - # persist the binary content for external verification - file { '/root/binary_data/retrieved_data1': - content => $_value_binary1 - } - - file { '/root/binary_data/retrieved_data2': - content => $_value_binary2 - } -} diff --git a/spec/support/modules/simpkv_test/manifests/binary_put.pp b/spec/support/modules/simpkv_test/manifests/binary_put.pp deleted file mode 100644 index a4a8207..0000000 --- a/spec/support/modules/simpkv_test/manifests/binary_put.pp +++ /dev/null @@ -1,7 +0,0 @@ -class simpkv_test::binary_put( - Binary $test_binary = binary_file('/root/binary_data/input_data'), - Hash $test_meta = { 'some' => 'metadata for binary' } -) { - simpkv::put('from_class/binary', $test_binary) - simpkv::put('from_class/binary_with_meta', $test_binary, $test_meta) -} diff --git a/spec/support/modules/simpkv_test/manifests/defines/put.pp b/spec/support/modules/simpkv_test/manifests/defines/put.pp deleted file mode 100644 index 237c1eb..0000000 --- a/spec/support/modules/simpkv_test/manifests/defines/put.pp +++ /dev/null @@ -1,9 +0,0 @@ -define simpkv_test::defines::put( - String $test_string = 'dstring', - Hash $test_meta = {}, - Hash $simpkv_options = { 'app_id' => "Simpkv_test::Defines::Put[${name}]" } -) { - - simpkv::put("from_define/${name}/string", $test_string, $test_meta, $simpkv_options) - simpkv_test::put_pwrapper("from_define/${name}/string_from_pfunction", $test_string, $simpkv_options, $test_meta) -} diff --git a/spec/support/modules/simpkv_test/manifests/defines/remove_folder.pp b/spec/support/modules/simpkv_test/manifests/defines/remove_folder.pp new file mode 100644 index 0000000..9e0259f --- /dev/null +++ b/spec/support/modules/simpkv_test/manifests/defines/remove_folder.pp @@ -0,0 +1,17 @@ +# @summary Define that simply calls simpkv::deletetree +# +# @param folder +# Name of the folder to remove +# +# @param simpkv_options +# Value of the simpkv_options parameter to be used in the simpkv::deletetree +# function call +# +define simpkv_test::defines::remove_folder( + Simpkv_test::Key $folder, + Hash $simpkv_options = {} +) { + + info("Calling simpkv::deletetree('${folder}', ${simpkv_options})") + simpkv::deletetree($folder, $simpkv_options) +} diff --git a/spec/support/modules/simpkv_test/manifests/defines/remove_key.pp b/spec/support/modules/simpkv_test/manifests/defines/remove_key.pp new file mode 100644 index 0000000..88dc992 --- /dev/null +++ b/spec/support/modules/simpkv_test/manifests/defines/remove_key.pp @@ -0,0 +1,17 @@ +# @summary Define that simply calls simpkv::delete +# +# @param key +# Name of the key to remove +# +# @param simpkv_options +# Value of the simpkv_options parameter to be used in the simpkv::delete +# function call +# +define simpkv_test::defines::remove_key( + Simpkv_test::Key $key, + Hash $simpkv_options = {} +) { + + info("Calling simpkv::delete('${key}', ${simpkv_options})") + simpkv::delete($key, $simpkv_options) +} diff --git a/spec/support/modules/simpkv_test/manifests/defines/retrieve_and_verify_folder.pp b/spec/support/modules/simpkv_test/manifests/defines/retrieve_and_verify_folder.pp new file mode 100644 index 0000000..a95e99d --- /dev/null +++ b/spec/support/modules/simpkv_test/manifests/defines/retrieve_and_verify_folder.pp @@ -0,0 +1,30 @@ +# @summary Define that calls simpkv::list and validates its result +# +# Fails if validation fails. +# +# @param folder +# Name of the folder to be listed +# +# @param expected_keys +# Expected key data +# +# @param expected_folders +# Expected folder data +# +# @param simpkv_options +# Value of the simpkv_options parameter to be used in the simpkv::list +# function call +# +define simpkv_test::defines::retrieve_and_verify_folder( + Simpkv_test::Key $folder, + Variant[Hash[Simpkv_test::Key,Simpkv_test::NonBinaryKeyData],Undef] $expected_keys, + Variant[Array[String[1]],Undef] $expected_folders, + Hash $simpkv_options = {} +) { + + $_message = "simpkv::list('${folder}', ${simpkv_options})" + info("Calling ${_message}") + + $_result = simpkv::list($folder, $simpkv_options) + simpkv_test::verify_folder_data($_result, $expected_keys, $expected_folders, $_message) +} diff --git a/spec/support/modules/simpkv_test/manifests/defines/retrieve_and_verify_key.pp b/spec/support/modules/simpkv_test/manifests/defines/retrieve_and_verify_key.pp new file mode 100644 index 0000000..b3ca359 --- /dev/null +++ b/spec/support/modules/simpkv_test/manifests/defines/retrieve_and_verify_key.pp @@ -0,0 +1,34 @@ +# @summary Define that calls simpkv::get and validates its result +# +# Fails if validation fails. +# +# @param key +# Name of the key to be retrieved +# +# @param expected_value +# Expected key value +# +# @param expected_metadata +# Expected key metadata +# +# @param simpkv_options +# Value of the simpkv_options parameter to be used in the simpkv::get +# function call +# +# @param binary +# Whether the key has a binary value +# +define simpkv_test::defines::retrieve_and_verify_key( + Simpkv_test::Key $key, + Any $expected_value, + Variant[Hash,Undef] $expected_metadata, + Hash $simpkv_options, + Boolean $binary +) { + + $_message = "simpkv::get('${key}', ${simpkv_options})" + info("Calling ${_message}") + $_result = simpkv::get($key, $simpkv_options) + simpkv_test::verify_key_data($_result, $expected_value, + $expected_metadata, $binary, $_message) +} diff --git a/spec/support/modules/simpkv_test/manifests/defines/store_key.pp b/spec/support/modules/simpkv_test/manifests/defines/store_key.pp new file mode 100644 index 0000000..8e7a18f --- /dev/null +++ b/spec/support/modules/simpkv_test/manifests/defines/store_key.pp @@ -0,0 +1,25 @@ +# @summary Define that simply calls simpkv::put +# +# @param key +# Name of the key to store +# +# @param value +# Value to store +# +# @param metadata +# Metadata to store +# +# @param simpkv_options +# Value of the simpkv_options parameter to be used in the simpkv::put +# function call +# +define simpkv_test::defines::store_key( + Simpkv_test::Key $key, + NotUndef $value, + Hash $metadata = {}, + Hash $simpkv_options = {} +) { + + info("Calling simpkv::put('${key}', ${value}, ${metadata}, ${simpkv_options})") + simpkv::put($key, $value, $metadata, $simpkv_options) +} diff --git a/spec/support/modules/simpkv_test/manifests/defines/verify_name_exists.pp b/spec/support/modules/simpkv_test/manifests/defines/verify_name_exists.pp new file mode 100644 index 0000000..7f1c997 --- /dev/null +++ b/spec/support/modules/simpkv_test/manifests/defines/verify_name_exists.pp @@ -0,0 +1,26 @@ +# @summary Define that calls simpkv::exists and validates its result +# +# Fails if validation fails. +# +# @param key +# Name of the key/folder whose existence is to be checked +# +# @param simpkv_options +# Value of the simpkv_options parameter to be used in the simpkv::exists +# function call +# +# @param valid +# Whether key/folder should exist +# +# @return [None] +# +define simpkv_test::defines::verify_name_exists( + Simpkv_test::Key $key, + Hash $simpkv_options = {}, + Boolean $valid +) { + $_message = "simpkv::exists('${key}', ${simpkv_options})" + info("Calling ${_message}") + $_key_exists = simpkv::exists($key, $simpkv_options) + simpkv_test::assert_equal($_key_exists, $valid, $_message) +} diff --git a/spec/support/modules/simpkv_test/manifests/delete.pp b/spec/support/modules/simpkv_test/manifests/delete.pp deleted file mode 100644 index d41ee47..0000000 --- a/spec/support/modules/simpkv_test/manifests/delete.pp +++ /dev/null @@ -1,48 +0,0 @@ -# Delete a subset of keys from the backend mapped to an app_id and verify -# only those keys were deleted -class simpkv_test::delete inherits simpkv_test::params -{ - # Delete Puppet env keys without metadata for the specified app_id - $simpkv_test::params::key_value_pairs.each |$key, $value| { - simpkv::delete($key, $simpkv_test::params::simpkv_options) - } - - # Verify Puppet env keys without metadata no longer exist for the specified - # app_id - $simpkv_test::params::key_value_pairs.each |$key, $value| { - simpkv_test::assert_equal( - simpkv::exists($key, $simpkv_test::params::simpkv_options), - false, - "simpkv::exists('${key}', ${simpkv_test::params::simpkv_options})" - ) - } - - # Verify global keys without still exist for the specified app_id - $simpkv_test::params::key_value_pairs.each |$key, $value| { - simpkv_test::assert_equal( - simpkv::exists($key, $simpkv_test::params::simpkv_global_options), - true, - "simpkv::exists('${key}', ${simpkv_test::params::simpkv_global_options})" - ) - } - - # Verify Puppet env keys with metadata still exist for the specified app_id - $simpkv_test::params::key_value_pairs.each |$key, $value| { - simpkv_test::assert_equal( - simpkv::exists("${key}_with_meta", $simpkv_test::params::simpkv_options), - true, - "simpkv::exists('${key}_with_meta', ${simpkv_test::params::simpkv_options})" - ) - } - - # Verify the Puppet env key added in a Puppet function call for the specified - # app_id still exists - simpkv_test::assert_equal( - simpkv::exists( - "${simpkv_test::params::test_keydir}/boolean_from_pfunction", - $simpkv_test::params::simpkv_options - ), - true, - "simpkv::exists('${simpkv_test::params::test_keydir}}/boolean_from_pfunction',${simpkv_test::params::simpkv_options})" - ) -} diff --git a/spec/support/modules/simpkv_test/manifests/deletetree.pp b/spec/support/modules/simpkv_test/manifests/deletetree.pp deleted file mode 100644 index 0950c0d..0000000 --- a/spec/support/modules/simpkv_test/manifests/deletetree.pp +++ /dev/null @@ -1,44 +0,0 @@ -# Delete parent dirs of Puppet env and global keys from the backend mapped to -# an app_id and verify all keys were deleted -class simpkv_test::deletetree inherits simpkv_test::params -{ - # Delete parent dir of global keys for the specified app_id - simpkv::deletetree($simpkv_test::params::test_keydir, $simpkv_test::params::simpkv_global_options) - - # Verify global keys no longer exist for the specified app_id - $simpkv_test::params::key_value_pairs.each |$key, $value| { - simpkv_test::assert_equal( - simpkv::exists($key, $simpkv_test::params::simpkv_global_options), - false, - "simpkv::exists('${key}', ${simpkv_test::params::simpkv_global_options})" - ) - } - - # Delete parent dir of Puppet env keys for the specified app_id - simpkv::deletetree($simpkv_test::params::test_keydir, $simpkv_test::params::simpkv_options) - - # Verify Puppet env keys with and without metadata no longer exist for the specified app_id - $simpkv_test::params::key_value_pairs.each |$key, $value| { - simpkv_test::assert_equal( - simpkv::exists($key, $simpkv_test::params::simpkv_options), - false, - "simpkv::exists('${key}', ${simpkv_test::params::simpkv_options})" - ) - - simpkv_test::assert_equal( - simpkv::exists("${key}_with_meta", $simpkv_test::params::simpkv_options), - false, - "simpkv::exists('${key}_with_meta', ${simpkv_test::params::simpkv_options})" - ) - } - - # Verify the key added in own Puppet function call for the specified app_id no longer exists - simpkv_test::assert_equal( - simpkv::exists( - "${simpkv_test::params::test_keydir}/boolean_from_pfunction", - $simpkv_test::params::simpkv_options - ), - false, - "simpkv::exists('${simpkv_test::params::test_keydir}}/boolean_from_pfunction',${simpkv_test::params::simpkv_options})" - ) -} diff --git a/spec/support/modules/simpkv_test/manifests/exists.pp b/spec/support/modules/simpkv_test/manifests/exists.pp deleted file mode 100644 index 782b53b..0000000 --- a/spec/support/modules/simpkv_test/manifests/exists.pp +++ /dev/null @@ -1,55 +0,0 @@ -# Check for the existance of keys stored via the simpkv_test::put Class -# -# FIXME: Not checking keys from simpkv_test::defines::put Defines -# -class simpkv_test::exists inherits simpkv_test::params -{ - # Check for keys with and without metadata for the specified app_id - $simpkv_test::params::key_value_pairs.each |$key, $value| { - # Puppet env keys without metadata - simpkv_test::assert_equal( - simpkv::exists($key, $simpkv_test::params::simpkv_options), - true, - "simpkv::exists('${key}', ${simpkv_test::params::simpkv_options})" - ) - - # Puppet env keys witht metadata - simpkv_test::assert_equal( - simpkv::exists("${key}_with_meta", $simpkv_test::params::simpkv_options), - true, - "simpkv::exists('${key}_with_meta', ${simpkv_test::params::simpkv_options})" - ) - - # global keys without metadata - simpkv_test::assert_equal( - simpkv::exists("${key}", $simpkv_test::params::simpkv_global_options), - true, - "simpkv::exists('${key}_with_meta', ${simpkv_test::params::simpkv_global_options})" - ) - } - - - # Check for the Puppet env key added in a Puppet function call for the - # specified app_id. - simpkv_test::assert_equal( - simpkv::exists( - "${simpkv_test::params::test_keydir}/boolean_from_pfunction", - $simpkv_test::params::simpkv_options - ), - true, - "simpkv::exists('${simpkv_test::params::test_keydir}}/boolean_from_pfunction', ${simpkv_test::params::simpkv_options})" - ) - - # Check for the Puppet env key added in a Puppet function call without the - # specified app_id. Should be in default backend but not the backend for the - # app_id. - $_empty_simpkv_options = {} - simpkv_test::assert_equal( - simpkv::exists( - "${simpkv_test::params::test_keydir}/boolean_from_pfunction_no_app_id", - $_empty_simpkv_options - ), - true, - "simpkv::exists('${simpkv_test::params::test_keydir}}/boolean_from_pfunction_no_appid')" - ) -} diff --git a/spec/support/modules/simpkv_test/manifests/get.pp b/spec/support/modules/simpkv_test/manifests/get.pp deleted file mode 100644 index 252476f..0000000 --- a/spec/support/modules/simpkv_test/manifests/get.pp +++ /dev/null @@ -1,36 +0,0 @@ -class simpkv_test::get inherits simpkv_test::params -{ - $_empty_test_meta = {} - $simpkv_test::params::key_value_pairs.each |$key, $value| { - # Get and verify Puppet env keys without metadata for the specified app_id - simpkv_test::assert_equal( - simpkv::get($key, $simpkv_test::params::simpkv_options), - { 'value' => $value }, - "simpkv::get('${key}', ${simpkv_test::params::simpkv_options})" - ) - - # Get and verify global keys without metadata for the specified app_id - simpkv_test::assert_equal( - simpkv::get($key, $simpkv_test::params::simpkv_global_options), - { 'value' => $value }, - "simpkv::get('${key}', ${simpkv_test::params::simpkv_global_options})" - ) - - # Get and verify Puppet env keys with metadata for the specified app_id - simpkv_test::assert_equal( - simpkv::get("${key}_with_meta", $simpkv_test::params::simpkv_options), - { 'value' => $value, 'metadata' => $simpkv_test::params::test_meta }, - "simpkv::get('${key}_with_meta',${simpkv_test::params::simpkv_options})" - ) - } - - # Get key added in own Puppet function call for the specified app_id - simpkv_test::assert_equal( - simpkv::get( - "${simpkv_test::params::test_keydir}/boolean_from_pfunction", - $simpkv_test::params::simpkv_options - ), - { 'value' => $simpkv_test::params::test_bool }, - "simpkv::get('${simpkv_test::params::test_keydir}/boolean_from_pfunction',${simpkv_test::params::simpkv_options})" - ) -} diff --git a/spec/support/modules/simpkv_test/manifests/list.pp b/spec/support/modules/simpkv_test/manifests/list.pp deleted file mode 100644 index e838c25..0000000 --- a/spec/support/modules/simpkv_test/manifests/list.pp +++ /dev/null @@ -1,79 +0,0 @@ -# List most of the keys/folders stored via the simpkv_test::put Class -# -# FIXME: -# - Not checking for keys without an app_id from simpkv_test::put -# - Not checking keys from simpkv_test::defines::put Defines -class simpkv_test::list inherits simpkv_test::params -{ - $_expected_env = { - 'keys' => { - basename($simpkv_test::params::test_bool_key) => { 'value' => $simpkv_test::params::test_bool }, - basename($simpkv_test::params::test_string_key) => { 'value' => $simpkv_test::params::test_string }, - basename($simpkv_test::params::test_integer_key) => { 'value' => $simpkv_test::params::test_integer }, - basename($simpkv_test::params::test_float_key) => { 'value' => $simpkv_test::params::test_float }, - basename($simpkv_test::params::test_array_strings_key) => { 'value' => $simpkv_test::params::test_array_strings }, - basename($simpkv_test::params::test_array_integers_key) => { 'value' => $simpkv_test::params::test_array_integers }, - basename($simpkv_test::params::test_hash_key) => { 'value' => $simpkv_test::params::test_hash }, - - basename("${simpkv_test::params::test_bool_key}_with_meta") => { 'value' => $simpkv_test::params::test_bool, 'metadata' => $simpkv_test::params::test_meta }, - basename("${simpkv_test::params::test_string_key}_with_meta") => { 'value' => $simpkv_test::params::test_string, 'metadata' => $simpkv_test::params::test_meta }, - basename("${simpkv_test::params::test_integer_key}_with_meta") => { 'value' => $simpkv_test::params::test_integer, 'metadata' => $simpkv_test::params::test_meta }, - basename("${simpkv_test::params::test_float_key}_with_meta") => { 'value' => $simpkv_test::params::test_float, 'metadata' => $simpkv_test::params::test_meta }, - basename("${simpkv_test::params::test_array_strings_key}_with_meta") => { 'value' => $simpkv_test::params::test_array_strings, 'metadata' => $simpkv_test::params::test_meta }, - basename("${simpkv_test::params::test_array_integers_key}_with_meta") => { 'value' => $simpkv_test::params::test_array_integers, 'metadata' => $simpkv_test::params::test_meta }, - basename("${simpkv_test::params::test_hash_key}_with_meta") => { 'value' => $simpkv_test::params::test_hash, 'metadata' => $simpkv_test::params::test_meta }, - - 'boolean_from_pfunction' => { 'value' => $simpkv_test::params::test_bool } - }, - 'folders' => [] - } - - simpkv_test::assert_equal( - simpkv::list($simpkv_test::params::test_keydir, $simpkv_test::params::simpkv_options), - $_expected_env, - "simpkv::list('${simpkv_test::params::test_keydir}', ${simpkv_test::params::simpkv_options})" - ) - - $_expected_global = { - 'keys' => { - basename($simpkv_test::params::test_bool_key) => { 'value' => $simpkv_test::params::test_bool }, - basename($simpkv_test::params::test_string_key) => { 'value' => $simpkv_test::params::test_string }, - basename($simpkv_test::params::test_integer_key) => { 'value' => $simpkv_test::params::test_integer }, - basename($simpkv_test::params::test_float_key) => { 'value' => $simpkv_test::params::test_float }, - basename($simpkv_test::params::test_array_strings_key) => { 'value' => $simpkv_test::params::test_array_strings }, - basename($simpkv_test::params::test_array_integers_key) => { 'value' => $simpkv_test::params::test_array_integers }, - basename($simpkv_test::params::test_hash_key) => { 'value' => $simpkv_test::params::test_hash } - }, - 'folders' => [] - } - - simpkv_test::assert_equal( - simpkv::list($simpkv_test::params::test_keydir, $simpkv_test::params::simpkv_global_options), - $_expected_global, - "simpkv::list('${simpkv_test::params::test_keydir}', ${simpkv_test::params::simpkv_global_options})" - ) - - # top level list for the Puppet env of the simpkv backend specified by - # $simpkv_test::params::simpkv_options - simpkv_test::assert_equal( - simpkv::list('/', $simpkv_test::params::simpkv_options), - {keys => {}, folders => [ $simpkv_test::params::test_keydir ]}, - "simpkv::list('/', ${simpkv_test::params::simpkv_options})" - ) - - # top level list for global keys of the simpkv backend specified by - # $simpkv_test::params::simpkv_options - simpkv_test::assert_equal( - simpkv::list('/', $simpkv_test::params::simpkv_global_options), - {keys => {}, folders => [ $simpkv_test::params::test_keydir ]}, - "simpkv::list('/', ${simpkv_test::params::simpkv_global_options})" - ) - - # top level list for global keys for default backend - $_default_global_options = { 'global' => true } - simpkv_test::assert_equal( - simpkv::list('/', $_default_global_options), - {keys => {}, folders => []}, - "simpkv::list('/', ${_default_global_options})" - ) -} diff --git a/spec/support/modules/simpkv_test/manifests/params.pp b/spec/support/modules/simpkv_test/manifests/params.pp deleted file mode 100644 index 717e95f..0000000 --- a/spec/support/modules/simpkv_test/manifests/params.pp +++ /dev/null @@ -1,33 +0,0 @@ -# This class sets key/value parameters used in simpkv_test manifests. -class simpkv_test::params ( - String $test_keydir = 'from_class', - String $test_bool_key = "${test_keydir}/boolean", - String $test_string_key = "${test_keydir}/string", - String $test_integer_key = "${test_keydir}/integer", - String $test_float_key = "${test_keydir}/float", - String $test_array_strings_key = "${test_keydir}/array_strings", - String $test_array_integers_key = "${test_keydir}/array_integers", - String $test_hash_key = "${test_keydir}/hash", - - Boolean $test_bool = true, - String $test_string = 'string1', - Integer $test_integer = 123, - Float $test_float = 4.567, - Array $test_array_strings = ['string2', 'string3' ], - Array[Integer] $test_array_integers = [ 8, 9, 10], - Hash $test_hash = { 'key1' => 'string4', 'key2' => 11, - 'key3' => false, 'key4' => { 'nkey1' => 'string5', 'nkey2' => true, 'nkey3' => 12 } }, - - Hash $key_value_pairs = { $test_bool_key => $test_bool, - $test_string_key => $test_string, - $test_integer_key => $test_integer, - $test_float_key => $test_float, - $test_array_strings_key => $test_array_strings, - $test_array_integers_key => $test_array_integers, - $test_hash_key => $test_hash }, - - Hash $test_meta = { 'some' => 'metadata' }, - String $app_id = 'simpkv_test_class', - Hash $simpkv_options = { 'app_id' => $app_id }, - Hash $simpkv_global_options = { 'app_id' => $app_id, 'global' => true } -) { } diff --git a/spec/support/modules/simpkv_test/manifests/put.pp b/spec/support/modules/simpkv_test/manifests/put.pp deleted file mode 100644 index 66fd270..0000000 --- a/spec/support/modules/simpkv_test/manifests/put.pp +++ /dev/null @@ -1,45 +0,0 @@ -class simpkv_test::put inherits simpkv_test::params -{ - $_empty_test_meta = {} - $simpkv_test::params::key_value_pairs.each |$key, $value| { - # Add Puppet env keys without metadata for the specified app_id - simpkv::put( - $key, - $value, - $_empty_test_meta, - $simpkv_test::params::simpkv_options - ) - - # Add Puppet env keys with metadata for the specified app_id - simpkv::put( - "${key}_with_meta", - $value, - $simpkv_test::params::test_meta, - $simpkv_test::params::simpkv_options - ) - - # Add global env keys without metadata for the specified app_id - simpkv::put( - $key, - $value, - $_empty_test_meta, - $simpkv_test::params::simpkv_global_options - ) - } - - # Add Puppet env key within a Puppet function call for the specified app_id. - simpkv_test::put_pwrapper( - "${simpkv_test::params::test_keydir}/boolean_from_pfunction", - $simpkv_test::params::test_bool, - $simpkv_test::params::simpkv_options - ) - - # Add Puppet env key within a Puppet function call but without the app_id. - # This key will be stored in the default backend. - $_empty_simpkv_options = {} - simpkv_test::put_pwrapper( - "${simpkv_test::params::test_keydir}/boolean_from_pfunction_no_app_id", - $simpkv_test::params::test_bool, - $_empty_simpkv_options - ) -} diff --git a/spec/support/modules/simpkv_test/manifests/remove_folders.pp b/spec/support/modules/simpkv_test/manifests/remove_folders.pp new file mode 100644 index 0000000..e12ad77 --- /dev/null +++ b/spec/support/modules/simpkv_test/manifests/remove_folders.pp @@ -0,0 +1,34 @@ +# @summary Remove folders using simpkv::deletetree +# +# @param foldername_info +# Info specifying the names of the folders to remove +# +class simpkv_test::remove_folders ( + Simpkv_test::NameInfo $foldername_info +) { + + $foldername_info.each |$app_id, $folder_struct| { + $folder_struct.each |$folder_type, $foldernames| { + $_simpkv_options = simpkv_test::simpkv_options($app_id, $folder_type) + + $foldernames.each |$folder| { + $_unique_id = "${app_id}_${folder_type}_${folder}" + case simpkv_test::code_source($_unique_id) { + 'class': { + info("Calling simpkv::deletetree('${folder}', ${_simpkv_options})") + simpkv::deletetree($folder, $_simpkv_options) + } + 'define': { + simpkv_test::defines::remove_folder { $_unique_id: + folder => $folder, + simpkv_options => $_simpkv_options + } + } + 'puppet_function': { + simpkv_test::puppet_functions::remove_folder($folder, $_simpkv_options) + } + } + } + } + } +} diff --git a/spec/support/modules/simpkv_test/manifests/remove_keys.pp b/spec/support/modules/simpkv_test/manifests/remove_keys.pp new file mode 100644 index 0000000..df2363e --- /dev/null +++ b/spec/support/modules/simpkv_test/manifests/remove_keys.pp @@ -0,0 +1,34 @@ +# @summary Remove keys using simpkv::delete +# +# @param keyname_info +# Info specifying the names of keys to remove +# +class simpkv_test::remove_keys ( + Simpkv_test::NameInfo $keyname_info +) { + + $keyname_info.each |$app_id, $key_struct| { + $key_struct.each |$key_type, $keynames| { + $_simpkv_options = simpkv_test::simpkv_options($app_id, $key_type) + + $keynames.each |$key| { + $_unique_id = "${app_id}_${key_type}_${key}" + case simpkv_test::code_source($_unique_id) { + 'class': { + info("Calling simpkv::delete('${key}', ${_simpkv_options})") + simpkv::delete($key, $_simpkv_options) + } + 'define': { + simpkv_test::defines::remove_key { $_unique_id: + key => $key, + simpkv_options => $_simpkv_options + } + } + 'puppet_function': { + simpkv_test::puppet_functions::remove_key($key, $_simpkv_options) + } + } + } + } + } +} diff --git a/spec/support/modules/simpkv_test/manifests/retrieve_and_verify_folders.pp b/spec/support/modules/simpkv_test/manifests/retrieve_and_verify_folders.pp new file mode 100644 index 0000000..a862046 --- /dev/null +++ b/spec/support/modules/simpkv_test/manifests/retrieve_and_verify_folders.pp @@ -0,0 +1,83 @@ +# @summary Retrieve folder lists with simpkv::list and verify the result +# +# @param valid_folder_info +# Info specifying folders that are expected to be present in the +# keystore and their contents +# +# @param invalid_folder_info +# Info specifying folders that are not expected to be present in +# the keystore +# +class simpkv_test::retrieve_and_verify_folders ( + Simpkv_test::FolderInfo $valid_folder_info, + Simpkv_test::FolderInfo $invalid_folder_info +) { + $valid_folder_info.each |$app_id, $folder_struct| { + $folder_struct.each |$folder_type, $folders| { + $_simpkv_options = simpkv_test::simpkv_options($app_id, $folder_type) + + $folders.each |$folder, $folder_data| { + $_expected_keys = pick($folder_data['keys'], {}) + $_expected_folders = pick($folder_data['folders'], []) + $_unique_id = "${app_id}_${folder_type}_${folder}" + case simpkv_test::code_source($_unique_id) { + 'class': { + $_message = "simpkv::list('${folder}', ${_simpkv_options})" + info("Calling ${_message}") + $_result = simpkv::list($folder, $_simpkv_options) + simpkv_test::verify_folder_data($_result, $_expected_keys, + $_expected_folders, $_message) + } + 'define': { + simpkv_test::defines::retrieve_and_verify_folder { $_unique_id: + folder => $folder, + expected_keys => $_expected_keys, + expected_folders => $_expected_folders, + simpkv_options => $_simpkv_options + } + } + 'puppet_function': { + simpkv_test::puppet_functions::retrieve_and_verify_folder($folder, + $_expected_keys, $_expected_folders, $_simpkv_options) + } + } + } + } + } + + $invalid_folder_info.each |$app_id, $folder_struct| { + $folder_struct.each |$folder_type, $folders| { + # Enable 'softfail', so failure returns Undef instead of failing catalog + # compilation + $_simpkv_options = simpkv_test::simpkv_options($app_id, $folder_type, + { 'softfail' => true }) + + $folders.each |$folder, $folder_data| { + $_expected_keys = undef + $_expected_folders = undef + $_unique_id = "${app_id}_${folder_type}_${folder}" + case simpkv_test::code_source($_unique_id) { + 'class': { + $_message = "simpkv::list('${folder}', ${_simpkv_options})" + info("Calling ${_message}") + $_result = simpkv::list($folder, $_simpkv_options) + simpkv_test::verify_folder_data( $_result, $_expected_keys, + $_expected_folders, $_message) + } + 'define': { + simpkv_test::defines::retrieve_and_verify_folder { $_unique_id: + folder => $folder, + expected_keys => $_expected_keys, + expected_folders => $_expected_folders, + simpkv_options => $_simpkv_options + } + } + 'puppet_function': { + simpkv_test::puppet_functions::retrieve_and_verify_folder( + $folder, $_expected_keys, $_expected_folders, $_simpkv_options) + } + } + } + } + } +} diff --git a/spec/support/modules/simpkv_test/manifests/retrieve_and_verify_keys.pp b/spec/support/modules/simpkv_test/manifests/retrieve_and_verify_keys.pp new file mode 100644 index 0000000..f599708 --- /dev/null +++ b/spec/support/modules/simpkv_test/manifests/retrieve_and_verify_keys.pp @@ -0,0 +1,95 @@ +# @summary Retrieve keys with simpkv::get and verifies the results +# +# @param valid_key_info +# Info specifying keys that are expected to be present in the +# keystore and their stored data +# +# @param invalid_key_info +# Info specifying keys that are not expected to be present in the +# keystore +# +class simpkv_test::retrieve_and_verify_keys ( + Simpkv_test::KeyInfo $valid_key_info, + Simpkv_test::KeyInfo $invalid_key_info +) { + + $valid_key_info.each |$app_id, $key_struct| { + $key_struct.each |$key_type, $keys| { + $_simpkv_options = simpkv_test::simpkv_options($app_id, $key_type) + + $keys.each |$key, $key_data| { + $_expected_value = simpkv_test::key_value($key_data) + if $_expected_value =~ Undef { + warning("Skipping '${app_id}' '${key_type}' key '${key}': Value not found in << ${key_data} >>") + next + } + + $_binary = ($_expected_value =~ Binary) + $_expected_metadata = $key_data['metadata'] + + $_unique_id = "${app_id}_${key_type}_${key}" + case simpkv_test::code_source($_unique_id) { + 'class': { + $_message = "simpkv::get('${key}', ${_simpkv_options})" + info("Calling ${_message}") + $_result = simpkv::get($key, $_simpkv_options) + simpkv_test::verify_key_data($_result, $_expected_value, + $_expected_metadata, $_binary, $_message) + } + 'define': { + simpkv_test::defines::retrieve_and_verify_key { $_unique_id: + key => $key, + expected_value => $_expected_value, + expected_metadata => $_expected_metadata, + simpkv_options => $_simpkv_options, + binary => $_binary + } + } + 'puppet_function': { + simpkv_test::puppet_functions::retrieve_and_verify_key($key, + $_expected_value, $_expected_metadata, $_simpkv_options, $_binary) + } + } + } + } + } + + $invalid_key_info.each |$app_id, $key_struct| { + $key_struct.each |$key_type, $keys| { + # Enable 'softfail', so failure returns Undef instead of failing catalog + # compilation + $_simpkv_options = simpkv_test::simpkv_options($app_id, $key_type, + { 'softfail' => true }) + + $keys.each |$key, $key_data| { + $_expected_value = undef + $_expected_metadata = undef + $_binary = false # value doesn't matter + + $_unique_id = "${app_id}_${key_type}_${key}" + case simpkv_test::code_source($_unique_id) { + 'class': { + $_message = "simpkv::get('${key}', ${_simpkv_options})" + info("Calling ${_message}") + $_result = simpkv::get($key, $_simpkv_options) + simpkv_test::verify_key_data($_result, $_expected_value, + $_expected_metadata, $_binary, $_message) + } + 'define': { + simpkv_test::defines::retrieve_and_verify_key { $_unique_id: + key => $key, + expected_value => $_expected_value, + expected_metadata => $_expected_metadata, + simpkv_options => $_simpkv_options, + binary => $_binary + } + } + 'puppet_function': { + simpkv_test::puppet_functions::retrieve_and_verify_key($key, + $_expected_value, $_expected_metadata, $_simpkv_options, $_binary) + } + } + } + } + } +} diff --git a/spec/support/modules/simpkv_test/manifests/store_keys.pp b/spec/support/modules/simpkv_test/manifests/store_keys.pp new file mode 100644 index 0000000..2753b76 --- /dev/null +++ b/spec/support/modules/simpkv_test/manifests/store_keys.pp @@ -0,0 +1,44 @@ +# @summary Store keys using simpkv::put +# +# @param key_info +# Info specifying the key names and data to be stored +# +class simpkv_test::store_keys ( + Simpkv_test::KeyInfo $key_info +) { + + $key_info.each |$app_id, $key_struct| { + $key_struct.each |$key_type, $keys| { + $_simpkv_options = simpkv_test::simpkv_options($app_id, $key_type) + + $keys.each |$key, $key_data| { + $_value = simpkv_test::key_value($key_data) + if $_value =~ Undef { + warning("Skipping '${app_id}' '${key_type}' key '${key}': Value not found in << ${key_data} >>") + next + } + + $_metadata = pick($key_data['metadata'], {}) + $_unique_id = "${app_id}_${key_type}_${key}" + case simpkv_test::code_source($_unique_id) { + 'class': { + info("Calling simpkv::put('${key}', ${_value}, ${_metadata}, ${_simpkv_options})") + simpkv::put($key, $_value, $_metadata, $_simpkv_options) + } + 'define': { + simpkv_test::defines::store_key { $_unique_id: + key => $key, + value => $_value, + metadata => $_metadata, + simpkv_options => $_simpkv_options + } + } + 'puppet_function': { + simpkv_test::puppet_functions::store_key($key, $_value, $_metadata, + $_simpkv_options) + } + } + } + } + } +} diff --git a/spec/support/modules/simpkv_test/manifests/verify_folders_exist.pp b/spec/support/modules/simpkv_test/manifests/verify_folders_exist.pp new file mode 100644 index 0000000..312e281 --- /dev/null +++ b/spec/support/modules/simpkv_test/manifests/verify_folders_exist.pp @@ -0,0 +1,51 @@ +# @summary Check for the existence of folders using simpkv::exists +# +# @param valid_foldername_info +# Info specifying names of folder that are expected to be present in the +# keystore +# +# @param invalid_foldername_info +# Info specifying names of folder that are not expected to be present in +# the keystore +# +class simpkv_test::verify_folders_exist ( + Simpkv_test::NameInfo $valid_foldername_info, + Simpkv_test::NameInfo $invalid_foldername_info +) { + + $_folders_to_check = { + true => $valid_foldername_info, + false => $invalid_foldername_info + } + + $_folders_to_check.each |$valid, $folder_info| { + $folder_info.each |$app_id, $folder_struct| { + $folder_struct.each |$folder_type, $foldernames| { + $_simpkv_options = simpkv_test::simpkv_options($app_id, $folder_type) + + $foldernames.each |$folder| { + $_unique_id = "${app_id}_${folder_type}_${folder}" + case simpkv_test::code_source($_unique_id) { + 'class': { + $_message = "simpkv::exists('${folder}', ${_simpkv_options})" + info("Calling ${_message}") + $_folder_exists = simpkv::exists($folder, $_simpkv_options) + simpkv_test::assert_equal($_folder_exists, $valid, $_message) + } + 'define': { + simpkv_test::defines::verify_name_exists{ $_unique_id: + key => $folder, + simpkv_options => $_simpkv_options, + valid => $valid + } + } + 'puppet_function': { + simpkv_test::puppet_functions::verify_name_exists($folder, + $_simpkv_options, $valid) + } + } + } + } + } + } +} diff --git a/spec/support/modules/simpkv_test/manifests/verify_keys_exist.pp b/spec/support/modules/simpkv_test/manifests/verify_keys_exist.pp new file mode 100644 index 0000000..1c96cb9 --- /dev/null +++ b/spec/support/modules/simpkv_test/manifests/verify_keys_exist.pp @@ -0,0 +1,51 @@ +# @summary Check for the existence of keys using simpkv::exists +# +# @param valid_keyname_info +# Info specifying names of keys that are expected to be present in the +# keystore +# +# @param invalid_keyname_info +# Info specifying names of keys that are not expected to be present in +# the keystore +# +class simpkv_test::verify_keys_exist ( + Simpkv_test::NameInfo $valid_keyname_info, + Simpkv_test::NameInfo $invalid_keyname_info +) { + + $_keys_to_check = { + true => $valid_keyname_info, + false => $invalid_keyname_info + } + + $_keys_to_check.each |$valid, $key_info| { + $key_info.each |$app_id, $key_struct| { + $key_struct.each |$key_type, $keynames| { + $_simpkv_options = simpkv_test::simpkv_options($app_id, $key_type) + + $keynames.each |$key| { + $_unique_id = "${app_id}_${key_type}_${key}" + case simpkv_test::code_source($_unique_id) { + 'class': { + $_message = "simpkv::exists('${key}', ${_simpkv_options})" + info("Calling ${_message}") + $_key_exists = simpkv::exists($key, $_simpkv_options) + simpkv_test::assert_equal( $_key_exists, $valid, $_message) + } + 'define': { + simpkv_test::defines::verify_name_exists{ $_unique_id: + key => $key, + simpkv_options => $_simpkv_options, + valid => $valid + } + } + 'puppet_function': { + simpkv_test::puppet_functions::verify_name_exists($key, + $_simpkv_options, $valid) + } + } + } + } + } + } +} diff --git a/spec/support/modules/simpkv_test/metadata.json b/spec/support/modules/simpkv_test/metadata.json index 964388d..021a2ac 100644 --- a/spec/support/modules/simpkv_test/metadata.json +++ b/spec/support/modules/simpkv_test/metadata.json @@ -1,8 +1,8 @@ { "name": "simp-simpkv_test", - "version": "1.0.0", + "version": "2.0.0", "author": "simp", - "summary": "test manifests for simpkv plugin testing", + "summary": "test manifests for simp kv testing", "license": "Apache-2.0", "source": "https://github.com/simp/pupmod-simp-simpkv", "project_page": "https://github.com/simp/pupmod-simp-simpkv", @@ -10,34 +10,22 @@ "tags": [], "dependencies": [ { - "name": "simp/simpkv", - "version_requirement": ">= 0.7.0" + "name": "puppetlabs/stdlib", + "version_requirement": ">= 4.9.0" }, { - "name": "simp/simplib", - "version_requirement": ">= 4.0.0 < 5.0.0" - } - ], - "operatingsystem_support": [ - { - "operatingsystem": "CentOS", - "operatingsystemrelease": [ - "6", - "7" - ] + "name": "simp/simpkv", + "version_requirement": ">= 0.8.0" }, { - "operatingsystem": "RedHat", - "operatingsystemrelease": [ - "6", - "7" - ] + "name": "simp/simplib", + "version_requirement": ">= 4.0.0" } ], "requirements": [ { "name": "puppet", - "version_requirement": ">= 5.0.0 < 7.0.0" + "version_requirement": ">= 6.5.0" } ] } diff --git a/spec/support/modules/simpkv_test/types/appid.pp b/spec/support/modules/simpkv_test/types/appid.pp new file mode 100644 index 0000000..e5d7ea8 --- /dev/null +++ b/spec/support/modules/simpkv_test/types/appid.pp @@ -0,0 +1,3 @@ +# String used as the `app_id` attribute of the `simpkv_options` parameter in +# a simpkv function call +type Simpkv_test::AppId = String diff --git a/spec/support/modules/simpkv_test/types/folderdata.pp b/spec/support/modules/simpkv_test/types/folderdata.pp new file mode 100644 index 0000000..6275359 --- /dev/null +++ b/spec/support/modules/simpkv_test/types/folderdata.pp @@ -0,0 +1,10 @@ +# Information about an individual folder in a keystore +type Simpkv_test::FolderData = Struct[{ + # Info about keys in the directory + # - Currently restricted to keys with non-binary data because of + # test manifest limitations + Optional[keys] => Hash[Simpkv_test::Key,Simpkv_test::NonBinaryKeyData], + + # List of subfolder names + Optional[folders] => Array[String[1]] +}] diff --git a/spec/support/modules/simpkv_test/types/folderinfo.pp b/spec/support/modules/simpkv_test/types/folderinfo.pp new file mode 100644 index 0000000..c266012 --- /dev/null +++ b/spec/support/modules/simpkv_test/types/folderinfo.pp @@ -0,0 +1,31 @@ +# Data structure specifying folder information +# +# Folders are unique based on 3 attributes: +# 1. The backend in which they are stored +# 2. Whether they are tied to a Puppet environment or global +# 3. The folder names (each of which may include a relative path) +# +# The grouping below was chosen to ensure uniqueness for test folders, +# **ASSUMING**, backends are uniquely mapped to the `app_id` attribute that +# will be used in the `simpkv_options` parameter of each simpkv function call. +# +# If you are mapping multiple `app_id` values to the same backend in a test, +# be sure you don't have any folders that will resolve to the same storage +# location! +# +type Simpkv_test::FolderInfo = Hash[ + + # When not empty, used to set the 'app_id' attribute of the `simpkv_options` + # parameter of each simpkv function call + Simpkv_test::AppId, + + Struct[{ + # - Any folder in 'env' is a folder tied to the Puppet environment. + # - Any folder in 'global' is a global folder. + # - For these folders, the 'global' attribute of the `simpkv_options` + # parameter of each simpkv function call will be automatically set + # to `true`. + Optional[env] => Simpkv_test::Folders, + Optional[global] => Simpkv_test::Folders + }] +] diff --git a/spec/support/modules/simpkv_test/types/folders.pp b/spec/support/modules/simpkv_test/types/folders.pp new file mode 100644 index 0000000..34a6e3d --- /dev/null +++ b/spec/support/modules/simpkv_test/types/folders.pp @@ -0,0 +1,2 @@ +# Data structure specifying folder listings +type Simpkv_test::Folders = Hash[Simpkv_test::Key, Simpkv_test::FolderData] diff --git a/spec/support/modules/simpkv_test/types/key.pp b/spec/support/modules/simpkv_test/types/key.pp new file mode 100644 index 0000000..b65396e --- /dev/null +++ b/spec/support/modules/simpkv_test/types/key.pp @@ -0,0 +1,5 @@ +# Key or folder name +# +# The regex is not perfect (doesn't catch sequences that look +# like relative paths), but sufficient for this test module. +type Simpkv_test::Key = Pattern['^[a-z0-9._:\-\/]+$'] diff --git a/spec/support/modules/simpkv_test/types/keydata.pp b/spec/support/modules/simpkv_test/types/keydata.pp new file mode 100644 index 0000000..12b9f1e --- /dev/null +++ b/spec/support/modules/simpkv_test/types/keydata.pp @@ -0,0 +1,18 @@ +# Information about an individual key in a keystore +type Simpkv_test::KeyData = Struct[{ + # Either 'value' or 'file' needs to be set. + # If both are set, 'value' will be used over 'file'. + # If neither are set, the Simpkv_test::KeyData instance will be skipped. + + # Non-binary value + Optional[value] => NotUndef, + + # File containing binary value + # - argument to binary_file, which is an absolute path or + # / string referencing a module file + Optional[file] => String[1], + + # Optional metadata stored with the value + Optional[metadata] => Hash +}] + diff --git a/spec/support/modules/simpkv_test/types/keyinfo.pp b/spec/support/modules/simpkv_test/types/keyinfo.pp new file mode 100644 index 0000000..6ceee85 --- /dev/null +++ b/spec/support/modules/simpkv_test/types/keyinfo.pp @@ -0,0 +1,32 @@ +# Data structure specifying key information +# +# Keys are unique based on 3 attributes: +# 1. The backend in which they are stored +# 2. Whether they are tied to a Puppet environment or global +# 3. The key names (each of which may include a relative folder path) +# +# The grouping below was chosen to ensure uniqueness for test keys, +# **ASSUMING**, backends are uniquely mapped to the `app_id` attribute that +# will be used in the `simpkv_options` parameter of each simpkv function call. +# +# If you are mapping multiple `app_id` values to the same backend in a test, +# be sure you don't have any keys that will resolve to the same storage +# location! +# +type Simpkv_test::KeyInfo = Hash[ + + # When not empty, used to set the 'app_id' attribute of the `simpkv_options` + # parameter of each simpkv function call + Simpkv_test::AppId, + + Struct[{ + # - Any key in 'env' is a key tied to the Puppet environment. + # - Any key in 'global' is a global key. + # - For these keys, the 'global' attribute of the `simpkv_options` + # parameter of each simpkv function call will be automatically set + # to `true`. + Optional[env] => Simpkv_test::Keys, + Optional[global] => Simpkv_test::Keys + }] +] + diff --git a/spec/support/modules/simpkv_test/types/keys.pp b/spec/support/modules/simpkv_test/types/keys.pp new file mode 100644 index 0000000..673d0bf --- /dev/null +++ b/spec/support/modules/simpkv_test/types/keys.pp @@ -0,0 +1,2 @@ +# Data structure specifying key/value pairs +type Simpkv_test::Keys = Hash[Simpkv_test::Key, Simpkv_test::KeyData] diff --git a/spec/support/modules/simpkv_test/types/nameinfo.pp b/spec/support/modules/simpkv_test/types/nameinfo.pp new file mode 100644 index 0000000..ccfc42f --- /dev/null +++ b/spec/support/modules/simpkv_test/types/nameinfo.pp @@ -0,0 +1,32 @@ +# Data structure specifying simply key/folder names +# +# Key/folder names are unique based on 3 attributes: +# 1. The backend in which they are stored +# 2. Whether they are tied to a Puppet environment or global +# 3. The key/folder names (each of which may include a relative folder path) +# +# The grouping below was chosen to ensure uniqueness for test key/folder names, +# **ASSUMING**, backends are uniquely mapped to the `app_id` attribute that +# will be used in the `simpkv_options` parameter of each simpkv function call. +# +# If you are mapping multiple `app_id` values to the same backend in a test, +# be sure you don't have any keys/folders that will resolve to the same storage +# location! +# +type Simpkv_test::NameInfo = Hash[ + + # When not empty, used to set the 'app_id' attribute of the `simpkv_options` + # parameter of each simpkv function call + Simpkv_test::AppId, + + Struct[{ + # - Any key/folder in 'env' is tied to the Puppet environment. + # - Any key/folder in 'global' is global + # - For these entities, the 'global' attribute of the `simpkv_options` + # parameter of each simpkv function call will be automatically set + # to `true`. + Optional[env] => Array[Simpkv_test::Key], + Optional[global] => Array[Simpkv_test::Key] + }] +] + diff --git a/spec/support/modules/simpkv_test/types/nonbinarykeydata.pp b/spec/support/modules/simpkv_test/types/nonbinarykeydata.pp new file mode 100644 index 0000000..fa308dd --- /dev/null +++ b/spec/support/modules/simpkv_test/types/nonbinarykeydata.pp @@ -0,0 +1,9 @@ +# Information about an individual non-binary key in a keystore +type Simpkv_test::NonBinaryKeyData = Struct[{ + # Non-binary value + value => NotUndef, + + # Optional metadata stored with the value + Optional[metadata] => Hash +}] +