snow_sync 3.1.2 → 3.1.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 7d72e4b145e73ab7e226651173c037d5e104aa06
4
- data.tar.gz: c94c90bda93ccd9680bb0e4bc641030fe1ae75fb
2
+ SHA256:
3
+ metadata.gz: 006d22f37ee45ef3de904baba95ba0ee0e6a80dc25259741bbab58e9e34db4ee
4
+ data.tar.gz: 0e31d3394fc906562060141146dc15032c8701d7da5ec76495b9cc7d17e68bd6
5
5
  SHA512:
6
- metadata.gz: 07568e10689e39c77d50aac5dc8dd9a73f9f4fda63ebb8e02bd930ff231c16f0eafad56d8240ffcb816e6fa58a37c93f8aece453278ae0b56e0995970d46fa5f
7
- data.tar.gz: d536814539b196f09019e80eeb2c004fbe10db7ebab8cf6566ede6cd93c045462ea9b8e129b0ed5bcc39de5d69e182be330b156380eddd4eb881ee05720bd98b
6
+ metadata.gz: f45e339f65b62bc897d697b1bb46f442cbb6a48f5ab6728701d7d1415efa91223725db708237b7637e8c34c8ad756b18d309a10a6a2a78ffeb3cc4c452637fe6
7
+ data.tar.gz: 4e3701f3d65594d6d284b99e86f8694d9565e87546570440ba89842163c1a1493aecdbbbc10e9ee755369f5e6a2ce66c351947b584b3d8bca5b8d9c13c640a20
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # SnowSync
2
2
 
