em-service-now 0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,28 @@
1
+ require 'date'
2
+ Gem::Specification.new do |spec|
3
+
4
+ spec.name = %q{em-service-now}
5
+ spec.version = '0.3'
6
+ spec.date = DateTime.now.strftime( "%Y-%m-%d" )
7
+ spec.authors = ["Richard","","",""]
8
+ spec.email = %q{ops@clue.co.za}
9
+ spec.summary = %q{Tools for interfacing with service-now.com}
10
+ spec.homepage = %q{https://github.com/cluetechnologies/em-service-now}
11
+ spec.description = %q{}
12
+ spec.add_runtime_dependency 'eventmachine', '~> 1'
13
+ spec.add_runtime_dependency 'em-http-request', '~> 1'
14
+ spec.add_runtime_dependency 'json'
15
+ spec.add_runtime_dependency 'yaml'
16
+ spec.files = [
17
+
18
+ 'em-service-now.gemspec',
19
+ 'lib/em-service-now.rb',
20
+ 'lib/version.rb',
21
+ 'spec/spec_helper.rb',
22
+ 'spec/spec_config.yml.tmpl',
23
+ 'spec/functional_spec.rb',
24
+ 'spec/em-service-now_spec.rb'
25
+
26
+ ]
27
+
28
+ end
@@ -0,0 +1,573 @@
1
+ require 'eventmachine'
2
+ require 'em-http-request'
3
+ require 'json'
4
+ require 'uri'
5
+ require 'yaml'
6
+
7
+ class ServiceNowException < Exception
8
+
9
+ end
10
+
11
+ class ConfigException < Exception
12
+
13
+ end unless defined?( ConfigException )
14
+
15
+ module ServiceNow
16
+
17
+ def service_now_init( config, logger = nil )
18
+
19
+ @config = {}
20
+ @config = config unless config.nil?
21
+
22
+ @logger = logger
23
+
24
+ @connect_timeout = 60
25
+ @connect_timeout = @config[:connect_timeout] unless @config[:connect_timeout].nil?
26
+
27
+ @timeout = 120
28
+ @timeout = @config[:timeout] unless @config[:timeout].nil?
29
+
30
+ @username = @config[:username]
31
+ @password = @config[:password]
32
+ @url = @config[:url]
33
+
34
+ @service_now_running = false
35
+
36
+
37
+ raise ::ConfigException.new(
38
+
39
+ "#{self.class} requires :url: and :username: and :password: configured."
40
+
41
+ ) if (
42
+
43
+ @username.nil? or @username == '' or
44
+ @password.nil? or @password == '' or
45
+ @url.nil? or @url == ''
46
+
47
+ )
48
+
49
+ #
50
+ # Assumes already running inside an EM reactor
51
+ # If not, call em_service_now
52
+ #
53
+ @inline = true
54
+
55
+ get_cookies
56
+
57
+ end
58
+
59
+
60
+
61
+ def em_service_now_query( query, &block )
62
+
63
+ @inline = false
64
+
65
+ EM::run do
66
+
67
+ #
68
+ # Pass the block straight through.
69
+ #
70
+ service_now_query( query, &block )
71
+
72
+ end
73
+
74
+ end
75
+
76
+ def on_error( url, http, &block )
77
+
78
+ EM::stop unless @inline
79
+
80
+ error = "transport or http error #{http.error}"
81
+
82
+ @logger.error "#{self.class} ERROR:#{error}" unless @logger.nil?
83
+
84
+ yield nil, error if block
85
+
86
+ @service_now_running = false
87
+
88
+ end
89
+
90
+
91
+ def on_success( url, http, &block )
92
+
93
+ store_cookies( http )
94
+
95
+ EM::stop unless @inline
96
+
97
+ unless http.response_header.status == 200
98
+
99
+ error = "Response #{http.response_header.status} from #{url}"
100
+
101
+ @logger.error "#{self.class} ERROR:#{error}" unless @logger.nil?
102
+
103
+ end
104
+
105
+ if error != nil or http.response == ""
106
+
107
+ error = "Empty JSON response from #{url}"
108
+
109
+ @logger.error "#{self.class} ERROR:#{error}" unless @logger.nil?
110
+
111
+ end
112
+
113
+ if /do\?CSV\&/.match( url )
114
+
115
+ parse_csv( http, &block )
116
+
117
+ @service_now_running = false
118
+
119
+ return
120
+
121
+ end
122
+
123
+ unless error != nil or records = JSON.parse( http.response )
124
+
125
+ error = "Malformed JSON response from #{url}"
126
+
127
+ @logger.error "#{self.class} ERROR:#{error}" unless @logger.nil?
128
+
129
+ end
130
+
131
+ if error.nil? and records.has_key?('error')
132
+
133
+ #
134
+ # SNOW returns a 200 'successs' and puts the error in the JSON
135
+ #
136
+ error = "#{records['error']}from #{url}"
137
+
138
+ @logger.error "#{self.class} ERROR:#{error}" unless @logger.nil?
139
+
140
+ end
141
+
142
+ if error.nil? and records.has_key?('records')
143
+
144
+ records['records'].each do |record|
145
+
146
+ #
147
+ # Have records, yield them each
148
+ #
149
+ yield record, nil if block
150
+
151
+ end
152
+
153
+ else
154
+
155
+ yield nil, error if block
156
+
157
+ end
158
+
159
+ @service_now_running = false
160
+
161
+ end
162
+
163
+ def em_service_now( type, query, records_array = nil, &block )
164
+
165
+ @inline = false
166
+
167
+ EM::run do
168
+
169
+ service_now( type, query, records_array, &block )
170
+
171
+ end
172
+
173
+ end
174
+
175
+
176
+ def service_now( type, query, records_array = nil, &block )
177
+
178
+ @service_now_running = true
179
+
180
+ url = nil
181
+
182
+ table = query['table']
183
+
184
+ case type
185
+
186
+ when :getRecords, :getKeys, :getCSV
187
+
188
+ return service_now_query( type, query, &block )
189
+
190
+ when :insert
191
+
192
+ url = "#{@url}/#{table}.do?JSON&sysparm_action=insertMultiple"
193
+ body = {
194
+
195
+ 'records' => records_array
196
+
197
+ }
198
+
199
+ when :update
200
+
201
+ url = "#{@url}/#{table}.do?JSON"
202
+ url="#{url}&sysparm_action=update"
203
+ url = append_query( url, query )
204
+ body = records_array[0]
205
+
206
+ else
207
+
208
+ raise ServiceNowException.new(
209
+
210
+ "no such query type '#{type}'"
211
+
212
+ )
213
+
214
+ end
215
+
216
+ json_body = JSON.dump(body)
217
+
218
+ @logger.debug "ServiceNow URL:#{url}" unless @logger.nil?
219
+
220
+ http = EventMachine::HttpRequest.new( url ).post(
221
+
222
+ generate_POST_request( json_body )
223
+
224
+ )
225
+
226
+ http.errback do
227
+
228
+ on_error( url, http, &block )
229
+
230
+ end
231
+
232
+ http.callback do
233
+
234
+ if http.response_header.status == 401
235
+
236
+ #
237
+ # Authentication failed
238
+ #
239
+ login_and_retry( url, json_body, &block )
240
+
241
+ else
242
+
243
+ on_success( url, http, &block )
244
+
245
+ end
246
+
247
+ end
248
+
249
+ end
250
+
251
+ private
252
+
253
+ def get_cookies
254
+
255
+ dir = Dir.getwd
256
+ file = 'service_now.cookie'
257
+
258
+ #
259
+ # Assemble cookie file location
260
+ #
261
+
262
+ begin
263
+
264
+ unless DAEMON_ROOT.nil?
265
+
266
+ dir = "#{DAEMON_ROOT}/log"
267
+
268
+ unless File.directory?( "#{DAEMON_ROOT}/log" )
269
+
270
+ dir = DAEMON_ROOT
271
+
272
+ end
273
+
274
+ end
275
+
276
+ unless DAEMON_NAME.nil?
277
+
278
+ file = "service_now.#{DAEMON_NAME}.cookie"
279
+
280
+ end
281
+
282
+ rescue; end
283
+
284
+ @cookiefile = "#{dir}/#{file}"
285
+
286
+ #
287
+ # Load the cookies from file
288
+ #
289
+ if File.file?( @cookiefile )
290
+
291
+ begin
292
+
293
+ @cookies = YAML.load_file( @cookiefile )
294
+
295
+ rescue; end
296
+
297
+ end
298
+
299
+ end
300
+
301
+ def store_cookies( http )
302
+
303
+ #
304
+ # Only store cookies if JSESSIONID is in [0]'th cookie
305
+ #
306
+ # ie. At the creation of the SNOWside session. All subsequently
307
+ # received cookie arrays do not contain the JSESSIONID in
308
+ # reply, so it would be overwritten in the cookie file,
309
+ #
310
+ # Effectively making the session cookie only work once.
311
+ #
312
+
313
+ return unless /^JSESSIONID/.match( http.response_header["SET_COOKIE"][0] )
314
+
315
+ begin
316
+
317
+ File.open( @cookiefile, 'w' ) do |f|
318
+
319
+ YAML::dump( http.response_header["SET_COOKIE"], f )
320
+
321
+ end
322
+
323
+ rescue
324
+
325
+ end
326
+
327
+ end
328
+
329
+ def parse_csv( http, &block )
330
+
331
+ require 'csv'
332
+
333
+ headings = nil
334
+
335
+ begin
336
+
337
+ CSV.parse( http.response ).each do |row|
338
+
339
+ if headings.nil? then
340
+
341
+ headings = row
342
+ next
343
+
344
+ else
345
+
346
+ record = Hash[*headings.zip( row ).flatten]
347
+
348
+ yield record, nil if block
349
+
350
+ end
351
+
352
+ end
353
+
354
+ rescue Exception => e
355
+
356
+ yield nil, e.to_s if block
357
+
358
+ end
359
+
360
+ end
361
+
362
+ def append_csv_query( url, query )
363
+
364
+ url = "#{url}&" unless query['where'].nil?
365
+
366
+ query['where'].each do |field, value|
367
+
368
+ if /^\=/.match( value )
369
+ url = "#{url}#{field}#{value[1..-1]}^"
370
+
371
+ else
372
+
373
+ url = "#{url}#{field}=#{value}^"
374
+
375
+ end
376
+
377
+ end unless query['where'].nil?
378
+
379
+ url.gsub!( /\^$/, '' )
380
+ url = URI.escape( url )
381
+ url = url.gsub( %r[,], '%2C' )
382
+
383
+ return url
384
+
385
+ end
386
+
387
+ def append_query( url, query )
388
+
389
+ url = "#{url}&sysparm_query=" unless query['where'].nil?
390
+
391
+ query['where'].each do |field, value|
392
+
393
+ if /^\=/.match( value )
394
+
395
+ url = "#{url}#{field}#{value[1..-1]}^"
396
+
397
+ else
398
+
399
+ url = "#{url}#{field}=#{value}^"
400
+
401
+ end
402
+
403
+ end unless query['where'].nil?
404
+
405
+ url.gsub!( /\^$/, '' )
406
+ url = URI.escape( url )
407
+ url = url.gsub( %r[,], '%2C' )
408
+
409
+ return url
410
+
411
+ end
412
+
413
+ def generate_GET_request
414
+
415
+ return \
416
+ :connect_timeout => @connect_timeout,
417
+ :timeout => @timeout,
418
+ :head => {
419
+
420
+ 'cookie' => @cookies,
421
+ 'Content-Type' => 'application/json'
422
+
423
+ } unless @cookies.nil?
424
+
425
+ return \
426
+ :connect_timeout => @connect_timeout,
427
+ :timeout => @timeout,
428
+ :head => {
429
+
430
+ 'Authorization' => [ @username, @password ],
431
+ 'Content-Type' => 'application/json'
432
+
433
+ }
434
+
435
+ end
436
+
437
+ def generate_POST_request( body )
438
+
439
+ return \
440
+ :connect_timeout => @connect_timeout,
441
+ :timeout => @timeout,
442
+ :head => {
443
+
444
+ 'cookie' => @cookies,
445
+ 'Content-Type' => 'application/json'
446
+
447
+ },
448
+ :body => body \
449
+ unless @cookies.nil?
450
+
451
+ return \
452
+ :connect_timeout => @connect_timeout,
453
+ :timeout => @timeout,
454
+ :head => {
455
+
456
+ 'Authorization' => [ @username, @password ],
457
+ 'Content-Type' => 'application/json'
458
+
459
+ },
460
+ :body => body
461
+
462
+ end
463
+
464
+ def service_now_query( type, query, &block )
465
+
466
+ result = []
467
+ error = nil
468
+
469
+ table = query['table']
470
+
471
+ if query['where'].nil? and type == :select
472
+
473
+ @logger.warn( "WARNING! No 'where' clause! - Use :selectKeys on large dataset, SNOW might return only a subset of the result" )
474
+
475
+ end
476
+
477
+ case type
478
+
479
+ when :getKeys
480
+
481
+ url = "#{@url}/#{table}.do?JSON&sysparm_action=getKeys"
482
+ url = append_query( url, query )
483
+
484
+ when :getRecords
485
+
486
+ url = "#{@url}/#{table}.do?JSON&sysparm_action=getRecords"
487
+ url = append_query( url, query )
488
+
489
+ when :getCSV
490
+
491
+ url = "#{@url}/#{table}.do?CSV"
492
+ url = append_csv_query( url, query )
493
+
494
+ end
495
+
496
+ @logger.debug "ServiceNow URL:#{url}" unless @logger.nil?
497
+
498
+ http = EventMachine::HttpRequest.new( url ).get(
499
+
500
+ generate_GET_request
501
+
502
+ )
503
+
504
+ http.errback do
505
+
506
+ on_error( url, http, &block )
507
+
508
+ end
509
+
510
+ http.callback do
511
+
512
+ if http.response_header.status == 401
513
+
514
+ #
515
+ # Authentication failed
516
+ #
517
+ login_and_retry( url, &block )
518
+
519
+ else
520
+
521
+ on_success( url, http, &block )
522
+
523
+ end
524
+
525
+ end
526
+
527
+ end
528
+
529
+ def login_and_retry( url, body = nil, &block )
530
+
531
+ @logger.warn "#{self.class} creating new session"
532
+
533
+ #
534
+ # Nil cookies will cause an authentication
535
+ # and the new cookies will be saved to file
536
+ # on the reply.
537
+ #
538
+
539
+ @cookies = nil
540
+
541
+ if body.nil?
542
+
543
+ http = EventMachine::HttpRequest.new( url ).get(
544
+
545
+ generate_GET_request
546
+
547
+ )
548
+
549
+ else
550
+
551
+ http = EventMachine::HttpRequest.new( url ).post(
552
+
553
+ generate_POST_request( body )
554
+
555
+ )
556
+
557
+ end
558
+
559
+ http.errback do
560
+
561
+ on_error( url, http, &block )
562
+
563
+ end
564
+
565
+ http.callback do
566
+
567
+ on_success( url, http, &block )
568
+
569
+ end
570
+
571
+ end
572
+
573
+ end
@@ -0,0 +1,5 @@
1
+ module ServiceNow
2
+
3
+ Version = VERSION = '0.3'
4
+
5
+ end
@@ -0,0 +1,366 @@
1
+ require 'spec_helper'
2
+
3
+ describe ServiceNow do
4
+
5
+ before :all do
6
+
7
+ LOG.off
8
+
9
+ @cookies = 'NONE'
10
+
11
+ @get_companies = {
12
+
13
+ 'table' => 'core_company',
14
+ 'where' => {
15
+
16
+ 'status' => 'Operational'
17
+
18
+ }
19
+
20
+ }
21
+
22
+ end
23
+
24
+ subject {
25
+
26
+ Object.extend( ServiceNow )
27
+
28
+ }
29
+
30
+ it 'requires configuration' do
31
+
32
+ config_copy = Hash.new
33
+ config_copy[:username] = CONFIG['config'][:username]
34
+ config_copy[:password] = CONFIG['config'][:password]
35
+
36
+ expect {
37
+
38
+ subject.service_now_init( config_copy, LOG )
39
+
40
+ }.to raise_error(
41
+
42
+ ConfigException,
43
+
44
+ /requires :url: and :username: and :password: configured/
45
+
46
+ )
47
+
48
+ end
49
+
50
+ it 'errors on transport errors' do
51
+
52
+ config_copy = Hash.new
53
+ config_copy[:username] = CONFIG['config'][:username]
54
+ config_copy[:password] = CONFIG['config'][:password]
55
+ config_copy[:url] = 'https://no.such.thing'
56
+
57
+ result = nil
58
+
59
+ subject.service_now_init( config_copy, LOG )
60
+
61
+ subject.em_service_now( :getKeys, @get_companies ) do |record, status|
62
+
63
+ result = status.inspect
64
+
65
+ end
66
+
67
+ result.should match /transport or http error/
68
+
69
+ end
70
+
71
+ context 'can query/insert/update' do
72
+
73
+ before :each do
74
+
75
+ subject.service_now_init( CONFIG['config'], LOG )
76
+
77
+ @url = CONFIG['config'][:url]
78
+
79
+ subject.instance_variable_set( :@cookies, @cookies )
80
+
81
+ @http_request = mock( 'EventMachine::HttpRequest' )
82
+
83
+ @http_request.should_receive(
84
+
85
+ :errback
86
+
87
+ )
88
+
89
+ @http_request.should_receive(
90
+
91
+ :callback
92
+
93
+ )
94
+
95
+ end
96
+
97
+ it 'supports getKeys' do
98
+
99
+ query = {
100
+
101
+ 'table' => 'table',
102
+ 'where' => {
103
+
104
+ 'column1' => 'value1',
105
+ 'column2' => 'value2'
106
+
107
+ }
108
+
109
+ }
110
+
111
+ @http_request.should_receive(
112
+
113
+ :get
114
+
115
+ ).with({
116
+
117
+ :connect_timeout => 60,
118
+ :timeout => 120,
119
+ :head => {
120
+
121
+ "Content-Type" => "application/json",
122
+ "cookie" => @cookies
123
+
124
+ },
125
+
126
+ }).and_return(
127
+
128
+ @http_request
129
+
130
+ )
131
+
132
+ EventMachine::HttpRequest.should_receive(
133
+
134
+ :new
135
+
136
+ ).with(
137
+
138
+ "#{@url}/table.do?JSON&sysparm_action=getKeys&sysparm_query=column1=value1%5Ecolumn2=value2"
139
+
140
+ ).and_return(
141
+
142
+ @http_request
143
+
144
+ )
145
+
146
+ subject.service_now( :getKeys, query )
147
+
148
+ end
149
+
150
+ it 'supports special query things' do
151
+
152
+ query = {
153
+
154
+ 'table' => 'table',
155
+ 'where' => {
156
+
157
+ 'field' => '=NOT IN1,2'
158
+
159
+ }
160
+
161
+ }
162
+
163
+ @http_request.should_receive(
164
+
165
+ :get
166
+
167
+ ).with({
168
+
169
+ :connect_timeout => 60,
170
+ :timeout => 120,
171
+ :head => {
172
+
173
+ "Content-Type" => "application/json",
174
+ "cookie" => @cookies
175
+
176
+ },
177
+
178
+ }).and_return(
179
+
180
+ @http_request
181
+
182
+ )
183
+
184
+ EventMachine::HttpRequest.should_receive(
185
+
186
+ :new
187
+
188
+ ).with(
189
+
190
+ "#{@url}/table.do?JSON&sysparm_action=getKeys&sysparm_query=fieldNOT%20IN1%2C2"
191
+
192
+ ).and_return(
193
+
194
+ @http_request
195
+
196
+ )
197
+
198
+ subject.service_now( :getKeys, query )
199
+
200
+ end
201
+
202
+ it 'can insert a record' do
203
+
204
+ query = {
205
+
206
+ 'table' => 'table'
207
+
208
+ }
209
+
210
+ records_array = [{
211
+
212
+ 'column1' => 'value1',
213
+ 'column2' => 'value2'
214
+
215
+ }]
216
+
217
+ body = '{"records":[{"column1":"value1","column2":"value2"}]}'
218
+
219
+ @http_request.should_receive(
220
+
221
+ :post
222
+
223
+ ).with({
224
+
225
+ :connect_timeout => 60,
226
+ :timeout => 120,
227
+ :head => {
228
+
229
+ "Content-Type" => "application/json",
230
+ "cookie" => @cookies
231
+
232
+ },
233
+ :body => body
234
+
235
+ }).and_return(
236
+
237
+ @http_request
238
+
239
+ )
240
+
241
+ EventMachine::HttpRequest.should_receive(
242
+
243
+ :new
244
+
245
+ ).with(
246
+
247
+ "#{@url}/table.do?JSON&sysparm_action=insertMultiple"
248
+
249
+ ).and_return(
250
+
251
+ @http_request
252
+
253
+ )
254
+
255
+ subject.service_now( :insert, query, records_array )
256
+
257
+ end
258
+
259
+ it 'can update a record' do
260
+
261
+ query = {
262
+
263
+ 'table' => 'core_company',
264
+ 'where' => {
265
+
266
+ 'sys_id' => '_____SYS___ID____'
267
+
268
+ }
269
+
270
+ }
271
+
272
+ record_array = [{
273
+
274
+ 'u_column_one' => 'one',
275
+ 'u_column_two' => 'two'
276
+
277
+ }]
278
+
279
+ body = '{"u_column_one":"one","u_column_two":"two"}'
280
+
281
+ @http_request.should_receive(
282
+
283
+ :post
284
+
285
+ ).with({
286
+
287
+ :connect_timeout => 60,
288
+ :timeout => 120,
289
+ :head => {
290
+
291
+ "Content-Type" => "application/json",
292
+ "cookie" => @cookies
293
+
294
+ },
295
+ :body => body
296
+
297
+ }).and_return(
298
+
299
+ @http_request
300
+
301
+ )
302
+
303
+ EventMachine::HttpRequest.should_receive(
304
+
305
+ :new
306
+
307
+ ).with(
308
+
309
+ "#{@url}/core_company.do?JSON&sysparm_action=update&sysparm_query=sys_id=_____SYS___ID____"
310
+
311
+ ).and_return(
312
+
313
+ @http_request
314
+
315
+ )
316
+
317
+ subject.service_now( :update, query, record_array )
318
+
319
+ end
320
+
321
+ it 'supports STARTSWITH' do
322
+
323
+ subject.service_now_init( CONFIG['config'], LOG )
324
+
325
+ result = []
326
+
327
+ EventMachine::HttpRequest.should_receive(
328
+
329
+ :new
330
+
331
+ ).with(
332
+
333
+ "#{@url}/core_company.do?JSON&sysparm_action=getKeys&sysparm_query=nameSTARTSWITHClue"
334
+
335
+ ).and_return(
336
+
337
+ @http_request
338
+
339
+ )
340
+
341
+ @http_request.should_receive(
342
+
343
+ :get
344
+
345
+ ).and_return(
346
+
347
+ @http_request
348
+
349
+ )
350
+
351
+ subject.service_now( :getKeys, {
352
+
353
+ 'table' => 'core_company',
354
+ 'where' => {
355
+
356
+ 'name' => '=STARTSWITHClue'
357
+
358
+ }
359
+
360
+ } )
361
+
362
+ end
363
+
364
+ end
365
+
366
+ end
@@ -0,0 +1,154 @@
1
+ require 'spec_helper'
2
+
3
+ describe ServiceNow do
4
+
5
+ subject {
6
+
7
+ LOG.on
8
+ subj = Object.extend( ServiceNow )
9
+ subj.service_now_init( CONFIG['config'], LOG )
10
+ subj
11
+
12
+ }
13
+
14
+ pending 'can get by CSV interface' do
15
+
16
+ query = CONFIG['queries']['get_specific_report']
17
+
18
+ result = []
19
+ subject.em_service_now( :getCSV, query ) do |record, error|
20
+
21
+
22
+ result << record unless record.nil?
23
+
24
+ end
25
+
26
+ result.length.should > 1
27
+
28
+ end
29
+
30
+ pending 'can get by JSON interface' do
31
+
32
+ company = nil
33
+
34
+ query = CONFIG['queries']['get_specific_company']
35
+ expectation = CONFIG['queries']['get_specific_company_expectation']
36
+
37
+ subject.em_service_now( :getRecords, query ) do |record, status|
38
+
39
+ company = record
40
+
41
+ end
42
+
43
+ company['name'].should == expectation
44
+
45
+ end
46
+
47
+ pending 'errors on invalid table name' do
48
+
49
+ result = nil
50
+
51
+ subject.em_service_now( :getKeys, {
52
+
53
+ 'table' => 'nosuchtable',
54
+ 'where' => {
55
+ 'u_no_such_column' => 'MIA'
56
+ }
57
+
58
+ } ) do |record, error|
59
+
60
+ result = error
61
+
62
+ end
63
+
64
+ result.should match /Empty JSON response from/
65
+
66
+ end
67
+
68
+ pending 'can create an incident' do
69
+
70
+ query = {
71
+
72
+ 'table' => 'incident'
73
+
74
+ }
75
+
76
+ records = [
77
+
78
+ CONFIG['incident']['create']
79
+
80
+ ]
81
+
82
+ subject.em_service_now( :insert, query, records )
83
+
84
+ end
85
+
86
+ pending 'can update incidents by company, short_description and status' do
87
+
88
+ update_column = CONFIG['incident']['update']['column']
89
+ update_value = CONFIG['incident']['update']['value']
90
+
91
+ query = {
92
+
93
+ 'table' => 'incident',
94
+
95
+ 'where' => {
96
+
97
+ 'company' => CONFIG['incident']['create']['company'],
98
+ 'state' => '=NOT IN6,7',
99
+ 'short_description' => CONFIG['incident']['create']['short_description']
100
+
101
+ }
102
+
103
+ }
104
+
105
+ records = [{
106
+
107
+ update_column => update_value
108
+
109
+ }]
110
+
111
+ result = nil
112
+
113
+ subject.em_service_now( :update, query, records ) do |record, error|
114
+
115
+ result = record
116
+
117
+ end
118
+
119
+ result[ update_column ].should == update_value
120
+
121
+ end
122
+
123
+
124
+ pending 'can close incidents by company, short_description and status' do
125
+
126
+ query = {
127
+
128
+ 'table' => 'incident',
129
+
130
+ 'where' => {
131
+
132
+ 'company' => CONFIG['incident']['create']['company'],
133
+ 'state' => '=NOT IN6,7',
134
+ 'short_description' => CONFIG['incident']['create']['short_description']
135
+
136
+ }
137
+
138
+ }
139
+
140
+ records = [{
141
+
142
+ 'u_next_step' => 'Set to Resolved'
143
+
144
+ }]
145
+
146
+ subject.em_service_now( :update, query, records ) do |record, error|
147
+
148
+ raise error.inspect unless error.nil?
149
+
150
+ end
151
+
152
+ end
153
+
154
+ end
@@ -0,0 +1,40 @@
1
+ config:
2
+
3
+ :username: username@domain.com
4
+ :password: password
5
+ :url: https://yourDEVinstance.service-now.com
6
+
7
+ queries:
8
+
9
+ get_specific_report:
10
+ #
11
+ # fetches a configured snow report
12
+ #
13
+ table: sys_report_template
14
+ #
15
+ # Should refer to configured report's sys_id
16
+ #
17
+ where:
18
+ jvar_report_id: 5896e8a30c16a00087c61678d080f220
19
+
20
+ get_specific_company_expectation: COMPANY NAME
21
+ get_specific_company:
22
+ table: core_company
23
+ where:
24
+ name: COMPANY NAME
25
+
26
+
27
+ incident:
28
+
29
+ create:
30
+ company: 5fac1edc0a0a3c1e00ccdb50799bcec1
31
+ assignment_group: d625dccec0a8016700a222a0f7900d06
32
+ category: Lab
33
+ subcategory: Software
34
+ short_description: puppet error name
35
+ description: Description Text
36
+
37
+ update:
38
+ column: u_event_count
39
+ value: '40'
40
+
@@ -0,0 +1,43 @@
1
+ require 'em-service-now'
2
+
3
+ SPEC_CONFIG_FILE = "#{File.dirname( __FILE__ )}/spec_config.yml"
4
+
5
+ CONFIG = YAML.load_file(
6
+
7
+ SPEC_CONFIG_FILE
8
+
9
+ ) if File.file?( SPEC_CONFIG_FILE )
10
+ CONFIG = {} unless defined?( CONFIG )
11
+
12
+ class FakeLogger
13
+
14
+ def initialize( parameter = :noisey )
15
+ @parameter = parameter
16
+ end
17
+
18
+ def on
19
+ @parameter = :noisey
20
+ end
21
+
22
+ def off
23
+ @parameter = :silent
24
+ end
25
+
26
+ def method_missing( symbol, *args, &block )
27
+ puts "LOG.#{symbol}: #{args}" unless @parameter == :silent
28
+ end
29
+
30
+ #
31
+ # rspec won't match unless for these unless they'r defined
32
+ #
33
+ def info( msg )
34
+ puts "LOG.info: [#{msg}]" unless @parameter == :silent
35
+ end
36
+
37
+ def warn( msg )
38
+ puts "LOG.warn: [#{msg}]" unless @parameter == :silent
39
+ end
40
+
41
+ end
42
+
43
+ LOG = FakeLogger.new
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: em-service-now
3
+ version: !ruby/object:Gem::Version
4
+ hash: 13
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 3
9
+ version: "0.3"
10
+ platform: ruby
11
+ authors:
12
+ - Richard
13
+ - ""
14
+ - ""
15
+ - ""
16
+ autorequire:
17
+ bindir: bin
18
+ cert_chain: []
19
+
20
+ date: 2012-06-22 00:00:00 Z
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: eventmachine
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ hash: 1
31
+ segments:
32
+ - 1
33
+ version: "1"
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: em-http-request
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ hash: 1
45
+ segments:
46
+ - 1
47
+ version: "1"
48
+ type: :runtime
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: json
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ type: :runtime
63
+ version_requirements: *id003
64
+ - !ruby/object:Gem::Dependency
65
+ name: yaml
66
+ prerelease: false
67
+ requirement: &id004 !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 3
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ type: :runtime
77
+ version_requirements: *id004
78
+ description: ""
79
+ email: ops@clue.co.za
80
+ executables: []
81
+
82
+ extensions: []
83
+
84
+ extra_rdoc_files: []
85
+
86
+ files:
87
+ - em-service-now.gemspec
88
+ - lib/em-service-now.rb
89
+ - lib/version.rb
90
+ - spec/spec_helper.rb
91
+ - spec/spec_config.yml.tmpl
92
+ - spec/functional_spec.rb
93
+ - spec/em-service-now_spec.rb
94
+ homepage: https://github.com/cluetechnologies/em-service-now
95
+ licenses: []
96
+
97
+ post_install_message:
98
+ rdoc_options: []
99
+
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ hash: 3
108
+ segments:
109
+ - 0
110
+ version: "0"
111
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
+ none: false
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ hash: 3
117
+ segments:
118
+ - 0
119
+ version: "0"
120
+ requirements: []
121
+
122
+ rubyforge_project:
123
+ rubygems_version: 1.8.5
124
+ signing_key:
125
+ specification_version: 3
126
+ summary: Tools for interfacing with service-now.com
127
+ test_files: []
128
+