snow_sync 3.1.5 → 3.1.6

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: 94f2f27e9878dc97c7f3cc662cf3519fbccb3cd771666feb5a9976585607ae4f
4
- data.tar.gz: 8803cd91afadab4e1e0a572f46547fb569518c50a15121003496eb4f7cdca47b
3
+ metadata.gz: 006d22f37ee45ef3de904baba95ba0ee0e6a80dc25259741bbab58e9e34db4ee
4
+ data.tar.gz: 0e31d3394fc906562060141146dc15032c8701d7da5ec76495b9cc7d17e68bd6
5
5
  SHA512:
6
- metadata.gz: 00dfb1a35ef10a6331c7df8f84df2ab401a7d6de794317be1d6a04c2808830e063b1830e12081fb2aa93dcf81f34164dedc930a224c37b684cf2e07824a23a0e
7
- data.tar.gz: 7eeeec614853accf1ba6c72f10e24f5210ae811bf01cc773c70eb5f9f71e7ebb1505b244bb24c7a4def4bb5134fc4195103686190617d7693f9d72a7bb3b422b
6
+ metadata.gz: f45e339f65b62bc897d697b1bb46f442cbb6a48f5ab6728701d7d1415efa91223725db708237b7637e8c34c8ad756b18d309a10a6a2a78ffeb3cc4c452637fe6
7
+ data.tar.gz: 4e3701f3d65594d6d284b99e86f8694d9565e87546570440ba89842163c1a1493aecdbbbc10e9ee755369f5e6a2ce66c351947b584b3d8bca5b8d9c13c640a20
data/README.md CHANGED
@@ -62,12 +62,12 @@ cd /lib/snow_sync
62
62
  ```
63
63
 
64
64
  * Setup the configurations in the configs.yml
65
- * Now supports multi-table map configurations
65
+ * Supports multi-table map configurations
66
66
  * YAML configuration path is the current working directory
67
67
  * Append /api/now/table/ to the base_url
68
68
 
69
69
  ```bash
70
- guard -i
70
+ bundle exec guard -i
71
71
  ```
72
72
 
73
73
  **Note:** if the sync directory is deleted after a successful sync, reset the credential configs in the configs.yml so they can be re-encrypted on the next sync
@@ -79,7 +79,7 @@ guard -i
79
79
  cd <path-to-the-snow-sync-dir>/gems/snow_sync-<version>
80
80
  ```
81
81
 
82
- * Integration tests use a test record in the instance, unit tests do not
82
+ * Integration tests use a test record in the test instance
83
83
  * Setup the test configurations in the test_configs.yml
84
84
  * YAML configuration path is the current working directory
85
85
  * Append /api/now/table/ to the base_url
@@ -88,6 +88,12 @@ cd <path-to-the-snow-sync-dir>/gems/snow_sync-<version>
88
88
  bundle exec rspec spec/sync_util_spec.rb