3
- [![Gem Version](https://img.shields.io/badge/gem-v3.1.2-brightgreen.svg)](https://rubygems.org/gems/snow_sync) [![Dependency Status](https://img.shields.io/badge/dependencies-up--to--date-blue.svg)](https://rubygems.org/gems/snow_sync) [![Downloads](https://img.shields.io/badge/downloads-5k%2B-lightgrey.svg)](https://rubygems.org/gems/snow_sync)
3
+ [![Gem Version](https://img.shields.io/badge/gem-v3.1.5-brightgreen.svg)](https://rubygems.org/gems/snow_sync) [![Dependency Status](https://img.shields.io/badge/dependencies-up--to--date-blue.svg)](https://rubygems.org/gems/snow_sync) [![Downloads](https://img.shields.io/badge/downloads-25k%2B-lightgrey.svg)](https://rubygems.org/gems/snow_sync)
4
4
 
5
5
  SnowSync is a file sync utility tool and API which provides a bridge for off platform ServiceNow development using an IDE or text editor locally.
6
6
 
@@ -9,15 +9,15 @@ SnowSync syncronizes configured fields (scripts) for a ServiceNow instance local
9
9
  ## Installation
10
10
 
11
11
  ```bash
12
- mkdir snow_sync
12
+ mkdir snow-sync
13
13
  ```
14
14
 
15
15
  ```bash
16
- cd snow_sync
16
+ cd snow-sync
17
17
  ```
18
18
 
19
19
  ```ruby
20
- gem install --install-dir <path-to-the-snow_sync-dir> snow_sync
20
+ gem install --install-dir <path-to-the-snow-sync-dir> snow_sync
21
21
  ```
22
22
 
23
23
  ## Setup & Usage
@@ -30,19 +30,27 @@ gem install bundler
30
30
  cd <path-to-the-snow_sync-dir>/gems/snow_sync-<version>
31
31
  ```
32
32
 
33
+ OSX users run the following command:
34
+
35
+ ```bash
36
+ brew install terminal-notifier
37
+ ```
38
+
33
39
  Create a Gemfile and add the following Gem dependencies:
34
40
 
35
41
  ```ruby
36
- source 'https://rubygems.org'
37
- gem 'facets', '~> 3.1.0'
38
- gem 'guard', '~> 2.14.0'
39
- gem 'guard-yield', '~> 0.1.0'
40
- gem 'json', '>= 1.8.3', '~> 1.8.0'
41
- gem 'libnotify', '~> 0.9.1'
42
- gem 'rake', '~> 10.0.0'
43
- gem 'rest-client', '~> 2.0.0'
44
- gem 'rspec', '~> 3.5.0'
45
- gem 'thor', '0.19.1'
42
+ source "https://rubygems.org"
43
+ gem "facets", "~> 3.1.0"
44
+ gem "guard", "~> 2.14.0"
45
+ gem "guard-yield", "~> 0.1.0"
46
+ gem "json", "~> 2.6.1"
47
+ gem "libnotify", "~> 0.9.2"
48
+ gem "rake", "~> 13.0.6"
49
+ gem "rest-client", "~> 2.0.0"
50
+ gem "rspec", "~> 3.10.0"
51
+ gem "rspec-core", "~> 3.10.1"
52
+ gem "terminal-notifier-guard", "~> 1.7"
53
+ gem "thor", "0.19.1"
46
54
  ```
47
55
 
48
56
  ```bash
@@ -54,12 +62,12 @@ cd /lib/snow_sync
54
62
  ```
55
63
 
56
64
  * Setup the configurations in the configs.yml
57
- * Now supports multi-table map configurations
58
- * Configuration path is the current working directory
65
+ * Supports multi-table map configurations
66
+ * YAML configuration path is the current working directory
59
67
  * Append /api/now/table/ to the base_url
60
68
 
61
69
  ```bash
62
- guard -i
70
+ bundle exec guard -i
63
71
  ```
64
72
 
65
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
@@ -68,17 +76,22 @@ guard -i
68
76
  ## Running the Tests
69
77
 
70
78
  ```bash
71
- cd <path-to-the-snow_sync-dir>/gems/snow_sync-<version>
79
+ cd <path-to-the-snow-sync-dir>/gems/snow_sync-<version>
72
80
  ```
73
81
 
74
- * Integration tests use a test record in the instance (e.g. a script include)
75
- * Unit tests are all stubbed out
82
+ * Integration tests use a test record in the test instance
76
83
  * Setup the test configurations in the test_configs.yml
77
- * Configuration path is the current working directory
84
+ * YAML configuration path is the current working directory
78
85
  * Append /api/now/table/ to the base_url
79
86
 
80
87
  ```ruby
81
- rspec spec/sync_util_spec.rb
88
+ bundle exec rspec spec/sync_util_spec.rb
89
+ ```
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
82
95
  ```
83
96
 
84
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
@@ -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.2"
2
+ VERSION = "3.1.6"
3
3
  end
@@ -0,0 +1,30 @@
1
+ describe "Dockerfile" do
2
+
3
+ def run_os_check(command)
4
+ `#{command}`.downcase
5
+ end
6
+
7
+ it "installs the right version of Ubuntu" do
8
+ os = "ubuntu"
9
+ version = "20.04"
10
+ installation = run_os_check('lsb_release -a')
11
+ expect(installation).to include(os)
12
+ expect(installation).to include(version)
13
+ end
14
+
15
+ it "installs vim" do
16
+ installation = run_os_check('vim --version')
17
+ expect(installation).to include('vim - vi')
18
+ end
19
+
20
+ it "installs git" do
21
+ installation = run_os_check('git version')
22
+ expect(installation).to include('git version')
23
+ end
24
+
25
+ it "installs ruby" do
26
+ installation = run_os_check('ruby -v')
27
+ expect(installation).to include('ruby')
28
+ end
29
+
30
+ 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
@@ -1,9 +1,8 @@
1
1
  require "spec_helper"
2
2
 
3
- ## --> unit tests
4
3
  describe "utility object" do
5
4
 
6
- let! :util do
5
+ let :util do
7
6
  SnowSync::SyncUtil.new(opts = "test")
8
7
  end
9
8
 
@@ -21,22 +20,22 @@ describe "utility object" do
21
20
 
22
21
  end
23
22
 
24
- describe "create_directory" do
23
+ describe "#create_directory" do
25
24
 
26
- let! :util do
25
+ let :util do
27
26
  SnowSync::SyncUtil.new(opts = "test")
28
27
  end
29
28
 
30
- let! :created_time do
31
- util.create_directory("sync")
32
- return File.ctime("sync")
33
- end
34
-
35
29
  it "should create a directory" do
30
+ util.create_directory("sync")
36
31
  dir = `ls`.split("\n")
37
32
  expect(dir.include?("sync")).to eq true
38
33
  end
39
34
 
35
+ let :created_time do
36
+ File.ctime("sync")
37
+ end
38
+
40
39
  it "should not create directory" do
41
40
  util.create_directory("sync")
42
41
  check_created_time = File.ctime("sync")
@@ -45,15 +44,22 @@ describe "create_directory" do
45
44
 
46
45
  end
47
46
 
48
- describe "create_file" do
47
+ describe "#create_file" do
49
48
 
50
- let! :util do
49
+ let :util do
51
50
  SnowSync::SyncUtil.new(opts = "test")
52
51
  end
53
52
 
54
- it "should create a file" do
55
- FileUtils.mkdir_p("sync")
53
+ before do
56
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
57
63
  json = { "property" => "value" }
58
64
  name = "TestClass".snakecase
59
65
  path = proc do
@@ -61,13 +67,11 @@ describe "create_file" do
61
67
  end
62
68
  util.create_file(name, json, &path)
63
69
  expect(File.exists?("test_class.js")).to eq true
64
- FileUtils.cd("../..")
65
- FileUtils.rm_rf("sync")
66
70
  end
67
71
 
68
72
  end
69
73
 
70
- describe "check_required_configs" do
74
+ describe "#check_required_configs" do
71
75
 
72
76
  let :util do
73
77
  SnowSync::SyncUtil.new(opts = "test")
@@ -75,35 +79,40 @@ describe "check_required_configs" do
75
79
 
76
80
  it "should raise an exception when there is no config path" do
77
81
  util.configs["conf_path"] = nil
78
- 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/)
79
84
  end
80
85
 
81
86
  it "should raise an exception when there is no base url" do
82
87
  util.configs["base_url"] = nil
83
- 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/)
84
90
  end
85
91
 
86
92
  it "should raise an exception when there is no username" do
87
93
  util.configs["creds"]["user"] = nil
88
- 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/)
89
96
  end
90
97
 
91
98
  it "should raise an exception when there is no password" do
92
99
  util.configs["creds"]["pass"] = nil
93
- 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/)
94
102
  end
