topological_inventory-providers-common 1.0.4 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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