diff --git a/.rubocop.yml b/.rubocop.yml index 4adb7f0..a73994d 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,549 +1,549 @@ require: rubocop-rspec AllCops: TargetRubyVersion: 2.1 Include: - ./**/*.rb Exclude: - files/**/* - vendor/**/* - .vendor/**/* - pkg/**/* - spec/fixtures/**/* - Gemfile - Rakefile - Guardfile - Vagrantfile Lint/ConditionPosition: Enabled: True Lint/ElseLayout: Enabled: True Lint/UnreachableCode: Enabled: True Lint/UselessComparison: Enabled: True Lint/EnsureReturn: Enabled: True Lint/HandleExceptions: Enabled: True Lint/LiteralInCondition: Enabled: True Lint/ShadowingOuterLocalVariable: Enabled: True Lint/LiteralInInterpolation: Enabled: True Style/HashSyntax: Enabled: True Style/RedundantReturn: Enabled: True Layout/EndOfLine: Enabled: False Lint/AmbiguousOperator: Enabled: True Lint/AssignmentInCondition: Enabled: True Layout/SpaceBeforeComment: Enabled: True Style/AndOr: Enabled: True Style/RedundantSelf: Enabled: True Metrics/BlockLength: Enabled: False # Method length is not necessarily an indicator of code quality Metrics/MethodLength: Enabled: False # Module length is not necessarily an indicator of code quality Metrics/ModuleLength: Enabled: False Style/WhileUntilModifier: Enabled: True Lint/AmbiguousRegexpLiteral: Enabled: True Security/Eval: Enabled: True Lint/BlockAlignment: Enabled: True Lint/DefEndAlignment: Enabled: True Lint/EndAlignment: Enabled: True Lint/DeprecatedClassMethods: Enabled: True Lint/Loop: Enabled: True Lint/ParenthesesAsGroupedExpression: Enabled: True Lint/RescueException: Enabled: True Lint/StringConversionInInterpolation: Enabled: True Lint/UnusedBlockArgument: Enabled: True Lint/UnusedMethodArgument: Enabled: True Lint/UselessAccessModifier: Enabled: True Lint/UselessAssignment: Enabled: True Lint/Void: Enabled: True Layout/AccessModifierIndentation: Enabled: True Style/AccessorMethodName: Enabled: True Style/Alias: Enabled: True Layout/AlignArray: Enabled: True Layout/AlignHash: Enabled: True Layout/AlignParameters: Enabled: True Metrics/BlockNesting: Enabled: True Style/AsciiComments: Enabled: True Style/Attr: Enabled: True Style/BracesAroundHashParameters: Enabled: True Style/CaseEquality: Enabled: True Layout/CaseIndentation: Enabled: True Style/CharacterLiteral: Enabled: True Style/ClassAndModuleCamelCase: Enabled: True Style/ClassAndModuleChildren: Enabled: False Style/ClassCheck: Enabled: True # Class length is not necessarily an indicator of code quality Metrics/ClassLength: Enabled: False Style/ClassMethods: Enabled: True Style/ClassVars: Enabled: True Style/WhenThen: Enabled: True Style/WordArray: Enabled: True Style/UnneededPercentQ: Enabled: True Layout/Tab: Enabled: True Layout/SpaceBeforeSemicolon: Enabled: True Layout/TrailingBlankLines: Enabled: True Layout/SpaceInsideBlockBraces: Enabled: True Layout/SpaceInsideBrackets: Enabled: True Layout/SpaceInsideHashLiteralBraces: Enabled: True Layout/SpaceInsideParens: Enabled: True Layout/LeadingCommentSpace: Enabled: True Layout/SpaceBeforeFirstArg: Enabled: True Layout/SpaceAfterColon: Enabled: True Layout/SpaceAfterComma: Enabled: True Layout/SpaceAfterMethodName: Enabled: True Layout/SpaceAfterNot: Enabled: True Layout/SpaceAfterSemicolon: Enabled: True Layout/SpaceAroundEqualsInParameterDefault: Enabled: True Layout/SpaceAroundOperators: Enabled: True Layout/SpaceBeforeBlockBraces: Enabled: True Layout/SpaceBeforeComma: Enabled: True Style/CollectionMethods: Enabled: True Layout/CommentIndentation: Enabled: True Style/ColonMethodCall: Enabled: True Style/CommentAnnotation: Enabled: True # 'Complexity' is very relative Metrics/CyclomaticComplexity: Enabled: False Style/ConstantName: Enabled: True Style/Documentation: Enabled: False Style/DefWithParentheses: Enabled: True Style/PreferredHashMethods: Enabled: True Layout/DotPosition: EnforcedStyle: trailing Style/DoubleNegation: Enabled: True Style/EachWithObject: Enabled: True Layout/EmptyLineBetweenDefs: Enabled: True Layout/IndentArray: Enabled: True Layout/IndentHash: Enabled: True Layout/IndentationConsistency: Enabled: True Layout/IndentationWidth: Enabled: True Layout/EmptyLines: Enabled: True Layout/EmptyLinesAroundAccessModifier: Enabled: True Style/EmptyLiteral: Enabled: True # Configuration parameters: AllowURI, URISchemes. Metrics/LineLength: Enabled: False Style/MethodCallWithoutArgsParentheses: Enabled: True Style/MethodDefParentheses: Enabled: True Style/LineEndConcatenation: Enabled: True Layout/TrailingWhitespace: Enabled: True Style/StringLiterals: Enabled: True Style/TrailingCommaInArguments: Enabled: True Style/TrailingCommaInLiteral: Enabled: True Style/GlobalVars: Enabled: True Style/GuardClause: Enabled: True Style/IfUnlessModifier: Enabled: True Style/MultilineIfThen: Enabled: True Style/NegatedIf: Enabled: True Style/NegatedWhile: Enabled: True Style/Next: Enabled: True Style/SingleLineBlockParams: Enabled: True Style/SingleLineMethods: Enabled: True Style/SpecialGlobalVars: Enabled: True Style/TrivialAccessors: Enabled: True Style/UnlessElse: Enabled: True Style/VariableInterpolation: Enabled: True Style/VariableName: Enabled: True Style/WhileUntilDo: Enabled: True Style/EvenOdd: Enabled: True Style/FileName: Enabled: True Style/For: Enabled: True Style/Lambda: Enabled: True Style/MethodName: Enabled: True Style/MultilineTernaryOperator: Enabled: True Style/NestedTernaryOperator: Enabled: True Style/NilComparison: Enabled: True Style/FormatString: Enabled: True Style/MultilineBlockChain: Enabled: True Style/Semicolon: Enabled: True Style/SignalException: Enabled: True Style/NonNilCheck: Enabled: True Style/Not: Enabled: True Style/NumericLiterals: Enabled: True Style/OneLineConditional: Enabled: True Style/OpMethod: Enabled: True Style/ParenthesesAroundCondition: Enabled: True Style/PercentLiteralDelimiters: Enabled: True Style/PerlBackrefs: Enabled: True Style/PredicateName: Enabled: True Style/RedundantException: Enabled: True Style/SelfAssignment: Enabled: True Style/Proc: Enabled: True Style/RaiseArgs: Enabled: True Style/RedundantBegin: Enabled: True Style/RescueModifier: Enabled: True # based on https://github.com/voxpupuli/modulesync_config/issues/168 Style/RegexpLiteral: EnforcedStyle: percent_r Enabled: True Lint/UnderscorePrefixedVariableName: Enabled: True Metrics/ParameterLists: Enabled: False Lint/RequireParentheses: Enabled: True Style/ModuleFunction: Enabled: True Lint/Debugger: Enabled: True Style/IfWithSemicolon: Enabled: True Style/Encoding: Enabled: True Style/BlockDelimiters: Enabled: True Layout/MultilineBlockLayout: Enabled: True # 'Complexity' is very relative Metrics/AbcSize: Enabled: False # 'Complexity' is very relative Metrics/PerceivedComplexity: Enabled: False Lint/UselessAssignment: Enabled: True Layout/ClosingParenthesisIndentation: Enabled: True # RSpec RSpec/BeforeAfterAll: Exclude: - spec/acceptance/**/* # We don't use rspec in this way RSpec/DescribeClass: Enabled: False # Example length is not necessarily an indicator of code quality RSpec/ExampleLength: Enabled: False RSpec/NamedSubject: Enabled: False # disabled for now since they cause a lot of issues # these issues aren't easy to fix RSpec/RepeatedDescription: Enabled: False RSpec/NestedGroups: Enabled: False # this is broken on ruby1.9 Layout/IndentHeredoc: Enabled: False # disable Yaml safe_load. This is needed to support ruby2.0.0 development envs Security/YAMLLoad: Enabled: false # This affects hiera interpolation, as well as some configs that we push. Style/FormatStringToken: Enabled: false # This is useful, but sometimes a little too picky about where unit tests files # are located. RSpec/FilePath: Enabled: false # silence it to support older jruby (<= v1.9) which can not handle e.g. %i[] -Style/SymbolArray: +Style/WordArray: Enabled: false diff --git a/lib/puppet/type/grafana_ldap_config.rb b/lib/puppet/type/grafana_ldap_config.rb index a98b479..f007d32 100644 --- a/lib/puppet/type/grafana_ldap_config.rb +++ b/lib/puppet/type/grafana_ldap_config.rb @@ -1,182 +1,184 @@ require 'toml' Puppet::Type.newtype(:grafana_ldap_config) do @doc = 'Manage Grafana LDAP configuration' @toml_header = <<-EOF # # Grafana LDAP configuration # # generated by Puppet module puppet-grafana # https://github.com/voxpupuli/puppet-grafana # # *** Edit at your own peril *** # # ############################################# # EOF # currently not ensurable as we are not parsing the LDAP toml config. # ensurable newparam(:title, namevar: true) do desc 'Path to ldap.toml' validate do |value| raise ArgumentError, _('name/title must be a String') unless value.is_a?(String) end end newparam(:owner) do desc 'Owner of the LDAP configuration-file either as String or Integer (default: root)' defaultto 'root' validate do |value| raise ArgumentError, _('owner must be a String or Integer') unless value.is_a?(String) || value.is_a?(Integer) end end newparam(:group) do desc 'Group of the LDAP configuration file either as String or Integer (default: grafana)' defaultto 'grafana' validate do |value| raise ArgumentError, _('group must be a String or Integer') unless value.is_a?(String) || value.is_a?(Integer) end end newparam(:mode) do desc 'File-permissions mode of the LDAP configuration file as String' defaultto '0440' validate do |value| - # regex-pattern stolen from Puppetlabs here - all credis to them! + raise ArgumentError, _('file-permissions must be a String') unless value.is_a?(String) + raise ArgumentError, _('file-permissions must be a String') if value.empty? + # regex-pattern stolen from here - all credis to them! # https://github.com/puppetlabs/puppetlabs-stdlib/blob/master/types/filemode.pp # currently disabled, as it fails when implicitly called. # # raise ArgumentError, _('file-permissions is not valid') unless value.to_s.match(%r{/\A(([0-7]{1,4})|(([ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=][0-7]+)(,([ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=][0-7]+))*))\z/}) end end newparam(:replace, boolean: true, parent: Puppet::Parameter::Boolean) do desc 'Replace existing files' defaultto true end newparam(:backup, boolean: true, parent: Puppet::Parameter::Boolean) do desc 'Backup existing files before replacing them into the file-bucket' defaultto false end newparam(:validate_cmd) do desc 'A command to validate the new Grafana LDAP configuration before actually replacing it' validate do |value| - raise ArgumentError, _('group must be a String or undef') unless value.nil? || value.is_a?(String) + raise ArgumentError, _('validate_cmd must be a String or undef') unless value.nil? || value.is_a?(String) end end def ldap_servers catalog.resources.each_with_object({}) do |resource, memo| next unless resource.is_a?(Puppet::Type.type(:grafana_ldap_server)) next unless resource[:name].is_a?(String) memo[resource[:name]] = resource memo end end def should_content return @generated_config if @generated_config @generated_config = {} ldap_servers.each do |server_k, server_v| # convert symbols to strings server_params = Hash[server_v.original_parameters.map { |k, v| [k.to_s, v] }] server_attributes = server_params['attributes'] server_params.delete('attributes') # grafana-syntax for multiple hosts is a space-separate list. server_params['host'] = server_params['hosts'].join(' ') server_params.delete('hosts') server_group_mappings = server_v.group_mappings server_block = { 'servers' => [server_params], 'servers.attributes' => server_attributes, 'servers.group_mappings' => server_group_mappings }.compact @generated_config[server_k] = server_block end @generated_config.compact end def generate file_opts = {} # currently not ensurable # file_opts = { # ensure: (self[:ensure] == :absent) ? :absent : :file, # } [:name, :owner, :group, :mode, :replace, :backup, # this we have currently not implemented # :selinux_ignore_defaults, # :selrange, # :selrole, # :seltype, # :seluser, # :show_diff, :validate_cmd].each do |param| file_opts[param] = self[param] unless self[param].nil? end metaparams = Puppet::Type.metaparams excluded_metaparams = ['before', 'notify', 'require', 'subscribe', 'tag'] metaparams.reject! { |param| excluded_metaparams.include? param } metaparams.each do |metaparam| file_opts[metaparam] = self[metaparam] unless self[metaparam].nil? end [Puppet::Type.type(:file).new(file_opts)] end def eval_generate ldap_servers = should_content if !ldap_servers.nil? && !ldap_servers.empty? toml_contents = [] toml_contents << @toml_header toml_contents << ldap_servers.map do |k, v| str = [] str << "\n\n" str << <<-EOF # # #{k} # EOF str << TOML::Generator.new(v).body str.join end catalog.resource("File[#{self[:name]}]")[:content] = toml_contents.join end [catalog.resource("File[#{self[:name]}]")] end autonotify(:class) do 'grafana::service' end end diff --git a/spec/unit/puppet/type/grafana_ldap_config_spec.rb b/spec/unit/puppet/type/grafana_ldap_config_spec.rb new file mode 100644 index 0000000..e8a32ed --- /dev/null +++ b/spec/unit/puppet/type/grafana_ldap_config_spec.rb @@ -0,0 +1,164 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +require 'spec_helper' + +describe Puppet::Type.type(:grafana_ldap_config) do + # resource title + context 'validate resource title' do + it 'fails if title is not set' do + expect do + described_class.new name: nil + end.to raise_error(Puppet::Error, %r{Title or name must be provided}) + end + + it 'fails if title is not a string' do + expect do + described_class.new name: 123 + end.to raise_error(Puppet::ResourceError, %r{must be a String}) + end + end + + # owner + context 'validate owner' do + it 'fails if owner is wrong type' do + expect do + described_class.new name: 'foo_bar', owner: true + end.to raise_error(Puppet::ResourceError, %r{must be a String or Integer}) + end + + it 'succeeds if owner is string' do + expect do + described_class.new name: 'foo_bar', owner: 'foo' + end + end + + it 'succeeds if owner is numeric' do + expect do + described_class.new name: 'foo_bar', owner: 111 + end + end + end + + # group + context 'validate group' do + it 'fails if group is wrong type' do + expect do + described_class.new name: 'foo_bar', group: true + end.to raise_error(Puppet::ResourceError, %r{must be a String or Integer}) + end + + it 'succeeds if group is string' do + expect do + described_class.new name: 'foo_bar', group: 'foo' + end + end + + it 'succeeds if group is numeric' do + expect do + described_class.new name: 'foo_bar', owner: 111 + end + end + end + + # mode + context 'validate mode' do + it 'fails if mode is wrong type' do + expect do + described_class.new name: 'foo_bar', mode: 123 + end.to raise_error(Puppet::ResourceError, %r{must be a String}) + end + + it 'fails if mode is empty' do + expect do + described_class.new name: 'foo_bar', mode: '' + end.to raise_error(Puppet::ResourceError, %r{must be a String}) + end + + # currently disabled + # it 'fails if mode is invalid' do + # expect do + # described_class.new name: 'foo_bar', mode: 'abcd' + # end.to raise_error(Puppet::ResourceError, %r{is not valid}) + # end + + it 'succeeds if mode is string' do + expect do + described_class.new name: 'foo_bar', mode: '0755' + end + end + end + + # replace + context 'validate replace' do + it 'fails if replace is not a boolean' do + expect do + described_class.new name: 'foo_bar', replace: 'bla' + end.to raise_error(Puppet::ResourceError, %r{Valid values are}) + end + + it 'succeeds if replace' do + expect do + described_class.new name: 'foo_bar', replace: true + end + end + end + + # backup + context 'validate backup' do + it 'fails if backup is not a boolean' do + expect do + described_class.new name: 'foo_bar', backup: 'bla' + end.to raise_error(Puppet::ResourceError, %r{Valid values are}) + end + + it 'succeeds if backup' do + expect do + described_class.new name: 'foo_bar', backup: true + end + end + end + + # validate_cmd + context 'validate validate_cmd' do + it 'fails if validate_cmd is wrong type' do + expect do + described_class.new name: 'foo_bar', validate_cmd: 123 + end.to raise_error(Puppet::Error, %r{must be a String}) + end + + it 'succeeds if group is string' do + expect do + described_class.new name: 'foo_bar', validate_cmd: '0755' + end + end + end + + # ldap_servers + context 'validate ldap_servers' do + it 'correctly returns the declared LDAP servers' do + catalog = Puppet::Resource::Catalog.new + server = Puppet::Type.type(:grafana_ldap_server).new( + name: 'ldap.example.com', + hosts: ['ldap.example.com'], + search_base_dns: ['ou=auth'] + ) + config = Puppet::Type.type(:grafana_ldap_config).new name: 'ldap1' + + catalog.add_resource server + catalog.add_resource config + + expect(config.ldap_servers.keys).to include('ldap.example.com') + end + end +end diff --git a/spec/unit/puppet/type/grafana_ldap_group_mapping_spec.rb b/spec/unit/puppet/type/grafana_ldap_group_mapping_spec.rb new file mode 100644 index 0000000..410be52 --- /dev/null +++ b/spec/unit/puppet/type/grafana_ldap_group_mapping_spec.rb @@ -0,0 +1,151 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +require 'spec_helper' + +describe Puppet::Type.type(:grafana_ldap_group_mapping) do + # resource title + context 'validate resource title' do + it 'fails if title is not set' do + expect do + described_class.new name: nil + end.to raise_error(Puppet::Error, %r{Title or name must be provided}) + end + + it 'fails if title is empty' do + expect do + described_class.new name: '' + end.to raise_error(RuntimeError, %r{needs to be a non-empty string}) + end + + it 'fails if title is not a string' do + expect do + described_class.new name: 123 + end.to raise_error(Puppet::ResourceError, %r{must be a String}) + end + end + + # ldap_server_name + context 'validate ldap_server_name' do + it 'fails if ldap_server_name is not set' do + expect do + described_class.new name: 'foo_bar', ldap_server_name: nil, group_dn: 'bar' + end.to raise_error(Puppet::Error, %r{Got nil value for}) + end + + it 'fails if ldap_server_name is empty' do + expect do + described_class.new name: 'foo_bar', ldap_server_name: '', group_dn: 'bar' + end.to raise_error(RuntimeError, %r{needs to be a non-empty string}) + end + + it 'fails if ldap_server_name is not a string' do + expect do + described_class.new name: '123_bar', ldap_server_name: 123, group_dn: 'bar' + end.to raise_error(Puppet::ResourceError, %r{must be a String}) + end + end + + # group_dn + context 'validate group_dn' do + it 'fails if group_dn is not set' do + expect do + described_class.new name: 'foo_bar', ldap_server_name: 'foo', group_dn: nil + end.to raise_error(Puppet::Error, %r{Got nil value for}) + end + + it 'fails if group_dn is empty' do + expect do + described_class.new name: 'foo_bar', ldap_server_name: 'foo', group_dn: '' + end.to raise_error(RuntimeError, %r{needs to be a non-empty string}) + end + + it 'fails if group_dn is not a string' do + expect do + described_class.new name: 'foo_123', ldap_server_name: 'foo', group_dn: 123 + end.to raise_error(Puppet::ResourceError, %r{must be a String}) + end + end + + # org_role + context 'validate org_role' do + it 'fails if org_role is not set' do + expect do + described_class.new name: 'foo_bar', ldap_server_name: 'foo', group_dn: 'bar', org_role: nil + end.to raise_error(Puppet::Error, %r{Got nil value for}) + end + + it 'fails if org_role is not a string' do + expect do + described_class.new name: 'foo_bar', ldap_server_name: 'foo', group_dn: 'bar', org_role: 123 + end.to raise_error(Puppet::ResourceError, %r{Valid values are}) + end + + it 'fails if org_role is an unknown role' do + expect do + described_class.new name: 'foo_bar', ldap_server_name: 'foo', group_dn: 'bar', org_role: 'bla' + end.to raise_error(Puppet::Error, %r{Valid values are}) + end + + it 'succeeds if all is correct' do + expect do + described_class.new name: 'foo_bar', ldap_server_name: 'foo', group_dn: 'bar', org_role: 'Editor' + end + end + end + + # grafana_admin + context 'validate grafana_admin' do + it 'fails if org_role is not a boolean' do + expect do + described_class.new name: 'foo_bar', ldap_server_name: 'foo', group_dn: 'bar', org_role: 'Admin', grafana_admin: 'bla' + end.to raise_error(Puppet::ResourceError, %r{Valid values are}) + end + + it 'succeeds if grafana_admin' do + expect do + described_class.new name: 'foo_bar', ldap_server_name: 'foo', group_dn: 'bar', org_role: 'Admin', grafana_admin: true + end + end + end + + context 'valid viewer' do + let(:group_mapping) do + described_class.new name: 'foo_bar', ldap_server_name: 'foo', group_dn: 'bar', org_role: 'Viewer', grafana_admin: false + end + + it 'given all parameters' do + expect(group_mapping[:org_role]).to eq(:Viewer) + end + end + + context 'valid editor' do + let(:group_mapping) do + described_class.new name: 'foo_bar', ldap_server_name: 'foo', group_dn: 'bar', org_role: 'Editor', grafana_admin: false + end + + it 'given all parameters' do + expect(group_mapping[:org_role]).to eq(:Editor) + end + end + + context 'valid admin' do + let(:group_mapping) do + described_class.new name: 'foo_bar', ldap_server_name: 'foo', group_dn: 'bar', org_role: 'Admin', grafana_admin: true + end + + it 'given all parameters' do + expect(group_mapping[:org_role]).to eq(:Admin) + end + end +end diff --git a/spec/unit/puppet/type/grafana_ldap_server_spec.rb b/spec/unit/puppet/type/grafana_ldap_server_spec.rb new file mode 100644 index 0000000..0706c0d --- /dev/null +++ b/spec/unit/puppet/type/grafana_ldap_server_spec.rb @@ -0,0 +1,337 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +require 'spec_helper' + +describe Puppet::Type.type(:grafana_ldap_server) do + # resource title + context 'validate resource title' do + it 'fails if title is not set' do + expect do + described_class.new name: nil + end.to raise_error(Puppet::Error, %r{Title or name must be provided}) + end + + it 'fails if title is empty' do + expect do + described_class.new name: '' + end.to raise_error(RuntimeError, %r{must not be empty}) + end + + it 'fails if title is not a string' do + expect do + described_class.new name: 123 + end.to raise_error(Puppet::ResourceError, %r{must be a String}) + end + end + + # hosts + context 'validate hosts' do + it 'fails if hosts is not set' do + expect do + described_class.new name: 'server1', hosts: nil + end.to raise_error(Puppet::Error, %r{Got nil value for}) + end + + it 'fails if hosts is not an array' do + expect do + described_class.new name: 'server1', hosts: '' + end.to raise_error(RuntimeError, %r{must be an Array}) + end + + it 'fails if hosts is empty' do + expect do + described_class.new name: 'server1', hosts: [] + end.to raise_error(RuntimeError, %r{must not be empty}) + end + end + + # port + context 'validate port' do + it 'fails if port is empty' do + expect do + described_class.new name: 'server1', hosts: ['server1'], port: 0 + end.to raise_error(RuntimeError, %r{must be an Integer within}) + end + + it 'fails if port is a string' do + expect do + described_class.new name: 'server1', hosts: ['server1'], port: '123' + end.to raise_error(Puppet::ResourceError, %r{must be an Integer within}) + end + + it 'fails if port is greater than 65535' do + expect do + described_class.new name: 'server1', hosts: ['server1'], port: 123_456 + end.to raise_error(Puppet::ResourceError, %r{must be an Integer within}) + end + end + + # use_ssl + context 'validate use_ssl' do + it 'fails if use_ssl is not boolean' do + expect do + described_class.new name: 'server1', hosts: ['server1'], use_ssl: 'foobar' + end.to raise_error(Puppet::Error, %r{Valid values are true}) + end + + it 'succeeds if all is correct' do + expect do + described_class.new name: 'server1', hosts: ['server1'], use_ssl: true + end + end + end + + # start_tls + context 'validate start_tls' do + it 'fails if start_tls is not boolean' do + expect do + described_class.new name: 'server1', hosts: ['server1'], start_tls: 'foobar' + end.to raise_error(Puppet::Error, %r{Valid values are true}) + end + + it 'succeeds if all is correct' do + expect do + described_class.new name: 'server1', hosts: ['server1'], start_tls: true + end + end + end + + # ssl_skip_verify + context 'validate ssl_skip_verify' do + it 'fails if ssl_skip_verify is not boolean' do + expect do + described_class.new name: 'server1', hosts: ['server1'], ssl_skip_verify: 'foobar' + end.to raise_error(Puppet::Error, %r{Valid values are true}) + end + + it 'succeeds if all is correct' do + expect do + described_class.new name: 'server1', hosts: ['server1'], ssl_skip_verify: true + end + end + end + + # root_ca_cert + context 'validate root_ca_cert' do + it 'fails if root_ca_cert is empty' do + expect do + described_class.new name: 'server1', hosts: ['server1'], root_ca_cert: '' + end.to raise_error(RuntimeError, %r{must be set when SSL}) + end + + it 'fails if root_ca_cert is not a string' do + expect do + described_class.new name: 'server1', hosts: ['server1'], root_ca_cert: 12_345 + end.to raise_error(Puppet::Error, %r{must be a String}) + end + + it 'succeeds if all is correct' do + expect do + described_class.new name: 'server1', hosts: ['server1'], root_ca_cert: '/etc/ssl/certs/ca-certificate.crt' + end + end + end + + # client_cert + context 'validate client_cert' do + it 'fails if client_cert is not a string' do + expect do + described_class.new name: 'server1', hosts: ['server1'], client_cert: 12_345 + end.to raise_error(Puppet::Error, %r{must be a String}) + end + + it 'succeeds if all is correct' do + expect do + described_class.new name: 'server1', hosts: ['server1'], client_cert: '/etc/ssl/host.crt' + end + end + end + + # client_key + context 'validate client_key' do + it 'fails if client_key is not a string' do + expect do + described_class.new name: 'server1', hosts: ['server1'], client_key: 12_345 + end.to raise_error(Puppet::Error, %r{must be a String}) + end + + it 'succeeds if all is correct' do + expect do + described_class.new name: 'server1', hosts: ['server1'], client_key: '/etc/ssl/certs/ca-certificate.crt' + end + end + end + + # bind_dn + context 'validate bind_dn' do + it 'fails if bind_dn is not a string' do + expect do + described_class.new name: 'server1', hosts: ['server1'], bind_dn: 12_345 + end.to raise_error(Puppet::Error, %r{must be a String}) + end + + it 'succeeds if all is correct' do + expect do + described_class.new name: 'server1', hosts: ['server1'], bind_dn: 'cn=Admin', search_base_dns: ['ou=users'] + end + end + end + + # bind_password + context 'validate bind_password' do + it 'fails if bind_password is not a string' do + expect do + described_class.new name: 'server1', hosts: ['server1'], bind_password: 12_345 + end.to raise_error(Puppet::Error, %r{must be a String}) + end + + it 'succeeds if all is correct' do + expect do + described_class.new name: 'server1', hosts: ['server1'], bind_password: 'foobar', search_base_dns: ['ou=users'] + end + end + end + + # search_filter + context 'validate search_filter' do + it 'fails if search_filter is not a string' do + expect do + described_class.new name: 'server1', hosts: ['server1'], search_filter: 12_345 + end.to raise_error(Puppet::Error, %r{must be a String}) + end + + it 'succeeds if all is correct' do + expect do + described_class.new name: 'server1', hosts: ['server1'], search_filter: 'uid=%u', search_base_dns: ['ou=users'] + end + end + end + + # search_base_dns + context 'validate search_base_dns' do + it 'fails if search_base_dns is not an array' do + expect do + described_class.new name: 'server1', hosts: ['server1'], search_base_dns: 12_345 + end.to raise_error(Puppet::Error, %r{must be an Array}) + end + + it 'fails if search_base_dns array members are not strings' do + expect do + described_class.new name: 'server1', hosts: ['server1'], search_base_dns: [12_345] + end.to raise_error(Puppet::Error, %r{must be a String}) + end + + it 'fails if search_base_dns array is empty' do + expect do + described_class.new name: 'server1', hosts: ['server1'], search_base_dns: [] + end.to raise_error(RuntimeError, %r{needs to contain at least one LDAP base-dn}) + end + + it 'succeeds if all is correct' do + expect do + described_class.new name: 'server1', hosts: ['server1'], search_base_dns: ['ou=users'] + end + end + end + + # group_search_filter + context 'validate group_search_filter' do + it 'fails if group_search_filter is not a string' do + expect do + described_class.new name: 'server1', hosts: ['server1'], group_search_filter: 12_345 + end.to raise_error(Puppet::Error, %r{must be a String}) + end + + it 'succeeds if all is correct' do + expect do + described_class.new name: 'server1', hosts: ['server1'], group_search_filter: 'cn=adminsgroup', search_base_dns: ['ou=users'] + end + end + end + + # group_search_filter_user_attribute + context 'validate group_search_filter_user_attribute' do + it 'fails if group_search_filter_user_attribute is not a string' do + expect do + described_class.new name: 'server1', hosts: ['server1'], group_search_filter_user_attribute: 12_345 + end.to raise_error(Puppet::Error, %r{must be a String}) + end + + it 'succeeds if all is correct' do + expect do + described_class.new name: 'server1', hosts: ['server1'], group_search_filter_user_attribute: 'dn', search_base_dns: ['ou=users'] + end + end + end + + # group_search_base_dns + context 'validate group_search_base_dns' do + it 'fails if group_search_base_dns is not an array' do + expect do + described_class.new name: 'server1', hosts: ['server1'], group_search_base_dns: 12_345 + end.to raise_error(Puppet::Error, %r{must be an Array}) + end + + it 'fails if group_search_base_dns array members are not strings' do + expect do + described_class.new name: 'server1', hosts: ['server1'], group_search_base_dns: [12_345] + end.to raise_error(Puppet::Error, %r{must be a String}) + end + + it 'fails if group_search_base_dns array is empty' do + expect do + described_class.new name: 'server1', hosts: ['server1'], group_search_base_dns: [], search_base_dns: ['ou=auth'] + end.to raise_error(RuntimeError, %r{needs to contain at least one LDAP base-dn}) + end + + it 'succeeds if all is correct' do + expect do + described_class.new name: 'server1', hosts: ['server1'], group_search_base_dns: ['ou=users'] + end + end + end + + # attributes + context 'validate attributes' do + it 'fails if attributes is not a hash' do + expect do + described_class.new name: 'server1', hosts: ['server1'], attributes: [12_345] + end.to raise_error(Puppet::Error, %r{must be a Hash}) + end + + it 'fails if unknown attribute' do + expect do + described_class.new name: 'server1', hosts: ['server1'], attributes: { 'foo' => 'bar' } + end.to raise_error(Puppet::Error, %r{contains an unknown key}) + end + + it 'fails if wrong key type' do + expect do + described_class.new name: 'server1', hosts: ['server1'], attributes: { 12_345 => 'bar' } + end.to raise_error(Puppet::Error, %r{must be Strings}) + end + + it 'fails if wrong value type' do + expect do + described_class.new name: 'server1', hosts: ['server1'], attributes: { 'surname' => {} } + end.to raise_error(Puppet::Error, %r{must be Strings}) + end + + it 'succeeds if all is correct' do + expect do + described_class.new name: 'server1', hosts: ['server1'], attributes: { 'username' => 'uid' } + end + end + end +end