95
103
 
96
104
  it "should raise an exception when there are no tables mapped" do
97
105
  tables = util.configs["table_map"].keys
98
106
  tables.each do |table|
99
107
  util.configs["table_map"][table]["table"] = nil
100
- 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/)
101
110
  end
102
111
  end
103
112
 
104
113
  end
105
114
 
106
- describe "classify" do
115
+ describe "#classify" do
107
116
 
108
117
  let :util do
109
118
  SnowSync::SyncUtil.new(opts = "test")
@@ -118,7 +127,7 @@ describe "classify" do
118
127
 
119
128
  end
120
129
 
121
- describe "table_lookup" do
130
+ describe "#table_lookup" do
122
131
 
123
132
  let :util do
124
133
  SnowSync::SyncUtil.new(opts = "test")
@@ -132,15 +141,21 @@ describe "table_lookup" do
132
141
 
133
142
  end
134
143
 
135
- describe "merge_update" do
144
+ describe "#merge_update" do
136
145
 
137
- let! :util do
146
+ let :util do
138
147
  SnowSync::SyncUtil.new(opts = "test")
139
148
  end
140
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
+
141
158
  it "should merge script with the configs object" do
142
- FileUtils.mkdir_p("sync")
143
- FileUtils.mkdir_p("sync/script_include")
144
159
  json_resp = "var test = 'test'; \n" +
145
160
  "var testing = function(arg) { \n\tgs.print(arg) \n}; \n" +
146
161
  "testing('test');"
@@ -154,26 +169,30 @@ describe "merge_update" do
154
169
  path = file.split("/")
155
170
  type = path[1]
156
171
  file = path[2]
157
- table_map = util.table_lookup(type, file)
158
- util.merge_update(type, file, table_map)
172
+ util.merge_update(type, file)
159
173
  expect(util.configs["table_map"]["script_include"]["mod"] != nil).to eq true
160
- FileUtils.rm_rf("sync")
161
174
  end
162
175
 
163
176
  end
164
177
 
165
- ## --> integration tests
166
- describe "setup_sync_directories" do
178
+ describe "#run_setup_and_sync" do
167
179
 
168
- let! :util do
180
+ let :util do
169
181
  SnowSync::SyncUtil.new(opts = "test")
170
182
  end
171
183
 
172
- 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
173
193
  util.run_setup_and_sync
174
194
  file = File.open("sync/script_include/test_class.js")
175
195
  expect(file.is_a?(Object)).to eq true
176
- FileUtils.rm_rf("sync")
177
196
  end
178
197
 
179
198
  end
@@ -184,23 +203,32 @@ describe "push_modifications - single table configuration" do
184
203
  SnowSync::SyncUtil.new(opts = "test")
185
204
  end
186
205
 
206
+ before do
207
+ util.encrypt_credentials
208
+ end
209
+
210
+ after do
211
+ FileUtils.rm_rf("sync")
212
+ end
213
+
187
214
  it "should push modifications to a configured instance" do
188
215
  util.run_setup_and_sync
189
216
  file = File.open("sync/script_include/test_class.js", "r+")
190
217
  lines = file.readlines
191
218
  file.close
192
- lines[0] = "// test comment -\n"
219
+ lines[0] = "// test comment - single push \n"
193
220
  newfile = File.new("sync/script_include/test_class.js", "w")
194
221
  lines.each do |line|
195
222
  newfile.write(line)
196
223
  end
197
224
  newfile.close
198
225
  util.push_modifications(["sync/script_include/test_class.js"])
226
+ # resync confirms mods were pushed to the instance
199
227
  util.run_setup_and_sync
