foreman_scc_manager 1.6.1 → 1.6.2

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.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/scc_accounts_controller.rb +17 -11
  3. data/app/lib/actions/scc_manager/subscribe_product.rb +1 -0
  4. data/app/lib/actions/scc_manager/sync.rb +1 -0
  5. data/app/lib/actions/scc_manager/sync_plan_account_repositories.rb +38 -0
  6. data/app/lib/actions/scc_manager/sync_repositories.rb +3 -2
  7. data/app/lib/scc_manager.rb +1 -0
  8. data/app/models/concerns/recurring_logic_extensions.rb +9 -0
  9. data/app/models/scc_account.rb +123 -1
  10. data/app/models/scc_account_sync_plan_task_group.rb +7 -0
  11. data/app/models/scc_product.rb +1 -0
  12. data/app/views/scc_account_sync_plan_task_groups/_scc_account_sync_plan_task_groups.html.erb +4 -0
  13. data/app/views/scc_accounts/_form.html.erb +4 -0
  14. data/config/routes.rb +1 -0
  15. data/db/migrate/20190417202427_add_recurring_sync.foreman_scc_manager.rb +26 -0
  16. data/lib/foreman_scc_manager/engine.rb +4 -0
  17. data/lib/foreman_scc_manager/version.rb +1 -1
  18. data/lib/tasks/rubocop.rake +32 -0
  19. data/lib/tasks/test.rake +26 -0
  20. data/test/features/data_products_page1.json +10468 -0
  21. data/test/features/data_products_page2.json +11277 -0
  22. data/test/features/data_subscriptions.json +88 -0
  23. data/test/features/sync_test.rb +141 -0
  24. data/test/fixtures/models/scc_accounts.yml +24 -0
  25. data/test/fixtures/models/scc_products.yml +21 -0
  26. data/test/models/scc_account_test.rb +74 -0
  27. data/test/models/scc_product_test.rb +32 -0
  28. data/test/support/fixtures_support.rb +12 -0
  29. data/test/test_plugin_helper.rb +54 -0
  30. metadata +43 -5
  31. data/lib/tasks/foreman_scc_manager_tasks.rake +0 -45
