diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..d8f63dd --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,64 @@ +inherit_from: .rubocop_todo.yml + +Layout/ClassStructure: + Enabled: true +Layout/FirstArgumentIndentation: + EnforcedStyle: consistent +Layout/FirstArrayElementIndentation: + EnforcedStyle: consistent +Layout/FirstHashElementIndentation: + EnforcedStyle: consistent +Layout/FirstArrayElementLineBreak: + Enabled: true +Layout/FirstHashElementLineBreak: + Enabled: true +Layout/FirstMethodArgumentLineBreak: + Enabled: true +Layout/FirstMethodParameterLineBreak: + Enabled: true +Layout/MultilineArrayLineBreaks: + Enabled: true +Layout/MultilineHashKeyLineBreaks: + Enabled: true +Layout/MultilineMethodArgumentLineBreaks: + Enabled: true +Layout/MultilineMethodCallIndentation: + EnforcedStyle: indented + +Metrics/ClassLength: + Max: 200 +Metrics/MethodLength: + Max: 25 + +Style/AccessorGrouping: + Enabled: false +Style/ClassAndModuleChildren: + EnforcedStyle: compact +Style/Documentation: + Enabled: false +Style/FrozenStringLiteralComment: + Enabled: false +Style/HashSyntax: + EnforcedShorthandSyntax: never +Style/RegexpLiteral: + AllowInnerSlashes: true +Style/SymbolArray: + EnforcedStyle: brackets +Style/SpecialGlobalVars: + Enabled: false +Style/WordArray: + EnforcedStyle: brackets + +RSpec/ExampleLength: + Max: 10 +RSpec/ExpectChange: + EnforcedStyle: 'block' +RSpec/IndexedLet: + Enabled: false +RSpec/MultipleMemoizedHelpers: + Max: 20 +RSpec/NestedGroups: + Max: 5 + +require: + - rubocop-rspec diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml new file mode 100644 index 0000000..51e7c1c --- /dev/null +++ b/.rubocop_todo.yml @@ -0,0 +1,191 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2024-11-07 16:14:10 UTC using RuboCop version 1.68.0. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 1 +# Configuration parameters: Severity, Include. +# Include: **/*.gemspec +Gemspec/RequiredRubyVersion: + Exclude: + - 'unit_tests_utils.gemspec' + +# Offense count: 4 +Lint/RescueException: + Exclude: + - 'lib/unit_tests_utils/postgresql_web_service_client.rb' + +# Offense count: 2 +Lint/ShadowingOuterLocalVariable: + Exclude: + - 'lib/unit_tests_utils/postgresql_web_service_client.rb' + +# Offense count: 1 +# Configuration parameters: AllowComments, AllowNil. +Lint/SuppressedException: + Exclude: + - 'lib/unit_tests_utils/turbulence.rb' + +# Offense count: 1 +Lint/UnreachableCode: + Exclude: + - 'lib/unit_tests_utils/turbulence.rb' + +# Offense count: 16 +# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. +Metrics/AbcSize: + Max: 39 + +# Offense count: 2 +# Configuration parameters: CountComments, Max, CountAsOne. +Metrics/ClassLength: + Exclude: + - 'lib/unit_tests_utils/postgresql_web_service_client.rb' + - 'lib/unit_tests_utils/turbulence.rb' + +# Offense count: 4 +# Configuration parameters: AllowedMethods, AllowedPatterns. +Metrics/CyclomaticComplexity: + Max: 12 + +# Offense count: 1 +# Configuration parameters: CountComments, Max, CountAsOne, AllowedMethods, AllowedPatterns. +Metrics/MethodLength: + Exclude: + - 'lib/unit_tests_utils/turbulence.rb' + +# Offense count: 1 +# Configuration parameters: CountComments, CountAsOne. +Metrics/ModuleLength: + Max: 177 + +# Offense count: 3 +# Configuration parameters: AllowedMethods, AllowedPatterns. +Metrics/PerceivedComplexity: + Max: 12 + +# Offense count: 5 +# Configuration parameters: NamePrefix, ForbiddenPrefixes, AllowedMethods, MethodDefinitionMacros. +# NamePrefix: is_, has_, have_ +# ForbiddenPrefixes: is_, has_, have_ +# AllowedMethods: is_a? +# MethodDefinitionMacros: define_method, define_singleton_method +Naming/PredicateName: + Exclude: + - 'spec/**/*' + - 'lib/unit_tests_utils/postgresql_web_service_client.rb' + - 'lib/unit_tests_utils/traversal.rb' + - 'lib/unit_tests_utils/turbulence.rb' + +# Offense count: 6 +# Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers, AllowedPatterns. +# SupportedStyles: snake_case, normalcase, non_integer +# AllowedIdentifiers: capture3, iso8601, rfc1123_date, rfc822, rfc2822, rfc3339, x86_64 +Naming/VariableNumber: + Exclude: + - 'spec/lib/unit_tests_utils/manifest_spec.rb' + +# Offense count: 2 +# Configuration parameters: Prefixes, AllowedPatterns. +# Prefixes: when, with, without +RSpec/ContextWording: + Exclude: + - 'spec/lib/unit_tests_utils/manifest_spec.rb' + - 'spec/lib/unit_tests_utils/traversal_spec.rb' + +# Offense count: 2 +# Configuration parameters: Max, CountAsOne. +RSpec/ExampleLength: + Exclude: + - 'spec/lib/unit_tests_utils/bosh_spec.rb' + +# Offense count: 6 +RSpec/ExpectInHook: + Exclude: + - 'spec/lib/unit_tests_utils/bosh_spec.rb' + - 'spec/lib/unit_tests_utils/internal_dns_spec.rb' + +# Offense count: 61 +# Configuration parameters: . +# SupportedStyles: have_received, receive +RSpec/MessageSpies: + EnforcedStyle: receive + +# Offense count: 54 +RSpec/MultipleExpectations: + Max: 7 + +# Offense count: 5 +# Configuration parameters: EnforcedStyle, IgnoreSharedExamples. +# SupportedStyles: always, named_only +RSpec/NamedSubject: + Exclude: + - 'spec/lib/unit_tests_utils/cmd_spec.rb' + - 'spec/lib/unit_tests_utils/template_render_spec.rb' + +# Offense count: 1 +# Configuration parameters: AllowedPatterns. +# AllowedPatterns: ^expect_, ^assert_ +RSpec/NoExpectationExample: + Exclude: + - 'spec/lib/unit_tests_utils/credhub_spec.rb' + +# Offense count: 4 +# Configuration parameters: Include, CustomTransform, IgnoreMethods, IgnoreMetadata. +# Include: **/*_spec.rb +RSpec/SpecFilePathFormat: + Exclude: + - '**/spec/routing/**/*' + - 'spec/lib/unit_tests_utils/credhub_spec.rb' + - 'spec/lib/unit_tests_utils/postgresql_client_spec.rb' + - 'spec/lib/unit_tests_utils/postgresql_web_service_client_spec.rb' + - 'spec/lib/unit_tests_utils/traversal_spec.rb' + +# Offense count: 4 +RSpec/StubbedMock: + Exclude: + - 'spec/lib/unit_tests_utils/bosh_spec.rb' + - 'spec/lib/unit_tests_utils/internal_dns_spec.rb' + +# Offense count: 12 +RSpec/SubjectStub: + Exclude: + - 'spec/lib/unit_tests_utils/postgresql_client_spec.rb' + +# Offense count: 2 +# Configuration parameters: IgnoreNameless, IgnoreSymbolicNames. +RSpec/VerifiedDoubles: + Exclude: + - 'spec/lib/unit_tests_utils/cmd_spec.rb' + - 'spec/lib/unit_tests_utils/postgresql_web_service_client_spec.rb' + +# Offense count: 1 +Style/ClassVars: + Exclude: + - 'lib/unit_tests_utils/manifest.rb' + +# Offense count: 4 +# This cop supports safe autocorrection (--autocorrect). +Style/IfUnlessModifier: + Exclude: + - 'lib/unit_tests_utils/bosh.rb' + - 'lib/unit_tests_utils/cmd.rb' + - 'lib/unit_tests_utils/consul.rb' + +# Offense count: 3 +# Configuration parameters: AllowedMethods. +# AllowedMethods: respond_to_missing? +Style/OptionalBooleanParameter: + Exclude: + - 'lib/unit_tests_utils/bosh.rb' + - 'lib/unit_tests_utils/manifest.rb' + +# Offense count: 24 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns. +# URISchemes: http, https +Layout/LineLength: + Max: 205 diff --git a/Gemfile b/Gemfile index 5d4e385..e1ebc3a 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,7 @@ source 'https://rubygems.org' +gem 'destructor' +gem 'httparty', '0.22.0' +gem 'pg', '1.5.9' gem 'rspec' gem 'rubocop' -gem 'destructor' -gem 'httparty', '0.21.0' -gem 'pg', '0.21.0' diff --git a/Gemfile.lock b/Gemfile.lock index 879a55b..7d9407a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,64 +2,65 @@ GEM remote: https://rubygems.org/ specs: ast (2.4.2) - base64 (0.1.1) + bigdecimal (3.1.8) + csv (3.3.0) destructor (0.1.0) - diff-lcs (1.5.0) - httparty (0.21.0) + diff-lcs (1.5.1) + httparty (0.22.0) + csv mini_mime (>= 1.0.0) multi_xml (>= 0.5.2) - json (2.6.3) + json (2.8.1) language_server-protocol (3.17.0.3) mini_mime (1.1.5) - multi_xml (0.6.0) - parallel (1.23.0) - parser (3.2.2.3) + multi_xml (0.7.1) + bigdecimal (~> 3.1) + parallel (1.26.3) + parser (3.3.6.0) ast (~> 2.4.1) racc - pg (0.21.0) - racc (1.7.1) + pg (1.5.9) + racc (1.8.1) rainbow (3.1.1) - regexp_parser (2.8.1) - rexml (3.2.6) - rspec (3.12.0) - rspec-core (~> 3.12.0) - rspec-expectations (~> 3.12.0) - rspec-mocks (~> 3.12.0) - rspec-core (3.12.2) - rspec-support (~> 3.12.0) - rspec-expectations (3.12.3) + regexp_parser (2.9.2) + rspec (3.13.0) + rspec-core (~> 3.13.0) + rspec-expectations (~> 3.13.0) + rspec-mocks (~> 3.13.0) + rspec-core (3.13.2) + rspec-support (~> 3.13.0) + rspec-expectations (3.13.3) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.12.0) - rspec-mocks (3.12.6) + rspec-support (~> 3.13.0) + rspec-mocks (3.13.2) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.12.0) - rspec-support (3.12.1) - rubocop (1.56.3) - base64 (~> 0.1.1) + rspec-support (~> 3.13.0) + rspec-support (3.13.1) + rubocop (1.68.0) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) - parser (>= 3.2.2.3) + parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 1.8, < 3.0) - rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.28.1, < 2.0) + regexp_parser (>= 2.4, < 3.0) + rubocop-ast (>= 1.32.2, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.29.0) - parser (>= 3.2.1.0) + rubocop-ast (1.34.0) + parser (>= 3.3.1.0) ruby-progressbar (1.13.0) - unicode-display_width (2.4.2) + unicode-display_width (2.6.0) PLATFORMS + arm64-darwin-23 ruby DEPENDENCIES destructor - httparty (= 0.21.0) - pg (= 0.21.0) + httparty (= 0.22.0) + pg (= 1.5.9) rspec rubocop BUNDLED WITH - 2.3.16 + 2.5.23 diff --git a/lib/unit_tests_utils/bosh.rb b/lib/unit_tests_utils/bosh.rb index af5ffa2..2c3844e 100644 --- a/lib/unit_tests_utils/bosh.rb +++ b/lib/unit_tests_utils/bosh.rb @@ -8,9 +8,12 @@ def self.deploy(deployment_name, manifest_path, additional_vars = [], ops_files vars << " -l #{ENV['PATH_TO_CREDS']}" if ENV['PATH_TO_CREDS'] additional_vars.each { |key, value| vars << " --var #{key}='#{value}'" } - ops_files.each { |file| vars << " --ops-file #{file}"} + ops_files.each { |file| vars << " --ops-file #{file}" } - execute_or_raise_error("bosh --non-interactive -d #{deployment_name} deploy #{vars} #{manifest_path}", "Deploy failed") + execute_or_raise_error( + "bosh --non-interactive -d #{deployment_name} deploy #{vars} #{manifest_path}", + 'Deploy failed' + ) wait_for_task_to_finish(deployment_name) end @@ -21,12 +24,19 @@ def self.deploy_manifest(deployment_name, manifest, additional_vars = []) vars << " -l #{ENV['PATH_TO_CREDS']}" if ENV['PATH_TO_CREDS'] additional_vars.each { |key, value| vars << " --var #{key}='#{value}'" } - execute_or_raise_error_in("bosh --non-interactive -d #{deployment_name} deploy #{vars}", manifest.manifest.to_yaml, "Deploy failed") + execute_or_raise_error_in( + "bosh --non-interactive -d #{deployment_name} deploy #{vars}", + manifest.manifest.to_yaml, + 'Deploy failed' + ) wait_for_task_to_finish(deployment_name) end def self.find_in_deployment_manifest(deployment_name, ops_search_path = '') - manifest_as_str = execute_or_raise_error("bosh --non-interactive -d #{deployment_name} manifest", "Couldn't fetch deployment mainfest") + manifest_as_str = execute_or_raise_error( + "bosh --non-interactive -d #{deployment_name} manifest", + "Couldn't fetch deployment mainfest" + ) manifest = YAML.load(manifest_as_str) if ops_search_path.empty? manifest @@ -36,15 +46,23 @@ def self.find_in_deployment_manifest(deployment_name, ops_search_path = '') end def self.delete_deployment(deployment_name) - execute_or_raise_error("bosh --non-interactive -d #{deployment_name} delete-deployment --force", "Delete deployment failed") + execute_or_raise_error( + "bosh --non-interactive -d #{deployment_name} delete-deployment --force", + 'Delete deployment failed' + ) wait_for_task_to_finish(deployment_name) end def self.start_instance(deployment_name, instance_name, index = '0', debug = true) if debug - execute_or_raise_error("bosh --non-interactive -d #{deployment_name} start #{instance_name}/#{index}", "Starting instance failed") + execute_or_raise_error( + "bosh --non-interactive -d #{deployment_name} start #{instance_name}/#{index}", + 'Starting instance failed' + ) else - execute_or_raise_error("bosh --non-interactive -d #{deployment_name} start #{instance_name}/#{index} > /dev/null 2> /dev/null", "Starting instance failed") + execute_or_raise_error( + "bosh --non-interactive -d #{deployment_name} start #{instance_name}/#{index} > /dev/null 2> /dev/null", 'Starting instance failed' + ) end wait_for_task_to_finish(deployment_name) end @@ -54,49 +72,62 @@ def self.start_instance(deployment_name, instance_name, index = '0', debug = tru # are provided. # The corresponding documentation of the lifecycle hooks starts here: https://bosh.io/docs/drain def self.stop_instance(deployment_name, instance_name, index = '0', params = '') - execute_or_raise_error("bosh --non-interactive -d #{deployment_name} stop #{instance_name}/#{index} #{params}".strip, "Stopping instance failed") + execute_or_raise_error( + "bosh --non-interactive -d #{deployment_name} stop #{instance_name}/#{index} #{params}".strip, 'Stopping instance failed' + ) wait_for_task_to_finish(deployment_name) end def self.run_errand(deployment_name, errand_name) - execute_or_raise_error("bosh --non-interactive -d #{deployment_name} run-errand #{errand_name}", "Failed to run errand #{errand_name}") + execute_or_raise_error( + "bosh --non-interactive -d #{deployment_name} run-errand #{errand_name}", + "Failed to run errand #{errand_name}" + ) wait_for_task_to_finish(deployment_name) end def self.create_and_upload_dev_release(base_dir, release_name, version_prefix = '') version = dev_release_version(version_prefix) - raw_json = execute_or_raise_error("bosh --json create-release --dir #{base_dir} --name #{release_name} --version #{version} --force", "Creating release failed") + raw_json = execute_or_raise_error( + "bosh --json create-release --dir #{base_dir} --name #{release_name} --version #{version} --force", 'Creating release failed' + ) metadata = parse_json_from_create_release(raw_json) release_name = "#{metadata[:unit_test_release_name]}-#{metadata[:unit_test_release_version]}.yml" release_path = File.join(base_dir, 'dev_releases', metadata[:unit_test_release_name], release_name) - execute_or_raise_error("bosh upload-release --dir #{base_dir} #{release_path}", "Uploading release failed") + execute_or_raise_error("bosh upload-release --dir #{base_dir} #{release_path}", 'Uploading release failed') metadata end def self.instance_status(deployment_name, instance_name, index = nil) - output = execute_or_raise_error("bosh --non-interactive -d #{deployment_name} instances --details --json", "Instance status failed") + output = execute_or_raise_error( + "bosh --non-interactive -d #{deployment_name} instances --details --json", + 'Instance status failed' + ) json = JSON.parse(output) - raise Exception.new("Could not find 'Tables'. Maybe this is a request timeout.") if json['Tables'].nil? + raise BoshError, "Could not find 'Tables'. Maybe this is a request timeout." if json['Tables'].nil? rows = json['Tables'].first.select { |table| table == 'Rows' } rows['Rows'].select do |vm| vm['instance'].split('/')[0] == instance_name and - (index.nil? or vm['index'] == index) + (index.nil? or vm['index'] == index) end end def self.delete_release(release_name, release_version = nil) release_name << "/#{release_version}" unless release_version.nil? - execute_or_raise_error("bosh --non-interactive delete-release #{release_name}", "Delete release failed") + execute_or_raise_error("bosh --non-interactive delete-release #{release_name}", 'Delete release failed') end def self.ssh(deployment_name, command, instance_name = nil, index = '0') if instance_name - execute_or_raise_error("bosh -d #{deployment_name} ssh #{instance_name}/#{index} -c '#{command}'", "Cannot execute command #{command}") + execute_or_raise_error( + "bosh -d #{deployment_name} ssh #{instance_name}/#{index} -c '#{command}'", + "Cannot execute command #{command}" + ) else execute_or_raise_error("bosh -d #{deployment_name} ssh -c '#{command}'", "Cannot execute command #{command}") end @@ -105,24 +136,34 @@ def self.ssh(deployment_name, command, instance_name = nil, index = '0') # returns an array of json object containing all the information about the instances # HINT: Consul DNS Name does only conatain hostpart! def self.get_deployment_info(deployment_name) - raw_json = execute_or_raise_error("bosh --non-interactive -d #{deployment_name} instances --json -i", "Cannot generate JSON with instances information") + raw_json = execute_or_raise_error( + "bosh --non-interactive -d #{deployment_name} instances --json -i", + 'Cannot generate JSON with instances information' + ) json = JSON.parse(raw_json) - result = Array.new + result = [] json['Tables'].first['Rows'].each do |row| - instancegroupname = row['instance'].split("/")[0] - id = row['instance'].split("/")[1] - result << { "instancegroupname" => instancegroupname, "id" => id, "index" => row["index"], "ip" => row["ips"], "cid" => row["vm_cid"], "az" => row["az"], "consuldnsname" => "#{deployment_name}-#{instancegroupname}-#{row["index"]}", "bootstrap" => row["bootstrap"] } + instancegroupname = row['instance'].split('/')[0] + id = row['instance'].split('/')[1] + result << { + 'instancegroupname' => instancegroupname, + 'id' => id, + 'index' => row['index'], + 'ip' => row['ips'], + 'cid' => row['vm_cid'], + 'az' => row['az'], + 'consuldnsname' => "#{deployment_name}-#{instancegroupname}-#{row['index']}", + 'bootstrap' => row['bootstrap'] + } end - return result + result end def get_id_for_index(deployment_name, instancename, jobindex) deployment_info = get_deployment_info(deployment_name) deployment_info.each do |instance| - if instance['instancegroupname'] == instancename && instance['index'] == jobindex - return instance['id'] - end + return instance['id'] if instance['instancegroupname'] == instancename && instance['index'] == jobindex end end @@ -134,17 +175,15 @@ def self.interpolate(manifest_path, additional_vars = [], vars_errs = false, ops ops_files.each { |file| vars << " --ops-file #{file}" } vars << ' --var-errs' if vars_errs - execute_or_raise_error("bosh interpolate #{vars} #{manifest_path}", "Interpolate failed") + execute_or_raise_error("bosh interpolate #{vars} #{manifest_path}", 'Interpolate failed') end - private - def self.wait_for_task_to_finish(deployment_name) `bosh -d #{deployment_name} task > /dev/null 2>&1` end def self.dev_release_version(version_prefix) - version = "dev." + version = 'dev.' version << "#{version_prefix}." unless version_prefix.empty? version << Time.now.to_i.to_s @@ -154,7 +193,7 @@ def self.dev_release_version(version_prefix) def self.parse_json_from_create_release(raw_json) json = JSON.parse(raw_json) - raise Exception.new("Could not find 'Tables'. Maybe this is a request timeout.") if json['Tables'].nil? + raise BoshError, "Could not find 'Tables'. Maybe this is a request timeout." if json['Tables'].nil? metadata = json['Tables'].select { |table| table['Content'].empty? }.first['Rows'].first normalized_version = metadata['version'].gsub('.', '-') @@ -169,20 +208,22 @@ def self.parse_json_from_create_release(raw_json) def self.execute_or_raise_error(command, msg) stdout, stderr, exit_status = Open3.capture3(command) - if !exit_status.nil? && exit_status.to_i > 0 - raise BoshError.new("#{msg} - exit_status: #{exit_status}\nstdout: #{stdout}\nstderr: #{stderr}") + if !exit_status.nil? && exit_status.to_i.positive? + raise BoshError, "#{msg} - exit_status: #{exit_status}\nstdout: #{stdout}\nstderr: #{stderr}" end - return stdout + + stdout end # execute_or_raise_error_in executes the command with stdin provided and # raises an error if the command is unsuccessful. def self.execute_or_raise_error_in(stdin, command, msg) stdout, stderr, exit_status = Open3.capture3(command, stdin_data: stdin) - if !exit_status.nil? && exit_status.to_i > 0 - raise BoshError.new("#{msg} - exit_status: #{exit_status}\nstdout: #{stdout}\nstderr: #{stderr}") + if !exit_status.nil? && exit_status.to_i.positive? + raise BoshError, "#{msg} - exit_status: #{exit_status}\nstdout: #{stdout}\nstderr: #{stderr}" end - return stdout + + stdout end class BoshError < StandardError; end diff --git a/lib/unit_tests_utils/cmd.rb b/lib/unit_tests_utils/cmd.rb index 607f3df..589d48d 100644 --- a/lib/unit_tests_utils/cmd.rb +++ b/lib/unit_tests_utils/cmd.rb @@ -4,29 +4,28 @@ module UnitTestsUtils::Cmd # Executes a command on the local machine and throws an error if exit status is not 0 (success) def self.exec(command, msg) stdout, stderr, exit_status = Open3.capture3(command) - if !exit_status.nil? && exit_status.to_i > 0 - raise CmdError.new("#{msg} - exit_status: #{exit_status}\nstdout: #{stdout}\nstderr: #{stderr}") + if !exit_status.nil? && exit_status.to_i.positive? + raise CmdError, "#{msg} - exit_status: #{exit_status}\nstdout: #{stdout}\nstderr: #{stderr}" end - return stdout, stderr + + [stdout, stderr] end def self.exec_with_retry(error_message, backoff: 5, retries: 1200) counter = 0 - while ! result = yield do + until (result = yield) sleep(backoff) puts "Attempt number #{counter} out of #{retries} retries" - if counter >= retries - raise CmdError.new(error_message) - end + raise CmdError, error_message if counter >= retries counter += 1 end - return result - end + result + end class CmdError < StandardError; end end diff --git a/lib/unit_tests_utils/consul.rb b/lib/unit_tests_utils/consul.rb index aa30753..fd71d55 100644 --- a/lib/unit_tests_utils/consul.rb +++ b/lib/unit_tests_utils/consul.rb @@ -13,9 +13,10 @@ def self.deregister_master_alias(master_alias) http_code = `curl -s -S -w %{http_code} -o /dev/null --connect-timeout 15 -X PUT -d '#{payload}' #{consul_endpoint}` - if "#{http_code}" != "200" - raise ("could not deregister master alias: #{http_code} payload: #{payload}, endpoint: #{consul_endpoint}") + if http_code.to_s != '200' + raise("could not deregister master alias: #{http_code} payload: #{payload}, endpoint: #{consul_endpoint}") end - return true + + true end end diff --git a/lib/unit_tests_utils/credhub.rb b/lib/unit_tests_utils/credhub.rb index c7bb092..05d5525 100644 --- a/lib/unit_tests_utils/credhub.rb +++ b/lib/unit_tests_utils/credhub.rb @@ -1,18 +1,16 @@ require_relative 'cmd' class UnitTestsUtils::CredHub - APP = 'credhub' - GET_COMMAND = 'get' - JSON_FORMAT_SUB_COMMAND = '--output-json' - COMMAND_FAIL_PREFIX_MESSAGE = 'CredHub command failed:' + APP = 'credhub'.freeze + GET_COMMAND = 'get'.freeze + JSON_FORMAT_SUB_COMMAND = '--output-json'.freeze + COMMAND_FAIL_PREFIX_MESSAGE = 'CredHub command failed:'.freeze def self.get_by_name(name) stdout, stderr = execute(GET_COMMAND, "--name='#{name}'") - return JSON.parse(stdout), stderr + [JSON.parse(stdout), stderr] end - private - def self.execute(command, sub_command, response_format = JSON_FORMAT_SUB_COMMAND) command = "#{APP} #{command} #{sub_command} #{response_format}" UnitTestsUtils::Cmd.exec(command, "#{COMMAND_FAIL_PREFIX_MESSAGE} #{command}") diff --git a/lib/unit_tests_utils/internal_dns.rb b/lib/unit_tests_utils/internal_dns.rb index c2e2df2..b5619cb 100644 --- a/lib/unit_tests_utils/internal_dns.rb +++ b/lib/unit_tests_utils/internal_dns.rb @@ -1,16 +1,14 @@ module UnitTestsUtils::InternalDNS # DEPRECATED: Please use resolve_domain_name instead. def self.resolv(hostname) - warn "[DEPRECATION] `resolv` is deprecated. Please use `resolve_domain_name` instead." + warn '[DEPRECATION] `resolv` is deprecated. Please use `resolve_domain_name` instead.' resolve_domain_name(hostname).first end def self.resolve_domain_name(hostname) - if self.valid_ips?([hostname]) - return [hostname] - end + return [hostname] if valid_ips?([hostname]) - return `dig +short #{hostname} @#{nameserver_ip}`.strip.split("\n") + `dig +short #{hostname} @#{nameserver_ip}`.strip.split("\n") end def self.host_addresses(hostnames, port) diff --git a/lib/unit_tests_utils/manifest.rb b/lib/unit_tests_utils/manifest.rb index c47221b..29b380d 100644 --- a/lib/unit_tests_utils/manifest.rb +++ b/lib/unit_tests_utils/manifest.rb @@ -8,26 +8,26 @@ class UnitTestsUtils::Manifest attr_reader :path, :manifest, :additional_vars def self.create(name, manifest_path, additional_vars = {}, ignore_existing = false) - raise ArgumentError, "Manifest for name #{name} already exists" if !ignore_existing && @@instances.has_key?(name) + raise ArgumentError, "Manifest for name #{name} already exists" if !ignore_existing && @@instances.key?(name) - @@instances[name] = self.new(manifest_path, additional_vars) + @@instances[name] = new(manifest_path, additional_vars) end def self.fetch(name) - raise ArgumentError, "Manifest for name #{name} does not exist" unless @@instances.has_key?(name) + raise ArgumentError, "Manifest for name #{name} does not exist" unless @@instances.key?(name) @@instances[name] end def self.create_from_env(manifest_prefix, additional_vars = {}) - manifest_prefix_length= manifest_prefix.length + manifest_prefix_length = manifest_prefix.length ENV.each_key do |name| - if name.start_with?(manifest_prefix) - manifest_name = name[manifest_prefix_length..-1].to_sym + next unless name.start_with?(manifest_prefix) - self.create(manifest_name, ENV[name], additional_vars) - end + manifest_name = name[manifest_prefix_length..].to_sym + + create(manifest_name, ENV[name], additional_vars) end end @@ -35,7 +35,7 @@ def initialize(manifest_path, additional_vars = {}, ops_files = []) @path = manifest_path interpolated_manifest = UnitTestsUtils::Bosh.interpolate(manifest_path, additional_vars, false, ops_files) @manifest = YAML.load(interpolated_manifest) - @additional_vars = Hash[additional_vars.map { |key, value| [key.to_sym, value] }] + @additional_vars = additional_vars.transform_keys(&:to_sym) end def name @@ -43,7 +43,7 @@ def name additional_vars_key = manifest['name'][/^\(\((.*)\)\)$/, 1] additional_vars_key = additional_vars_key.to_sym if additional_vars_key - if additional_vars_key && additional_vars.has_key?(additional_vars_key) + if additional_vars_key && additional_vars.key?(additional_vars_key) additional_vars[additional_vars_key] else manifest['name'] @@ -60,7 +60,7 @@ def instance_count(instance_name) end def hostname(instance_name = nil, index = '0') - instance_name = instance_names.first unless instance_name + instance_name ||= instance_names.first key = "#{instance_name}/#{index}" hostnames[key] @@ -72,7 +72,8 @@ def hostnames instance_names.each do |instance_name| instance_count(instance_name).times do |index| - hostnames["#{instance_name}/#{index}"] = "#{name}-#{instance_name}-#{index}.node.#{properties['consul']['dc']}.#{properties['consul']['domain']}" + hostnames["#{instance_name}/#{index}"] = + "#{name}-#{instance_name}-#{index}.node.#{properties['consul']['dc']}.#{properties['consul']['domain']}" end end @@ -85,14 +86,14 @@ def properties(path = nil) UnitTestsUtils::Manifest::Traversal.new(manifest).find(path) else {}.tap do |merged_properties| - instance_groups = manifest.dig('instance_groups') + instance_groups = manifest['instance_groups'] instance_groups.each do |instance| - instance.each do |key,value| - if key == "jobs" - value.each do |job| - property = job.dig('properties') - deep_merge!(merged_properties, (property || {})) - end + instance.each do |key, value| + next unless key == 'jobs' + + value.each do |job| + property = job['properties'] + deep_merge!(merged_properties, (property || {})) end end end @@ -111,10 +112,9 @@ def properties(path = nil) # section of the instance group. def get_network(instance_name) network = instance_group(instance_name)['properties']['network'] - if instance_group(instance_name)['networks'].any? { |n| n['name'] == network } - return network - end - raise "properties.network was not found in networks" + return network if instance_group(instance_name)['networks'].any? { |n| n['name'] == network } + + raise 'properties.network was not found in networks' end # set_network changes the network in the internal representation of the @@ -124,7 +124,7 @@ def set_network(instance_name, new_network) ig = instance_group(instance_name) ig['networks'].delete_if { |n| n['name'] == old_network } ig['properties']['network'] = new_network - ig['networks'].push( { "name" => new_network } ) + ig['networks'].push({ 'name' => new_network }) end def instance_group(instance_name) diff --git a/lib/unit_tests_utils/postgresql_client.rb b/lib/unit_tests_utils/postgresql_client.rb index 33ead11..81cec9e 100644 --- a/lib/unit_tests_utils/postgresql_client.rb +++ b/lib/unit_tests_utils/postgresql_client.rb @@ -4,31 +4,29 @@ class UnitTestsUtils::PostgreSQLClient attr_reader :args - POSTGRESQL_PROPERTIES_PATH = '/instance_groups/name=pg/jobs/name=postgresql-ha/properties' + POSTGRESQL_PROPERTIES_PATH = '/instance_groups/name=pg/jobs/name=postgresql-ha/properties'.freeze TEST_TABLE = 'a9s_pg_tests'.freeze - def initialize(args) - @args = args - @args[:dbname] ||= 'area51' - @args[:sslmode] ||= 'disable' - end - def self.create_from_manifest(manifest, args = {}) args[:host] ||= manifest.hostname args[:user] ||= manifest.properties['postgresql-ha']['admin_credentials']['username'] args[:password] ||= manifest.properties['postgresql-ha']['admin_credentials']['password'] - if manifest.properties("#{POSTGRESQL_PROPERTIES_PATH}/postgresql-ha/ssl?/enable") - args[:sslmode] = "require" - end + args[:sslmode] = 'require' if manifest.properties("#{POSTGRESQL_PROPERTIES_PATH}/postgresql-ha/ssl?/enable") - self.new(args) + new(args) + end + + def initialize(args) + @args = args + @args[:dbname] ||= 'area51' + @args[:sslmode] ||= 'disable' end def ping(extra_args = {}) ping_args = args.merge(extra_args) logger.debug("* Creating ping with args: *#{ping_args}*") - return PG::Connection.ping(ping_args) + PG::Connection.ping(ping_args) end def drop_table @@ -36,12 +34,14 @@ def drop_table end def create_table - execute("CREATE TABLE IF NOT EXISTS #{TEST_TABLE} (test_key TEXT PRIMARY KEY NOT NULL, " \ - "test_value TEXT NOT NULL)") + execute( + "CREATE TABLE IF NOT EXISTS #{TEST_TABLE} (test_key TEXT PRIMARY KEY NOT NULL, " \ + 'test_value TEXT NOT NULL)' + ) end def generate_data - {'test_key' => "#{SecureRandom.uuid}", 'test_value' => "#{SecureRandom.uuid}"} + { 'test_key' => SecureRandom.uuid.to_s, 'test_value' => SecureRandom.uuid.to_s } end def insert(data) @@ -79,13 +79,13 @@ def extensions def connect(extra_args = {}) connect_args = args.merge(extra_args) logger.debug("* Creating connection with args: *#{connect_args}*") - return PG::Connection.new(connect_args) + PG::Connection.new(connect_args) end def execute(sql, args = {}) conn = connect(args) - return conn.exec(sql) + conn.exec(sql) ensure - conn.close if !conn.nil? + conn&.close end end diff --git a/lib/unit_tests_utils/postgresql_web_service_client.rb b/lib/unit_tests_utils/postgresql_web_service_client.rb index 42affb9..c91cfd2 100644 --- a/lib/unit_tests_utils/postgresql_web_service_client.rb +++ b/lib/unit_tests_utils/postgresql_web_service_client.rb @@ -4,7 +4,11 @@ class UnitTestsUtils::PGWebServiceClient attr_reader :manifest, :manifest_name, :password - DEFAULT_WEB_SERVICE_PASSWORD = 'password' + DEFAULT_WEB_SERVICE_PASSWORD = 'password'.freeze + + def self.master_hostname(manifest) + "#{manifest.name}-psql-master-alias.node.#{manifest.properties['consul']['dc']}.#{manifest.properties['consul']['domain']}" + end def initialize(manifest, options = {}) @manifest_name = options[:new_manifest_name] || manifest.name @@ -13,77 +17,70 @@ def initialize(manifest, options = {}) @manifest = manifest end - def self.master_hostname(manifest) - "#{manifest.name}-psql-master-alias.node.#{manifest.properties['consul']['dc']}.#{manifest.properties['consul']['domain']}" - end - def node_ips instances = UnitTestsUtils::Bosh.instance_status(manifest_name, manifest.instance_names.first) - instances.map { |instance| instance["ips"] } + instances.map { |instance| instance['ips'] } end def wait_cluster_is_ready(period = 5, retries = 1200) counter = 0 - while ! is_cluster_ready do + until is_cluster_ready sleep(period) - if counter >= retries - raise Exception.new("Timed out waiting for deployment to be ready") - end + raise StandardError, 'Timed out waiting for deployment to be ready' if counter >= retries + counter += 1 end end def master_node node_ips.each do |node_ip| - begin - result = HTTParty.get("http://#{node_ip}:63145/v1/master", basic_auth: webservice_credentials) + result = HTTParty.get("http://#{node_ip}:63145/v1/master", basic_auth: webservice_credentials) - logger.debug("Response from *#{node_ip}* - Master node: #{result}") + logger.debug("Response from *#{node_ip}* - Master node: #{result}") - if result.response.kind_of?(Net::HTTPSuccess) - body = JSON.parse(result.body) - return body if body["data"] != "No Quorum" - end - rescue Exception - logger.debug("Could not reach node: #{node_ip}") + if result.response.is_a?(Net::HTTPSuccess) + body = JSON.parse(result.body) + return body if body['data'] != 'No Quorum' end + rescue Exception + logger.debug("Could not reach node: #{node_ip}") end - raise Exception.new("Could not reach any node") + raise StandardError, 'Could not reach any node' end def master_ip - return master_node["data"]["node_ip"] + master_node['data']['node_ip'] end def standby_ips - standby_nodes.map { |node| node["data"]["node_ip"] } + standby_nodes.map { |node| node['data']['node_ip'] } end def standby_nodes nodes = node_ips.map do |node_ip| - begin - JSON.parse(HTTParty.get("http://#{node_ip}:63145/v1/status", basic_auth: webservice_credentials).body) - rescue Exception - logger.debug("Could not reach node: #{node_ip}") - nil - end + JSON.parse(HTTParty.get("http://#{node_ip}:63145/v1/status", basic_auth: webservice_credentials).body) + rescue Exception + logger.debug("Could not reach node: #{node_ip}") + nil end - return nodes.select { |node| !node.nil? && node["status"] == "succeeded" && node["data"]["mode"] == "standby" } + nodes.select { |node| !node.nil? && node['status'] == 'succeeded' && node['data']['mode'] == 'standby' } end def standby_min_age - return 60 if manifest.properties["postgresql-info-webservice"].nil? - return 60 if manifest.properties["postgresql-info-webservice"]["monitor"].nil? - return 60 if manifest.properties["postgresql-info-webservice"]["monitor"]["min_standby_age"].nil? - return manifest.properties["postgresql-info-webservice"]["monitor"]["min_standby_age"].to_i + return 60 if manifest.properties['postgresql-info-webservice'].nil? + return 60 if manifest.properties['postgresql-info-webservice']['monitor'].nil? + return 60 if manifest.properties['postgresql-info-webservice']['monitor']['min_standby_age'].nil? + + manifest.properties['postgresql-info-webservice']['monitor']['min_standby_age'].to_i end def check_interval - return 2 if manifest.properties["postgresql-info-webservice"].nil? - return 2 if manifest.properties["postgresql-info-webservice"]["monitor"].nil? - return 2 if manifest.properties["postgresql-info-webservice"]["monitor"]["heartbeat_interval"].nil? - return manifest.properties["postgresql-info-webservice"]["monitor"]["heartbeat_interval"].to_i + return 2 if manifest.properties['postgresql-info-webservice'].nil? + return 2 if manifest.properties['postgresql-info-webservice']['monitor'].nil? + return 2 if manifest.properties['postgresql-info-webservice']['monitor']['heartbeat_interval'].nil? + + manifest.properties['postgresql-info-webservice']['monitor']['heartbeat_interval'].to_i end def wait_monitor_block_node(node_id, sleeping_period = 5, retries = 1200) @@ -91,22 +88,21 @@ def wait_monitor_block_node(node_id, sleeping_period = 5, retries = 1200) counter = 0 is_blocked = false - while ! is_blocked do + until is_blocked node = cluster_status.select do |node| logger.debug("Checking node - node_id: *#{node_id}*, node: *#{node}*") - node["data"]["id"] == node_id + node['data']['id'] == node_id end.first logger.debug("Got node - node: *#{node}*") - is_blocked = node["data"]["blocked"] if !node.nil? + is_blocked = node['data']['blocked'] unless node.nil? sleep(sleeping_period) - if counter >= retries - raise Exception.new("Timed out waiting for node to be rejecting connections") - end + raise StandardError, 'Timed out waiting for node to be rejecting connections' if counter >= retries + counter += 1 end - logger.debug("Finished waiting node to be rejecting connections") + logger.debug('Finished waiting node to be rejecting connections') end def wait_monitor_unblock_node(node_id, sleeping_period = 5, retries = 1200) @@ -114,52 +110,56 @@ def wait_monitor_unblock_node(node_id, sleeping_period = 5, retries = 1200) counter = 0 is_blocked = true - while is_blocked do + while is_blocked node = cluster_status.select do |node| logger.debug("Checking node - node_id: *#{node_id}*, node: *#{node}*") - node["data"]["id"] == node_id + node['data']['id'] == node_id end.first logger.debug("Got node - node: *#{node}*") - is_blocked = node["data"]["blocked"] if !node.nil? + is_blocked = node['data']['blocked'] unless node.nil? sleep(sleeping_period) - if counter >= retries - raise Exception.new("Timed out waiting for node to accept connections") - end + raise StandardError, 'Timed out waiting for node to accept connections' if counter >= retries + counter += 1 end - logger.debug("Finished waiting node to accept connections") + logger.debug('Finished waiting node to accept connections') end def cluster_replication_status nodes = node_ips.map do |node_ip| - begin - JSON.parse(HTTParty.get("http://#{node_ip}:63145/v1/replication_status", - basic_auth: webservice_credentials).body) - rescue Exception - logger.debug("Could not reach node: #{node_ip}") - nil - end + JSON.parse( + HTTParty.get( + "http://#{node_ip}:63145/v1/replication_status", + basic_auth: webservice_credentials + ).body + ) + rescue Exception + logger.debug("Could not reach node: #{node_ip}") + nil end - return nodes.select { |node| !node.nil? && node["status"] == "success" } + nodes.select { |node| !node.nil? && node['status'] == 'success' } end def all_standby_nodes_unblocked(tolerance = 120) min_age = standby_min_age cluster_nodes = cluster_replication_status - logger.debug("Checking if whole cluster is accepting connections - " \ - "cluster_nodes: #{cluster_nodes}") - standby_nodes = cluster_nodes.select { |node| node["data"]["pg_mode"] == "standby" } + logger.debug( + 'Checking if whole cluster is accepting connections - ' \ + "cluster_nodes: #{cluster_nodes}" + ) + standby_nodes = cluster_nodes.select { |node| node['data']['pg_mode'] == 'standby' } standby_nodes.each do |node| - pg_client = UnitTestsUtils::PostgreSQLClient.create_from_manifest(manifest, { host: node["data"]["node"]["ip"] }) + pg_client = UnitTestsUtils::PostgreSQLClient.create_from_manifest(manifest, { host: node['data']['node']['ip'] }) begin - if pg_client.ping > 0 + if pg_client.ping.positive? - if node["data"]["standby_age"] > min_age + tolerance - raise Exception.new("Standby node is rejecting connection after tolerance time - " \ - "tolerance: *#{min_age + tolerance}*, min_age: *#{min_age}*") + if node['data']['standby_age'] > min_age + tolerance + raise StandardError, + 'Standby node is rejecting connection after tolerance time - ' \ + "tolerance: *#{min_age + tolerance}*, min_age: *#{min_age}*" end return false @@ -168,15 +168,13 @@ def all_standby_nodes_unblocked(tolerance = 120) return false end end - return true + true end def wait_standby_accept_connections(period = 5) - logger.debug("Waiting all standby nodes reach minimum age.") - while !all_standby_nodes_unblocked do - sleep(period) - end - logger.debug("Finished waiting all standby nodes reach minimum age") + logger.debug('Waiting all standby nodes reach minimum age.') + sleep(period) until all_standby_nodes_unblocked + logger.debug('Finished waiting all standby nodes reach minimum age') end def cluster_is_sync @@ -185,90 +183,86 @@ def cluster_is_sync host = master_ip logger.debug("Checking if cluster has replicated the data - host: #{host}") pg_client = UnitTestsUtils::PostgreSQLClient.create_from_manifest(manifest, { host: host }) - res = pg_client.execute("SELECT pg_current_wal_lsn();", { dbname: "postgres" }) + res = pg_client.execute('SELECT pg_current_wal_lsn();', { dbname: 'postgres' }) master_lsn = lsn_to_i(res.values.flatten.first) standby_ips.each do |node| pg_client = UnitTestsUtils::PostgreSQLClient.create_from_manifest(manifest, { host: node }) - res = pg_client.execute("SELECT pg_last_wal_receive_lsn();", { dbname: "postgres" }) + res = pg_client.execute('SELECT pg_last_wal_receive_lsn();', { dbname: 'postgres' }) standby_lsn = lsn_to_i(res.values.flatten.first) logger.debug("Master_lsn: (#{host}) - *#{master_lsn}*, Standby_lsn: (#{node}) - *#{standby_lsn}*") - if standby_lsn < master_lsn - return false - end + return false if standby_lsn < master_lsn end - return true + true end def wait_cluster_is_sync(period = 5, retries = 1200) - logger.debug("Waiting cluster is synchonized.") + logger.debug('Waiting cluster is synchonized.') counter = 0 - while ! cluster_is_sync do + until cluster_is_sync sleep(period) - if counter >= retries - raise Exception.new("Timed out waiting for cluster to replicate data") - end + raise StandardError, 'Timed out waiting for cluster to replicate data' if counter >= retries + counter += 1 end - logger.debug("Finished waiting cluster synchronization") + logger.debug('Finished waiting cluster synchronization') end def is_cluster_stable - logger.debug("Checking if cluster is stable") + logger.debug('Checking if cluster is stable') master = master_node logger.debug("Got master - master: #{master}") # Check if there is a master already - return false if master["status"] != "succeeded" + return false if master['status'] != 'succeeded' # Remove unreacheable nodes nodes = cluster_status.select do |node| - node["status"] == "succeeded" if not node.nil? + node['status'] == 'succeeded' unless node.nil? end logger.debug("Got online nodes - nodes: #{nodes}") # FIXME: This is bad, we should not remove the blocked nodes. - nodes_accepting_connections = nodes.select do |node| - !node["data"]["blocked"] + nodes_accepting_connections = nodes.reject do |node| + node['data']['blocked'] end logger.debug("Nodes accepting connections - nodes_accepting_connections: #{nodes_accepting_connections}") # Check if all reacheable nodes are running and following the same master nodes_accepting_connections.each do |node| - if node["data"]["failover_in_progress"] || - node["data"]["upstream_node_id"] != master["data"]["id"] || - node["data"]["status"] != "running" + if node['data']['failover_in_progress'] || + node['data']['upstream_node_id'] != master['data']['id'] || + node['data']['status'] != 'running' return false end end - standby_nodes = nodes.select { |node| node["data"]["mode"] == "standby" } + standby_nodes = nodes.select { |node| node['data']['mode'] == 'standby' } logger.debug("Standby nodes state - standby_nodes: *#{standby_nodes}*") standby_nodes.each do |standby_node| - return false if standby_node["data"]["blocked"] + return false if standby_node['data']['blocked'] end - return true + true end def wait_failover(period = 5, retries = 1200) - logger.debug("Waiting for failover to happen...") + logger.debug('Waiting for failover to happen...') counter = 0 - while ! is_cluster_stable do + until is_cluster_stable sleep(period) - if counter >= retries - raise Exception.new("Timed out waiting for cluster to complete failover") - end + raise StandardError, 'Timed out waiting for cluster to complete failover' if counter >= retries + counter += 1 end - logger.debug("Finished waiting for failover to happen...") + logger.debug('Finished waiting for failover to happen...') end def cluster_status @@ -281,41 +275,42 @@ def cluster_status nil end end - nodes.select { |node| node != nil } + nodes.reject(&:nil?) end def is_cluster_ready - logger.debug("Getting cluster status...") + logger.debug('Getting cluster status...') nodes_status = cluster_status logger.debug("Cluster status: #{nodes_status}") - nodes = nodes_status.select { |node_status| node_status["status"] == "succeeded" && node_status["data"]["status"] == "running" } + nodes = nodes_status.select do |node_status| + node_status['status'] == 'succeeded' && node_status['data']['status'] == 'running' + end - return nodes.length == nodes_status.length && has_a_master(nodes_status) + nodes.length == nodes_status.length && has_a_master(nodes_status) end private def webservice_credentials { - :username => "admin", - :password => password + username: 'admin', + password: password } end def has_a_master(nodes) masters = nodes.select do |node| - node["status"] == "succeeded" && - node["data"]["mode"] == "master" && - node["data"]["status"] == "running" && - node["data"]["id"] == node["data"]["upstream_node_id"] && - node["data"]["master_in_majority_partition"] == true + node['status'] == 'succeeded' && + node['data']['mode'] == 'master' && + node['data']['status'] == 'running' && + node['data']['id'] == node['data']['upstream_node_id'] && + node['data']['master_in_majority_partition'] == true end - return masters.length > 0 + masters.length.positive? end def lsn_to_i(lsn) - split_lsn = lsn.split("/") + split_lsn = lsn.split('/') split_lsn[0].hex << 32 | split_lsn[1].hex end - end diff --git a/lib/unit_tests_utils/rspec_logger.rb b/lib/unit_tests_utils/rspec_logger.rb index c3a2e77..6d41b09 100644 --- a/lib/unit_tests_utils/rspec_logger.rb +++ b/lib/unit_tests_utils/rspec_logger.rb @@ -1,15 +1,13 @@ class UnitTestsUtils::RspecLogger - attr_reader :buffer attr_accessor :io_output def initialize @io_output = $stdout @buffer = [] - @live_log = !ENV['UNIT_TEST_DEBUG'].nil? && ENV['UNIT_TEST_DEBUG'] == "true" + @live_log = !ENV['UNIT_TEST_DEBUG'].nil? && ENV['UNIT_TEST_DEBUG'] == 'true' end - def debug(message) method = caller_locations.first append("[#{method.base_label}:#{method.lineno}] - #{message}") @@ -29,7 +27,7 @@ def clear def append(message) if live_log - io_output.puts "#{(object_id << 1)} - #{message}" + io_output.puts "#{object_id << 1} - #{message}" else buffer.push(message) end diff --git a/lib/unit_tests_utils/template_render.rb b/lib/unit_tests_utils/template_render.rb index b511880..524c7d9 100644 --- a/lib/unit_tests_utils/template_render.rb +++ b/lib/unit_tests_utils/template_render.rb @@ -20,7 +20,7 @@ def render(vars = {}) def save(dst_file, vars = {}) rendered_content = render(vars) - File.open(dst_file, "w") { |f| f.write(rendered_content) } + File.open(dst_file, 'w') { |f| f.write(rendered_content) } end private diff --git a/lib/unit_tests_utils/traversal.rb b/lib/unit_tests_utils/traversal.rb index b6caf92..ebd4b40 100644 --- a/lib/unit_tests_utils/traversal.rb +++ b/lib/unit_tests_utils/traversal.rb @@ -16,7 +16,7 @@ def traverse(manifest, path) first = formatted_key(raw_first) rest = rest.join('/') - if rest == "" + if rest == '' if first.include?('=') components = first.split('=') found = manifest.find { |pair| pair[components.first] == components.last } @@ -31,13 +31,9 @@ def traverse(manifest, path) return traverse(found, rest) end - if manifest.is_a?(Hash) - if manifest.key?(first) - return traverse(manifest[first], rest) - end - end + return traverse(manifest[first], rest) if manifest.is_a?(Hash) && manifest.key?(first) - raise NotImplementedError if !is_optional(raw_first) + raise NotImplementedError unless is_optional(raw_first) end private diff --git a/lib/unit_tests_utils/turbulence.rb b/lib/unit_tests_utils/turbulence.rb index bad84fc..e882104 100644 --- a/lib/unit_tests_utils/turbulence.rb +++ b/lib/unit_tests_utils/turbulence.rb @@ -7,7 +7,6 @@ require 'timeout' class UnitTestsUtils::Turbulence - # URL should be i.e. https://IP:PORT/api/v1/incidents def initialize(logger) @logger = logger @@ -16,14 +15,14 @@ def initialize(logger) @url = "https://#{host}:#{port}/api/v1/incidents" @username = get_from_env('TURBULENCE_USER') @password = get_from_env('TURBULENCE_SECRET') - @locked_instances = Set.new() + @locked_instances = Set.new end # this will be called right before the GC cleans up an # object instance - def finalize() + def finalize # below function is not yet fully functional - unlock_all_instances() + unlock_all_instances end def get_vm_id(deployment, instance_jobname, instance_index) @@ -35,7 +34,7 @@ def get_vm_id(deployment, instance_jobname, instance_index) bosh_ids_sorted[jobname] = bosh_ids_sorted[jobname] || [] bosh_ids_sorted[jobname].push(guid) end - return bosh_ids_sorted[instance_jobname][instance_index.to_i] + bosh_ids_sorted[instance_jobname][instance_index.to_i] end # deployment_name: should be a string @@ -44,20 +43,21 @@ def get_vm_id(deployment, instance_jobname, instance_index) def crash_vms_without_blocking(deployment_name, ids: []) # below function is not yet fully functional # lock_instances(ids) - body = { "Tasks" => - [ - { "Type" => "Shutdown", "Crash" => true } - ] - } - body["Selector"] = get_vms_selector(deployment_name, ids: ids) - return send_post_request(body) + body = { + 'Tasks' => + [ + { 'Type' => 'Shutdown', 'Crash' => true } + ] + } + body['Selector'] = get_vms_selector(deployment_name, ids: ids) + send_post_request(body) end def crash_vms(deployment, ids: []) lock_instances(deployment, ids: ids) incident_id = crash_vms_without_blocking(deployment, ids: ids) block_until_crashed(deployment, ids: ids) - return incident_id + incident_id end # Isolates the given VMs via IPtables, only SSH and Boshagent will still be @@ -167,12 +167,15 @@ def crash_vms(deployment, ids: []) # getting the status of an incident def get_incident_status(id) raise NotImplementedError - response = HTTParty.get("#{url.to_str}/:#{id}", :headers => { 'Content-Type' => 'application/json' }, :basic_auth => auth, verify: false ) - unless response.success? - raise "Request to turbulence(#{url.to_str}/:#{id}) failed" - end - response_body = JSON.parse(response.body) - return response_body + response = HTTParty.get( + "#{url.to_str}/:#{id}", + headers: { 'Content-Type' => 'application/json' }, + basic_auth: auth, + verify: false + ) + raise "Request to turbulence(#{url.to_str}/:#{id}) failed" unless response.success? + + JSON.parse(response.body) end def start_vms(deployment, ids: [], port: nil) @@ -189,47 +192,48 @@ def start_vms(deployment, ids: [], port: nil) def send_post_request(body) response = HTTParty.post( url.to_str, - :body => body.to_json, - :headers => { 'Content-Type' => 'application/json' }, - :basic_auth => auth, + body: body.to_json, + headers: { 'Content-Type' => 'application/json' }, + basic_auth: auth, verify: false ) logger.debug( - "POST Request to Turbulence: \n" + - "\tURL: #{url.to_str}\n" + - "\tAUTH: #{auth}\n" + + "POST Request to Turbulence: \n" \ + "\tURL: #{url.to_str}\n" \ + "\tAUTH: #{auth}\n" \ "\tBODY: #{body.to_json}" ) unless response.success? - raise "Request to turbulence(#{url.to_str}) failed, \n" + - "\tauth: #{auth.inspect}, \n" + - "\tBody: #{body}, \n" + - "\tResponse: #{response.body}" + raise "Request to turbulence(#{url.to_str}) failed, \n" \ + "\tauth: #{auth.inspect}, \n" \ + "\tBody: #{body}, \n" \ + "\tResponse: #{response.body}" end response_body = JSON.parse(response.body) - return response_body["ID"] + response_body['ID'] end # deployment_name: should be a string # ids: an array of vm guid's def get_vms_selector(deployment_name, ids: []) { - "Deployment" => { - "Name" => deployment_name, - "Limit" => "100%" - }, - "ID" => { "Values" => ids } + 'Deployment' => { + 'Name' => deployment_name, + 'Limit' => '100%' + }, + 'ID' => { 'Values' => ids } } end def auth - {:username => "#{username}", :password => "#{password}"} + { username: username.to_s, password: password.to_s } end def get_from_env(name) raise "ENV variable '#{name}' required!" unless ENV[name] + ENV[name] end @@ -250,7 +254,7 @@ def get_ips_for_deployment(deployment, ids: []) wanted_ip_addresses.push(current_ip_address) if ids.include? current_id end end - return wanted_ip_addresses + wanted_ip_addresses end def lock_instances(deployment, ids: []) @@ -263,13 +267,13 @@ def lock_instances(deployment, ids: []) end def unlock_instances(deployment, ids: []) - @logger.debug("unignoring instances") + @logger.debug('unignoring instances') ids = fix_ids_for_bosh(deployment, ids: ids) - @logger.debug("#{ids.inspect}") + @logger.debug(ids.inspect.to_s) ids.each do |id| @logger.debug("bosh unignore -d #{deployment} #{id}") result = `bosh unignore -d '#{deployment}' '#{id}'` - @logger.debug("#{result.inspect}") + @logger.debug(result.inspect.to_s) @locked_instances.delete([deployment, id]) end end @@ -279,7 +283,7 @@ def unlock_instances_and_block_until_running(deployment, ids: [], port: nil) block_until_recreated(deployment, ids: ids, port: port) end - def unlock_all_instances() + def unlock_all_instances @locked_instances.each do |deployment, id| `bosh unignore -d '#{deployment}' '#{id}'` end @@ -292,7 +296,7 @@ def get_bosh_ids(deployment) bosh_vms.split("\n").each do |line| bosh_ids.push(line.split("\t")[0].strip) end - return bosh_ids + bosh_ids end # This transforms IDs suitable for Turbulence into the format BOSH understands @@ -308,18 +312,18 @@ def fix_ids_for_bosh(deployment, ids: []) fixed_ids = bosh_ids else bosh_ids.each do |id| - search_term = id.split("/")[1].strip + search_term = id.split('/')[1].strip fixed_ids.push(id) if ids.find { |e| search_term == e } end end - return fixed_ids + fixed_ids end def block_until_crashed(deployment, ids: []) addresses = get_ips_for_deployment(deployment, ids: ids) pings_successful = true loopcounter = 0 - while pings_successful do + while pings_successful sleep 5 ping_statuses = [] addresses.each do |ip| @@ -337,7 +341,7 @@ def block_until_recreated(deployment, ids: [], port: nil) addresses = get_ips_for_deployment(deployment, ids: ids) pings_successful = false loopcounter = 0 - until pings_successful do + until pings_successful sleep 5 ping_statuses = [] addresses.each do |ip| @@ -354,7 +358,7 @@ def block_until_recreated(deployment, ids: [], port: nil) ports_open = false ports_open = true if port.nil? loopcounter = 0 - until ports_open do + until ports_open sleep 5 port_statuses = [] addresses.each do |ip| @@ -372,19 +376,16 @@ def block_until_recreated(deployment, ids: [], port: nil) def is_port_open?(ip, port) begin - Timeout::timeout(1) do - begin - s = TCPSocket.new(ip, port) - s.close - return true - rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH - return false - end + Timeout.timeout(1) do + s = TCPSocket.new(ip, port) + s.close + return true + rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH + return false end rescue Timeout::Error end - return false + false end - end diff --git a/spec/lib/unit_tests_utils/bosh_spec.rb b/spec/lib/unit_tests_utils/bosh_spec.rb index 10bec02..9dc5dc8 100644 --- a/spec/lib/unit_tests_utils/bosh_spec.rb +++ b/spec/lib/unit_tests_utils/bosh_spec.rb @@ -1,26 +1,28 @@ require 'spec_helper' describe UnitTestsUtils::Bosh do - let(:deployment_name) { "database-ha" } - let(:manifest_path) { "./database-ha.yml" } - let(:instance_name) { "database" } - let(:release_name) { "release_name" } - let(:release_version) { "0+dev.1" } - let(:bosh_error_messages) { { - create_release: 'Creating release failed', - delete_deployment: 'Delete deployment failed', - delete_release: 'Delete release failed', - deploy: 'Deploy failed', - instances: 'Instance status failed', - ssh: 'Cannot execute command ', - interpolate: 'Interpolate failed', - start: 'Starting instance failed', - stop: 'Stopping instance failed', - task: 'Cannot wait for task to finish', - upload_release: 'Uploading release failed' - } } - - describe ".deploy" do + let(:deployment_name) { 'database-ha' } + let(:manifest_path) { './database-ha.yml' } + let(:instance_name) { 'database' } + let(:release_name) { 'release_name' } + let(:release_version) { '0+dev.1' } + let(:bosh_error_messages) do + { + create_release: 'Creating release failed', + delete_deployment: 'Delete deployment failed', + delete_release: 'Delete release failed', + deploy: 'Deploy failed', + instances: 'Instance status failed', + ssh: 'Cannot execute command ', + interpolate: 'Interpolate failed', + start: 'Starting instance failed', + stop: 'Stopping instance failed', + task: 'Cannot wait for task to finish', + upload_release: 'Uploading release failed' + } + end + + describe '.deploy' do let(:path_to_creds) { './config.yml' } let(:path_to_iaas_config) { './iaas_config.yml' } let(:additional_vars) { { key1: 'value1', key2: 'value2' } } @@ -30,186 +32,196 @@ additional_ops_files.map { |file| "--ops-file #{file}" }.join(' ') end - before :each do - expect(ENV).to receive(:[]).with('PATH_TO_IAAS_CONFIG').at_least(:once). - and_return(path_to_iaas_config) + before do + expect(ENV).to receive(:[]).with('PATH_TO_IAAS_CONFIG').at_least(:once) + .and_return(path_to_iaas_config) end - context "when the PATH_TO_CREDS env var is set" do - before :each do - expect(ENV).to receive(:[]).with('PATH_TO_CREDS').at_least(:once). - and_return(path_to_creds) + context 'when the PATH_TO_CREDS env var is set' do + before do + expect(ENV).to receive(:[]).with('PATH_TO_CREDS').at_least(:once) + .and_return(path_to_creds) end - context "when NO additional vars are given" do - it "runs a bosh deployment" do - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh --non-interactive -d #{deployment_name} deploy -l #{ENV['PATH_TO_IAAS_CONFIG']} -l #{ENV['PATH_TO_CREDS']} #{manifest_path}", bosh_error_messages[:deploy]). - and_return(nil) - expect(UnitTestsUtils::Bosh).to receive(:`).once. - with("bosh -d #{deployment_name} task > /dev/null 2>&1") + context 'when NO additional vars are given' do + it 'runs a bosh deployment' do + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh --non-interactive -d #{deployment_name} deploy -l #{ENV['PATH_TO_IAAS_CONFIG']} -l #{ENV['PATH_TO_CREDS']} #{manifest_path}", bosh_error_messages[:deploy]) + .and_return(nil) + expect(described_class).to receive(:`).once + .with("bosh -d #{deployment_name} task > /dev/null 2>&1") - UnitTestsUtils::Bosh.deploy(deployment_name, manifest_path) + described_class.deploy(deployment_name, manifest_path) end end - context "when additional vars are given" do - it "runs a bosh deployment" do - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh --non-interactive -d #{deployment_name} deploy -l #{ENV['PATH_TO_IAAS_CONFIG']} -l #{ENV['PATH_TO_CREDS']} #{additional_vars_string} #{manifest_path}", bosh_error_messages[:deploy]). - and_return(nil) - expect(UnitTestsUtils::Bosh).to receive(:`).once. - with("bosh -d #{deployment_name} task > /dev/null 2>&1") + context 'when additional vars are given' do + it 'runs a bosh deployment' do + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh --non-interactive -d #{deployment_name} deploy -l #{ENV['PATH_TO_IAAS_CONFIG']} -l #{ENV['PATH_TO_CREDS']} #{additional_vars_string} #{manifest_path}", bosh_error_messages[:deploy]) + .and_return(nil) + expect(described_class).to receive(:`).once + .with("bosh -d #{deployment_name} task > /dev/null 2>&1") - UnitTestsUtils::Bosh.deploy(deployment_name, manifest_path, additional_vars) + described_class.deploy(deployment_name, manifest_path, additional_vars) end end - context "when additional ops files are given" do - it "runs a bosh deployment" do - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh --non-interactive -d #{deployment_name} deploy " \ + context 'when additional ops files are given' do + it 'runs a bosh deployment' do + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh --non-interactive -d #{deployment_name} deploy " \ "-l #{ENV['PATH_TO_IAAS_CONFIG']} -l #{ENV['PATH_TO_CREDS']} " \ "#{additional_vars_string} #{additional_ops_files_string} #{manifest_path}", - bosh_error_messages[:deploy]). - and_return(nil) - expect(UnitTestsUtils::Bosh).to receive(:`).once. - with("bosh -d #{deployment_name} task > /dev/null 2>&1") - - UnitTestsUtils::Bosh.deploy(deployment_name, manifest_path, - additional_vars, additional_ops_files) + bosh_error_messages[:deploy]) + .and_return(nil) + expect(described_class).to receive(:`).once + .with("bosh -d #{deployment_name} task > /dev/null 2>&1") + + described_class.deploy( + deployment_name, + manifest_path, + additional_vars, + additional_ops_files + ) end end end - context "when the PATH_TO_CREDS env var is not set" do - before :each do - expect(ENV).to receive(:[]).with('PATH_TO_CREDS'). - and_return(nil) + context 'when the PATH_TO_CREDS env var is not set' do + before do + expect(ENV).to receive(:[]).with('PATH_TO_CREDS') + .and_return(nil) end - context "when NO additional vars are given" do - it "runs a bosh deployment" do - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh --non-interactive -d #{deployment_name} deploy -l #{ENV['PATH_TO_IAAS_CONFIG']} #{manifest_path}", bosh_error_messages[:deploy]). - and_return(nil) - expect(UnitTestsUtils::Bosh).to receive(:`).once. - with("bosh -d #{deployment_name} task > /dev/null 2>&1") + context 'when NO additional vars are given' do + it 'runs a bosh deployment' do + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh --non-interactive -d #{deployment_name} deploy -l #{ENV['PATH_TO_IAAS_CONFIG']} #{manifest_path}", bosh_error_messages[:deploy]) + .and_return(nil) + expect(described_class).to receive(:`).once + .with("bosh -d #{deployment_name} task > /dev/null 2>&1") - UnitTestsUtils::Bosh.deploy(deployment_name, manifest_path) + described_class.deploy(deployment_name, manifest_path) end end - context "when additional vars are given" do - it "runs a bosh deployment" do - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh --non-interactive -d #{deployment_name} deploy -l #{ENV['PATH_TO_IAAS_CONFIG']} #{additional_vars_string} #{manifest_path}", bosh_error_messages[:deploy]). - and_return(nil) - expect(UnitTestsUtils::Bosh).to receive(:`).once. - with("bosh -d #{deployment_name} task > /dev/null 2>&1") + context 'when additional vars are given' do + it 'runs a bosh deployment' do + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh --non-interactive -d #{deployment_name} deploy -l #{ENV['PATH_TO_IAAS_CONFIG']} #{additional_vars_string} #{manifest_path}", bosh_error_messages[:deploy]) + .and_return(nil) + expect(described_class).to receive(:`).once + .with("bosh -d #{deployment_name} task > /dev/null 2>&1") - UnitTestsUtils::Bosh.deploy(deployment_name, manifest_path, additional_vars) + described_class.deploy(deployment_name, manifest_path, additional_vars) end end - context "when additional ops files are given" do - it "runs a bosh deployment" do - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh --non-interactive -d #{deployment_name} deploy " \ + context 'when additional ops files are given' do + it 'runs a bosh deployment' do + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh --non-interactive -d #{deployment_name} deploy " \ "-l #{ENV['PATH_TO_IAAS_CONFIG']} " \ "#{additional_vars_string} #{additional_ops_files_string} #{manifest_path}", - bosh_error_messages[:deploy]). - and_return(nil) - expect(UnitTestsUtils::Bosh).to receive(:`).once. - with("bosh -d #{deployment_name} task > /dev/null 2>&1") - - UnitTestsUtils::Bosh.deploy(deployment_name, manifest_path, - additional_vars, additional_ops_files) + bosh_error_messages[:deploy]) + .and_return(nil) + expect(described_class).to receive(:`).once + .with("bosh -d #{deployment_name} task > /dev/null 2>&1") + + described_class.deploy( + deployment_name, + manifest_path, + additional_vars, + additional_ops_files + ) end end end end - describe ".delete_deployment" do - it "runs a bosh delete-deployment" do - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh --non-interactive -d #{deployment_name} delete-deployment --force", bosh_error_messages[:delete_deployment]) - expect(UnitTestsUtils::Bosh).to receive(:`).once. - with("bosh -d #{deployment_name} task > /dev/null 2>&1") + describe '.delete_deployment' do + it 'runs a bosh delete-deployment' do + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh --non-interactive -d #{deployment_name} delete-deployment --force", bosh_error_messages[:delete_deployment]) + expect(described_class).to receive(:`).once + .with("bosh -d #{deployment_name} task > /dev/null 2>&1") - UnitTestsUtils::Bosh.delete_deployment(deployment_name) + described_class.delete_deployment(deployment_name) end end - describe ".start_instance" do - context "when the index is given" do + describe '.start_instance' do + context 'when the index is given' do let(:index) { 1 } - it "runs a bosh start on the given instance and index" do - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh --non-interactive -d #{deployment_name} start #{instance_name}/#{index}", bosh_error_messages[:start]) - expect(UnitTestsUtils::Bosh).to receive(:`).once. - with("bosh -d #{deployment_name} task > /dev/null 2>&1") - UnitTestsUtils::Bosh.start_instance(deployment_name, instance_name, index) + it 'runs a bosh start on the given instance and index' do + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh --non-interactive -d #{deployment_name} start #{instance_name}/#{index}", bosh_error_messages[:start]) + expect(described_class).to receive(:`).once + .with("bosh -d #{deployment_name} task > /dev/null 2>&1") + + described_class.start_instance(deployment_name, instance_name, index) end end - context "when the index is not given" do - it "runs a bosh start on the given instance with index 0" do - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh --non-interactive -d #{deployment_name} start #{instance_name}/0", bosh_error_messages[:start]) - expect(UnitTestsUtils::Bosh).to receive(:`).once. - with("bosh -d #{deployment_name} task > /dev/null 2>&1") + context 'when the index is not given' do + it 'runs a bosh start on the given instance with index 0' do + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh --non-interactive -d #{deployment_name} start #{instance_name}/0", bosh_error_messages[:start]) + expect(described_class).to receive(:`).once + .with("bosh -d #{deployment_name} task > /dev/null 2>&1") - UnitTestsUtils::Bosh.start_instance(deployment_name, instance_name) + described_class.start_instance(deployment_name, instance_name) end end end - describe ".stop_instance" do - context "when the index is given" do + describe '.stop_instance' do + context 'when the index is given' do let(:index) { 1 } - it "runs a bosh stop on the given instance and index" do - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh --non-interactive -d #{deployment_name} stop #{instance_name}/#{index}", bosh_error_messages[:stop]) - expect(UnitTestsUtils::Bosh).to receive(:`).once. - with("bosh -d #{deployment_name} task > /dev/null 2>&1") - UnitTestsUtils::Bosh.stop_instance(deployment_name, instance_name, index) + it 'runs a bosh stop on the given instance and index' do + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh --non-interactive -d #{deployment_name} stop #{instance_name}/#{index}", bosh_error_messages[:stop]) + expect(described_class).to receive(:`).once + .with("bosh -d #{deployment_name} task > /dev/null 2>&1") + + described_class.stop_instance(deployment_name, instance_name, index) end end - context "when the index is not given" do - it "runs a bosh stop on the given instance with index 0" do - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh --non-interactive -d #{deployment_name} stop #{instance_name}/0", bosh_error_messages[:stop]) - expect(UnitTestsUtils::Bosh).to receive(:`).once. - with("bosh -d #{deployment_name} task > /dev/null 2>&1") + context 'when the index is not given' do + it 'runs a bosh stop on the given instance with index 0' do + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh --non-interactive -d #{deployment_name} stop #{instance_name}/0", bosh_error_messages[:stop]) + expect(described_class).to receive(:`).once + .with("bosh -d #{deployment_name} task > /dev/null 2>&1") - UnitTestsUtils::Bosh.stop_instance(deployment_name, instance_name) + described_class.stop_instance(deployment_name, instance_name) end end end - describe ".run_errand" do - let(:errand_name) { "myerrand" } + describe '.run_errand' do + let(:errand_name) { 'myerrand' } - context "when deployment name and errand name is given" do - it "runs the errand" do - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh --non-interactive -d #{deployment_name} run-errand #{errand_name}", - "Failed to run errand #{errand_name}"). - and_return(nil) + context 'when deployment name and errand name is given' do + it 'runs the errand' do + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh --non-interactive -d #{deployment_name} run-errand #{errand_name}", + "Failed to run errand #{errand_name}") + .and_return(nil) - expect(UnitTestsUtils::Bosh).to receive(:`).once. - with("bosh -d #{deployment_name} task > /dev/null 2>&1") + expect(described_class).to receive(:`).once + .with("bosh -d #{deployment_name} task > /dev/null 2>&1") - UnitTestsUtils::Bosh.run_errand(deployment_name, errand_name) + described_class.run_errand(deployment_name, errand_name) end end end - describe ".create_and_upload_dev_release" do + describe '.create_and_upload_dev_release' do let(:base_dir) { './' } let(:release_path) { File.join(base_dir, 'dev_releases', release_name, "#{release_name}-#{release_version}.yml") } let(:metadata) do @@ -221,17 +233,18 @@ } end - it "runs a bosh create-release and upload-release" do - allow(UnitTestsUtils::Bosh).to receive(:dev_release_version).and_return(release_version) + it 'runs a bosh create-release and upload-release' do + allow(described_class).to receive(:dev_release_version).and_return(release_version) - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh --json create-release --dir #{base_dir} --name #{release_name} --version " \ - "#{release_version} --force", bosh_error_messages[:create_release]). - and_return(bosh_release_output(release_name, release_version)) - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh upload-release --dir #{base_dir} #{release_path}", bosh_error_messages[:upload_release]) + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh --json create-release --dir #{base_dir} --name #{release_name} --version " \ + "#{release_version} --force", + bosh_error_messages[:create_release]) + .and_return(bosh_release_output(release_name, release_version)) + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh upload-release --dir #{base_dir} #{release_path}", bosh_error_messages[:upload_release]) - expect(UnitTestsUtils::Bosh.create_and_upload_dev_release(base_dir, release_name)).to eq metadata + expect(described_class.create_and_upload_dev_release(base_dir, release_name)).to eq metadata end end @@ -245,79 +258,79 @@ def bosh_release_output(release_name, release_version) json.to_json end - describe ".delete_release" do - it "runs a bosh delete-release" do - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh --non-interactive delete-release #{release_name}", bosh_error_messages[:delete_release]) + describe '.delete_release' do + it 'runs a bosh delete-release' do + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh --non-interactive delete-release #{release_name}", bosh_error_messages[:delete_release]) - UnitTestsUtils::Bosh.delete_release(release_name) + described_class.delete_release(release_name) end end - describe ".ssh" do - let(:command) { "ls" } + describe '.ssh' do + let(:command) { 'ls' } - context "when an instance name is given" do - context "when an index is given" do - let(:index) { "1" } + context 'when an instance name is given' do + context 'when an index is given' do + let(:index) { '1' } - it "runs bosh ssh" do - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh -d #{deployment_name} ssh #{instance_name}/#{index} -c '#{command}'", bosh_error_messages[:ssh] + command) + it 'runs bosh ssh' do + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh -d #{deployment_name} ssh #{instance_name}/#{index} -c '#{command}'", bosh_error_messages[:ssh] + command) - UnitTestsUtils::Bosh.ssh(deployment_name, command, instance_name, index) + described_class.ssh(deployment_name, command, instance_name, index) end end - context "when the index is not given" do - it "runs bosh ssh" do - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh -d #{deployment_name} ssh #{instance_name}/0 -c '#{command}'", bosh_error_messages[:ssh] + command) + context 'when the index is not given' do + it 'runs bosh ssh' do + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh -d #{deployment_name} ssh #{instance_name}/0 -c '#{command}'", bosh_error_messages[:ssh] + command) - UnitTestsUtils::Bosh.ssh(deployment_name, command, instance_name) + described_class.ssh(deployment_name, command, instance_name) end end end - context "when no instance is given" do - it "runs bosh ssh" do - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh -d #{deployment_name} ssh -c '#{command}'", bosh_error_messages[:ssh] + command) + context 'when no instance is given' do + it 'runs bosh ssh' do + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh -d #{deployment_name} ssh -c '#{command}'", bosh_error_messages[:ssh] + command) - UnitTestsUtils::Bosh.ssh(deployment_name, command) + described_class.ssh(deployment_name, command) end end end - describe ".interpolate" do + describe '.interpolate' do let(:path_to_creds) { Fixtures.file_path 'creds.yml' } let(:path_to_iaas_config) { Fixtures.file_path 'iaas_config.yml' } let(:additional_vars) { { key1: 'value1', key2: 'value2' } } let(:additional_vars_string) { additional_vars.map { |key, value| "--var #{key}='#{value}'" }.join(' ') } - context "when the PATH_TO_CREDS env var is set" do - before :each do - stubbed_env = ENV.clone + context 'when the PATH_TO_CREDS env var is set' do + before do + stubbed_env = ENV.to_h stubbed_env['PATH_TO_IAAS_CONFIG'] = path_to_iaas_config stubbed_env['PATH_TO_CREDS'] = path_to_creds stub_const('ENV', stubbed_env) end - context "when NO additional vars are given" do - it "interpolates a deployment manifest" do - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh interpolate -l #{ENV['PATH_TO_IAAS_CONFIG']} -l #{ENV['PATH_TO_CREDS']} #{manifest_path}", bosh_error_messages[:interpolate]) + context 'when NO additional vars are given' do + it 'interpolates a deployment manifest' do + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh interpolate -l #{ENV['PATH_TO_IAAS_CONFIG']} -l #{ENV['PATH_TO_CREDS']} #{manifest_path}", bosh_error_messages[:interpolate]) - UnitTestsUtils::Bosh.interpolate(manifest_path) + described_class.interpolate(manifest_path) end end - context "when additional vars are given" do - it "interpolates a deployment manifest" do - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh interpolate -l #{ENV['PATH_TO_IAAS_CONFIG']} -l #{ENV['PATH_TO_CREDS']} #{additional_vars_string} #{manifest_path}", bosh_error_messages[:interpolate]) + context 'when additional vars are given' do + it 'interpolates a deployment manifest' do + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh interpolate -l #{ENV['PATH_TO_IAAS_CONFIG']} -l #{ENV['PATH_TO_CREDS']} #{additional_vars_string} #{manifest_path}", bosh_error_messages[:interpolate]) - UnitTestsUtils::Bosh.interpolate(manifest_path, additional_vars) + described_class.interpolate(manifest_path, additional_vars) end end @@ -325,101 +338,102 @@ def bosh_release_output(release_name, release_version) let(:ops_files) { ['/tmp/dummy-ops.yml', '/tmp/dummy-ops-2.yml'] } let(:ops_files_string) { ops_files.map { |file| "--ops-file #{file}" }.join(' ') } - it "interpolates a deployment manifest" do - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh interpolate -l #{ENV['PATH_TO_IAAS_CONFIG']} -l #{ENV['PATH_TO_CREDS']} " \ - "#{additional_vars_string} #{ops_files_string} #{manifest_path}", bosh_error_messages[:interpolate]) + it 'interpolates a deployment manifest' do + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh interpolate -l #{ENV['PATH_TO_IAAS_CONFIG']} -l #{ENV['PATH_TO_CREDS']} " \ + "#{additional_vars_string} #{ops_files_string} #{manifest_path}", + bosh_error_messages[:interpolate]) - UnitTestsUtils::Bosh.interpolate(manifest_path, additional_vars, false, ops_files) + described_class.interpolate(manifest_path, additional_vars, false, ops_files) end end end - context "when the PATH_TO_CREDS env var is not set" do - before :each do - stubbed_env = ENV.clone + context 'when the PATH_TO_CREDS env var is not set' do + before do + stubbed_env = ENV.to_h stubbed_env['PATH_TO_IAAS_CONFIG'] = path_to_iaas_config stubbed_env['PATH_TO_CREDS'] = nil stub_const('ENV', stubbed_env) end - context "when NO additional vars are given" do - it "interpolates a deployment manifest" do - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh interpolate -l #{ENV['PATH_TO_IAAS_CONFIG']} #{manifest_path}", bosh_error_messages[:interpolate]) + context 'when NO additional vars are given' do + it 'interpolates a deployment manifest' do + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh interpolate -l #{ENV['PATH_TO_IAAS_CONFIG']} #{manifest_path}", bosh_error_messages[:interpolate]) - UnitTestsUtils::Bosh.interpolate(manifest_path) + described_class.interpolate(manifest_path) end end - context "when additional vars are given" do - it "interpolates a deployment manifest" do - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh interpolate -l #{ENV['PATH_TO_IAAS_CONFIG']} #{additional_vars_string} #{manifest_path}", bosh_error_messages[:interpolate]) + context 'when additional vars are given' do + it 'interpolates a deployment manifest' do + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh interpolate -l #{ENV['PATH_TO_IAAS_CONFIG']} #{additional_vars_string} #{manifest_path}", bosh_error_messages[:interpolate]) - UnitTestsUtils::Bosh.interpolate(manifest_path, additional_vars) + described_class.interpolate(manifest_path, additional_vars) end end end end - describe ".instance_status" do - context "when the index is not given" do - it "runs a bosh instance" do - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh --non-interactive -d #{deployment_name} instances --details --json", bosh_error_messages[:instances]). - and_return(Fixtures.file_content('bosh-instances-details-output.json')) + describe '.instance_status' do + context 'when the index is not given' do + it 'runs a bosh instance' do + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh --non-interactive -d #{deployment_name} instances --details --json", bosh_error_messages[:instances]) + .and_return(Fixtures.file_content('bosh-instances-details-output.json')) - result = UnitTestsUtils::Bosh.instance_status(deployment_name, instance_name) + result = described_class.instance_status(deployment_name, instance_name) expect(result.length).to eq(3) end end - context "when the index is given" do - it "runs a bosh instance" do - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh --non-interactive -d #{deployment_name} instances --details --json", bosh_error_messages[:instances]). - and_return(Fixtures.file_content('bosh-instances-details-output.json')) + context 'when the index is given' do + it 'runs a bosh instance' do + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh --non-interactive -d #{deployment_name} instances --details --json", bosh_error_messages[:instances]) + .and_return(Fixtures.file_content('bosh-instances-details-output.json')) - result = UnitTestsUtils::Bosh.instance_status(deployment_name, instance_name, "0") + result = described_class.instance_status(deployment_name, instance_name, '0') expect(result.length).to eq(1) - expect(result.first["index"]).to eq("0") + expect(result.first['index']).to eq('0') end end - context "when bosh is unavailable" do - it "raises an exception" do - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh --non-interactive -d #{deployment_name} instances --details --json", bosh_error_messages[:instances]). - and_return(Fixtures.file_content('bosh-instances-ps-error.json')) + context 'when bosh is unavailable' do + it 'raises an exception' do + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh --non-interactive -d #{deployment_name} instances --details --json", bosh_error_messages[:instances]) + .and_return(Fixtures.file_content('bosh-instances-ps-error.json')) expect do - UnitTestsUtils::Bosh.instance_status(deployment_name, instance_name) + described_class.instance_status(deployment_name, instance_name) end.to raise_error(Exception, "Could not find 'Tables'. Maybe this is a request timeout.") end end - context "when bosh gives an invalid json as response" do - it "raises a json exception" do - expect(UnitTestsUtils::Bosh).to receive(:execute_or_raise_error).once. - with("bosh --non-interactive -d #{deployment_name} instances --details --json", bosh_error_messages[:instances]). - and_return(Fixtures.file_content('bosh-invalid-json-output.json')) + context 'when bosh gives an invalid json as response' do + it 'raises a json exception' do + expect(described_class).to receive(:execute_or_raise_error).once + .with("bosh --non-interactive -d #{deployment_name} instances --details --json", bosh_error_messages[:instances]) + .and_return(Fixtures.file_content('bosh-invalid-json-output.json')) expect do - UnitTestsUtils::Bosh.instance_status(deployment_name, instance_name) + described_class.instance_status(deployment_name, instance_name) end.to raise_error(JSON::ParserError) end end end - describe ".execute_or_raise_error" do - context "when the command returns a zero status" do + describe '.execute_or_raise_error' do + context 'when the command returns a zero status' do it "returns the command's stdout" do return_message = '' raises_error = false begin - return_message = UnitTestsUtils::Bosh.execute_or_raise_error("echo myteststring", "this is not meant to fail") - rescue UnitTestsUtils::Bosh::BoshError => _ + return_message = described_class.execute_or_raise_error('echo myteststring', 'this is not meant to fail') + rescue UnitTestsUtils::Bosh::BoshError => _e raises_error = true end expect(return_message).to eql("myteststring\n") @@ -427,11 +441,11 @@ def bosh_release_output(release_name, release_version) end end - context "when the command returns a non-zero status" do - it "raises a BOSH exception with error message" do + context 'when the command returns a non-zero status' do + it 'raises a BOSH exception with error message' do raises_error = false begin - UnitTestsUtils::Bosh.execute_or_raise_error("/usr/bin/env false", "this is meant to fail") + described_class.execute_or_raise_error('/usr/bin/env false', 'this is meant to fail') rescue UnitTestsUtils::Bosh::BoshError => e expect(e.message).to match(/this is meant to fail - exit_status: pid [0-9]+ exit 1\s*stdout:\s*stderr:\s*/) raises_error = true diff --git a/spec/lib/unit_tests_utils/cmd_spec.rb b/spec/lib/unit_tests_utils/cmd_spec.rb index d093389..32e522b 100644 --- a/spec/lib/unit_tests_utils/cmd_spec.rb +++ b/spec/lib/unit_tests_utils/cmd_spec.rb @@ -2,59 +2,61 @@ describe UnitTestsUtils::Cmd do let(:echo_output) { "echo_output\n" } - let(:error_message) { "error_message" } + let(:error_message) { 'error_message' } - describe ".exec" do - context "when executing a command with error message" do - it "runs the command" do - stdout, stderr = UnitTestsUtils::Cmd.exec("echo #{echo_output}", - msg: "Failed to execute echo") + describe '.exec' do + context 'when executing a command with error message' do + it 'runs the command' do + stdout, stderr = described_class.exec( + "echo #{echo_output}", + msg: 'Failed to execute echo' + ) expect(stdout).to eq(echo_output) expect(stderr).to be_empty end - it "failes when command exits is non successful" do + it 'failes when command exits is non successful' do expect do - UnitTestsUtils::Cmd.exec("[ 2 -lt 1 ]", msg: error_message) + described_class.exec('[ 2 -lt 1 ]', msg: error_message) end.to raise_error UnitTestsUtils::Cmd::CmdError end end end - describe ".exec_with_retry" do - subject{ UnitTestsUtils::Cmd.exec_with_retry("some error message", retries: 2, backoff: 0) { executed_block } } + describe '.exec_with_retry' do + subject { described_class.exec_with_retry('some error message', retries: 2, backoff: 0) { executed_block } } context 'when executing command raised error' do - let(:some_object){ double(counter: nil) } + let(:some_object) { double(counter: nil) } - it "with broken command" do - def executed_block; UnitTestsUtils::Cmd.exec("[ 2 -lt 1 ]", msg: error_message) end + it 'with broken command' do + def executed_block = UnitTestsUtils::Cmd.exec('[ 2 -lt 1 ]', msg: error_message) - expect{subject}.to raise_error(UnitTestsUtils::Cmd::CmdError, /#{error_message}/) + expect { subject }.to raise_error(UnitTestsUtils::Cmd::CmdError, /#{error_message}/) end it 'with exceeded counter number' do - def executed_block; some_object.counter end + def executed_block = some_object.counter - expect(STDOUT).to receive(:puts).with('Attempt number 0 out of 2 retries') - expect(STDOUT).to receive(:puts).with('Attempt number 1 out of 2 retries') - expect(STDOUT).to receive(:puts).with('Attempt number 2 out of 2 retries') + expect($stdout).to receive(:puts).with('Attempt number 0 out of 2 retries') + expect($stdout).to receive(:puts).with('Attempt number 1 out of 2 retries') + expect($stdout).to receive(:puts).with('Attempt number 2 out of 2 retries') - expect{subject}.to raise_error(UnitTestsUtils::Cmd::CmdError, /some error message/) + expect { subject }.to raise_error(UnitTestsUtils::Cmd::CmdError, /some error message/) end end context 'when command passes' do it 'with simple block' do - def executed_block; 1+3 end + def executed_block = 1.+(3) expect(subject).to eq 4 end it 'with command inside the block' do - def executed_block; UnitTestsUtils::Cmd.exec("echo #{echo_output}", msg: "Failed to execute echo") end + def executed_block = UnitTestsUtils::Cmd.exec("echo #{echo_output}", msg: 'Failed to execute echo') - stdout, stderr = subject + stdout, = subject expect(stdout).to eq echo_output end diff --git a/spec/lib/unit_tests_utils/consul_spec.rb b/spec/lib/unit_tests_utils/consul_spec.rb index ceaf662..687e3df 100644 --- a/spec/lib/unit_tests_utils/consul_spec.rb +++ b/spec/lib/unit_tests_utils/consul_spec.rb @@ -1,30 +1,29 @@ require 'spec_helper' describe UnitTestsUtils::Consul do - let(:internal_consul_ip) { "1.2.3.4" } + let(:internal_consul_ip) { '1.2.3.4' } - before :each do - allow(ENV).to receive(:[]).with("INTERNAL_CONSUL_IP"). - and_return(internal_consul_ip) + before do + allow(ENV).to receive(:[]).with('INTERNAL_CONSUL_IP') + .and_return(internal_consul_ip) end - describe ".get_value_for_key" do - let(:key) { "key" } - let(:result) { "result" } + describe '.get_value_for_key' do + let(:key) { 'key' } + let(:result) { 'result' } - it "curls consul for the given key" do - expect(UnitTestsUtils::Consul).to receive(:`).once. - with("curl -s http://#{internal_consul_ip}:8500/v1/kv/#{key}?raw"). - and_return(result) + it 'curls consul for the given key' do + expect(described_class).to receive(:`).once + .with("curl -s http://#{internal_consul_ip}:8500/v1/kv/#{key}?raw") + .and_return(result) - expect(UnitTestsUtils::Consul.get_value_for_key(key)).to eq result + expect(described_class.get_value_for_key(key)).to eq result end end - describe ".ip_address" do - it "returns the env var INTERNAL_CONSUL_IP" do - expect(UnitTestsUtils::Consul.ip_address).to eq internal_consul_ip + describe '.ip_address' do + it 'returns the env var INTERNAL_CONSUL_IP' do + expect(described_class.ip_address).to eq internal_consul_ip end end end - diff --git a/spec/lib/unit_tests_utils/credhub_spec.rb b/spec/lib/unit_tests_utils/credhub_spec.rb index fe9154b..16e56e7 100644 --- a/spec/lib/unit_tests_utils/credhub_spec.rb +++ b/spec/lib/unit_tests_utils/credhub_spec.rb @@ -2,8 +2,9 @@ describe UnitTestsUtils::CredHub do describe '#get_by_name' do + subject(:get_by_name) { described_class.get_by_name(name) } + let(:name) { 'anything' } - subject(:get_by_name) { UnitTestsUtils::CredHub.get_by_name(name) } it 'executes with the right command' do command_expected = "credhub get --name='#{name}' --output-json" diff --git a/spec/lib/unit_tests_utils/git_spec.rb b/spec/lib/unit_tests_utils/git_spec.rb index c6e0dea..37707e5 100644 --- a/spec/lib/unit_tests_utils/git_spec.rb +++ b/spec/lib/unit_tests_utils/git_spec.rb @@ -4,28 +4,28 @@ let(:shortened_hash) { '01092b4' } let(:long_hash) { '01092b48eb7a0809bb6d5a2dcac6efb662ec21a0' } - before(:example) do - allow(UnitTestsUtils::Git). - to receive(:`). - with('git log -1 --format="%h"'). - and_return("#{shortened_hash}\n") - allow(UnitTestsUtils::Git). - to receive(:`). - with('git log -1 --format="%H"'). - and_return("#{long_hash}\n") + before do + allow(described_class) + .to receive(:`) + .with('git log -1 --format="%h"') + .and_return("#{shortened_hash}\n") + allow(described_class) + .to receive(:`) + .with('git log -1 --format="%H"') + .and_return("#{long_hash}\n") end describe '.last_commit_hash' do context 'when the shortened commit hash is requested' do it 'returns the shortened commit hash' do - expect(UnitTestsUtils::Git.last_commit_hash).to eq shortened_hash - expect(UnitTestsUtils::Git.last_commit_hash(shortened_hash: true)).to eq shortened_hash + expect(described_class.last_commit_hash).to eq shortened_hash + expect(described_class.last_commit_hash(shortened_hash: true)).to eq shortened_hash end end context 'when the long commit hash is requested' do it 'returns the long commit hash' do - expect(UnitTestsUtils::Git.last_commit_hash(shortened_hash: false)).to eq long_hash + expect(described_class.last_commit_hash(shortened_hash: false)).to eq long_hash end end end diff --git a/spec/lib/unit_tests_utils/internal_dns_spec.rb b/spec/lib/unit_tests_utils/internal_dns_spec.rb index 4518fba..7e2bf13 100644 --- a/spec/lib/unit_tests_utils/internal_dns_spec.rb +++ b/spec/lib/unit_tests_utils/internal_dns_spec.rb @@ -1,150 +1,150 @@ require 'spec_helper' describe UnitTestsUtils::InternalDNS do - let(:internal_dns_ip) { "1.2.3.4" } - let(:hostname1) { "hostname1.domain" } - let(:hostname2) { "hostname2.domain" } - let(:hostname3) { "hostname3.domain" } - let(:ip1) { "2.3.4.5" } - let(:ip2) { "3.4.5.6" } - let(:ip3) { "4.5.6.7" } - - before :each do - allow(ENV).to receive(:[]).with("INTERNAL_DNS_IP"). - and_return(internal_dns_ip) + let(:internal_dns_ip) { '1.2.3.4' } + let(:hostname1) { 'hostname1.domain' } + let(:hostname2) { 'hostname2.domain' } + let(:hostname3) { 'hostname3.domain' } + let(:ip1) { '2.3.4.5' } + let(:ip2) { '3.4.5.6' } + let(:ip3) { '4.5.6.7' } + + before do + allow(ENV).to receive(:[]).with('INTERNAL_DNS_IP') + .and_return(internal_dns_ip) end - describe ".resolv" do - before(:example) do - allow(UnitTestsUtils::InternalDNS). - to receive(:resolve_domain_name). - with(hostname1). - and_return([ip1, ip2, ip3]) - allow(UnitTestsUtils::InternalDNS). - to receive(:resolve_domain_name). - with(hostname2). - and_return([ip1]) - allow(UnitTestsUtils::InternalDNS). - to receive(:resolve_domain_name). - with(hostname3). - and_return([]) + describe '.resolv' do + before do + allow(described_class) + .to receive(:resolve_domain_name) + .with(hostname1) + .and_return([ip1, ip2, ip3]) + allow(described_class) + .to receive(:resolve_domain_name) + .with(hostname2) + .and_return([ip1]) + allow(described_class) + .to receive(:resolve_domain_name) + .with(hostname3) + .and_return([]) end - it "digs the first ip and strips the result" do - expect(UnitTestsUtils::InternalDNS.resolv(hostname1)).to eq ip1 - expect(UnitTestsUtils::InternalDNS.resolv(hostname2)).to eq ip1 - expect(UnitTestsUtils::InternalDNS.resolv(hostname3)).to be_nil + it 'digs the first ip and strips the result' do + expect(described_class.resolv(hostname1)).to eq ip1 + expect(described_class.resolv(hostname2)).to eq ip1 + expect(described_class.resolv(hostname3)).to be_nil end end - describe ".resolve_domain_name" do - before(:example) do - expect(UnitTestsUtils::InternalDNS). - to receive(:`). - with("dig +short #{hostname1} @#{internal_dns_ip}"). - and_return("#{ip1}\n#{ip2}\n#{ip3}\n") - expect(UnitTestsUtils::InternalDNS). - to receive(:`). - with("dig +short #{hostname2} @#{internal_dns_ip}"). - and_return("#{ip1}\n") - expect(UnitTestsUtils::InternalDNS). - to receive(:`). - with("dig +short #{hostname3} @#{internal_dns_ip}"). - and_return('') + describe '.resolve_domain_name' do + before do + expect(described_class) + .to receive(:`) + .with("dig +short #{hostname1} @#{internal_dns_ip}") + .and_return("#{ip1}\n#{ip2}\n#{ip3}\n") + expect(described_class) + .to receive(:`) + .with("dig +short #{hostname2} @#{internal_dns_ip}") + .and_return("#{ip1}\n") + expect(described_class) + .to receive(:`) + .with("dig +short #{hostname3} @#{internal_dns_ip}") + .and_return('') end - it "digs the ip, strips the result and split it into an array with one position per returned ip" do - expect(UnitTestsUtils::InternalDNS.resolve_domain_name(hostname1)).to eq [ip1, ip2, ip3] - expect(UnitTestsUtils::InternalDNS.resolve_domain_name(hostname2)).to eq [ip1] - expect(UnitTestsUtils::InternalDNS.resolve_domain_name(hostname3)).to eq [] + it 'digs the ip, strips the result and split it into an array with one position per returned ip' do + expect(described_class.resolve_domain_name(hostname1)).to eq [ip1, ip2, ip3] + expect(described_class.resolve_domain_name(hostname2)).to eq [ip1] + expect(described_class.resolve_domain_name(hostname3)).to eq [] end end - describe ".host_adresses" do - let(:port) { "1234" } - - before(:example) do - allow(UnitTestsUtils::InternalDNS). - to receive("resolve_domain_name"). - with(hostname1). - and_return([ip1, ip2]) - allow(UnitTestsUtils::InternalDNS). - to receive("resolve_domain_name"). - with(hostname2). - and_return([ip3]) + describe '.host_adresses' do + let(:port) { '1234' } + + before do + allow(described_class) + .to receive('resolve_domain_name') + .with(hostname1) + .and_return([ip1, ip2]) + allow(described_class) + .to receive('resolve_domain_name') + .with(hostname2) + .and_return([ip3]) end - it "resolves all hostnames and add the port" do - expect(UnitTestsUtils::InternalDNS.host_addresses([hostname1], port)). - to eq ["#{ip1}:#{port}", "#{ip2}:#{port}"] - expect(UnitTestsUtils::InternalDNS.host_addresses([hostname2], port)). - to eq ["#{ip3}:#{port}"] - expect(UnitTestsUtils::InternalDNS.host_addresses([hostname1, hostname2], port)). - to eq ["#{ip1}:#{port}", "#{ip2}:#{port}", "#{ip3}:#{port}"] + it 'resolves all hostnames and add the port' do + expect(described_class.host_addresses([hostname1], port)) + .to eq ["#{ip1}:#{port}", "#{ip2}:#{port}"] + expect(described_class.host_addresses([hostname2], port)) + .to eq ["#{ip3}:#{port}"] + expect(described_class.host_addresses([hostname1, hostname2], port)) + .to eq ["#{ip1}:#{port}", "#{ip2}:#{port}", "#{ip3}:#{port}"] end end - describe ".nameserver_ip" do - it "returns the env var INTERNAL_DNS_IP" do - expect(UnitTestsUtils::InternalDNS.nameserver_ip).to eq internal_dns_ip + describe '.nameserver_ip' do + it 'returns the env var INTERNAL_DNS_IP' do + expect(described_class.nameserver_ip).to eq internal_dns_ip end end - describe ".valid_hostnames?" do - before(:example) do - allow(UnitTestsUtils::InternalDNS). - to receive(:resolve_domain_name). - with(hostname1). - and_return([ip1]) - allow(UnitTestsUtils::InternalDNS). - to receive(:resolve_domain_name). - with(hostname2). - and_return([ip2, ip3]) + describe '.valid_hostnames?' do + before do + allow(described_class) + .to receive(:resolve_domain_name) + .with(hostname1) + .and_return([ip1]) + allow(described_class) + .to receive(:resolve_domain_name) + .with(hostname2) + .and_return([ip2, ip3]) end - context "when the list is invalid" do - before(:example) do - allow(UnitTestsUtils::InternalDNS). - to receive(:resolve_domain_name). - with(hostname3). - and_return([]) + context 'when the list is invalid' do + before do + allow(described_class) + .to receive(:resolve_domain_name) + .with(hostname3) + .and_return([]) end - it "returns false" do - expect(UnitTestsUtils::InternalDNS.valid_hostnames?([hostname3])).to be_falsey - expect(UnitTestsUtils::InternalDNS.valid_hostnames?([hostname1, hostname3])).to be_falsey - expect(UnitTestsUtils::InternalDNS.valid_hostnames?([hostname2, hostname3])).to be_falsey + it 'returns false' do + expect(described_class).not_to be_valid_hostnames([hostname3]) + expect(described_class).not_to be_valid_hostnames([hostname1, hostname3]) + expect(described_class).not_to be_valid_hostnames([hostname2, hostname3]) end end - context "when the list is valid" do - it "returns true" do - expect(UnitTestsUtils::InternalDNS.valid_hostnames?([])).to be_truthy - expect(UnitTestsUtils::InternalDNS.valid_hostnames?([hostname1])).to be_truthy - expect(UnitTestsUtils::InternalDNS.valid_hostnames?([hostname2])).to be_truthy - expect(UnitTestsUtils::InternalDNS.valid_hostnames?([hostname1, hostname2])).to be_truthy + context 'when the list is valid' do + it 'returns true' do + expect(described_class).to be_valid_hostnames([]) + expect(described_class).to be_valid_hostnames([hostname1]) + expect(described_class).to be_valid_hostnames([hostname2]) + expect(described_class).to be_valid_hostnames([hostname1, hostname2]) end end end - describe ".valid_ips?" do - context " when a list is invalid" do - it "return false" do - expect(UnitTestsUtils::InternalDNS.valid_ips?([""])).to be_falsey - expect(UnitTestsUtils::InternalDNS.valid_ips?(["no"])).to be_falsey - expect(UnitTestsUtils::InternalDNS.valid_ips?(["1.2.3"])).to be_falsey - expect(UnitTestsUtils::InternalDNS.valid_ips?(["1.2.3.a"])).to be_falsey - expect(UnitTestsUtils::InternalDNS.valid_ips?(["111.222.333.4444"])).to be_falsey - expect(UnitTestsUtils::InternalDNS.valid_ips?(["1a2b3c4"])).to be_falsey - expect(UnitTestsUtils::InternalDNS.valid_ips?([ip1, ""])).to be_falsey + describe '.valid_ips?' do + context 'when a list is invalid' do + it 'return false' do + expect(described_class).not_to be_valid_ips(['']) + expect(described_class).not_to be_valid_ips(['no']) + expect(described_class).not_to be_valid_ips(['1.2.3']) + expect(described_class).not_to be_valid_ips(['1.2.3.a']) + expect(described_class).not_to be_valid_ips(['111.222.333.4444']) + expect(described_class).not_to be_valid_ips(['1a2b3c4']) + expect(described_class).not_to be_valid_ips([ip1, '']) end end - context "when a list is valid" do - it "return true" do - expect(UnitTestsUtils::InternalDNS.valid_ips?([])).to be_truthy - expect(UnitTestsUtils::InternalDNS.valid_ips?([ip1])).to be_truthy - expect(UnitTestsUtils::InternalDNS.valid_ips?([ip1, ip2, ip3])).to be_truthy + context 'when a list is valid' do + it 'return true' do + expect(described_class).to be_valid_ips([]) + expect(described_class).to be_valid_ips([ip1]) + expect(described_class).to be_valid_ips([ip1, ip2, ip3]) end end end diff --git a/spec/lib/unit_tests_utils/manifest_spec.rb b/spec/lib/unit_tests_utils/manifest_spec.rb index 948e483..ee201ad 100644 --- a/spec/lib/unit_tests_utils/manifest_spec.rb +++ b/spec/lib/unit_tests_utils/manifest_spec.rb @@ -1,34 +1,36 @@ require 'spec_helper' describe UnitTestsUtils::Manifest do - let(:manifest_path) { Fixtures.file_path("manifest-with-static-name.yml") } + let(:manifest_path) { Fixtures.file_path('manifest-with-static-name.yml') } let(:manifest_additional_vars) { { unit_test_name: 'service-ha', key1: 'value1', key2: 'value2' } } - let(:manifest_yaml) { + let(:manifest_yaml) do interpolated_manifest = UnitTestsUtils::Bosh.interpolate(manifest_path, manifest_additional_vars) YAML.load(interpolated_manifest) - } + end let(:manifest_instance_names) { ['database', 'backup'] } - let(:manifest_hostnames) { { - "database/0" => "service-ha-database-0.node.datacenter.foo", - "database/1" => "service-ha-database-1.node.datacenter.foo", - "database/2" => "service-ha-database-2.node.datacenter.foo", - "backup/0" => "service-ha-backup-0.node.datacenter.foo" - } } - let(:manifest) { UnitTestsUtils::Manifest.new(manifest_path) } + let(:manifest_hostnames) do + { + 'database/0' => 'service-ha-database-0.node.datacenter.foo', + 'database/1' => 'service-ha-database-1.node.datacenter.foo', + 'database/2' => 'service-ha-database-2.node.datacenter.foo', + 'backup/0' => 'service-ha-backup-0.node.datacenter.foo' + } + end + let(:manifest) { described_class.new(manifest_path) } let(:path_to_creds) { Fixtures.file_path 'creds.yml' } let(:path_to_iaas_config) { Fixtures.file_path 'iaas_config.yml' } - before :each do - stubbed_env = ENV.clone + before do + stubbed_env = ENV.to_h stubbed_env['PATH_TO_IAAS_CONFIG'] = path_to_iaas_config stubbed_env['PATH_TO_CREDS'] = path_to_creds stub_const('ENV', stubbed_env) end - describe ".create" do - context "when no manifest with the name exists" do - it "creates a new instance and returns them" do - manifest = UnitTestsUtils::Manifest.create(:TEST_CREATE_1, manifest_path, manifest_additional_vars) + describe '.create' do + context 'when no manifest with the name exists' do + it 'creates a new instance and returns them' do + manifest = described_class.create(:TEST_CREATE_1, manifest_path, manifest_additional_vars) expect(manifest.path).to eq manifest_path expect(manifest.manifest).to eq manifest_yaml @@ -36,31 +38,33 @@ end end - context "when a manifest for the name already exist" do - before(:example) do - UnitTestsUtils::Manifest.create(:TEST_CREATE_2, manifest_path, manifest_additional_vars) + context 'when a manifest for the name already exist' do + before do + described_class.create(:TEST_CREATE_2, manifest_path, manifest_additional_vars) end - it "raises an error" do - expect { UnitTestsUtils::Manifest.create(:TEST_CREATE_2, manifest_path, manifest_additional_vars) }.to raise_error(ArgumentError) + it 'raises an error' do + expect do + described_class.create(:TEST_CREATE_2, manifest_path, manifest_additional_vars) + end.to raise_error(ArgumentError) end end end - describe ".fetch" do - context "when no manifest with the name exists" do - it "raises an error" do - expect { UnitTestsUtils::Manifest.fetch(:TEST_GET_1) }.to raise_error(ArgumentError) + describe '.fetch' do + context 'when no manifest with the name exists' do + it 'raises an error' do + expect { described_class.fetch(:TEST_GET_1) }.to raise_error(ArgumentError) end end - context "when a manifest for the name already exist" do - before(:example) do - UnitTestsUtils::Manifest.create(:TEST_GET_2, manifest_path, manifest_additional_vars) + context 'when a manifest for the name already exist' do + before do + described_class.create(:TEST_GET_2, manifest_path, manifest_additional_vars) end - it "returns the manifest for that name" do - manifest = UnitTestsUtils::Manifest.fetch(:TEST_GET_2) + it 'returns the manifest for that name' do + manifest = described_class.fetch(:TEST_GET_2) expect(manifest.path).to eq manifest_path expect(manifest.manifest).to eq manifest_yaml @@ -69,20 +73,20 @@ end end - describe ".create_from_env" do - context "when environment variables with such prefixes exists" do - it "creates new instances for those names" + describe '.create_from_env' do + context 'when environment variables with such prefixes exists' do + it 'creates new instances for those names' end - context "when no environment variables with such prefixes exists" do - it "creates does nothing" + context 'when no environment variables with such prefixes exists' do + it 'creates does nothing' end end - describe ".new" do - context "when just a manifest_path is given" do - it "creates an object and sets the @path, loads the @manifest and sets empty @additional_vars" do - manifest_without_additional_vars = UnitTestsUtils::Manifest.new(manifest_path) + describe '.new' do + context 'when just a manifest_path is given' do + it 'creates an object and sets the @path, loads the @manifest and sets empty @additional_vars' do + manifest_without_additional_vars = described_class.new(manifest_path) expect(manifest_without_additional_vars.path).to eq manifest_path expect(manifest_without_additional_vars.manifest).to eq manifest_yaml @@ -90,10 +94,10 @@ end end - context "when a manifest_path and additional vars are given" do - context "when additional vars contains symbols as keys" do - it "creates an object and sets the @path, loads the @manifest and sets the @additional_vars" do - manifest_with_additional_vars = UnitTestsUtils::Manifest.new(manifest_path, manifest_additional_vars) + context 'when a manifest_path and additional vars are given' do + context 'when additional vars contains symbols as keys' do + it 'creates an object and sets the @path, loads the @manifest and sets the @additional_vars' do + manifest_with_additional_vars = described_class.new(manifest_path, manifest_additional_vars) expect(manifest_with_additional_vars.path).to eq manifest_path expect(manifest_with_additional_vars.manifest).to eq manifest_yaml @@ -101,11 +105,13 @@ end end - context "when additional vars contains strings as keys" do - let(:manifest_additional_vars_strings) { { 'unit_test_name' => 'service-ha', 'key1' => 'value1', 'key2' => 'value2' } } + context 'when additional vars contains strings as keys' do + let(:manifest_additional_vars_strings) do + { 'unit_test_name' => 'service-ha', 'key1' => 'value1', 'key2' => 'value2' } + end - it "creates an object and sets the @path, loads the @manifest, converts the string keys from the additional vars to symbol keys and sets the @additional_vars" do - manifest_with_additional_vars = UnitTestsUtils::Manifest.new(manifest_path, manifest_additional_vars_strings) + it 'creates an object and sets the @path, loads the @manifest, converts the string keys from the additional vars to symbol keys and sets the @additional_vars' do + manifest_with_additional_vars = described_class.new(manifest_path, manifest_additional_vars_strings) expect(manifest_with_additional_vars.path).to eq manifest_path expect(manifest_with_additional_vars.manifest).to eq manifest_yaml @@ -114,16 +120,25 @@ end context 'when ops files are given' do - let(:ops_files) { [Fixtures.file_path("change-name-ops.yml")] } + let(:ops_files) { [Fixtures.file_path('change-name-ops.yml')] } let(:new_name) { 'newdummyname' } - let(:manifest_yaml_with_ops) { - interpolated_manifest = UnitTestsUtils::Bosh.interpolate(manifest_path, manifest_additional_vars, false, ops_files) + let(:manifest_yaml_with_ops) do + interpolated_manifest = UnitTestsUtils::Bosh.interpolate( + manifest_path, + manifest_additional_vars, + false, + ops_files + ) YAML.load(interpolated_manifest) - } + end it 'updates the name of the manifest' do - manifest_with_additional_vars = UnitTestsUtils::Manifest.new(manifest_path, manifest_additional_vars, ops_files) + manifest_with_additional_vars = described_class.new( + manifest_path, + manifest_additional_vars, + ops_files + ) expect(manifest_with_additional_vars.path).to eq manifest_path expect(manifest_with_additional_vars.name).to eq new_name @@ -133,126 +148,135 @@ end end - describe "#name" do - context "when name is static" do - it "returns the name found in the manifest" do + describe '#name' do + context 'when name is static' do + it 'returns the name found in the manifest' do expect(manifest.name).to eq manifest_yaml['name'] end end - context "when name is dynamic and set in the additional vars" do - let(:manifest_path) { Fixtures.file_path("manifest-with-dynamic-name.yml") } - let(:manifest) { UnitTestsUtils::Manifest.new(manifest_path, manifest_additional_vars) } + context 'when name is dynamic and set in the additional vars' do + let(:manifest_path) { Fixtures.file_path('manifest-with-dynamic-name.yml') } + let(:manifest) { described_class.new(manifest_path, manifest_additional_vars) } - it "returns the name from the additional vars" do + it 'returns the name from the additional vars' do expect(manifest.name).to eq manifest_additional_vars[:unit_test_name] end end - context "when name is dynamic and NOT set in the additional vars" do - let(:manifest_path) { Fixtures.file_path("manifest-with-dynamic-name.yml") } - let(:manifest_yaml) { + context 'when name is dynamic and NOT set in the additional vars' do + let(:manifest_path) { Fixtures.file_path('manifest-with-dynamic-name.yml') } + let(:manifest_yaml) do interpolated_manifest = UnitTestsUtils::Bosh.interpolate(manifest_path, manifest_additional_vars) YAML.load(interpolated_manifest) - } - let(:manifest) { UnitTestsUtils::Manifest.new(manifest_path) } + end + let(:manifest) { described_class.new(manifest_path) } - it "returns the dynamic name" do + it 'returns the dynamic name' do expect(manifest.name).to eq manifest_yaml['name'] end end end - describe "#instance_names" do - it "returns the name of all instances" do + describe '#instance_names' do + it 'returns the name of all instances' do expect(manifest.instance_names).to eq manifest_instance_names end end - describe "#instance_count" do - it "returns to number of instances for a given instance_name" do - expect(manifest.instance_count("database")). to eq 3 - expect(manifest.instance_count("backup")). to eq 1 + describe '#instance_count' do + it 'returns to number of instances for a given instance_name' do + expect(manifest.instance_count('database')).to eq 3 + expect(manifest.instance_count('backup')).to eq 1 end end - describe "#hostname" do - context "when the instance_name is given" do - context "when the index is given" do - it "returns out the hostname of the service node with the specified index" do - expect(manifest.hostname("database", "1")).to eq manifest_hostnames['database/1'] + describe '#hostname' do + context 'when the instance_name is given' do + context 'when the index is given' do + it 'returns out the hostname of the service node with the specified index' do + expect(manifest.hostname('database', '1')).to eq manifest_hostnames['database/1'] end end - context "when the index is not given" do - it "returns out the hostname of the first service node" do - expect(manifest.hostname("backup")).to eq manifest_hostnames['backup/0'] + context 'when the index is not given' do + it 'returns out the hostname of the first service node' do + expect(manifest.hostname('backup')).to eq manifest_hostnames['backup/0'] end end end - context "when neither an instance name nor an index are given" do - it "returns out the hostname of the first service node" do + context 'when neither an instance name nor an index are given' do + it 'returns out the hostname of the first service node' do expect(manifest.hostname).to eq manifest_hostnames['database/0'] end end end - describe "#hostnames" do - it "returns all the hostnames of the manifest" do - expect(manifest.hostnames). to eq manifest_hostnames + describe '#hostnames' do + it 'returns all the hostnames of the manifest' do + expect(manifest.hostnames).to eq manifest_hostnames end end - describe "#properties" do - context "when global properties are present only" do - let(:manifest_properties) { { "consul" => { "dc" => "datacenter", "domain" => "foo" } } } + describe '#properties' do + context 'when global properties are present only' do + let(:manifest_properties) { { 'consul' => { 'dc' => 'datacenter', 'domain' => 'foo' } } } - it "returns a hash including the global properties" do + it 'returns a hash including the global properties' do expect(manifest.properties).to eq manifest_properties end end - context "when local properties are present only" do - let(:manifest_path) { Fixtures.file_path("manifest-with-local-properties-only.yml") } + context 'when local properties are present only' do + let(:manifest_path) { Fixtures.file_path('manifest-with-local-properties-only.yml') } let(:manifest_properties) { { 'property0' => 0, 'property1' => 1 } } - it "returns a hash including the local properties" do + it 'returns a hash including the local properties' do expect(manifest.properties).to eq manifest_properties end end - context "when both local and global properties are present" do - let(:manifest_path) { Fixtures.file_path("manifest-with-both-global-local-properties.yml") } - let(:manifest_properties) { {"consul"=>{"dc"=>"datacenter", "domain"=>"foo"}, "property0"=>0, "property1"=>1} } + context 'when both local and global properties are present' do + let(:manifest_path) { Fixtures.file_path('manifest-with-both-global-local-properties.yml') } + let(:manifest_properties) do + { 'consul' => { 'dc' => 'datacenter', 'domain' => 'foo' }, 'property0' => 0, 'property1' => 1 } + end - it "returns a hash including both the global and local properties" do + it 'returns a hash including both the global and local properties' do expect(manifest.properties).to eq manifest_properties end end context 'duplicate keys' do - let(:manifest_path) { Fixtures.file_path("manifest-deep-merge-properties.yml") } - let(:manifest_propertes) { {'opensearch' => { 'admin' => { 'username' => 'username0', 'password' => 'password0' }, 'cluster_name' => 'some-cluster' } } } + let(:manifest_path) { Fixtures.file_path('manifest-deep-merge-properties.yml') } + let(:manifest_propertes) do + { + 'opensearch' => { + 'admin' => { 'username' => 'username0', 'password' => 'password0' }, + 'cluster_name' => 'some-cluster' + } + } + end it 'merges all local properties' do - expect(manifest.properties). to eq manifest_propertes + expect(manifest.properties).to eq manifest_propertes end end end - describe "#get_network" do - let(:default_network) { "dynamic" } + describe '#get_network' do + let(:default_network) { 'dynamic' } - it "returns the default network when manifest unmodified" do + it 'returns the default network when manifest unmodified' do expect(manifest.get_network(manifest.instance_names.first)).to eq default_network end end - describe "#set_network" do - let(:new_network) { "relocated" } + describe '#set_network' do + let(:new_network) { 'relocated' } - it "sets the network properties in the manifest and we an get it" do + it 'sets the network properties in the manifest and we an get it' do manifest.set_network(manifest.instance_names.first, new_network) expect(manifest.get_network(manifest.instance_names.first)).to eq new_network end diff --git a/spec/lib/unit_tests_utils/postgresql_client_spec.rb b/spec/lib/unit_tests_utils/postgresql_client_spec.rb index f48b385..7155008 100644 --- a/spec/lib/unit_tests_utils/postgresql_client_spec.rb +++ b/spec/lib/unit_tests_utils/postgresql_client_spec.rb @@ -1,19 +1,18 @@ require 'spec_helper' describe UnitTestsUtils::PostgreSQLClient do + subject(:client) { described_class.new(args) } + let(:test_table) { UnitTestsUtils::PostgreSQLClient::TEST_TABLE } let(:args) do { host: 'dummyhost', - sslmode: 'require', + sslmode: 'require' } end - subject(:client) { UnitTestsUtils::PostgreSQLClient.new(args) } - describe '#new' do context 'when new args are given' do - it 'is applied to the client' do expect(client.args[:host]).to eq(args[:host]) expect(client.args[:sslmode]).to eq(args[:sslmode]) @@ -27,21 +26,23 @@ describe '#drop_table' do it 'drops a table if it exists' do - expect(client).to receive(:execute). - with("DROP TABLE IF EXISTS #{test_table}").and_return(PG::Result.new()).once + result_double = instance_double(PG::Result) + expect(client).to receive(:execute) + .with("DROP TABLE IF EXISTS #{test_table}").and_return(result_double).once - expect(client.drop_table).to be_a(PG::Result) - end + expect(client.drop_table).to be(result_double) + end end describe '#create_table' do it 'creates a table with the default name' do - expect(client).to receive(:execute). - with("CREATE TABLE IF NOT EXISTS #{test_table} (test_key TEXT PRIMARY KEY NOT NULL, " \ - "test_value TEXT NOT NULL)").and_return(PG::Result.new()).once + result_double = instance_double(PG::Result) + expect(client).to receive(:execute) + .with("CREATE TABLE IF NOT EXISTS #{test_table} (test_key TEXT PRIMARY KEY NOT NULL, " \ + 'test_value TEXT NOT NULL)').and_return(result_double).once - expect(client.create_table).to be_a(PG::Result) - end + expect(client.create_table).to be(result_double) + end end describe '#generate_data' do @@ -53,14 +54,15 @@ end describe '#insert' do - let(:data) { { 'test_key' => 'dummy_key', 'test_value' => 'dummy_value'} } + let(:data) { { 'test_key' => 'dummy_key', 'test_value' => 'dummy_value' } } it 'executes create table if not exists and inserts data' do - expect(client).to receive(:execute). - with("INSERT INTO #{test_table} VALUES ('#{data['test_key']}', '#{data['test_value']}')"). - and_return(PG::Result.new()).once + result_double = instance_double(PG::Result) + expect(client).to receive(:execute) + .with("INSERT INTO #{test_table} VALUES ('#{data['test_key']}', '#{data['test_value']}')") + .and_return(result_double).once - expect(client.insert(data)).to_not be_nil + expect(client.insert(data)).not_to be_nil end end @@ -70,11 +72,12 @@ context 'when no args are given' do it 'selects with default args' do - expect(client).to receive(:execute). - with("SELECT test_key, test_value FROM #{test_table} WHERE test_key = '#{data['test_key']}'", {}). - and_return(PG::Result.new()).once + result_double = instance_double(PG::Result) + expect(client).to receive(:execute) + .with("SELECT test_key, test_value FROM #{test_table} WHERE test_key = '#{data['test_key']}'", {}) + .and_return(result_double).once - expect(client.select(data)).to_not be_nil + expect(client.select(data)).not_to be_nil end end @@ -82,31 +85,33 @@ let(:args) { { host: 'other_dummy_host' } } it 'passes the args to the client' do - expect(client).to receive(:execute). - with("SELECT test_key, test_value FROM #{test_table} WHERE test_key = '#{data['test_key']}'", args). - and_return(PG::Result.new()).once + result_double = instance_double(PG::Result) + expect(client).to receive(:execute) + .with("SELECT test_key, test_value FROM #{test_table} WHERE test_key = '#{data['test_key']}'", args) + .and_return(result_double).once - expect(client.select(data, args)).to_not be_nil + expect(client.select(data, args)).not_to be_nil end end end describe '#replication_slots' do it 'lists the replication slots' do - expect(client).to receive(:execute). - with('SELECT * FROM pg_replication_slots;'). - and_return(PG::Result.new()).once + result_double = instance_double(PG::Result) + expect(client).to receive(:execute) + .with('SELECT * FROM pg_replication_slots;') + .and_return(result_double).once - expect(client.replication_slots).to_not be_nil + expect(client.replication_slots).not_to be_nil end end describe '#max_connections' do it 'get max connections value' do max_connections_expected = 10 - expect(client).to receive(:execute). - with('SHOW max_connections'). - and_return(['max_connections' => max_connections_expected.to_s]).once + expect(client).to receive(:execute) + .with('SHOW max_connections') + .and_return(['max_connections' => max_connections_expected.to_s]).once expect(client.max_connections).to eq(max_connections_expected) end @@ -114,28 +119,28 @@ describe '#data_checksums?' do it 'get data checksum value as true' do - expect(client).to receive(:execute). - with('SHOW data_checksums'). - and_return(['data_checksums' => 'on']).once + expect(client).to receive(:execute) + .with('SHOW data_checksums') + .and_return(['data_checksums' => 'on']).once - expect(client.data_checksums?).to eq(true) + expect(client.data_checksums?).to be(true) end it 'get data checksum value as false' do - expect(client).to receive(:execute). - with('SHOW data_checksums'). - and_return(['data_checksums' => 'anything']).once + expect(client).to receive(:execute) + .with('SHOW data_checksums') + .and_return(['data_checksums' => 'anything']).once - expect(client.data_checksums?).to eq(false) + expect(client.data_checksums?).to be(false) end end describe '#database' do it 'get databases' do database_name = 'database_name' - expect(client).to receive(:execute). - with("SELECT 1 FROM pg_database WHERE datname = '#{database_name}'"). - and_return(['datname' => database_name]).once + expect(client).to receive(:execute) + .with("SELECT 1 FROM pg_database WHERE datname = '#{database_name}'") + .and_return(['datname' => database_name]).once expect(client.database(database_name).size).to eq(1) end @@ -144,9 +149,9 @@ describe '#work_mem' do it 'get work memory value' do work_mem_expected = 8 - expect(client).to receive(:execute). - with('SHOW work_mem'). - and_return(['work_mem' => work_mem_expected.to_s]).once + expect(client).to receive(:execute) + .with('SHOW work_mem') + .and_return(['work_mem' => work_mem_expected.to_s]).once expect(client.work_mem).to eq(work_mem_expected) end @@ -155,9 +160,9 @@ describe '#extensions' do it 'get extensions' do extname_expected = 'extname' - expect(client).to receive(:execute). - with('SELECT extname FROM pg_extension'). - and_return(['extname' => extname_expected]).once + expect(client).to receive(:execute) + .with('SELECT extname FROM pg_extension') + .and_return(['extname' => extname_expected]).once expect(client.extensions[0]).to eq(extname_expected) end diff --git a/spec/lib/unit_tests_utils/postgresql_web_service_client_spec.rb b/spec/lib/unit_tests_utils/postgresql_web_service_client_spec.rb index bedccd3..b6db9db 100644 --- a/spec/lib/unit_tests_utils/postgresql_web_service_client_spec.rb +++ b/spec/lib/unit_tests_utils/postgresql_web_service_client_spec.rb @@ -1,14 +1,15 @@ require 'spec_helper' describe UnitTestsUtils::PGWebServiceClient do - describe "#initialize" do + describe '#initialize' do + subject(:pg_web_service_client) { described_class.new(manifest, pg_web_service_options) } + let(:manifest_id) { 'manifest_id' } let(:manifest) do manifest_mocked = double('') allow(manifest_mocked).to receive(:name).and_return(manifest_id) manifest_mocked end - subject(:pg_web_service_client) { UnitTestsUtils::PGWebServiceClient.new(manifest, pg_web_service_options) } context 'when there are not options' do let(:pg_web_service_options) { {} } diff --git a/spec/lib/unit_tests_utils/rspec_logger_spec.rb b/spec/lib/unit_tests_utils/rspec_logger_spec.rb index 4f48edf..5bbb2e3 100644 --- a/spec/lib/unit_tests_utils/rspec_logger_spec.rb +++ b/spec/lib/unit_tests_utils/rspec_logger_spec.rb @@ -4,7 +4,7 @@ describe UnitTestsUtils::RspecLogger do context 'when buffering' do subject(:logger) do - UnitTestsUtils::RspecLogger.new.tap do |i| + described_class.new.tap do |i| i.io_output = StringIO.new end end @@ -16,7 +16,7 @@ describe 'buffer' do it 'buffers messages' do - expect(logger.buffer.length).to eql(2) + expect(logger.buffer.length).to be(2) end end @@ -24,12 +24,12 @@ it 'clears the buffer' do logger.clear - expect(logger.buffer.length).to eql(0) + expect(logger.buffer.length).to be(0) end end describe '#print' do - it "outputs all messages" do + it 'outputs all messages' do logger.print logger.io_output.rewind diff --git a/spec/lib/unit_tests_utils/template_render_spec.rb b/spec/lib/unit_tests_utils/template_render_spec.rb index 7664542..9389602 100644 --- a/spec/lib/unit_tests_utils/template_render_spec.rb +++ b/spec/lib/unit_tests_utils/template_render_spec.rb @@ -2,6 +2,8 @@ require 'yaml' describe UnitTestsUtils::TemplateRender do + subject { described_class.new(template) } + let(:template) { 'spec/fixtures/template-with-vars.yml' } let(:output_file) { '/tmp/template-with-vars.yml' } let(:vars) do @@ -11,10 +13,8 @@ } end - subject { UnitTestsUtils::TemplateRender.new(template) } - it 'renders the template in an output file' do - result = subject.save(output_file, vars) + subject.save(output_file, vars) manifest = YAML.load_file(output_file) expect(manifest['first_level']['first_entry']).to eq(vars[:first_var_content]) diff --git a/spec/lib/unit_tests_utils/traversal_spec.rb b/spec/lib/unit_tests_utils/traversal_spec.rb index 508695f..8d1caa9 100644 --- a/spec/lib/unit_tests_utils/traversal_spec.rb +++ b/spec/lib/unit_tests_utils/traversal_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe UnitTestsUtils::Manifest::Traversal do - context "Traversal of manifest yml using BOSH ops path" do + context 'Traversal of manifest yml using BOSH ops path' do [ { h: { 'a' => 1 }, @@ -14,59 +14,61 @@ expected: 2 }, { - h: {'a' => [{'b' => 'value'}]}, + h: { 'a' => [{ 'b' => 'value' }] }, path: '/a/b=value', - expected: {'b' => 'value'} + expected: { 'b' => 'value' } }, { - h: { 'a' => [ { 'b' => 'value', 'c' => { 'd' => 'e'} }, { 'n' => 'value' } ] }, + h: { 'a' => [{ 'b' => 'value', 'c' => { 'd' => 'e' } }, { 'n' => 'value' }] }, path: '/a/b=value/c', - expected: { 'd' => 'e'} + expected: { 'd' => 'e' } }, { - h: { 'a' => [ { 'b' => 'value', 'c' => { 'd' => 'e'} }, { 'n' => 'value' } ] }, + h: { 'a' => [{ 'b' => 'value', 'c' => { 'd' => 'e' } }, { 'n' => 'value' }] }, path: '/a/b=value/c/d', expected: 'e' }, { - h: { 'a' => [ { 'b' => 'value', 'c' => { 'd' => { 'f' => 'e' } } } , { 'n' => 'value' } ] }, + h: { 'a' => [{ 'b' => 'value', 'c' => { 'd' => { 'f' => 'e' } } }, { 'n' => 'value' }] }, path: '/a/b=value/c/d/f', expected: 'e' }, { - h: { 'a' => [ { 'b' => 'value', 'c' => [ { 'e' => 'value'} ] }, { 'n' => 'value' } ] }, + h: { 'a' => [{ 'b' => 'value', 'c' => [{ 'e' => 'value' }] }, { 'n' => 'value' }] }, path: '/a/b=value/c/e=value', expected: { 'e' => 'value' } }, { - h: { 'a' => [ { 'b' => 'value', 'c' => { 'd' => 'e'} }, { 'n' => 'value' } ] }, + h: { 'a' => [{ 'b' => 'value', 'c' => { 'd' => 'e' } }, { 'n' => 'value' }] }, path: '/a/b=value/c?/f?', expected: nil }, { - h: { 'a' => [ { 'b' => 'value', 'c' => { 'd' => 'e'} }, { 'n' => 'value' } ] }, + h: { 'a' => [{ 'b' => 'value', 'c' => { 'd' => 'e' } }, { 'n' => 'value' }] }, path: '/a/b=value/c?/f?/g?', expected: nil }, { - h: { 'a' => [ { 'b' => 'value', 'c' => { 'd' => 'e'} }, { 'n' => 'value' } ] }, + h: { 'a' => [{ 'b' => 'value', 'c' => { 'd' => 'e' } }, { 'n' => 'value' }] }, path: '/a/b=value/c?', expected: { 'd' => 'e' } - }, + } ].each do |entry| - it "Successful traversal of yaml objects using ops path syntax" do - expect(UnitTestsUtils::Manifest::Traversal.new(entry[:h]).find(entry[:path])).to eql(entry[:expected]) + it 'Successful traversal of yaml objects using ops path syntax' do + expect(described_class.new(entry[:h]).find(entry[:path])).to eql(entry[:expected]) end end [ { - h: [ { 'a' => 'b' } ] , + h: [{ 'a' => 'b' }], path: '/a/b' - }, + } ].each do |entry| - it "raises an exception when the object is not a hash" do - expect { UnitTestsUtils::Manifest::Traversal.new(entry[:h]).find(entry[:path]) }.to raise_error(NotImplementedError) + it 'raises an exception when the object is not a hash' do + expect do + described_class.new(entry[:h]).find(entry[:path]) + end.to raise_error(NotImplementedError) end end end diff --git a/unit_tests_utils.gemspec b/unit_tests_utils.gemspec index ffc4e0e..ee58da6 100644 --- a/unit_tests_utils.gemspec +++ b/unit_tests_utils.gemspec @@ -1,14 +1,23 @@ -# coding: utf-8 - Gem::Specification.new do |s| s.name = 'unit-tests-utils' s.version = '2.14.0' s.date = '2022-08-26' s.summary = 'Common unit tests utils' s.description = 'This gems includes all resources needed for the a9s BOSH release unit tests.' - s.authors = ['Michael Lieser', 'Dennis Groß', 'Lucas Pinto', 'Kevin Konrad', - 'Jens Breuer', 'Khaled Blah', 'Morgan Hill', 'Thomas Bruckmann', - 'Robert Gogolok', 'Heitor Meira', 'Cedrik Heusser', 'Francisco Germano'] + s.authors = [ + 'Michael Lieser', + 'Dennis Groß', + 'Lucas Pinto', + 'Kevin Konrad', + 'Jens Breuer', + 'Khaled Blah', + 'Morgan Hill', + 'Thomas Bruckmann', + 'Robert Gogolok', + 'Heitor Meira', + 'Cedrik Heusser', + 'Francisco Germano' + ] s.email = 'support@anynines.com' s.files = [ 'lib/unit_tests_utils.rb', @@ -19,11 +28,11 @@ Gem::Specification.new do |s| 'lib/unit_tests_utils/internal_dns.rb', 'lib/unit_tests_utils/manifest.rb', 'lib/unit_tests_utils/postgresql_web_service_client.rb', - 'lib/unit_tests_utils/turbulence.rb', + 'lib/unit_tests_utils/turbulence.rb' ] s.homepage = 'http://www.anynines.com/' s.license = 'Nonstandard' - s.add_runtime_dependency 'httparty', '0.21.0' - s.add_runtime_dependency 'pg', '0.21.0' + s.add_runtime_dependency 'httparty', '0.22.0' + s.add_runtime_dependency 'pg', '1.5.9' end