89
89
  ```
90
90
 
91
+ * Unit tests are pure, so they're not externally dependent
92
+
93
+ ```ruby
94
+ bundle exec rspec spec/sync_util_mock_spec.rb
95
+ ```
96
+
91
97
  **Note:** if the sync directory is deleted after a successful sync, reset the credential configs in the test_configs.yml so they can be re-encrypted on the next sync
92
98
 
93
99
  ## License
@@ -16,18 +16,19 @@ yield_options = {
16
16
  logger.info "Guard::Yield - Done!"
17
17
  end,
18
18
 
19
- run_on_modifications: proc do |log, _, files|
20
- log.info "!!: #{files * ','}"
19
+ run_on_modifications: proc do |logger, _, files|
21
20
  @util.push_modifications(files)
22
- @util.notify(files, log)
21
+ logger.info "!!: #{files}"
22
+ uname = `uname`.chomp.downcase
23
+ @util.notify(files, uname, logger)
23
24
  end,
24
25
 
25
- run_on_additions: proc do |log, _, files|
26
- log.info "++: #{files * ','}"
26
+ run_on_additions: proc do |logger, _, files|
27
+ logger.info "++: #{files}"
27
28
  end,
28
29
 
29
- run_on_removals: proc do |log, _, files|
30
- log.warn "xx: #{files * ','}"
30
+ run_on_removals: proc do |logger, _, files|
31
+ logger.warn "xx: #{files}"
31
32
  end,
32
33
 
33
34
  }
@@ -6,6 +6,7 @@ base_url:
6
6
  creds:
7
7
  user:
8
8
  pass:
9
+ encrypted:
9
10
 
10
11
  table_map:
11
12
  script_include:
@@ -75,8 +75,7 @@ module SnowSync
75
75
  # Encrypts config credentials based on previous sync
76
76
 
77
77
  def encrypt_credentials
78
- previous_sync = File.directory?("sync")
79
- if !previous_sync
78
+ unless @configs["creds"]["encrypted"]
80
79
  configs_path = @configs["conf_path"] + @cf
81
80
  configs = YAML::load_file(configs_path)
82
81
  # local configuration changes
@@ -84,10 +83,12 @@ module SnowSync
84
83
  passb64 = Base64.strict_encode64(@configs["creds"]["pass"])
85
84
  configs["creds"]["user"] = userb64
86
85
  configs["creds"]["pass"] = passb64
86
+ configs["creds"]["encrypted"] = true
87
87
  File.open(configs_path, 'w') { |f| YAML::dump(configs, f) }
88
88
  # object state configuration changes
89
89
  @configs["creds"]["user"] = userb64
90
90
  @configs["creds"]["pass"] = passb64
91
+ @configs["creds"]["encrypted"] = true
91
92
  end
92
93
  end
93
94
 
@@ -155,9 +156,8 @@ module SnowSync
155
156
  # Merges JS file changes with the encapsulated table response value
156
157
  # @param [String] type Config table label
157
158
  # @param [String] file JS file by name
158
- # @param [Hash] table_hash Configured servicenow table hash
159
159
 
160
- def merge_update(type, file, table_hash)
160
+ def merge_update(type, file)
161
161
  FileUtils.cd("sync" + "/" + type)
162
162
  script_body = File.open(file).read
163
163
  @configs["table_map"][type]["mod"] = script_body
@@ -182,7 +182,7 @@ module SnowSync
182
182
  type = path[1]
183
183
  file = path[2]
184
184
  table_hash = table_lookup(type, file)
185
- merge_update(type, file, table_hash)
185
+ merge_update(type, file)
186
186
  begin
187
187
  user = Base64.strict_decode64(@configs["creds"]["user"])
188
188
  pass = Base64.strict_decode64(@configs["creds"]["pass"])
@@ -201,22 +201,22 @@ module SnowSync
201
201
 
202
202
  # Dispatches osx & linux platform notification when file updates are pushed
203
203
  # @param [Array] update File updated
204
- # @param [Object] log Log object
204
+ # @param [String] uname Operating system name
205
+ # @param [Object] logger Logger object
205
206
 
206
- def notify(update, log)
207
- if `uname` =~ /Darwin/
207
+ def notify(update, uname, logger)
208
+ if uname =~ /darwin/
208
209
  TerminalNotifier::Guard.success(
209
- "File: #{update * ','}",
210
+ "File: #{update}",
210
211
  :title => "ServiceNow Script Update"
211
212
  )
212
- log.info "->: osx notification dispatched"
213
- elsif `uname` =~ /Linux/
213
+ logger.info "->: osx notification dispatched"
214
+ elsif uname =~ /linux/
214
215
  Libnotify.show(
215
216
  :summary => "ServiceNow Script Update",
216
- :body => "File: #{update * ','}",
217
- :timeout => 1.5
217
+ :body => "File: #{update}"
218
218
  )
219
- log.info "->: linux notification dispatched"
219
+ logger.info "->: linux notification dispatched"
220
220
  end
221
221
  end
222
222
 
@@ -1,3 +1,3 @@
1
1
  module SnowSync
2
- VERSION = "3.1.5"
2
+ VERSION = "3.1.6"
3
3
  end
data/spec/spec_helper.rb CHANGED
@@ -5,8 +5,8 @@ RSpec.configure do |config|
5
5
  require "json"
6
6
  require_relative "../lib/snow_sync/sync_util.rb"
7
7
 
8
- @util = SnowSync::SyncUtil.new(opts = "test")
9
- @util.encrypt_credentials
8
+ config.color
9
+ config.formatter = :documentation
10
10
 
11
11
  config.expect_with :rspec do |expectations|
12
12
  expectations.include_chain_clauses_in_custom_matcher_descriptions = true
@@ -0,0 +1,549 @@
1
+ require "spec_helper"
2
+
3
+ describe "#initialize" do
4
+
5
+ before do
6
+ allow(YAML).to receive(:load_file)
7
+ allow(Logger).to receive(:new)
8
+ end
9
+
10
+ it "should construct an instance" do
11
+ SnowSync::SyncUtil.new(opts = "test")
12
+ expect(YAML).to have_received(:load_file).with("test_configs.yml")
13
+ expect(Logger).to have_received(:new).with(STDERR)
14
+ end
15
+
16
+ end
17
+
18
+ describe "#create_directory" do
19
+
20
+ let :util do
21
+ SnowSync::SyncUtil.new(opts = "test")
22
+ end
23
+
24
+ let :logger do
25
+ instance_double(Logger)
26
+ end
27
+
28
+ let :dir_name do
29
+ "sync"
30
+ end
31
+
32
+ before do
33
+ allow(File).to receive(:directory?).and_return(false)
34
+ allow(FileUtils).to receive(:mkdir_p)
35
+ allow(Logger).to receive(:new).and_return(logger)
36
+ allow(logger).to receive(:info)
37
+ end
38
+
39
+ it "should create a directory" do
40
+ util.create_directory(dir_name)
41
+ expect(File).to have_received(:directory?).with(dir_name)
42
+ expect(FileUtils).to have_received(:mkdir_p).with(dir_name)
43
+ expect(logger).to have_received(:info).with("++: #{dir_name}")
44
+ end
45
+
46
+ end
47
+
48
+ describe "#create_subdirectory" do
49
+
50
+ let :util do
51
+ SnowSync::SyncUtil.new(opts = "test")
52
+ end
53
+
54
+ let :path do
55
+ proc { FileUtils.cd("sync") }
56
+ end
57
+
58
+ let :sub_dir_name do
59
+ "sub-dir-of-sync"
60
+ end
61
+
62
+ before do
63
+ allow_any_instance_of(SnowSync::SyncUtil).to receive(:create_directory)
64
+ .and_return("++: #{sub_dir_name}")
65
+ end
66
+
67
+ it "should create a subdirectory" do
68
+ expect(util.create_subdirectory(sub_dir_name, &path)).to eq("++: #{sub_dir_name}")
69
+ end
70
+
71
+ end
72
+
73
+ describe "#create_file" do
74
+
75
+ let :util do
76
+ SnowSync::SyncUtil.new(opts = "test")
77
+ end
78
+
79
+ let :logger do
80
+ instance_double(Logger)
81
+ end
82
+
83
+ let :file_name do
84
+ "test_file"
85
+ end
86
+
87
+ let :json do
88
+ { "test-json": "testing" }
89
+ end
90
+
91
+ let :path do
92
+ proc { }
93
+ end
94
+
95
+ before do
96
+ allow(File).to receive(:open).and_call_original
97
+ allow(Logger).to receive(:new).and_return(logger)
98
+ allow(logger).to receive(:info)
99
+ end
100
+
101
+ after do
102
+ test_file = `ls`.split("\n").pop
103
+ FileUtils.rm_rf(test_file)
104
+ end
105
+
106
+ it "should create a js file" do
107
+ util.create_file(file_name, json, &path)
108
+ expect(File).to have_received(:open).with(file_name + ".js", "w")
109
+ expect(logger).to have_received(:info).with("->: #{file_name}" + ".js")
110
+ expect(`ls`.split("\n").pop).to eq("test_file.js")
111
+ expect(File.open("#{file_name}.js").read).to eq("{:\"test-json\"=>\"testing\"}")
112
+ end
113
+
114
+ end
115
+
116
+ describe "#check_required_configs" do
117
+
118
+ let :util do
119
+ SnowSync::SyncUtil.new(opts = "test")
120
+ end
121
+
122
+ it "should raise an exception when there is no config path" do
123
+ util.configs["conf_path"] = nil
124
+ expect{util.check_required_configs}.to raise_error(
125
+ /Check the configuration path, base url, credentials or table to sync/)
126
+ end
127
+
128
+ it "should raise an exception when there is no base url" do
129
+ util.configs["base_url"] = nil
130
+ expect{util.check_required_configs}.to raise_error(
131
+ /Check the configuration path, base url, credentials or table to sync/)
132
+ end
133
+
134
+ it "should raise an exception when there is no username" do
135
+ util.configs["creds"]["user"] = nil
136
+ expect{util.check_required_configs}.to raise_error(
137
+ /Check the configuration path, base url, credentials or table to sync/)
138
+ end
139
+
140
+ it "should raise an exception when there is no password" do
141
+ util.configs["creds"]["pass"] = nil
142
+ expect{util.check_required_configs}.to raise_error(
143
+ /Check the configuration path, base url, credentials or table to sync/)
144
+ end
145
+
146
+ it "should raise an exception when there are no tables mapped" do
147
+ tables = util.configs["table_map"].keys
148
+ tables.each do |table|
149
+ util.configs["table_map"][table]["table"] = nil
150
+ expect{util.check_required_configs}.to raise_error(
151
+ /Check the configuration path, base url, credentials or table to sync/)
152
+ end
153
+ end
154
+
155
+ end
156
+
157
+ describe "#encrypt_credentials" do
158
+
159
+ let :util do
160
+ SnowSync::SyncUtil.new(opts = "test")
161
+ end
162
+
163
+ before do
164
+ FileUtils.touch("spec/test_configs.yml")
165
+ local_configs = {
166
+ "conf_path" => "spec/",
167
+ "base_url" => nil,
168
+ "creds" => {
169
+ "user" => "test-name",
170
+ "pass" => "test-password",
171
+ "encrypted" => false
172
+ }
173
+ }
174
+ allow(YAML).to receive(:load_file).and_return(local_configs)
175
+ allow(Base64).to receive(:strict_encode64).and_call_original
176
+ allow(File).to receive(:open).and_call_original
177
+ end
178
+
179
+ after do
180
+ FileUtils.rm_rf("spec/test_configs.yml")
181
+ end
182
+
183
+ it "should encrypt credentials" do
184
+ util.configs["conf_path"] = "spec/"
185
+ util.configs["creds"]["user"] = "test-name"
186
+ util.configs["creds"]["pass"] = "test-password"
187
+ util.encrypt_credentials
188
+ expect(YAML).to have_received(:load_file).with("spec/test_configs.yml")
189
+ allow(Base64).to receive(:strict_encode64).twice
190
+ expect(File).to have_received(:open).with("spec/test_configs.yml", "w")
191
+ # configs object state updates
192
+ expect(util.configs["creds"]["user"]).to eq("dGVzdC1uYW1l")
193
+ expect(util.configs["creds"]["pass"]).to eq("dGVzdC1wYXNzd29yZA==")
194
+ expect(util.configs["creds"]["encrypted"]).to eq(true)
195
+ # test configs file updates
196
+ encrypted_content = YAML::load_file("spec/test_configs.yml")
197
+ expect(encrypted_content["creds"]["user"]).to eq("dGVzdC1uYW1l")
198
+ expect(encrypted_content["creds"]["pass"]).to eq("dGVzdC1wYXNzd29yZA==")
199
+ expect(encrypted_content["creds"]["encrypted"]).to eq(true)
200
+ end
201
+ end
202
+
203
+ describe "#run_setup_and_sync" do
204
+
205
+ let :util do
206
+ SnowSync::SyncUtil.new(opts = "test")
207
+ end
208
+
209
+ let :logger do
210
+ instance_double(Logger)
211
+ end
212
+
213
+ before do
214
+ allow(Base64).to receive(:strict_decode64).and_call_original
215
+ allow(Base64).to receive(:strict_encode64).and_call_original
216
+ allow(RestClient).to receive(:get).and_return("{\"result\":[{ \"status\": \"200\" }]}")
217
+ allow(FileUtils).to receive(:cd)
218
+ end
219
+
220
+ it "should run setup & sync - sync directory present path" do
221
+ # allow not included in 'before' setup to set return bool
222
+ allow(File).to receive(:directory?).and_return(true)
223
+ expect_any_instance_of(SnowSync::SyncUtil).to receive(:create_subdirectory)
224
+ expect_any_instance_of(SnowSync::SyncUtil).to receive(:create_file)
225
+ util.configs = { "conf_path" => nil,
226
+ "base_url" => "https://test.com/api/now/table/",
227
+ "creds" => {
228
+ "user" => "dGVzdC1uYW1l",
229
+ "pass" => "dGVzdC1wYXNzd29yZA=="
230
+ },
231
+ "table_map" => {
232
+ "script_include" => {
233
+ "name" => "TestClass",
234
+ "table" => "sys_script_include",
235
+ "sys_id" => "xxxxxx-sysid-xxxxxx",
236
+ "field" => "test-field"
237
+ }
238
+ }
239
+ }
240
+ util.run_setup_and_sync
241
+ expect(File).to have_received(:directory?).with("sync")
242
+ expect(Base64).to have_received(:strict_decode64).with("dGVzdC1uYW1l")
243
+ expect(Base64).to have_received(:strict_decode64).with("dGVzdC1wYXNzd29yZA==")
244
+ expect(Base64).to have_received(:strict_encode64).with("test-name:test-password")
245
+ expect(RestClient).to have_received(:get).with(
246
+ "https://test.com/api/now/table/sys_script_include?sysparm_query=sys_id%3D" +
247
+ "xxxxxx-sysid-xxxxxx%5Ename%3DTestClass",
248
+ {:authorization => "Basic " + "dGVzdC1uYW1lOnRlc3QtcGFzc3dvcmQ=",
249
+ :accept => "application/json"})
250
+ expect(FileUtils).to have_received(:cd).with("../..")
251
+ end
252
+
253
+ it "should run setup & sync - sync directory not present path" do
254
+ # allow not included in 'before' setup to set return bool
255
+ allow(File).to receive(:directory?).and_return(false)
256
+ expect_any_instance_of(SnowSync::SyncUtil).to receive(:create_directory)
257
+ expect_any_instance_of(SnowSync::SyncUtil).to receive(:create_subdirectory)
258
+ expect_any_instance_of(SnowSync::SyncUtil).to receive(:create_file)
259
+ util.configs = { "conf_path" => nil,
260
+ "base_url" => "https://test.com/api/now/table/",
261
+ "creds" => {
262
+ "user" => "dGVzdC1uYW1l",
263
+ "pass" => "dGVzdC1wYXNzd29yZA=="
264
+ },
265
+ "table_map" => {
266
+ "script_include" => {
267
+ "name" => "TestClass",
268
+ "table" => "sys_script_include",
269
+ "sys_id" => "xxxxxx-sysid-xxxxxx",
270
+ "field" => "test-field"
271
+ }
272
+ }
273
+ }
274
+ util.run_setup_and_sync
275
+ expect(File).to have_received(:directory?).with("sync")
276
+ expect(Base64).to have_received(:strict_decode64).with("dGVzdC1uYW1l")
277
+ expect(Base64).to have_received(:strict_decode64).with("dGVzdC1wYXNzd29yZA==")
278
+ expect(Base64).to have_received(:strict_encode64).with("test-name:test-password")
279
+ expect(RestClient).to have_received(:get).with(
280
+ "https://test.com/api/now/table/sys_script_include?sysparm_query=sys_id%3D" +
281
+ "xxxxxx-sysid-xxxxxx%5Ename%3DTestClass",
282
+ {:authorization => "Basic " + "dGVzdC1uYW1lOnRlc3QtcGFzc3dvcmQ=",
283
+ :accept => "application/json"})
284
+ expect(FileUtils).to have_received(:cd).with("../..")
285
+ end
286
+
287
+ it "should handle an exception" do
288
+ # allow not included in 'before' setup to set return bool
289
+ allow(File).to receive(:directory?).and_return(true)
290
+ expect_any_instance_of(SnowSync::SyncUtil).to receive(:create_subdirectory)
291
+ allow(RestClient).to receive(:get).and_raise(RestClient::ExceptionWithResponse)
292
+ allow(Logger).to receive(:new).and_return(logger)
293
+ allow(logger).to receive(:error)
294
+ util.configs = { "conf_path" => nil,
295
+ "base_url" => "https://test.com/api/now/table/",
296
+ "creds" => {
297
+ "user" => "dGVzdC1uYW1l",
298
+ "pass" => "dGVzdC1wYXNzd29yZA=="
299
+ },
300
+ "table_map" => {
301
+ "script_include" => {
302
+ "name" => "TestClass",
303
+ "table" => "sys_script_include",
304
+ "sys_id" => "xxxxxx-sysid-xxxxxx",
305
+ "field" => "test-field"
306
+ }
307
+ }
308
+ }
309
+ util.run_setup_and_sync
310
+ expect(logger).to have_received(:error)
311
+ .with("ERROR: RestClient::ExceptionWithResponse").once
312
+ end
313
+
314
+ end
315
+
316
+ describe "#classify" do
317
+
318
+ let :util do
319
+ SnowSync::SyncUtil.new(opts = "test")
320
+ end
321
+
322
+ it "should convert snake_case string to CamelCase" do
323
+ expect(util.classify("test_class.js")).to eq("TestClass")
324
+ end
325
+
326
+ end
327
+
328
+ describe "#table_lookup" do
329
+
330
+ let :util do
331
+ SnowSync::SyncUtil.new(opts = "test")
332
+ end
333
+
334
+ it "should return configured SN table" do
335
+ util.configs = { "conf_path" => nil,
336
+ "base_url" => "https://test.com/api/now/table/",
337
+ "creds" => {
338
+ "user" => "dGVzdC1uYW1l",
339
+ "pass" => "dGVzdC1wYXNzd29yZA=="
340
+ },
341
+ "table_map" => {
342
+ "script_include" => {
343
+ "name" => "TestClass",
344
+ "table" => "sys_script_include",
345
+ "sys_id" => "xxxxxx-sysid-xxxxxx",
346
+ "field" => "test-field"
347
+ }
348
+ }
349
+ }
350
+ table_map = util.table_lookup("script_include", "test_class.js")
351
+ expect(table_map == { "name" => "TestClass",
352
+ "table" => "sys_script_include",
353
+ "sys_id" => "xxxxxx-sysid-xxxxxx",
354
+ "field" => "test-field"
355
+ }).to be(true)
356
+ end
357
+
358
+ end
359
+
360
+ describe "#merge_update" do
361
+
362
+ let! :util do
363
+ SnowSync::SyncUtil.new(opts = "test")
364
+ end
365
+
366
+ before do
367
+ allow(FileUtils).to receive(:cd)
368
+ allow(File).to receive(:open).and_return(IO)
369
+ allow(IO).to receive(:read).and_return("var x = 10;")
370
+ end
371
+
372
+ it "should merge a script change" do
373
+ util.configs = { "table_map" => {
374
+ "script_include" => {
375
+ "name" => "TestClass",
376
+ "table" => "sys_script_include",
377
+ "sys_id" => "xxxxxx-sysid-xxxxxx",
378
+ "field" => "test-field"
379
+ }
380
+ }
381
+ }
382
+ util.merge_update("script_include", "test_class.js")
383
+ expect(File).to have_received(:open).with("test_class.js")
384
+ expect(IO).to have_received(:read)
385
+ expect(FileUtils).to have_received(:cd).twice
386
+ expect(util.configs == { "table_map" => {
387
+ "script_include" => {
388
+ "name" => "TestClass",
389
+ "table" => "sys_script_include",
390
+ "sys_id" => "xxxxxx-sysid-xxxxxx",
391
+ "field" => "test-field",
392
+ "mod" => "var x = 10;"
393
+ }
394
+ }}).to be(true)
395
+ end
396
+
397
+ end
398
+
399
+ describe "#start_sync" do
400
+
401
+ let :util do
402
+ SnowSync::SyncUtil.new(opts = "test")
403
+ end
404
+
405
+ before do
406
+ allow_any_instance_of(SnowSync::SyncUtil).to receive(:check_required_configs)
407
+ allow_any_instance_of(SnowSync::SyncUtil).to receive(:encrypt_credentials)
408
+ allow_any_instance_of(SnowSync::SyncUtil).to receive(:run_setup_and_sync)
409
+ .and_return("sync-and-setup-complete!")
410
+ end
411
+
412
+ it "should create a subdirectory" do
413
+ expect(util.start_sync).to eq("sync-and-setup-complete!")
414
+ end
415
+
416
+ end
417
+
418
+ describe "#push_modifications" do
419
+
420
+ let :util do
421
+ SnowSync::SyncUtil.new(opts = "test")
422
+ end
423
+
424
+ let :logger do
425
+ instance_double(Logger)
426
+ end
427
+
428
+ before do
429
+ allow_any_instance_of(SnowSync::SyncUtil).to receive(:table_lookup)
430
+ .and_return({
431
+ "name" => "TestClass",
432
+ "table" => "sys_script_include",
433
+ "sys_id" => "xxxxxx-sysid-xxxxxx",
434
+ "field" => "test-field",
435
+ "mod" => "var x = 10;"
436
+ })
437
+ allow_any_instance_of(SnowSync::SyncUtil).to receive(:merge_update)
438
+ allow(Base64).to receive(:strict_decode64).and_call_original
439
+ allow(Base64).to receive(:strict_encode64).and_call_original
440
+ allow(RestClient).to receive(:patch).and_return("{\"result\":[{ \"status\": \"201\" }]}")
441
+ end
442
+
443
+ it "should push modifications to the instance" do
444
+ util.configs = { "conf_path" => nil,
445
+ "base_url" => "https://test.com/api/now/table/",
446
+ "creds" => {
447
+ "user" => "dGVzdC1uYW1l",
448
+ "pass" => "dGVzdC1wYXNzd29yZA=="
449
+ },
450
+ "table_map" => {
451
+ "script_include" => {
452
+ "name" => "TestClass",
453
+ "table" => "sys_script_include",
454
+ "sys_id" => "xxxxxx-sysid-xxxxxx",
455
+ "field" => "test-field",
456
+ "mod" => "var x = 10;"
457
+ }
458
+ }
459
+ }
460
+ util.push_modifications(["sync/script_include/test_class.js"])
461
+ expect(Base64).to have_received(:strict_decode64).with("dGVzdC1uYW1l")
462
+ expect(Base64).to have_received(:strict_decode64).with("dGVzdC1wYXNzd29yZA==")
463
+ expect(Base64).to have_received(:strict_encode64).with("test-name:test-password")
464
+ expect(RestClient).to have_received(:patch).with(
465
+ "https://test.com/api/now/table/sys_script_include/xxxxxx-sysid-xxxxxx",
466
+ "{\"test-field\":\"var x = 10;\"}",
467
+ {:authorization => "Basic " + "dGVzdC1uYW1lOnRlc3QtcGFzc3dvcmQ=",
468
+ :content_type => "application/json", :accept => "application/json"})
469
+ end
470
+
471
+ it "should handle an exception" do
472
+ allow(RestClient).to receive(:patch).and_raise(RestClient::ExceptionWithResponse)
473
+ allow(Logger).to receive(:new).and_return(logger)
474
+ allow(logger).to receive(:error)
475
+ util.configs = { "conf_path" => nil,
476
+ "base_url" => "https://test.com/api/now/table/",
477
+ "creds" => {
478
+ "user" => "dGVzdC1uYW1l",
479
+ "pass" => "dGVzdC1wYXNzd29yZA=="
480
+ },
481
+ "table_map" => {
482
+ "script_include" => {
483
+ "name" => "TestClass",
484
+ "table" => "sys_script_include",
485
+ "sys_id" => "xxxxxx-sysid-xxxxxx",
486
+ "field" => "test-field",
487
+ "mod" => "var x = 10;"
488
+ }
489
+ }
490
+ }
491
+ util.push_modifications(["sync/script_include/test_class.js"])
492
+ expect(logger).to have_received(:error)
493
+ .with("ERROR: RestClient::ExceptionWithResponse").once
494
+ end
495
+
496
+ end
497
+
498
+ describe "#notify" do
499
+
500
+ let :util do
501
+ SnowSync::SyncUtil.new(opts = "test")
502
+ end
503
+
504
+ let :logger do
505
+ instance_double(Logger)
506
+ end
507
+
508
+ let :update do
509
+ "test_class"
510
+ end
511
+
512
+ let :macosx? do
513
+ `uname`.chomp.downcase == "darwin"
514
+ end
515
+
516
+ let :linux? do
517
+ `uname`.chomp.downcase == "linux"
518
+ end
519
+
520
+ before do
521
+ allow(TerminalNotifier::Guard).to receive(:success) if macosx?
522
+ allow(Libnotify).to receive(:show) if linux?
523
+ allow(Logger).to receive(:new).and_return(logger)
524
+ allow(logger).to receive(:info)
525
+ end
526
+
527
+ condition = `uname`.chomp.downcase == "darwin"
528
+ context "when true", if: condition do
529
+ it "should send notification - macosx path" do
530
+ uname = "darwin"
531
+ util.notify(update, uname, util.logger)
532
+ expect(TerminalNotifier::Guard).to have_received(:success)
533
+ .with("File: #{update}", :title => "ServiceNow Script Update")
534
+ expect(logger).to have_received(:info).with("->: osx notification dispatched")
535
+ end
536
+ end
537
+
538
+ condition = `uname`.chomp.downcase == "linux"
539
+ context "when true", if: condition do
540
+ it "should send notification - linux path" do
541
+ uname = "linux"
542
+ util.notify(update, uname, util.logger)
543
+ expect(Libnotify).to have_received(:show)
544
+ .with(:summary => "ServiceNow Script Update", :body => "File: #{update}")
545
+ expect(logger).to have_received(:info).with("->: linux notification dispatched")
546
+ end
547
+ end
548
+
549
+ end
@@ -2,7 +2,7 @@ require "spec_helper"
2
2
 
3
3
  describe "utility object" do
4
4
 
5
- let! :util do
5
+ let :util do
6
6
  SnowSync::SyncUtil.new(opts = "test")
7
7
  end
8
8
 
@@ -20,22 +20,22 @@ describe "utility object" do
20
20
 
21
21
  end
22
22
 
23
- describe "create_directory" do
23
+ describe "#create_directory" do
24
24
 
25
- let! :util do
25
+ let :util do
26
26
  SnowSync::SyncUtil.new(opts = "test")
27
27
  end
28
28
 
29
- let! :created_time do
30
- util.create_directory("sync")
31
- return File.ctime("sync")
32
- end
33
-
34
29
  it "should create a directory" do
30
+ util.create_directory("sync")
35
31
  dir = `ls`.split("\n")
36
32
  expect(dir.include?("sync")).to eq true
37
33
  end
38
34
 
35
+ let :created_time do
36
+ File.ctime("sync")
37
+ end
38
+
39
39
  it "should not create directory" do
40
40
  util.create_directory("sync")
41
41
  check_created_time = File.ctime("sync")
@@ -44,15 +44,22 @@ describe "create_directory" do
44
44
 
45
45
  end
46
46
 
47
- describe "create_file" do
47
+ describe "#create_file" do
48
48
 
49
- let! :util do
49
+ let :util do
50
50
  SnowSync::SyncUtil.new(opts = "test")
51
51
  end
52
52
 
53
- it "should create a file" do
54
- FileUtils.mkdir_p("sync")
53
+ before do
55
54
  FileUtils.mkdir_p("sync/test_sub_dir")
55
+ end
56
+
57
+ after do
58
+ FileUtils.cd("../..")
59
+ FileUtils.rm_rf("sync")
60
+ end
61
+
62
+ it "should create a file" do
56
63
  json = { "property" => "value" }
57
64
  name = "TestClass".snakecase
58
65
  path = proc do
@@ -60,13 +67,11 @@ describe "create_file" do
60
67
  end
61
68
  util.create_file(name, json, &path)
62
69
  expect(File.exists?("test_class.js")).to eq true
63
- FileUtils.cd("../..")
64
- FileUtils.rm_rf("sync")
65
70
  end
66
71
 
67
72
  end
68
73
 
69
- describe "check_required_configs" do
74
+ describe "#check_required_configs" do
70
75
 
71
76
  let :util do
72
77
  SnowSync::SyncUtil.new(opts = "test")
@@ -74,35 +79,40 @@ describe "check_required_configs" do
74
79
 
75
80
  it "should raise an exception when there is no config path" do
76
81
  util.configs["conf_path"] = nil
77
- expect{util.check_required_configs}.to raise_error(/Check the configuration path, base url, credentials or table to sync/)
82
+ expect{util.check_required_configs}.to raise_error(
83
+ /Check the configuration path, base url, credentials or table to sync/)
78
84
  end
79
85
 
80
86
  it "should raise an exception when there is no base url" do
81
87
  util.configs["base_url"] = nil
82
- expect{util.check_required_configs}.to raise_error(/Check the configuration path, base url, credentials or table to sync/)
88
+ expect{util.check_required_configs}.to raise_error(
89
+ /Check the configuration path, base url, credentials or table to sync/)
83
90
  end
84
91
 
85
92
  it "should raise an exception when there is no username" do
86
93
  util.configs["creds"]["user"] = nil
87
- expect{util.check_required_configs}.to raise_error(/Check the configuration path, base url, credentials or table to sync/)
94
+ expect{util.check_required_configs}.to raise_error(
95
+ /Check the configuration path, base url, credentials or table to sync/)
88
96
  end
89
97
 
90
98
  it "should raise an exception when there is no password" do
91
99
  util.configs["creds"]["pass"] = nil
92
- expect{util.check_required_configs}.to raise_error(/Check the configuration path, base url, credentials or table to sync/)
100
+ expect{util.check_required_configs}.to raise_error(
101
+ /Check the configuration path, base url, credentials or table to sync/)
93
102
  end
94
103
 
95
104
  it "should raise an exception when there are no tables mapped" do
96
105
  tables = util.configs["table_map"].keys
97
106
  tables.each do |table|
98
107
  util.configs["table_map"][table]["table"] = nil
99
- expect{util.check_required_configs}.to raise_error(/Check the configuration path, base url, credentials or table to sync/)
108
+ expect{util.check_required_configs}.to raise_error(
109
+ /Check the configuration path, base url, credentials or table to sync/)
100
110
  end
101
111
  end
102
112
 
103
113
  end
104
114
 
105
- describe "classify" do
115
+ describe "#classify" do
106
116
 
107
117
  let :util do
108
118
  SnowSync::SyncUtil.new(opts = "test")
@@ -117,7 +127,7 @@ describe "classify" do
117
127
 
118
128
  end
119
129
 
120
- describe "table_lookup" do
130
+ describe "#table_lookup" do
121
131
 
122
132
  let :util do
123
133
  SnowSync::SyncUtil.new(opts = "test")
@@ -131,15 +141,21 @@ describe "table_lookup" do
131
141
 
132
142
  end
133
143
 
134
- describe "merge_update" do
144
+ describe "#merge_update" do
135
145
 
136
- let! :util do
146
+ let :util do
137
147
  SnowSync::SyncUtil.new(opts = "test")
138
148
  end
139
149
 
150
+ before do
151
+ FileUtils.mkdir_p("sync/script_include")
152
+ end
153
+
154
+ after do
155
+ FileUtils.rm_rf("sync")
156
+ end
157
+
140
158
  it "should merge script with the configs object" do
141
- FileUtils.mkdir_p("sync")
142
- FileUtils.mkdir_p("sync/script_include")
143
159
  json_resp = "var test = 'test'; \n" +
144
160
  "var testing = function(arg) { \n\tgs.print(arg) \n}; \n" +
145
161
  "testing('test');"
@@ -153,25 +169,30 @@ describe "merge_update" do
153
169
  path = file.split("/")
154
170
  type = path[1]
155
171
  file = path[2]
156
- table_map = util.table_lookup(type, file)
157
- util.merge_update(type, file, table_map)
172
+ util.merge_update(type, file)
158
173
  expect(util.configs["table_map"]["script_include"]["mod"] != nil).to eq true
159
- FileUtils.rm_rf("sync")
160
174
  end
161
175
 
162
176
  end
163
177
 
164
- describe "setup_sync_directories" do
178
+ describe "#run_setup_and_sync" do
165
179
 
166
- let! :util do
180
+ let :util do
167
181
  SnowSync::SyncUtil.new(opts = "test")
168
182
  end
169
183
 
170
- it "should setup and synchronize field from the SN instance" do
184
+ before do
185
+ util.encrypt_credentials
186
+ end
187
+
188
+ after do
189
+ FileUtils.rm_rf("sync")
190
+ end
191
+
192
+ it "should setup file locally and sync code from the instance" do
171
193
  util.run_setup_and_sync
172
194
  file = File.open("sync/script_include/test_class.js")
173
195
  expect(file.is_a?(Object)).to eq true
174
- FileUtils.rm_rf("sync")
175
196
  end
176
197
 
177
198
  end
@@ -182,23 +203,32 @@ describe "push_modifications - single table configuration" do
182
203
  SnowSync::SyncUtil.new(opts = "test")
183
204
  end
184
205
 
206
+ before do
207
+ util.encrypt_credentials
208
+ end
209
+
210
+ after do
211
+ FileUtils.rm_rf("sync")
212
+ end
213
+
185
214
  it "should push modifications to a configured instance" do
186
215
  util.run_setup_and_sync
187
216
  file = File.open("sync/script_include/test_class.js", "r+")
188
217
  lines = file.readlines
189
218
  file.close
190
- lines[0] = "// test comment -\n"
219
+ lines[0] = "// test comment - single push \n"
191
220
  newfile = File.new("sync/script_include/test_class.js", "w")
192
221
  lines.each do |line|
193
222
  newfile.write(line)
194
223
  end
195
224
  newfile.close
196
225
  util.push_modifications(["sync/script_include/test_class.js"])
226
+ # resync confirms mods were pushed to the instance
197
227
  util.run_setup_and_sync
198
228
  file = File.open("sync/script_include/test_class.js", "r+")
199
229
  lines = file.readlines
200
230
  file.close
201
- expect(lines[0]).to eq "// test comment -\n"
231
+ expect(lines[0]).to eq "// test comment - single push \n"
202
232
  end
203
233
 
204
234
  end
@@ -209,7 +239,15 @@ describe "push_modifications - mutli-table configuration" do
209
239
  SnowSync::SyncUtil.new(opts = "test")
210
240
  end
211
241
 
212
- it "should sync, update, queue, push, re-sync mods for a configured instance" do
242
+ before do
243
+ util.encrypt_credentials
244
+ end
245
+
246
+ after do
247
+ FileUtils.rm_rf("sync")
248
+ end
249
+
250
+ it "should push modifications to a configured instance" do
213
251
  def do_edit(file, edit)
214
252
  file = File.open(file, "r+")
215
253
  lines = file.readlines
@@ -229,14 +267,18 @@ describe "push_modifications - mutli-table configuration" do
229
267
  end
230
268
  util.run_setup_and_sync
231
269
  # sys_script_include
232
- do_edit("sync/script_include/test_class.js", "// test comment -\n")
270
+ do_edit(
271
+ "sync/script_include/test_class.js", "// test comment - multi push 1\n")
233
272
  # sys_ui_action
234
- do_edit("sync/ui_action/test_action.js", "// test comment -\n")
273
+ do_edit(
274
+ "sync/ui_action/test_action.js", "// test comment - multi push 2\n")
235
275
  # queued mods, push in sequence
236
- util.push_modifications(["sync/script_include/test_class.js", "sync/ui_action/test_action.js"])
276
+ util.push_modifications(
277
+ ["sync/script_include/test_class.js", "sync/ui_action/test_action.js"])
278
+ # resync confirms mods were pushed to the instance
237
279
  util.run_setup_and_sync
238
- run_check("sync/script_include/test_class.js", "// test comment -\n")
239
- run_check("sync/ui_action/test_action.js", "// test comment -\n")
280
+ run_check("sync/script_include/test_class.js", "// test comment - multi push 1\n")
281
+ run_check("sync/ui_action/test_action.js", "// test comment - multi push 2\n")
240
282
  end
241
283
 
242
284
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: snow_sync
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.5
4
+ version: 3.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Wallace
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-08 00:00:00.000000000 Z
11
+ date: 2022-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -197,6 +197,7 @@ files:
197
197
  - lib/snow_sync/version.rb
198
198
  - spec/docker_install_spec.rb
199
199
  - spec/spec_helper.rb
200
+ - spec/sync_util_mock_spec.rb
200
201
  - spec/sync_util_spec.rb
201
202
  homepage: https://rubygems.org/gems/snow_sync
202
203
  licenses: