foreman_teamdynamix 0.0.1

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.
data/locale/Makefile ADDED
@@ -0,0 +1,60 @@
1
+ #
2
+ # Makefile for PO merging and MO generation. More info in the README.
3
+ #
4
+ # make all-mo (default) - generate MO files
5
+ # make check - check translations using translate-tool
6
+ # make tx-update - download and merge translations from Transifex
7
+ # make clean - clean everything
8
+ #
9
+ DOMAIN = foreman_teamdynamix
10
+ VERSION = $(shell ruby -e 'require "rubygems";spec = Gem::Specification::load(Dir.glob("../*.gemspec")[0]);puts spec.version')
11
+ POTFILE = $(DOMAIN).pot
12
+ MOFILE = $(DOMAIN).mo
13
+ POFILES = $(shell find . -name '$(DOMAIN).po')
14
+ MOFILES = $(patsubst %.po,%.mo,$(POFILES))
15
+ POXFILES = $(patsubst %.po,%.pox,$(POFILES))
16
+ EDITFILES = $(patsubst %.po,%.edit.po,$(POFILES))
17
+
18
+ %.mo: %.po
19
+ mkdir -p $(shell dirname $@)/LC_MESSAGES
20
+ msgfmt -o $(shell dirname $@)/LC_MESSAGES/$(MOFILE) $<
21
+
22
+ # Generate MO files from PO files
23
+ all-mo: $(MOFILES)
24
+
25
+ # Check for malformed strings
26
+ %.pox: %.po
27
+ msgfmt -c $<
28
+ pofilter --nofuzzy -t variables -t blank -t urls -t emails -t long -t newlines \
29
+ -t endwhitespace -t endpunc -t puncspacing -t options -t printf -t validchars --gnome $< > $@
30
+ cat $@
31
+ ! grep -q msgid $@
32
+
33
+ %.edit.po:
34
+ touch $@
35
+
36
+ check: $(POXFILES)
37
+
38
+ # Unify duplicate translations
39
+ uniq-po:
40
+ for f in $(shell find ./ -name "*.po") ; do \
41
+ msguniq $$f -o $$f ; \
42
+ done
43
+
44
+ tx-pull: $(EDITFILES)
45
+ tx pull -f
46
+ for f in $(EDITFILES) ; do \
47
+ sed -i 's/^\("Project-Id-Version: \).*$$/\1$(DOMAIN) $(VERSION)\\n"/' $$f; \
48
+ done
49
+
50
+ tx-update: tx-pull
51
+ @echo
52
+ @echo Run rake plugin:gettext[$(DOMAIN)] from the Foreman installation, then make -C locale mo-files to finish
53
+ @echo
54
+
55
+ mo-files: $(MOFILES)
56
+ git add $(POFILES) $(POTFILE) ../locale/*/LC_MESSAGES
57
+ git commit -m "i18n - pulling from tx"
58
+ @echo
59
+ @echo Changes commited!
60
+ @echo
@@ -0,0 +1,18 @@
1
+ # foreman_teamdynamix
2
+ #
3
+ # This file is distributed under the same license as foreman_teamdynamix.
4
+ #
5
+ #, fuzzy
6
+ msgid ""
7
+ msgstr ""
8
+ "Project-Id-Version: version 0.0.1\n"
9
+ "Report-Msgid-Bugs-To: \n"
10
+ "POT-Creation-Date: 2014-08-20 08:46+0100\n"
11
+ "PO-Revision-Date: 2014-08-20 08:54+0100\n"
12
+ "Last-Translator: Foreman Team <foreman-dev@googlegroups.com>\n"
13
+ "Language-Team: Foreman Team <foreman-dev@googlegroups.com>\n"
14
+ "Language: \n"
15
+ "MIME-Version: 1.0\n"
16
+ "Content-Type: text/plain; charset=UTF-8\n"
17
+ "Content-Transfer-Encoding: 8bit\n"
18
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -0,0 +1,18 @@
1
+ # foreman_teamdynamix
2
+ #
3
+ # This file is distributed under the same license as foreman_teamdynamix.
4
+ #
5
+ #, fuzzy
6
+ msgid ""
7
+ msgstr ""
8
+ "Project-Id-Version: version 0.0.1\n"
9
+ "Report-Msgid-Bugs-To: \n"
10
+ "POT-Creation-Date: 2014-08-20 08:46+0100\n"
11
+ "PO-Revision-Date: 2014-08-20 08:46+0100\n"
12
+ "Last-Translator: Foreman Team <foreman-dev@googlegroups.com>\n"
13
+ "Language-Team: Foreman Team <foreman-dev@googlegroups.com>\n"
14
+ "Language: \n"
15
+ "MIME-Version: 1.0\n"
16
+ "Content-Type: text/plain; charset=UTF-8\n"
17
+ "Content-Transfer-Encoding: 8bit\n"
18
+ "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
data/locale/gemspec.rb ADDED
@@ -0,0 +1,2 @@
1
+ # Matches foreman_teamdynamix.gemspec
2
+ _('A Foreman Plugin to create a configurable TeamDynamix Asset when a host is created in Foreman')
@@ -0,0 +1,17 @@
1
+ class FakeTeamdynamixApi
2
+ def create_asset(*)
3
+ get_asset
4
+ end
5
+
6
+ def search_asset(*)
7
+ Array.wrap(get_asset)
8
+ end
9
+
10
+ def retire_asset(*)
11
+ true
12
+ end
13
+
14
+ def get_asset(*)
15
+ JSON.parse(File.read(File.join(File.dirname(__FILE__), 'sample_asset.json')))
16
+ end
17
+ end
@@ -0,0 +1,31 @@
1
+ require 'test_plugin_helper'
2
+
3
+ class HostsControllerTest < ActionController::TestCase
4
+ let(:td_tab_title) { SETTINGS[:teamdynamix][:title] || 'Team Dynamix' }
5
+ let(:host) { FactoryBot.create(:host, :managed) }
6
+ let(:td_api) { FakeTeamdynamixApi.new }
7
+ before do
8
+ Host::Managed.any_instance.stubs(:td_api).returns(td_api)
9
+ end
10
+ # rubocop:disable Style/StringLiterals, HttpPositionalArguments
11
+ describe 'Given host exist as an asset in TeamDynamix' do
12
+ describe 'when TeamDynamix asset attributes are configured' do
13
+ describe 'GET hosts/show' do
14
+ test 'loads the TeamDynamix tab' do
15
+ get :show, { :id => host.name }, set_session_user
16
+ assert_includes response.headers['Content-Type'], 'text/html'
17
+ assert_includes response.body, "<ul id=\"myTab\""
18
+ assert_equal response.status, 200
19
+ assert_includes response.body, "<li><a href=\"#teamdynamix\" data-toggle=\"tab\">#{td_tab_title}</a></li>"
20
+ assert_includes response.body, "<div id=\"teamdynamix\" class=\"tab-pane\" data-ajax-url=\"/hosts/#{host.name}/teamdynamix\" data-on-complete=\"onContentLoad\">"
21
+ end
22
+ test 'TeamDynamix tab contains configured asset attributes' do
23
+ skip
24
+ get hosts_teamdynamix_path, { :id => host.name }, set_session_user
25
+ assert_template 'foreman_teamdynamix'
26
+ end
27
+ end
28
+ end
29
+ end
30
+ # rubocop:enable Style/StringLiterals, HttpPositionalArguments
31
+ end
@@ -0,0 +1,63 @@
1
+ require 'test_plugin_helper'
2
+
3
+ class HostsHelperExtensionsTest < ActiveSupport::TestCase
4
+ include ActionView::Helpers::UrlHelper
5
+ include ForemanTeamdynamix::HostsHelperExtensions
6
+ let(:host) { FactoryBot.create(:host, :managed) }
7
+ let(:td_api) { FakeTeamdynamixApi.new }
8
+ before do
9
+ Host::Managed.any_instance.stubs(:td_api).returns(td_api)
10
+ @host = host
11
+ end
12
+
13
+ describe '#teamdynamix_fields' do
14
+ let(:sample_asset) { td_api.get_asset }
15
+ let(:default_fields) { [sample_asset_uri] }
16
+ let(:direct_attribs_config) { { 'Asset ID' => 'ID', 'Owner' => 'OwningCustomerName', 'Parent Asset' => 'ParentID' } }
17
+ let(:direct_attribs_fields) { get_direct_asset_attribs_val(direct_attribs_config) }
18
+ let(:expected_fields) { default_fields + direct_attribs_fields }
19
+ before do
20
+ SETTINGS[:teamdynamix][:fields] = {}
21
+ SETTINGS[:teamdynamix][:fields].merge!(direct_attribs_config)
22
+ end
23
+
24
+ context 'configuration only has attributes' do
25
+ test 'returns fields as expected' do
26
+ assert_equal teamdynamix_fields, expected_fields
27
+ end
28
+ end
29
+
30
+ context 'configuration has nested attributes' do
31
+ let(:nested_attribs_config) do
32
+ { 'mu.ci.Description' => "Attributes.'mu.ci.Description'",
33
+ 'Ticket Routing Details' => "Attributes.'Ticket Routing Details'" }
34
+ end
35
+ let(:nested_attribs_fields) { get_nested_asset_attribs_val(nested_attribs_config) }
36
+ let(:expected_fields) { default_fields + nested_attribs_fields }
37
+ before do
38
+ SETTINGS[:teamdynamix][:fields] = {}
39
+ SETTINGS[:teamdynamix][:fields].merge!(nested_attribs_config)
40
+ end
41
+ test 'returns fields as expected' do
42
+ assert_equal teamdynamix_fields, expected_fields
43
+ end
44
+ end
45
+ end
46
+
47
+ describe '#teamdynamix_title' do
48
+ let(:title_orig) { SETTINGS[:teamdynamix][:title] }
49
+ before do
50
+ title_orig
51
+ SETTINGS[:teamdynamix][:title] = 'TeamDynamix Tab'
52
+ end
53
+ test 'returns correct title' do
54
+ assert_equal teamdynamix_title, SETTINGS[:teamdynamix][:title]
55
+ end
56
+
57
+ test 'settings title is not present: return default title' do
58
+ SETTINGS[:teamdynamix][:title] = nil
59
+ assert_equal teamdynamix_title, 'Team Dynamix'
60
+ SETTINGS[:teamdynamix][:title] = title_orig
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,37 @@
1
+ require 'test_helper'
2
+
3
+ class HostExtensionsTests < ActiveSupport::TestCase
4
+ let(:td_api) { FakeTeamdynamixApi.new }
5
+ before do
6
+ Host::Managed.any_instance.stubs(:td_api).returns(td_api)
7
+ end
8
+
9
+ describe '#create' do
10
+ let(:host) { FactoryBot.create(:host, :managed) }
11
+ it 'triggers after_create callback on Host::Managed model' do
12
+ assert_send([Host::Managed, :after_validation, :create_teamdynamix_asset])
13
+ end
14
+
15
+ it 'calls Teamdynamix API to create an asset' do
16
+ assert_send([td_api, :create_asset, host])
17
+ end
18
+
19
+ it 'sets host#teamdynamix_asset_id' do
20
+ assert_not_nil(host.teamdynamix_asset_id)
21
+ end
22
+ end
23
+
24
+ describe '#destroy' do
25
+ let(:host) { FactoryBot.create(:host, :managed) }
26
+ before do
27
+ host.destroy
28
+ end
29
+ it 'triggers before_destroy callback' do
30
+ assert_send([Host::Managed, :before_destroy, :retire_teamdynamix_asset])
31
+ end
32
+
33
+ it 'calls Teamdynamix API to retire an asset' do
34
+ assert_send([td_api, :retire_asset, host.teamdynamix_asset_id])
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,193 @@
1
+ {
2
+ "ID": 1111,
3
+ "AppID": 111,
4
+ "AppName": "Assets/CIs",
5
+ "ProductModelID": 1070,
6
+ "ProductModelName": "Application/Software",
7
+ "ManufacturerID": 1030,
8
+ "ManufacturerName": "MU",
9
+ "SupplierID": 1031,
10
+ "SupplierName": "Supplier",
11
+ "StatusID": 641,
12
+ "StatusName": "In Use",
13
+ "LocationID": 0,
14
+ "LocationName": "None",
15
+ "LocationRoomID": 0,
16
+ "LocationRoomName": "None",
17
+ "Tag": null,
18
+ "SerialNumber": "delete.foreman_teamdynamix.com",
19
+ "Name": "delete.foreman_teamdynamix.com",
20
+ "PurchaseCost": 0,
21
+ "AcquisitionDate": "0001-01-01T05:00:00Z",
22
+ "ExpectedReplacementDate": "0001-01-01T05:00:00Z",
23
+ "RequestingCustomerID": "00000000-0000-0000-0000-000000000000",
24
+ "RequestingCustomerName": "None",
25
+ "RequestingDepartmentID": 0,
26
+ "RequestingDepartmentName": "None",
27
+ "OwningCustomerID": "00000000-0000-0000-0000-000000000000",
28
+ "OwningCustomerName": "some name",
29
+ "OwningDepartmentID": 16253,
30
+ "OwningDepartmentName": "Advancement Services",
31
+ "ParentID": 10306,
32
+ "ParentSerialNumber": "Banner",
33
+ "ParentName": "",
34
+ "ParentTag": null,
35
+ "MaintenanceScheduleID": 0,
36
+ "MaintenanceScheduleName": "None",
37
+ "ConfigurationItemID": 16308,
38
+ "CreatedDate": "2014-11-20T21:22:52.057Z",
39
+ "CreatedUid": "00000000-0000-0000-0000-000000000000",
40
+ "CreatedFullName": "some name",
41
+ "ModifiedDate": "2017-09-15T15:25:09.79Z",
42
+ "ModifiedUid": "00000000-0000-0000-0000-000000000000",
43
+ "ModifiedFullName": "some name",
44
+ "ExternalID": "Banner Advancement",
45
+ "ExternalSourceID": 0,
46
+ "ExternalSourceName": "None",
47
+ "Attributes": [
48
+ {
49
+ "ID": 11636,
50
+ "Name": "Ticket Routing Details",
51
+ "Order": 0,
52
+ "Description": "",
53
+ "SectionID": 0,
54
+ "SectionName": null,
55
+ "FieldType": "textarea",
56
+ "DataType": "String",
57
+ "Choices": [],
58
+ "IsRequired": false,
59
+ "IsUpdatable": true,
60
+ "Value": "sample",
61
+ "ValueText": "",
62
+ "ChoicesText": "",
63
+ "AssociatedItemIDs": [
64
+ 0
65
+ ]
66
+ },
67
+ {
68
+ "ID": 11632,
69
+ "Name": "mu.ci.Description",
70
+ "Order": 50,
71
+ "Description": "",
72
+ "SectionID": 0,
73
+ "SectionName": null,
74
+ "FieldType": "textarea",
75
+ "DataType": "String",
76
+ "Choices": [],
77
+ "IsRequired": false,
78
+ "IsUpdatable": false,
79
+ "Value": "Foreman host delete.foreman_teamdynamix.com created by ForemanTeamdynamix plugin",
80
+ "ValueText": "",
81
+ "ChoicesText": "",
82
+ "AssociatedItemIDs": [
83
+ 0
84
+ ]
85
+ },
86
+ {
87
+ "ID": 11634,
88
+ "Name": "mu.ci.Lifecycle Status",
89
+ "Order": 50,
90
+ "Description": "This is the ITSM Lifecycle phase",
91
+ "SectionID": 0,
92
+ "SectionName": null,
93
+ "FieldType": "dropdown",
94
+ "DataType": "String",
95
+ "Choices": [
96
+ {
97
+ "ID": 26191,
98
+ "Name": "Development",
99
+ "IsActive": true,
100
+ "DateCreated": "2014-11-13T19:56:04.747Z",
101
+ "DateModified": "2014-11-13T19:56:04.747Z",
102
+ "Order": 0
103
+ },
104
+ {
105
+ "ID": 26192,
106
+ "Name": "Early-life Support",
107
+ "IsActive": true,
108
+ "DateCreated": "2014-11-13T19:56:04.747Z",
109
+ "DateModified": "2014-11-13T19:56:04.747Z",
110
+ "Order": 0
111
+ },
112
+ {
113
+ "ID": 26194,
114
+ "Name": "Pre-production",
115
+ "IsActive": true,
116
+ "DateCreated": "2014-11-13T19:56:04.75Z",
117
+ "DateModified": "2014-11-13T19:56:04.75Z",
118
+ "Order": 0
119
+ },
120
+ {
121
+ "ID": 26193,
122
+ "Name": "Production",
123
+ "IsActive": true,
124
+ "DateCreated": "2014-11-13T19:56:04.747Z",
125
+ "DateModified": "2014-11-13T19:56:04.747Z",
126
+ "Order": 0
127
+ },
128
+ {
129
+ "ID": 26190,
130
+ "Name": "Test",
131
+ "IsActive": true,
132
+ "DateCreated": "2014-11-13T19:56:04.747Z",
133
+ "DateModified": "2014-11-13T19:56:04.747Z",
134
+ "Order": 0
135
+ }
136
+ ],
137
+ "IsRequired": true,
138
+ "IsUpdatable": false,
139
+ "Value": "26190",
140
+ "ValueText": "Production",
141
+ "ChoicesText": "Production",
142
+ "AssociatedItemIDs": [
143
+ 0
144
+ ]
145
+ },
146
+ {
147
+ "ID": 11639,
148
+ "Name": "mu.application.location",
149
+ "Order": 204,
150
+ "Description": "Where is the application running?",
151
+ "SectionID": 0,
152
+ "SectionName": null,
153
+ "FieldType": "hradio",
154
+ "DataType": "String",
155
+ "Choices": [
156
+ {
157
+ "ID": 26223,
158
+ "Name": "Cloud",
159
+ "IsActive": true,
160
+ "DateCreated": "2014-11-13T19:56:04.787Z",
161
+ "DateModified": "2014-11-13T19:56:04.787Z",
162
+ "Order": 0
163
+ },
164
+ {
165
+ "ID": 26224,
166
+ "Name": "Endpoint Device",
167
+ "IsActive": true,
168
+ "DateCreated": "2014-11-13T19:56:04.787Z",
169
+ "DateModified": "2014-11-13T19:56:04.787Z",
170
+ "Order": 0
171
+ },
172
+ {
173
+ "ID": 26222,
174
+ "Name": "Premise",
175
+ "IsActive": true,
176
+ "DateCreated": "2014-11-13T19:56:04.787Z",
177
+ "DateModified": "2014-11-13T19:56:04.787Z",
178
+ "Order": 0
179
+ }
180
+ ],
181
+ "IsRequired": false,
182
+ "IsUpdatable": false,
183
+ "Value": "26222",
184
+ "ValueText": "Premise",
185
+ "ChoicesText": "Premise",
186
+ "AssociatedItemIDs": [
187
+ 0
188
+ ]
189
+ }
190
+ ],
191
+ "Attachments": [],
192
+ "Uri": "api/730/assets/1111"
193
+ }
@@ -0,0 +1,165 @@
1
+ require 'test_plugin_helper'
2
+ # rubocop:disable Metrics/ClassLength
3
+ class TeamdynamixApiTest < ActiveSupport::TestCase
4
+ # rubocop:enable Metrics/ClassLength
5
+ let(:subject) { TeamdynamixApi.instance }
6
+ let(:api_config) { SETTINGS[:teamdynamix][:api] }
7
+ let(:app_id) { api_config[:appId].to_s }
8
+ let(:api_url) { api_config[:url] }
9
+ let(:host) { FactoryBot.build(:host, :managed) }
10
+ let(:auth_payload) { { username: api_config[:username], password: api_config[:password] }.to_json }
11
+ let(:dummy_token) { 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1bmlxdWVfbmFtZSI6InR5YWdpbkBtaWFtaW9oLmVkdSIsImlzcyI6IlREIiwiYXVkIjoiaHR0cHM6Ly93d3cudGVhbWR5bmFtaXguY29tLyIsImV4cCI6MTUxNzA2OTU1OSwibmJmIjoxNTE2OTgzMTU5fQ.PkvKbYQCV-hY7_ni4-Zg3qJARBagSzz99fclBYyxxas' }
12
+ let(:sample_asset) { FakeTeamdynamixApi.new.get_asset }
13
+ let(:sample_asset_id) { sample_asset['ID'].to_s }
14
+ let(:host_name) { 'delete.foreman_teamdynamix.com' }
15
+ let(:get_asset_path) { api_url + '/' + app_id + '/assets/' + sample_asset_id }
16
+ let(:create_status_id) { 641 }
17
+ let(:custom_attributes) do
18
+ [{ 'name' => 'mu.ci.Lifecycle Status', 'id' => 11_634, 'value' => '26193' },
19
+ { 'name' => 'mu.ci.Description', 'id' => 11_632, 'value' => 'Foreman host created by ForemanTeamdynamix plugin' }]
20
+ end
21
+ let(:create_path) { api_url + '/' + app_id + '/assets' }
22
+ let(:create_payload) do
23
+ { AppID: app_id,
24
+ SerialNumber: host_name,
25
+ Name: host_name,
26
+ StatusID: create_status_id,
27
+ Attributes: custom_attributes }
28
+ end
29
+ before do
30
+ stub_request(:post, api_url + '/auth')
31
+ .with(body: auth_payload,
32
+ headers: { 'Content-Type' => 'application/json' })
33
+ .to_return(status: 200, body: dummy_token)
34
+ host.name = host_name
35
+ end
36
+
37
+ describe '#update_asset' do
38
+ let(:update_path) { get_asset_path }
39
+ let(:update_payload) { { ID: host.teamdynamix_asset_id }.merge!(create_payload) }
40
+ before do
41
+ host.teamdynamix_asset_id = sample_asset_id
42
+ SETTINGS[:teamdynamix][:api][:create] = { StatusID: create_status_id,
43
+ Attributes: custom_attributes }
44
+ end
45
+ context 'Valid Request' do
46
+ before do
47
+ stub_request(:post, update_path)
48
+ .with(headers: { 'Authorization' => 'Bearer ' + dummy_token,
49
+ 'Content-Type' => 'application/json' },
50
+ body: update_payload)
51
+ .to_return(status: 200, body: sample_asset.to_json)
52
+ end
53
+ it 'successfully creates an asset and return it' do
54
+ asset = subject.update_asset(host)
55
+ assert_equal(asset['SerialNumber'], host.name)
56
+ assert_equal(asset['AppID'].to_s, app_id.to_s)
57
+ assert_equal(asset['StatusID'], create_status_id)
58
+ end
59
+ end
60
+ end
61
+
62
+ describe '#retire_asset' do
63
+ let(:retire_status_id) { 642 }
64
+ before do
65
+ subject.stubs(:get_asset).returns(sample_asset)
66
+ SETTINGS[:teamdynamix][:api][:delete] = { StatusID: retire_status_id }
67
+ end
68
+ describe 'valid request' do
69
+ let(:retired_asset) { sample_asset.merge('StatusID' => retire_status_id) }
70
+ let(:retire_path) { api_url + '/' + app_id + '/assets/' + sample_asset_id }
71
+ before do
72
+ stub_request(:post, retire_path)
73
+ .with(headers: { 'Authorization' => 'Bearer ' + dummy_token,
74
+ 'Content-Type' => 'application/json' })
75
+ .to_return(status: 200, body: retired_asset.to_json)
76
+ end
77
+ it 'marks the asset retired in Team Dynamix' do
78
+ assert_nothing_raised do
79
+ asset = subject.retire_asset(sample_asset_id)
80
+ assert_equal(asset['StatusID'], retire_status_id)
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ describe '#create_asset' do
87
+ before do
88
+ SETTINGS[:teamdynamix][:api][:create] = { StatusID: create_status_id,
89
+ Attributes: custom_attributes }
90
+ end
91
+ context 'Valid Request' do
92
+ before do
93
+ stub_request(:post, create_path)
94
+ .with(headers: { 'Authorization' => 'Bearer ' + dummy_token,
95
+ 'Content-Type' => 'application/json' },
96
+ body: create_payload)
97
+ .to_return(status: 200, body: sample_asset.to_json)
98
+ end
99
+ it 'successfully creates an asset and return it' do
100
+ asset = subject.create_asset(host)
101
+ assert_not_nil(asset['ID'])
102
+ assert_equal(asset['SerialNumber'], host.name)
103
+ assert_equal(asset['AppID'].to_s, app_id.to_s)
104
+ assert_equal(asset['StatusID'], create_status_id)
105
+ end
106
+ end
107
+
108
+ context 'Invalid Request: missing SerialNumber' do
109
+ # rubocop:disable Style/StringLiterals
110
+ let(:error_body) { "Name or serial number must be provided for asset records" }
111
+ let(:error) { { status: "400", msg: "", body: error_body }.to_json }
112
+ # rubocop:enable Style/StringLiterals
113
+ before do
114
+ stub_request(:post, create_path)
115
+ .with(headers: { 'Authorization' => 'Bearer ' + dummy_token,
116
+ 'Content-Type' => 'application/json' },
117
+ body: create_payload)
118
+ .to_return(status: 400, body: error_body)
119
+ end
120
+ it 'raises error with status 400 for invalid payload' do
121
+ assert_raises_with_message(RuntimeError, error) do
122
+ subject.create_asset(host)
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ describe '#request_token' do
129
+ describe 'valida credentials' do
130
+ end
131
+ it 'returns a bearer token if credentials are correct' do
132
+ assert_not_nil(subject.send(:request_token))
133
+ end
134
+
135
+ describe 'invalid credentials' do
136
+ # rubocop:disable Style/StringLiterals
137
+ let(:error_body) { "Invalid username or password." }
138
+ let(:error) { { status: "403", msg: "", body: error_body }.to_json }
139
+ # rubocop:enable Style/StringLiterals
140
+ before do
141
+ stub_request(:post, api_url + '/auth')
142
+ .with(body: auth_payload)
143
+ .to_return(status: 403, body: error_body)
144
+ end
145
+ it 'raises error with status 403' do
146
+ assert_raises_with_message(RuntimeError, error) do
147
+ subject.send(:request_token)
148
+ end
149
+ end
150
+ end
151
+ end
152
+
153
+ describe '#get_asset' do
154
+ context 'Valid Request' do
155
+ before do
156
+ stub_request(:get, get_asset_path)
157
+ .with(headers: { 'Authorization' => 'Bearer ' + dummy_token })
158
+ .to_return(status: 200, body: sample_asset.to_json)
159
+ end
160
+ it 'returns asset json' do
161
+ assert_equal(subject.get_asset(sample_asset_id), sample_asset)
162
+ end
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,38 @@
1
+ def override_settings
2
+ SETTINGS[:teamdynamix] = { api: { url: 'https://api.teamdynamix.com/TDWebApi/api',
3
+ appId: '111',
4
+ username: 'a_valid_username',
5
+ password: 'a_valid_pwd' } }
6
+ end
7
+ override_settings
8
+
9
+ def get_direct_asset_attribs_val(config)
10
+ direct_attrib_fields = []
11
+ config.each do |tag, attr_name|
12
+ direct_attrib_fields << [tag, sample_asset[attr_name]]
13
+ end
14
+ direct_attrib_fields
15
+ end
16
+
17
+ def get_nested_asset_attribs_val(config)
18
+ nested_attrib_fields = []
19
+ config.each do |tag, nested_attrib|
20
+ parent_attrib, child_attrib = nested_attrib.split(".'")
21
+ child_attrib.delete!("'")
22
+ attrib_val = sample_asset[parent_attrib].select { |attrib| attrib['Name'] == child_attrib }[0]['Value']
23
+ nested_attrib_fields << [tag, attrib_val]
24
+ end
25
+ nested_attrib_fields
26
+ end
27
+
28
+ def sample_asset_uri
29
+ api_url = SETTINGS[:teamdynamix][:api][:url]
30
+ asset_uri = api_url.split('api').first + sample_asset['Uri']
31
+ [_('URI'), link_to(sample_asset['Uri'], asset_uri, target: '_blank')]
32
+ end
33
+
34
+ require 'webmock/minitest'
35
+ WebMock.disable_net_connect!(allow_localhost: true)
36
+
37
+ require 'fake_teamdynamix_api'
38
+ require 'test_helper'
@@ -0,0 +1,11 @@
1
+ require 'test_plugin_helper'
2
+
3
+ class ForemanTeamdynamixTest < ActiveSupport::TestCase
4
+ setup do
5
+ User.current = User.find_by(login: 'admin')
6
+ end
7
+
8
+ test 'the truth' do
9
+ assert true
10
+ end
11
+ end