foreman_scc_manager 1.6.1 → 1.6.2

Sign up to get free protection for your applications and to get access to all the features.
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