topological_inventory-providers-common 1.0.4 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 00d8f69979f477e6b74d6c7b2785647cc043b3909a45ff424562504146955e2b
4
- data.tar.gz: 1b009a746f92137d0502c71bf67346ba86de56aba196eb05e52a6280b86861ec
3
+ metadata.gz: e289728fe42a0bdf12142485a444c851948e9db8ff215c6444f8a7b7bd98c409
4
+ data.tar.gz: 54241e05b5d38f449a905b4edecd725b5110eaba96c213098ade88643601de76
5
5
  SHA512:
6
- metadata.gz: 84a4936e15d4fa024d425d430ba2489485259e59be735e86aa3801852b5745825b324a58b2e847781700607d76c1e5e2deb13bb453f019dba2b0e5382f705c8b
7
- data.tar.gz: 10e5edc584fbfcfd85ae196aef5f83c1e7e42fb0e4325f29b302feecc8c2937925580e23d903442546e8af826afb91fd8c9ea2164812f4e1baabed2087fb6025
6
+ metadata.gz: 14d64a1f0c4b208a43692905a3e843f6c255145cda9cc1a928b8db0a1da02a387cca940146d8044cdcdfbad15bee694e71660d318a2184cf7b1f920f1d6e86fe
7
+ data.tar.gz: 5f6d8af6dff4fe080e223a9fb2e0ae81ac8d4c3789f5ef832043ad3b08f52ba2d72590963096a02eb9efc9ce31d6a0e36929a1d89c0ad54a2985aa7871921a74
@@ -12,12 +12,38 @@ jobs:
12
12
  runs-on: ubuntu-latest
13
13
 
14
14
  steps:
15
- - uses: actions/checkout@v1
15
+ - uses: actions/checkout@v2
16
16
 
17
- - name: Publish to Rubygems
18
- uses: cadwallion/publish-rubygems-action@v1.0
17
+ - name: Set up Ruby 2.6
18
+ uses: actions/setup-ruby@v1
19
+ with:
20
+ ruby-version: 2.6.x
21
+
22
+ - name: Read the version.rb
23
+ id: version_file
24
+ run: |
25
+ echo ::set-output name=data::$(grep VERSION lib/topological_inventory/providers/common/version.rb | awk {'print $3'} | tr -d '"')
26
+
27
+ - name: Echo the gem version
28
+ run: |
29
+ echo "v${{ steps.version_file.outputs.data }}"
30
+
31
+ - name: Publish to RubyGems
32
+ run: |
33
+ mkdir -p $HOME/.gem
34
+ touch $HOME/.gem/credentials
35
+ chmod 0600 $HOME/.gem/credentials
36
+ printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
37
+ gem build *.gemspec
38
+ gem push *.gem
19
39
  env:
20
- GITHUB_TOKEN: ${{secrets.GH_API_KEY}}
21
- RUBYGEMS_API_KEY: ${{secrets.RUBYGEMS_API_KEY}}
22
- RELEASE_COMMAND: rake release
40
+ GEM_HOST_API_KEY: ${{secrets.RUBYGEMS_API_KEY}}
23
41
 
42
+ - name: Create Release
43
+ id: create_release
44
+ uses: actions/create-release@v1
45
+ env:
46
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
47
+ with:
48
+ tag_name: "v${{ steps.version_file.outputs.data }}"
49
+ release_name: "v${{ steps.version_file.outputs.data }}"
@@ -4,9 +4,14 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [1.0.4] - 2020-06-09
7
+ ## [1.0.5]
8
+ Change release workflow to do everything manually #32
9
+ Add specs to released files #33
10
+
11
+ ## [1.0.4] - 2020-06-18
8
12
  Common availability check operation #25
9
13
  Rubocop and codecoverage #29
14
+ Add github workflow to release to rubygems automatically #31
10
15
 
11
16
  ## [1.0.3] - 2020-06-04
12
17
  ### Changed
@@ -29,7 +34,8 @@ manageiq-loggers to >= 0.4.2 #20
29
34
  ## [1.0.0] - 2020-03-19
30
35
  ### Initial release to rubygems.org
31
36
 
32
- [Unreleased]: https://github.com/RedHatInsights/topological_inventory-providers-common/compare/v1.0.4...HEAD
37
+ [Unreleased]: https://github.com/RedHatInsights/topological_inventory-providers-common/compare/v1.0.5...HEAD
38
+ [1.0.5]: https://github.com/RedHatInsights/topological_inventory-providers-common/compare/v1.0.4...v1.0.5
33
39
  [1.0.4]: https://github.com/RedHatInsights/topological_inventory-providers-common/compare/v1.0.3...v1.0.4