@@ -0,0 +1,88 @@
1
+ [
2
+ {
3
+ "id": 1,
4
+ "regcode": "0123456789ABCD",
5
+ "name": "Expired Product number one",
6
+ "type": "evaluation",
7
+ "status": "EXPIRED",
8
+ "starts_at": "2014-11-13T00:00:00.000Z",
9
+ "expires_at": "2015-01-12T00:00:00.000Z",
10
+ "system_limit": 1,
11
+ "systems_count": 3,
12
+ "virtual_count": null,
13
+ "product_classes": [
14
+ "HPC-X86",
15
+ "7261"
16
+ ],
17
+ "product_ids": [
18
+ 1234,
19
+ 5678
20
+ ],
21
+ "skus": [],
22
+ "systems": [
23
+ {
24
+ "id": 3,
25
+ "login": "SCC_0123456789abcdef0123456789abcdef",
26
+ "password": "fedcba9876543210",
27
+ "last_seen_at": null
28
+ },
29
+ {
30
+ "id": 4,
31
+ "login": "SCC_123456789abcdef0123456789abcdef0",
32
+ "password": "edcba9876543210f",
33
+ "last_seen_at": null
34
+ },
35
+ {
36
+ "id": 5,
37
+ "login": "SCC_23456789abcdef0123456789abcdef01",
38
+ "password": "dcba9876543210fe",
39
+ "last_seen_at": null
40
+ }
41
+ ]
42
+ },
43
+ {
44
+ "id": 2,
45
+ "regcode": "123456789ABCDE",
46
+ "name": "Some other Product which is ACTIVE",
47
+ "type": "full",
48
+ "status": "ACTIVE",
49
+ "starts_at": "2014-03-13T00:00:00.000Z",
50
+ "expires_at": "2020-01-31T00:00:00.000Z",
51
+ "system_limit": 1,
52
+ "systems_count": 0,
53
+ "virtual_count": null,
54
+ "product_classes": [
55
+ "VMDP"
56
+ ],
57
+ "product_ids": [
58
+ 1337
59
+ ],
60
+ "skus": [],
61
+ "systems": []
62
+ },
63
+ {
64
+ "id": 3,
65
+ "regcode": "23456789ABCDEF",
66
+ "name": "Yet Another ACTIVE SUSE Product",
67
+ "type": "full",
68
+ "status": "ACTIVE",
69
+ "starts_at": "2014-03-13T00:00:00.000Z",
70
+ "expires_at": "2020-01-31T00:00:00.000Z",
71
+ "system_limit": 1,
72
+ "systems_count": 0,
73
+ "virtual_count": null,
74
+ "product_classes": [
75
+ "HPC-X86",
76
+ "SUSE_RT",
77
+ "7261",
78
+ "13319"
79
+ ],
80
+ "product_ids": [
81
+ 123,
82
+ 456,
83
+ 789
84
+ ],
85
+ "skus": [],
86
+ "systems": []
87
+ }
88
+ ]
@@ -0,0 +1,141 @@
1
+ require 'test_plugin_helper'
2
+
3
+ class SccAccountSyncTest < ActiveSupport::TestCase
4
+ # rubocop:disable Metrics/MethodLength
5
+ def setup
6
+ # test_connection:
7
+ stub_request(:get, 'https://scc.example.com/connect/organizations/subscriptions')
8
+ .with(
9
+ headers: {
10
+ 'Accept' => 'application/vnd.scc.suse.com.v4+json',
11
+ 'Accept-Encoding' => 'gzip, deflate',
12
+ 'Authorization' => 'Basic b25ldXNlcjpvbmVwYXNz',
13
+ 'Host' => 'scc.example.com'
14
+ }
15
+ ).to_return(
16
+ status: 200,
17
+ body: Zlib.gzip(File.read("#{File.dirname(__FILE__)}/data_subscriptions.json")),
18
+ headers: {
19
+ server: 'nginx',
20
+ date: 'Tue, 05 Mar 2019 15:07:38 GMT',
21
+ content_type: 'application/json; charset=utf-8',
22
+ transfer_encoding: 'chunked',
23
+ connection: 'keep-alive',
24
+ vary: 'Accept-Encoding',
25
+ x_frame_options: 'SAMEORIGIN',
26
+ x_xss_protection: '1; mode=block',
27
+ x_content_type_options: 'nosniff',
28
+ per_page: '10',
29
+ total: '3',
30
+ scc_api_version: 'v4',
31
+ etag: 'W/"0123456789abcdef0123456789abcdef"',
32
+ cache_control: 'max-age=0, private, must-revalidate',
33
+ set_cookie: [
34
+ 'XSRF-TOKEN=TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBp%0Ac2NpbmcgZWxpdCwgc2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2l; path=/; secure',
35
+ 'Uy#u~osh#oh3ahv.op0OII; Expires=Fri, 02-Mar-2029 15:07:20 GMT; Path=/'
36
+ ],
37
+ x_request_id: '67450237-e4aa-4994-a47d-ed3ce142555b',
38
+ x_runtime: '0.144083',
39
+ strict_transport_security: 'max-age=15552000, max-age=300',
40
+ content_encoding: 'gzip'
41
+ }
42
+ )
43
+ ############
44
+ # Products #
45
+ ############
46
+ # products page1
47
+ stub_request(:get, 'https://scc.example.com/connect/organizations/products')
48
+ .with(
49
+ headers: {
50
+ 'Accept' => 'application/vnd.scc.suse.com.v4+json',
51
+ 'Accept-Encoding' => 'gzip, deflate',
52
+ 'Authorization' => 'Basic b25ldXNlcjpvbmVwYXNz',
53
+ 'Host' => 'scc.example.com'
54
+ }
55
+ ).to_return(
56
+ status: 200,
57
+ body: Zlib.gzip(File.read("#{File.dirname(__FILE__)}/data_products_page1.json")),
58
+ headers: {
59
+ server: 'nginx',
60
+ date: 'Mon, 11 Mar 2019 15:37:00 GMT',
61
+ content_type: 'application/json; charset=utf-8',
62
+ transfer_encoding: 'chunked',
63
+ connection: 'keep-alive',
64
+ vary: 'Accept-Encoding',
65
+ x_frame_options: 'SAMEORIGIN',
66
+ x_xss_protection: '1; mode=block',
67
+ x_content_type_options: 'nosniff',
68
+ link: '<https://scc.example.com/connect/organizations/products?page=2>; rel="last", <https://scc.example.com/connect/organizations/products?page=2>; rel="next"',
69
+ per_page: 25,
70
+ total: 50,
71
+ scc_api_version: 'v4',
72
+ etag: '57fbfddfb5cc165b2581d297cad27a53',
73
+ cache_control: 'max-age=0, private, must-revalidate',
74
+ set_cookie: [
75
+ 'XSRF-TOKEN=EABKsiefcpa7dMNEXRixmihKeUfIvXF4AwmNQt2wZG5Fm%2FPKvR0%2FMBDVV5lZJ3p4waUAcds2xWv42vbKg9GQhg%3D%3D; path=/; secure',
76
+ 'TbBx+jfg=v1jitvAA@@UII; Expires=Thu, 08-Mar-2029 15:37:15 GMT; Path=/'
77
+ ],
78
+ x_request_id: 'd2797941-1aed-499c-8e06-b4cb52515443',
79
+ x_runtime: '6.671012',
80
+ strict_transport_security: 'max-age=15552000, max-age=300',
81
+ content_encoding: 'gzip'
82
+ }
83
+ )
84
+ # products page2
85
+ stub_request(:get, 'https://scc.example.com/connect/organizations/products?page=2')
86
+ .with(
87
+ headers: {
88
+ 'Accept' => 'application/vnd.scc.suse.com.v4+json',
89
+ 'Accept-Encoding' => 'gzip, deflate',
90
+ 'Authorization' => 'Basic b25ldXNlcjpvbmVwYXNz',
91
+ 'Host' => 'scc.example.com'
92
+ }
93
+ ).to_return(
94
+ status: 200,
95
+ body: Zlib.gzip(File.read("#{File.dirname(__FILE__)}/data_products_page2.json")),
96
+ headers: {
97
+ server: 'nginx',
98
+ date: 'Mon, 11 Mar 2019 15:37:19 GMT',
99
+ content_type: 'application/json; charset=utf-8',
100
+ transfer_encoding: 'chunked',
101
+ connection: 'keep-alive',
102
+ vary: 'Accept-Encoding',
103
+ x_frame_options: 'SAMEORIGIN',
104
+ x_xss_protection: '1; mode=block',
105
+ x_content_type_options: 'nosniff',
106
+ link: '<https://scc.example.com/connect/organizations/products?page=1>; rel="first", <https://scc.example.com/connect/organizations/products?page=1>; rel="prev"',
107
+ per_page: 3,
108
+ total: 2,
109
+ scc_api_version: 'v4',
110
+ etag: '3fb638e3ab553dc6c88ef9914540b4bd',
111
+ cache_control: 'max-age=0, private, must-revalidate',
112
+ set_cookie: [
113
+ 'XSRF-TOKEN=z3bGc45lQxf%2FXq7qN7cwzJrK1zcw4e7uuskVCPejeN0zv3ExUcb8ev3jhGnDGJaSz3ZwV7Dk0SdLII%2FOcI2eEw%3D%3D; path=/; secure',
114
+ 'TbBx+jfg=v1oytvAA@@I73; Expires=Thu, 08-Mar-2029 15:37:23 GMT; Path=/'
115
+ ],
116
+ x_request_id: '17e6707a-1134-403d-a49c-7344442446c1',
117
+ x_runtime: '6.671012',
118
+ strict_transport_security: 'max-age=15552000, max-age=300',
119
+ content_encoding: 'gzip'
120
+ }
121
+ )
122
+ end
123
+ # rubocop:enable Metrics/MethodLength
124
+
125
+ test 'SCC server connection-test' do
126
+ assert scc_accounts(:one).test_connection
127
+ end
128
+
129
+ test 'SCC server sync products new' do
130
+ scc_account = scc_accounts(:one)
131
+ assert scc_account
132
+ products = ::SccManager.get_scc_data(
133
+ scc_account.base_url,
134
+ '/connect/organizations/products',
135
+ scc_account.login,
136
+ scc_account.password
137
+ )
138
+ assert_not_nil(products)
139
+ assert_equal(50, products.length)
140
+ end
141
+ end
@@ -0,0 +1,24 @@
1
+ ---
2
+ one:
3
+ login: oneuser
4
+ password: onepass
5
+ base_url: https://scc.example.com
6
+ name: onename
7
+ interval: never
8
+ organization_id: <%= ActiveRecord::FixtureSet.identify(:empty_organization) %>
9
+
10
+ two:
11
+ login: twouser
12
+ password: twopass
13
+ base_url: https://scc.example.com
14
+ name: twoname
15
+ interval: never
16
+ organization_id: <%= ActiveRecord::FixtureSet.identify(:empty_organization) %>
17
+
18
+ account_missing_url:
19
+ login: fakeuser1
20
+ password: fakepass1
21
+ name: fake1
22
+ interval: never
23
+ organization_id: <%= ActiveRecord::FixtureSet.identify(:empty_organization) %>
24
+ ...
@@ -0,0 +1,21 @@
1
+ # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
2
+
3
+ one:
4
+ scc_account_id: test_account1
5
+ scc_id: 111
6
+ name: one
7
+ version: 1
8
+ arch: x86_128
9
+ friendly_name: number one
10
+ description: lorem ipsum dolor sit amet
11
+ product_type: base
12
+
13
+ two:
14
+ scc_account_id: test_account1
15
+ scc_id: 222
16
+ name: two
17
+ version: 2
18
+ arch: x86_128
19
+ friendly_name: number two
20
+ description: lorem ipsum dolor sit amet
21
+ product_type: extras
@@ -0,0 +1,74 @@
1
+ require 'test_plugin_helper'
2
+
3
+ class SccAccountCreateTest < ActiveSupport::TestCase
4
+ def setup
5
+ @account = scc_accounts(:one)
6
+ end
7
+
8
+ test 'create' do
9
+ assert @account.save
10
+ refute_empty SccAccount.where(:id => @account.id)
11
+ end
12
+
13
+ test 'create default url' do
14
+ account = scc_accounts(:account_missing_url)
15
+ assert account.save
16
+ assert_equal account.base_url, 'https://scc.suse.com'
17
+ refute_empty SccAccount.where(:id => @account.id)
18
+ end
19
+
20
+ test 'create missing value' do
21
+ list = {
22
+ name: 'Not Working',
23
+ organization: get_organization,
24
+ # base_url has a default value set in DB
25
+ # base_url: 'https://scc.example.org',
26
+ login: 'account1',
27
+ password: 'secret'
28
+ }
29
+
30
+ # for every key in hash try to create account without it set
31
+ list.each_key do |k|
32
+ l = list.clone
33
+ l.delete(k)
34
+ assert_raises ActiveRecord::RecordInvalid do
35
+ SccAccount.new(l).save!
36
+ end
37
+ end
38
+ end
39
+
40
+ test 'create wrong interval-value' do
41
+ account = scc_accounts(:two)
42
+ account.interval = 'gazillion'
43
+ assert_not account.save
44
+ end
45
+
46
+ test 'password is saved encrypted when updated' do
47
+ assert SccAccount.encrypts? :password
48
+ @account.expects(:encryption_key).at_least_once.returns('25d224dd383e92a7e0c82b8bf7c985e815f34cf5')
49
+ @account.password = '123456'
50
+ as_admin do
51
+ assert @account.save
52
+ end
53
+ assert_equal @account.password, '123456'
54
+ refute_equal @account.password_in_db, '123456'
55
+ end
56
+ end
57
+
58
+ class SccAccountSearchTest < ActiveSupport::TestCase
59
+ test 'default ordered by login' do
60
+ assert_equal SccAccount.all.pluck(:login), ['oneuser', 'twouser', 'fakeuser1'].sort
61
+ end
62
+
63
+ test 'search login' do
64
+ one = scc_accounts(:one)
65
+ accounts = SccAccount.search_for("login = \"#{one.login}\"")
66
+ assert_includes accounts, one
67
+ refute_includes accounts, scc_accounts(:two)
68
+
69
+ empty = SccAccount.search_for('login = "nobody"')
70
+ assert_empty empty
71
+ end
72
+ end
73
+
74
+ # FIXME: test cascaded delete
@@ -0,0 +1,32 @@
1
+ require 'test_plugin_helper'
2
+
3
+ class SccProductCreateTest < ActiveSupport::TestCase
4
+ def setup
5
+ @product = scc_products(:one)
6
+ end
7
+
8
+ test 'create' do
9
+ assert @product.save
10
+ refute_empty SccProduct.where(id: @product.id)
11
+ end
12
+
13
+ test 'uniq_name' do
14
+ assert_equal @product.uniq_name, '111 number one'
15
+ end
16
+ end
17
+
18
+ class SccProductSearchTest < ActiveSupport::TestCase
19
+ test 'default ordered by name' do
20
+ assert_equal SccProduct.all.pluck(:name), ['one', 'two'].sort
21
+ end
22
+
23
+ test 'search name' do
24
+ one = scc_products(:one)
25
+ products = SccProduct.search_for("name = \"#{one.name}\"")
26
+ assert_includes products, one
27
+ refute_includes products, scc_products(:two)
28
+
29
+ empty = SccProduct.search_for('name = "nothing"')
30
+ assert_empty empty
31
+ end
32
+ end
@@ -0,0 +1,12 @@
1
+ module ForemanSccManager
2
+ module FixturesSupport
3
+ FIXTURE_CLASSES = {
4
+ scc_accounts: ForemanSccManager::SccAccount,
5
+ scc_products: ForemanSccManager::SccProduct
6
+ }.freeze
7
+
8
+ def self.set_fixture_classes(test_class)
9
+ FIXTURE_CLASSES.each { |k, v| test_class.set_fixture_class(k => v) }
10
+ end
11
+ end
12
+ end
@@ -1,2 +1,56 @@
1
1
  # This calls the main test_helper in Foreman-core