200
228
  file = File.open("sync/script_include/test_class.js", "r+")
201
229
  lines = file.readlines
202
230
  file.close
203
- expect(lines[0]).to eq "// test comment -\n"
231
+ expect(lines[0]).to eq "// test comment - single push \n"
204
232
  end
205
233
 
206
234
  end
@@ -211,7 +239,15 @@ describe "push_modifications - mutli-table configuration" do
211
239
  SnowSync::SyncUtil.new(opts = "test")
212
240
  end
213
241
 
214
- 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
215
251
  def do_edit(file, edit)
216
252
  file = File.open(file, "r+")
217
253
  lines = file.readlines
@@ -231,14 +267,18 @@ describe "push_modifications - mutli-table configuration" do
231
267
  end
232
268
  util.run_setup_and_sync
233
269
  # sys_script_include
234
- 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")
235
272
  # sys_ui_action
236
- do_edit("sync/ui_action/test.js", "// test comment -\n")
273
+ do_edit(
274
+ "sync/ui_action/test_action.js", "// test comment - multi push 2\n")
237
275
  # queued mods, push in sequence
238
- util.push_modifications(["sync/script_include/test_class.js", "sync/ui_action/test.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
239
279
  util.run_setup_and_sync
240
- run_check("sync/script_include/test_class.js", "// test comment -\n")
241
- run_check("sync/ui_action/test.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")
242
282
  end
243
283
 
244
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.2
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: 2017-06-03 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
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.13'
19
+ version: 2.3.3
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.13'
26
+ version: 2.3.3
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: facets
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -72,20 +72,14 @@ dependencies:
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 1.8.0
76
- - - ">="
77
- - !ruby/object:Gem::Version
78
- version: 1.8.3
75
+ version: 2.6.1
79
76
  type: :development
80
77
  prerelease: false
81
78
  version_requirements: !ruby/object:Gem::Requirement
82
79
  requirements:
83
80
  - - "~>"
84
81
  - !ruby/object:Gem::Version
85
- version: 1.8.0
86
- - - ">="
87
- - !ruby/object:Gem::Version
88
- version: 1.8.3
82
+ version: 2.6.1
89
83
  - !ruby/object:Gem::Dependency
90
84
  name: libnotify
91
85
  requirement: !ruby/object:Gem::Requirement
@@ -106,14 +100,14 @@ dependencies:
106
100
  requirements:
107
101
  - - "~>"
108
102
  - !ruby/object:Gem::Version
109
- version: 10.0.0
103
+ version: 13.0.6
110
104
  type: :development
111
105
  prerelease: false
112
106
  version_requirements: !ruby/object:Gem::Requirement
113
107
  requirements:
114
108
  - - "~>"
115
109
  - !ruby/object:Gem::Version
116
- version: 10.0.0
110
+ version: 13.0.6
117
111
  - !ruby/object:Gem::Dependency
118
112
  name: rest-client
119
113
  requirement: !ruby/object:Gem::Requirement
@@ -134,14 +128,28 @@ dependencies:
134
128
  requirements:
135
129
  - - "~>"
136
130
  - !ruby/object:Gem::Version
137
- version: 3.5.0
131
+ version: 3.10.0
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 3.10.0
139
+ - !ruby/object:Gem::Dependency
140
+ name: rspec-core
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: 3.10.1
138
146
  type: :development
139
147
  prerelease: false
140
148
  version_requirements: !ruby/object:Gem::Requirement
141
149
  requirements:
142
150
  - - "~>"
143
151
  - !ruby/object:Gem::Version
144
- version: 3.5.0
152
+ version: 3.10.1
145
153
  - !ruby/object:Gem::Dependency
146
154
  name: terminal-notifier-guard
147
155
  requirement: !ruby/object:Gem::Requirement
@@ -187,7 +195,9 @@ files:
187
195
  - lib/snow_sync/configs.yml
188
196
  - lib/snow_sync/sync_util.rb
189
197
  - lib/snow_sync/version.rb
198
+ - spec/docker_install_spec.rb
190
199
  - spec/spec_helper.rb
200
+ - spec/sync_util_mock_spec.rb
191
201
  - spec/sync_util_spec.rb
192
202
  homepage: https://rubygems.org/gems/snow_sync
193
203
  licenses:
@@ -208,8 +218,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
208
218
  - !ruby/object:Gem::Version
209
219
  version: '0'
210
220
  requirements: []
211
- rubyforge_project:
212
- rubygems_version: 2.6.8
221
+ rubygems_version: 3.3.3
213
222
  signing_key:
214
223
  specification_version: 4
215
224
  summary: SnowSync is a file sync utility tool and API which provides a bridge for