34
40
  [1.0.3]: https://github.com/RedHatInsights/topological_inventory-providers-common/compare/v1.0.2...v1.0.3
35
41
  [1.0.2]: https://github.com/RedHatInsights/topological_inventory-providers-common/compare/v1.0.1...v1.0.2
@@ -1,7 +1,7 @@
1
1
  module TopologicalInventory
2
2
  module Providers
3
3
  module Common
4
- VERSION = "1.0.4"
4
+ VERSION = "1.0.5"
5
5
  end
6
6
  end
7
7
  end
@@ -0,0 +1,22 @@
1
+ if ENV['CI']
2
+ require 'simplecov'
3
+ SimpleCov.start
4
+ end
5
+
6
+ require "bundler/setup"
7
+ require "topological_inventory/providers/common"
8
+ require "webmock/rspec"
9
+
10
+ Dir["./spec/support/**/*.rb"].each {|f| require f}
11
+
12
+ spec_path = File.dirname(__FILE__)
13
+ Dir[File.join(spec_path, "support/**/*.rb")].each { |f| require f }
14
+
15
+ RSpec.configure do |config|
16
+ # Enable flags like --only-failures and --next-failure
17
+ config.example_status_persistence_file_path = ".rspec_status"
18
+
19
+ config.expect_with :rspec do |c|
20
+ c.syntax = :expect
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ module InventorySpecHelper
2
+ def self.big_inventory(size, chunk_size)
3
+ {
4
+ :collections => [
5
+ :name => SecureRandom.uuid,
6
+ :data => data_chunks(size, chunk_size)
7
+ ]
8
+ }
9
+ end
10
+
11
+ def self.data_chunks(size, chunk)
12
+ Array.new(size / chunk) { "a" * chunk }
13
+ end
14
+ end
@@ -0,0 +1,175 @@
1
+ require "topological_inventory/providers/common/operations/source"
2
+
3
+ RSpec.shared_examples "availability_check" do
4
+ let(:host_url) { 'https://cloud.redhat.com' }
5
+ let(:sources_api_path) { '/api/sources/v3.0' }
6
+ let(:sources_internal_api_path) { '/internal/v1.0' }
7
+ let(:sources_api_url) { "#{host_url}#{sources_api_path}" }
8
+
9
+ let(:external_tenant) { '11001' }
10
+ let(:identity) { {'x-rh-identity' => Base64.strict_encode64({'identity' => {'account_number' => external_tenant, 'user' => {'is_org_admin' => true}}}.to_json)} }
11
+ let(:headers) { {'Content-Type' => 'application/json'}.merge(identity) }
12
+ let(:source_id) { '123' }
13
+ let(:endpoint_id) { '234' }
14
+ let(:authentication_id) { '345' }
15
+ let(:payload) do
16
+ {
17
+ 'params' => {
18
+ 'source_id' => source_id,
19
+ 'external_tenant' => external_tenant,
20
+ 'timestamp' => Time.now.utc
21
+ }
22
+ }
23
+ end
24
+
25
+ let(:list_endpoints_response) { "{\"data\":[{\"default\":true,\"host\":\"10.0.0.1\",\"id\":\"#{endpoint_id}\",\"path\":\"/\",\"role\":\"ansible\",\"scheme\":\"https\",\"source_id\":\"#{source_id}\",\"tenant\":\"#{external_tenant}\"}]}" }
26
+ let(:list_endpoint_authentications_response) { "{\"data\":[{\"authtype\":\"username_password\",\"id\":\"#{authentication_id}\",\"resource_id\":\"#{endpoint_id}\",\"resource_type\":\"Endpoint\",\"username\":\"admin\",\"tenant\":\"#{external_tenant}\"}]}" }
27
+ let(:list_endpoint_authentications_response_empty) { "{\"data\":[]}" }
28
+ let(:internal_api_authentication_response) { "{\"authtype\":\"username_password\",\"id\":\"#{authentication_id}\",\"resource_id\":\"#{endpoint_id}\",\"resource_type\":\"Endpoint\",\"username\":\"admin\",\"tenant\":\"#{external_tenant}\",\"password\":\"xxx\"}" }
29
+
30
+ subject { described_class.new(payload["params"]) }
31
+
32
+ context "when not checked recently" do
33
+ before do
34
+ allow(subject).to receive(:checked_recently?).and_return(false)
35
+ end
36
+
37
+ it "updates Source and Endpoint when available" do
38
+ # GET
39
+ stub_get(:endpoint, list_endpoints_response)
40
+ stub_get(:authentication, list_endpoint_authentications_response)
41
+ stub_get(:password, internal_api_authentication_response)
42
+
43
+ # PATCH
44
+ source_patch_body = {'availability_status' => described_class::STATUS_AVAILABLE, 'last_available_at' => subject.send(:check_time), 'last_checked_at' => subject.send(:check_time)}.to_json
45
+ endpoint_patch_body = {'availability_status' => described_class::STATUS_AVAILABLE, 'availability_status_error' => '', 'last_available_at' => subject.send(:check_time), 'last_checked_at' => subject.send(:check_time)}.to_json
46
+
47
+ stub_patch(:source, source_patch_body)
48
+ stub_patch(:endpoint, endpoint_patch_body)
49
+
50
+ # Check ---
51
+ expect(subject).to receive(:connection_check).and_return([described_class::STATUS_AVAILABLE, nil])
52
+
53
+ subject.availability_check
54
+
55
+ assert_patch(:source, source_patch_body)
56
+ assert_patch(:endpoint, endpoint_patch_body)
57
+ end
58
+
59
+ it "updates Source and Endpoint when unavailable" do
60
+ # GET
61
+ stub_get(:endpoint, list_endpoints_response)
62
+ stub_get(:authentication, list_endpoint_authentications_response)
63
+ stub_get(:password, internal_api_authentication_response)
64
+
65
+ # PATCH
66
+ connection_error_message = "Some connection error"
67
+ source_patch_body = {'availability_status' => described_class::STATUS_UNAVAILABLE, 'last_checked_at' => subject.send(:check_time)}.to_json
68
+ endpoint_patch_body = {'availability_status' => described_class::STATUS_UNAVAILABLE, 'availability_status_error' => connection_error_message, 'last_checked_at' => subject.send(:check_time)}.to_json
69
+
70
+ stub_patch(:source, source_patch_body)
71
+ stub_patch(:endpoint, endpoint_patch_body)
72
+
73
+ # Check ---
74
+ expect(subject).to receive(:connection_check).and_return([described_class::STATUS_UNAVAILABLE, connection_error_message])
75
+
76
+ subject.availability_check
77
+
78
+ assert_patch(:source, source_patch_body)
79
+ assert_patch(:endpoint, endpoint_patch_body)
80
+ end
81
+
82
+ it "updates only Source to 'unavailable' status if Endpoint not found" do
83
+ # GET
84
+ stub_get(:endpoint, '')
85
+
86
+ # PATCH
87
+ source_patch_body = {'availability_status' => described_class::STATUS_UNAVAILABLE, 'last_checked_at' => subject.send(:check_time)}.to_json
88
+ stub_patch(:source, source_patch_body)
89
+
90
+ # Check
91
+ api_client = subject.send(:api_client)
92
+ expect(api_client).not_to receive(:update_endpoint)
93
+
94
+ subject.availability_check
95
+
96
+ assert_patch(:source, source_patch_body)
97
+ end
98
+
99
+ it "updates Source and Endpoint to 'unavailable' if Authentication not found" do
100
+ # GET
101
+ stub_get(:endpoint, list_endpoints_response)
102
+ stub_get(:authentication, list_endpoint_authentications_response_empty)
103
+
104
+ # PATCH
105
+ source_patch_body = {'availability_status' => described_class::STATUS_UNAVAILABLE, 'last_checked_at' => subject.send(:check_time)}.to_json
106
+ endpoint_patch_body = {'availability_status' => described_class::STATUS_UNAVAILABLE, 'availability_status_error' => described_class::ERROR_MESSAGES[:authentication_not_found], 'last_checked_at' => subject.send(:check_time)}.to_json
107
+
108
+ stub_patch(:source, source_patch_body)
109
+ stub_patch(:endpoint, endpoint_patch_body)
110
+
111
+ # Check
112
+ expect(subject).not_to receive(:connection_check)
113
+ subject.availability_check
114
+
115
+ assert_patch(:source, source_patch_body)
116
+ assert_patch(:endpoint, endpoint_patch_body)
117
+ end
118
+ end
119
+
120
+ context "when checked recently" do
121
+ before do
122
+ allow(subject).to receive(:checked_recently?).and_return(true)
123
+ end
124
+
125
+ it "doesn't do connection check" do
126
+ expect(subject).not_to receive(:connection_check)
127
+ expect(WebMock).not_to have_requested(:patch, "#{sources_api_url}/sources/#{source_id}")
128
+ expect(WebMock).not_to have_requested(:patch, "#{sources_api_url}/endpoints/#{endpoint_id}")
129
+
130
+ subject.availability_check
131
+ end
132
+ end
133
+
134
+
135
+ def stub_get(object_type, response)
136
+ case object_type
137
+ when :endpoint
138
+ stub_request(:get, "#{sources_api_url}/sources/#{source_id}/endpoints")
139
+ .with(:headers => headers)
140
+ .to_return(:status => 200, :body => response, :headers => {})
141
+ when :authentication
142
+ stub_request(:get, "#{sources_api_url}/endpoints/#{endpoint_id}/authentications")
143
+ .with(:headers => headers)
144
+ .to_return(:status => 200, :body => response, :headers => {})
145
+ when :password
146
+ stub_request(:get, "#{host_url}#{sources_internal_api_path}/authentications/#{authentication_id}?expose_encrypted_attribute%5B%5D=password")
147
+ .with(:headers => headers)
148
+ .to_return(:status => 200, :body => response, :headers => {})
149
+ end
150
+ end
151
+
152
+ def stub_patch(object_type, data)
153
+ case object_type
154
+ when :source
155
+ stub_request(:patch, "#{sources_api_url}/sources/#{source_id}")
156
+ .with(:body => data, :headers => headers)
157
+ .to_return(:status => 200, :body => "", :headers => {})
158
+ when :endpoint
159
+ stub_request(:patch, "#{sources_api_url}/endpoints/#{endpoint_id}")
160
+ .with(:body => data, :headers => headers)
161
+ .to_return(:status => 200, :body => "", :headers => {})
162
+ end
163
+ end
164
+
165
+ def assert_patch(object_type, data)
166
+ case object_type
167
+ when :source
168
+ expect(WebMock).to have_requested(:patch, "#{sources_api_url}/sources/#{source_id}")
169
+ .with(:body => data, :headers => headers).once
170
+ when :endpoint
171
+ expect(WebMock).to have_requested(:patch, "#{sources_api_url}/endpoints/#{endpoint_id}")
172
+ .with(:body => data, :headers => headers).once
173
+ end
174
+ end
175
+ end
@@ -0,0 +1,44 @@
1
+ describe TopologicalInventory::Providers::Common::Collector::InventoryCollectionStorage do
2
+ before do
3
+ @storage = described_class.new
4
+ end
5
+
6
+ it "should add collection to data" do
7
+ @storage.add_collection(:vms)
8
+
9
+ expect(@storage.data[:vms]).not_to be_nil
10
+ end
11
+
12
+ it "should access the same collection through brackets, method name and data" do
13
+ @storage.add_collection(:vms)
14
+
15
+ vm_name = "My VM"
16
+
17
+ @storage[:vms].build(:name => vm_name)
18
+
19
+ expect(@storage.vms.data[0].name).to eq(vm_name)
20
+ expect(@storage[:vms].data[0].name).to eq(vm_name)
21
+ expect(@storage.data[:vms].data[0].name).to eq(vm_name)
22
+ end
23
+
24
+ it "should create collection automatically when api object exists" do
25
+ expect("TopologicalInventoryIngressApiClient::Vm".safe_constantize).not_to be_nil
26
+
27
+ storage = described_class.new
28
+ expect(storage.vms).to be_kind_of(TopologicalInventory::Providers::Common::Collector::InventoryCollectionWrapper)
29
+
30
+ storage = described_class.new
31
+ expect(storage[:vms]).to be_kind_of(TopologicalInventory::Providers::Common::Collector::InventoryCollectionWrapper)
32
+ end
33
+
34
+ it "should raise NameError when api object doesn't exist" do
35
+ expect("TopologicalInventoryIngressApiClient::SomethingNonexisting".safe_constantize).to be_nil
36
+
37
+ storage = described_class.new
38
+
39
+ expect { storage.add_collection(:something_nonexisting) }.to raise_error(NameError)
40
+
41
+ expect { storage.something_nonexisting.build(:name => "Vm") }.to raise_error(NameError)
42
+ end
43
+
44
+ end
@@ -0,0 +1,9 @@
1
+ describe TopologicalInventory::Providers::Common::Collector::InventoryCollectionWrapper do
2
+ it "builds only existing ingress api client's object" do
3
+ ic = described_class.new(:name => :some_undefined_class_in_api_models)
4
+ ic_existing = described_class.new(:name => :vm)
5
+
6
+ expect { ic.build({}) }.to raise_error(NameError)
7
+ expect(ic_existing.build({})).to be_kind_of(TopologicalInventoryIngressApiClient::Vm)
8
+ end
9
+ end
@@ -0,0 +1,150 @@
1
+ require "tempfile"
2
+ require "yaml"
3
+ require "json"
4
+
5
+ RSpec.describe TopologicalInventory::Providers::Common::CollectorsPool do
6
+ let(:source1) { {:source => '42b1893c-ebbd-44e9-89b1-5c29b5fe6e10', :schema => 'http', :host => 'cloud.redhat.com', :port => 80} }
7
+ let(:source2) { {:source => 'fe8bcaea-3670-42c7-bed9-71f6e0bceadd', :schema => 'https', :host => 'cloud.redhat.com', :port => 443} }
8
+ let(:source3) { {:source => '05838743-4285-404a-b4d6-294045c0d4be', :schema => 'xxx', :host => 'cloud.redhat.com', :port => 1234} }
9
+ let(:source4) { {:source => '5ed08a3c-3de4-4a90-8ce9-e0f724b2b2e6', :schema => 'xxx', :host => 'cloud.redhat.com', :port => 1234} }
10
+ let(:sources) { [source1, source2, source3] }
11
+
12
+ before do
13
+ clear_settings
14
+ end
15
+
16
+ subject { described_class.new(nil, nil, :thread_pool_size => 2) }
17
+
18
+ context "config reload" do
19
+ it "changes settings with different configs" do
20
+ settings = [{:sources => sources},
21
+ {:sources => [ source2, source4 ]}]
22
+
23
+ 2.times do |i|
24
+ config = Tempfile.new(["config#{i}", '.yml'])
25
+ begin
26
+ config.write(settings[i].to_yaml)
27
+ config.rewind
28
+
29
+ name, path = path_and_filename(config)
30
+ subject.send(:config_name=, name.split('.')[0])
31
+ allow(subject).to receive(:path_to_config).and_return(path)
32
+
33
+ subject.send(:reload_config)
34
+
35
+ expect(::Settings.sources.to_a.collect(&:to_hash)).to eq(settings[i][:sources])
36
+ ensure
37
+ config.close
38
+ config.unlink
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ context "secret reload" do
45
+ it "changes credentials with new secret" do
46
+ uuid = SecureRandom.uuid
47
+
48
+ secrets = [
49
+ {'updated_at' => Time.now.to_s, uuid => {'username' => 'admin1', 'password' => 'password1'}},
50
+ {'updated_at' => Time.now.to_s, uuid => {'username' => 'admin2', 'password' => 'password2'}},
51
+ ]
52
+
53
+ 2.times do |i|
54
+ secret = Tempfile.new(["credentials#{i}"])
55
+ begin
56
+ secret.write(secrets[i].to_json)
57
+ secret.rewind
58
+
59
+ name, path = path_and_filename(secret)
60
+
61
+ allow(subject).to receive(:path_to_secrets).and_return(path)
62
+ stub_const("#{described_class}::SECRET_FILENAME", name)
63
+
64
+ subject.send(:reload_secrets)
65
+
66
+ expect(subject.send(:secrets)).to eq(secrets[i])
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ context "add or remove collector" do
73
+ before do
74
+ ::Config.load_and_set_settings('some-value-needed.txt')
75
+ @collector = double("collector")
76
+ allow(subject).to receive(:new_collector).and_return(@collector)
77
+ end
78
+
79
+ context "without secrets check" do
80
+ before do
81
+ allow(subject).to receive(:secrets_for_source).and_return({})
82
+ end
83
+
84
+ it "adds new collectors from settings" do
85
+ allow(@collector).to receive(:collect!).and_return(nil)
86
+ expect(@collector).to receive(:collect!).exactly(sources.size).times
87
+
88
+ sources.each do |source|
89
+ stub_settings_merge(:sources => ::Settings.sources.to_a + [source])
90
+
91
+ subject.send(:queue_collectors)
92
+ end
93
+
94
+ pool = subject.send(:thread_pool)
95
+ pool.shutdown
96
+ pool.wait_for_termination
97
+ end
98
+ end
99
+
100
+ context "with secrets check" do
101
+ let(:secrets) do
102
+ { 'updated_at' => Time.now.to_s,
103
+ source1[:source] => { 'username' => 'admin1', 'password' => 'password1' },
104
+ source2[:source] => { 'username' => 'admin2', 'password' => 'password2' },
105
+ 'unknown' => { 'username' => 'admin3', 'password' => 'password3' }
106
+ }
107
+ end
108
+
109
+ before do
110
+ allow(@collector).to receive(:collect!).and_return(nil)
111
+ end
112
+
113
+ it "creates only collectors found in both secret and config" do
114
+ # 4 sources in yaml config
115
+ stub_settings_merge(:sources => sources + [source4])
116
+ # 3 sources in secret
117
+ allow(subject).to receive(:secrets).and_return(secrets)
118
+
119
+ # for each source in yaml secret is searched (4x)
120
+ expect(subject).to receive(:secrets_for_source).and_call_original.exactly(4).times
121
+ # only 2 corresponding
122
+ expect(@collector).to receive(:collect!).exactly(2).times
123
+
124
+ subject.send(:queue_collectors)
125
+
126
+ pool = subject.send(:thread_pool)
127
+ pool.shutdown
128
+ pool.wait_for_termination
129
+ end
130
+ end
131
+ end
132
+
133
+ def stub_settings_merge(hash)
134
+ if defined?(::Settings)
135
+ Settings.add_source!(hash)
136
+ Settings.reload!
137
+ end
138
+ end
139
+
140
+ def clear_settings
141
+ ::Settings.keys.dup.each { |k| ::Settings.delete_field(k) } if defined?(::Settings)
142
+ end
143
+
144
+ def path_and_filename(tempfile)
145
+ parts = tempfile.path.split('/')
146
+ name = parts[-1]
147
+ path = parts[0..-2].join('/')
148
+ [name, path]
149
+ end
150
+ end
@@ -0,0 +1,38 @@
1
+ RSpec.describe TopologicalInventory::Providers::Common::Logger do
2
+ let(:status) { :test }
3
+ let(:source) { '92844e11-17d5-4998-a33d-d886c3c7a80e' }
4
+ let(:entity_type) { 'test-entity' }
5
+ let(:refresh_state_uuid) { 'cd22ba1c-56f6-4fd4-a191-ec8eb8e993a8' }
6
+ let(:sweep_scope) { [entity_type] }
7
+ let(:total_parts) { 10 }
8
+
9
+ subject { described_class.new }
10
+
11
+ it 'receives collecting method' do
12
+ msg = "[#{status.to_s.upcase}] Collecting #{entity_type}"
13
+ msg += ", :total parts => #{total_parts}" if total_parts.present?
14
+ msg += ", :source_uid => #{source}, :refresh_state_uuid => #{refresh_state_uuid}"
15
+ expect(subject).to receive(:info).with(msg)
16
+
17
+ subject.collecting(status, source, entity_type, refresh_state_uuid, total_parts)
18
+ end
19
+
20
+ it 'receives sweeping method' do
21
+ msg = "[#{status.to_s.upcase}] Sweeping inactive records, :sweep_scope => #{sweep_scope}, :source_uid => #{source}, :refresh_state_uuid => #{refresh_state_uuid}"
22
+ expect(subject).to receive(:info).with(msg)
23
+
24
+ subject.sweeping(status, source, sweep_scope, refresh_state_uuid)
25
+ end
26
+
27
+ it 'receives collecting error method' do
28
+ begin
29
+ raise 'Test exception'
30
+ rescue => e
31
+ msg = "[ERROR] Collecting #{entity_type}, :source_uid => #{source}, :refresh_state_uuid => #{refresh_state_uuid}"
32
+ msg += ":message => #{e.message}\n#{e.backtrace.join("\n")}"
33
+ expect(subject).to receive(:error).with(msg)
34
+
35
+ subject.collecting_error(source, entity_type, refresh_state_uuid, e)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,102 @@
1
+ require "topological_inventory/providers/common/operations/processor"
2
+
3
+ RSpec.describe TopologicalInventory::Providers::Common::Operations::Processor do
4
+ let(:topology_api_client) { double }
5
+ let(:source_id) { 1 }
6
+ let(:source_ref) { 1000 }
7
+ let(:service_plan) { double("TopologicalInventoryApiClient::ServicePlan") }
8
+ let(:service_offering) { double("TopologicalInventoryApiClient::ServiceOffering") }
9
+
10
+ # Overriden in contexts
11
+ let(:payload) { {} }
12
+
13
+ before do
14
+ @processor = described_class.new(nil, nil, payload)
15
+ allow(@processor).to receive(:logger).and_return(double('null_object').as_null_object)
16
+
17
+ allow(service_plan).to receive(:service_offering_id).and_return(1)
18
+ allow(service_plan).to receive(:name).and_return(double)
19
+
20
+ allow(service_offering).to receive(:name).and_return(double)
21
+ allow(service_offering).to receive(:source_ref).and_return(source_ref)
22
+ allow(service_offering).to receive(:extra).and_return({:type => 'job_template'})
23
+ allow(service_offering).to receive(:source_id).and_return(source_id)
24
+
25
+ @endpoint_client = double
26
+ allow(@endpoint_client).to receive(:order_service)
27
+
28
+ allow(@processor).to receive(:endpoint_client).and_return(@endpoint_client)
29
+ allow(@processor).to receive(:topology_api_client).and_return(topology_api_client)
30
+ allow(topology_api_client).to receive(:update_task)
31
+ allow(topology_api_client).to receive(:show_service_plan).and_return(service_plan)
32
+ allow(topology_api_client).to receive(:show_service_offering).and_return(service_offering)
33
+ end
34
+
35
+ context "Order by ServicePlan" do
36
+ let(:payload) do
37
+ {
38
+ 'request_context' => {"x-rh-identity" => 'abcd'},
39
+ 'params' => {
40
+ 'order_params' => {
41
+ 'service_plan_id' => 1,
42
+ 'service_parameters' => { :name => "Job 1",
43
+ :param1 => "Test Topology",
44
+ :param2 => 50 },
45
+ 'provider_control_parameters' => {}
46
+ },
47
+ 'service_plan_id' => 1,
48
+ 'task_id' => 1 # in tp-inv api (Task)
49
+ }
50
+ }
51
+ end
52
+
53
+ describe "#order_service" do
54
+ it "orders job" do
55
+ allow(@processor).to receive(:poll_order_complete_thread).and_return(double)
56
+
57
+ expect(@endpoint_client).to receive(:order_service).with(service_offering, service_plan, payload['params']['order_params'])
58
+ @processor.send(:order_service, payload['params'])
59
+ end
60
+
61
+ it "updates task on error" do
62
+ err_message = "Sample error"
63
+
64
+ allow(@processor).to receive(:poll_order_complete_thread).and_return(double)
65
+ allow(@processor).to receive(:update_task).and_return(double)
66
+ allow(@endpoint_client).to receive(:order_service).and_raise(err_message)
67
+
68
+ expect(@processor).to receive(:update_task).with(payload['params']['task_id'], :state => "completed", :status => "error", :context => { :error => err_message })
69
+
70
+ @processor.send(:order_service, payload['params'])
71
+ end
72
+ end
73
+ end
74
+
75
+ context "Order by ServiceOffering" do
76
+ let(:payload) do
77
+ {
78
+ 'request_context' => {"x-rh-identity" => 'abcd'},
79
+ 'params' => {
80
+ 'order_params' => {
81
+ 'service_offering_id' => 1,
82
+ 'service_parameters' => { :name => "Job 1",
83
+ :param1 => "Test Topology",
84
+ :param2 => 50 },
85
+ 'provider_control_parameters' => {}
86
+ },
87
+ 'service_offering_id' => 1,
88
+ 'task_id' => 1 # in tp-inv api (Task)
89
+ }
90
+ }
91
+ end
92
+
93
+ describe "#order_service" do
94
+ it "orders job" do
95
+ allow(@processor).to receive(:poll_order_complete_thread).and_return(double)
96
+
97
+ expect(@endpoint_client).to receive(:order_service).with(service_offering, nil, payload['params']['order_params'])
98
+ @processor.send(:order_service, payload['params'])
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,5 @@
1
+ require "topological_inventory/providers/common/operations/source"
2
+
3
+ RSpec.describe TopologicalInventory::Providers::Common::Operations::Source do
4
+ it_behaves_like "availability_check"
5
+ end
@@ -0,0 +1,65 @@
1
+ require "topological_inventory/providers/common/save_inventory/saver"
2
+
3
+ RSpec.describe TopologicalInventory::Providers::Common::SaveInventory::Saver do
4
+ let(:client) { instance_double(TopologicalInventoryIngressApiClient::DefaultApi) }
5
+ let(:logger) { double }
6
+ let(:base_args) { {client: client, logger: logger} }
7
+
8
+ let(:small_json) { {:test => ["values"]} }
9
+ let(:big_json) { InventorySpecHelper.big_inventory(80_000, 1_000) }
10
+
11
+ describe "#save" do
12
+ subject { described_class.new(args).save(:inventory => inventory) }
13
+
14
+ context "when the data size is less than max_bytes" do
15
+ let(:args) { base_args }
16
+ let(:inventory) { small_json }
17
+
18
+ before do
19
+ allow(client).to receive(:save_inventory_with_http_info).with(small_json.to_json)
20
+ end
21
+
22
+ it "returns that it saved one chunk" do
23
+ is_expected.to eq 1
24
+ end
25
+
26
+ it "does not split the payload into batches" do
27
+ expect(client).to receive(:save_inventory_with_http_info).with(small_json.to_json).once
28
+ subject
29
+ end
30
+ end
31
+
32
+ context "when the data size is greater than specified max_bytes" do
33
+ let(:args) { base_args.merge!(:max_bytes => 19_512) }
34
+ let(:inventory) { big_json }
35
+
36
+ before do
37
+ allow(client).to receive(:save_inventory_with_http_info)
38
+ end
39
+
40
+ it "returns that it saved five chunks" do
41
+ is_expected.to eq 5
42
+ end
43
+
44
+ it "splits the payload up into chunks" do
45
+ expect(client).to receive(:save_inventory_with_http_info).exactly(5).times
46
+ subject
47
+ end
48
+ end
49
+
50
+ context "when the KAFKA_PAYLOAD_MAX_BYTES ENV var is set" do
51
+ let(:args) { base_args }
52
+ let(:inventory) { big_json }
53
+
54
+ before do
55
+ allow(ENV).to receive(:[]).with("KAFKA_PAYLOAD_MAX_BYTES").and_return("9_512")
56
+ allow(client).to receive(:save_inventory_with_http_info)
57
+ end
58
+
59
+ it "splits the payload into smaller chunks" do
60
+ expect(client).to receive(:save_inventory_with_http_info).exactly(10).times
61
+ is_expected.to eq 10
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,3 @@
1
+ RSpec.describe TopologicalInventory::Providers::Common do
2
+
3
+ end
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
17
17
  # Specify which files should be added to the gem when it is released.