2
2
  require 'test_helper'
3
+
4
+ require 'foreman_tasks/test_helpers'
5
+ require "#{ForemanSccManager::Engine.root}/test/support/fixtures_support"
6
+
7
+ module FixtureTestCase
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ extend ActiveRecord::TestFixtures
12
+
13
+ self.use_instantiated_fixtures = false
14
+ self.pre_loaded_fixtures = true
15
+
16
+ ForemanSccManager::FixturesSupport.set_fixture_classes(self)
17
+
18
+ # Fixtures are copied into a separate path to combine with Foreman fixtures. This directory
19
+ # is kept out of version control.
20
+ self.fixture_path = "#{Rails.root}/tmp/combined_fixtures/"
21
+ FileUtils.rm_rf(self.fixture_path) if File.directory?(self.fixture_path)
22
+ Dir.mkdir(self.fixture_path)
23
+ FileUtils.cp(Dir.glob("#{ForemanSccManager::Engine.root}/test/fixtures/models/*"), self.fixture_path)
24
+ FileUtils.cp(Dir.glob("#{Rails.root}/test/fixtures/*"), self.fixture_path)
25
+ fixtures(:all)
26
+ FIXTURES = load_fixtures(ActiveRecord::Base)
27
+
28
+ Setting::Content.load_defaults
29
+
30
+ User.current = ::User.unscoped.find(FIXTURES['users']['admin']['id'])
31
+ end
32
+ end
33
+
34
+ class ActiveSupport::TestCase
35
+ include FactoryBot::Syntax::Methods
36
+ include FixtureTestCase
37
+ include ForemanTasks::TestHelpers::WithInThreadExecutor
38
+
39
+ before do
40
+ Setting::Content.load_defaults
41
+ end
42
+
43
+ def get_organization(org = nil)
44
+ saved_user = User.current
45
+ User.current = User.unscoped.find(users(:admin).id)
46
+ org = org.nil? ? :empty_organization : org
47
+ organization = Organization.find(taxonomies(org.to_sym).id)
48
+ organization.stubs(:label_not_changed).returns(true)
49
+ organization.setup_label_from_name
50
+ location = Location.where(name: 'Location 1').first
51
+ organization.locations << location
52
+ organization.save!
53
+ User.current = saved_user
54
+ organization
55
+ end
56
+ end