18
18
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
19
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
20
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
+ `git ls-files -z`.split("\x0")
21
21
  end
22
22
  spec.bindir = "exe"
23
23
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: topological_inventory-providers-common
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Slemr
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-06-17 00:00:00.000000000 Z
11
+ date: 2020-06-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -254,6 +254,17 @@ files:
254
254
  - lib/topological_inventory/providers/common/save_inventory/exception.rb
255
255
  - lib/topological_inventory/providers/common/save_inventory/saver.rb
256
256
  - lib/topological_inventory/providers/common/version.rb
257
+ - spec/spec_helper.rb
258
+ - spec/support/inventory_helper.rb
259
+ - spec/support/shared/availability_check.rb
260
+ - spec/topological_inventory/providers/common/collectors/inventory_collection_storage_spec.rb
261
+ - spec/topological_inventory/providers/common/collectors/inventory_collection_wrapper_spec.rb
262
+ - spec/topological_inventory/providers/common/collectors_pool_spec.rb
263
+ - spec/topological_inventory/providers/common/logger_spec.rb
264
+ - spec/topological_inventory/providers/common/operations/processor_spec.rb
265
+ - spec/topological_inventory/providers/common/operations/source_spec.rb
266
+ - spec/topological_inventory/providers/common/save_inventory/saver_spec.rb
267
+ - spec/topological_inventory/providers/common_spec.rb
257
268
  - topological_inventory-providers-common.gemspec
258
269
  homepage: https://github.com/RedHatInsights/topological_inventory-providers-common
259
270
  licenses:
@@ -274,7 +285,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
274
285
  - !ruby/object:Gem::Version
275
286
  version: '0'
276
287
  requirements: []
277
- rubygems_version: 3.0.8
288
+ rubygems_version: 3.0.3
278
289
  signing_key:
279
290
  specification_version: 4
280
291
  summary: Common classes for topological-inventory collectors/operations