klink-ruby-api 1.0.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.
- data/CHANGELOG +17 -0
- data/README +6 -0
- data/Rakefile +36 -0
- data/config/klink.example.yml +17 -0
- data/config/klink_test_suite.def +1526 -0
- data/lib/kinetic/link.rb +522 -0
- data/lib/klink-ruby-api.rb +1 -0
- data/test/functional/configurations_test.rb +68 -0
- data/test/functional/create_test.rb +26 -0
- data/test/functional/delete_test.rb +38 -0
- data/test/functional/entries_test.rb +45 -0
- data/test/functional/entry_test.rb +17 -0
- data/test/functional/statistics_test.rb +55 -0
- data/test/functional/structure_test.rb +30 -0
- data/test/functional/structures_test.rb +29 -0
- data/test/functional/update_test.rb +41 -0
- data/test/test_helper.rb +6 -0
- metadata +87 -0
data/lib/kinetic/link.rb
ADDED
@@ -0,0 +1,522 @@
|
|
1
|
+
# = Introduction
|
2
|
+
# The Klink Ruby API is a Ruby wrapper library to be used with a Klink web server. It provides a simple, easy to use
|
3
|
+
# llbrary of methods to access data and other information from a Remedy server.
|
4
|
+
#
|
5
|
+
|
6
|
+
require 'net/http'
|
7
|
+
require 'uri'
|
8
|
+
require 'rexml/document'
|
9
|
+
require 'yaml'
|
10
|
+
include REXML
|
11
|
+
|
12
|
+
|
13
|
+
module Kinetic
|
14
|
+
# Represents a connection to a Klink server.
|
15
|
+
class Link
|
16
|
+
|
17
|
+
Kinetic::Link::VERSION = '1.0.6'
|
18
|
+
|
19
|
+
@@link_api_version = "Kinetic Link #{Kinetic::Link::VERSION}"
|
20
|
+
|
21
|
+
# required connection information to connect to an ar_server via klink
|
22
|
+
@@user = nil
|
23
|
+
@@password = nil
|
24
|
+
@@klink_server = nil
|
25
|
+
@@ar_server = nil
|
26
|
+
|
27
|
+
# initialize to false
|
28
|
+
# set to connected once we have all the info needed to connect
|
29
|
+
@@connected = false
|
30
|
+
|
31
|
+
# TODO - Remove this function???
|
32
|
+
# Is this the right place for it to be?
|
33
|
+
# (Renamed - to see if anything else breaks)
|
34
|
+
# Max 30 chars unique
|
35
|
+
# can return less than 30 chars
|
36
|
+
# currently only numbers
|
37
|
+
# TODO - include alpha with case
|
38
|
+
# currently 10^30 uniques
|
39
|
+
# with mixed alpha 62^30
|
40
|
+
# possibly use sha1
|
41
|
+
def self.xxxget_guid
|
42
|
+
return (rand.to_s.split('.')[1].to_s + rand.to_s.split('.')[1].to_s).slice(0,30)
|
43
|
+
end
|
44
|
+
|
45
|
+
# setup connection info
|
46
|
+
# Example: Demo,"","klinkserver:8081.yourcompany.com,remedy.yourcompany.com
|
47
|
+
# TODO -- add AR Server port??? -- how does that work with Klink?
|
48
|
+
def self.set_connection(user,password,klink_server,ar_server)
|
49
|
+
@@user = user
|
50
|
+
@@password = password
|
51
|
+
@@klink_server = klink_server
|
52
|
+
@@ar_server = ar_server
|
53
|
+
end
|
54
|
+
|
55
|
+
# return true false, if false also return a message of how it failed
|
56
|
+
# get a list of forms - if that works - all is well
|
57
|
+
# all servers have some sort of form available to public
|
58
|
+
def self.test_connection
|
59
|
+
# This block tests the connection to the klink server alone
|
60
|
+
begin
|
61
|
+
html = Net::HTTP.get(URI.parse("http://#{@@klink_server}/klink/about"))
|
62
|
+
raise unless html =~ /<a href="http:\/\/www\.kineticdata\.com">/
|
63
|
+
rescue
|
64
|
+
return false, %`Could not connect to the specified Kinetic Link server "#{@@klink_server}"`
|
65
|
+
end
|
66
|
+
# This block tests the connection to the klink server and the remedy server
|
67
|
+
# by attempting to retrieve data from the remedy server through klink
|
68
|
+
begin
|
69
|
+
if(self.structures.length > 0) then
|
70
|
+
return true
|
71
|
+
else
|
72
|
+
return false, %`Could not find any forms on server "#{@@ar_server}"`
|
73
|
+
end
|
74
|
+
rescue Timeout::Error
|
75
|
+
return false, %`Timeout occured when attempting to retrieve data from server "#{@@ar_server}"`
|
76
|
+
rescue
|
77
|
+
return false, %`Exception raised when attempting to retrieve data from server "#{@@ar_server}"`
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# connect if possible return status of connection
|
82
|
+
def self.establish_connection
|
83
|
+
if(@@ar_server == nil) then
|
84
|
+
|
85
|
+
# TODO - grab this from somewhere
|
86
|
+
environment = $klink_env
|
87
|
+
|
88
|
+
raise "No environment set" if(environment == nil)
|
89
|
+
|
90
|
+
# TODO - assumes it finds a file
|
91
|
+
klink_config = YAML::load_file(
|
92
|
+
File.expand_path(File.join(".",'klink.yml')))
|
93
|
+
|
94
|
+
begin
|
95
|
+
@@user=klink_config[environment]['user']
|
96
|
+
@@password=klink_config[environment]['password']
|
97
|
+
@@klink_server=klink_config[environment]['klink_server']
|
98
|
+
@@ar_server=klink_config[environment]['ar_server']
|
99
|
+
rescue
|
100
|
+
raise "Problem reading environment: #{$klink_env}"
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
# Temp set to true
|
107
|
+
@@connected = true
|
108
|
+
|
109
|
+
# Set to actual
|
110
|
+
@@connected = self.test_connection
|
111
|
+
|
112
|
+
|
113
|
+
return true
|
114
|
+
end
|
115
|
+
|
116
|
+
# delete record with id from the form
|
117
|
+
def self.delete(form_name, request_id)
|
118
|
+
self.establish_connection if @@connected == false
|
119
|
+
|
120
|
+
uri = URI.escape("http://#{@@klink_server}/klink/delete/#{@@user}:#{@@password}@#{@@ar_server}/#{form_name}/#{request_id}")
|
121
|
+
|
122
|
+
response = Net::HTTP.get(URI.parse(uri))
|
123
|
+
xmldoc = Document.new response
|
124
|
+
|
125
|
+
ret_val = nil
|
126
|
+
error = nil
|
127
|
+
|
128
|
+
xmldoc.elements.each('Response') { |entry_item|
|
129
|
+
ret_val = entry_item.attributes['Success']
|
130
|
+
if ret_val == 'false' then
|
131
|
+
xmldoc.elements.each('Response/Messages/Message') {|error_item|
|
132
|
+
if error_item.attributes['MessageNumber'] == '302'
|
133
|
+
then error = '302' # Record does not exist
|
134
|
+
end
|
135
|
+
}
|
136
|
+
end
|
137
|
+
}
|
138
|
+
|
139
|
+
# 302 == <Message MessageNumber="302" Type="ERROR">Entry does not exist in database</Message>
|
140
|
+
raise response.to_s if (ret_val == "false" && error != '302')
|
141
|
+
|
142
|
+
return ret_val
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
# Finds the entry on the form identified by the request_id parameter. If the fields parameter is specified,
|
147
|
+
# only those fields will be retrieved from the form. There can be a noticeable performance gain when
|
148
|
+
# retrieving only a subset of fields from large forms.
|
149
|
+
#
|
150
|
+
# - form_name - the name of the form to retrieve records from
|
151
|
+
# - request_id - the value of the Request ID field for the record to be retrieved
|
152
|
+
# - fields - an optional list (Array, or comma-separated String) of field ids to retrieve (default is all fields)
|
153
|
+
#
|
154
|
+
# Returns a hash that represents the record. The hash contains a mapping of fields id to field value for each field specified.
|
155
|
+
#
|
156
|
+
def self.entry(form_name, request_id, fields = nil)
|
157
|
+
self.establish_connection if @@connected == false
|
158
|
+
|
159
|
+
# build up the string of field ids to return
|
160
|
+
fields ||= ''
|
161
|
+
fields = fields.join(",") if fields.is_a? Array
|
162
|
+
fields.gsub!(' ', '')
|
163
|
+
field_list = "?items=#{fields}" unless fields.nil? || fields.empty?
|
164
|
+
|
165
|
+
uri = URI.escape("http://#{@@klink_server}/klink/entry/#{@@user}:#{@@password}@#{@@ar_server}/#{form_name}/#{request_id}#{field_list}")
|
166
|
+
|
167
|
+
response = Net::HTTP.get(URI.parse(uri))
|
168
|
+
xmldoc = Document.new(response)
|
169
|
+
|
170
|
+
ret_val = Hash.new
|
171
|
+
|
172
|
+
# TODO -- handle 'Status History' -- right now I just convert to ''
|
173
|
+
xmldoc.elements.each('Response/Result/Entry/EntryItem') { |entry_item|
|
174
|
+
ret_val[entry_item.attributes['ID']] = entry_item.text || ''
|
175
|
+
}
|
176
|
+
|
177
|
+
return ret_val
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
# Finds all the records from a form that match the qualification. If only a subset of fields on the form
|
182
|
+
# should be returned, please see the entries_with_fields method.
|
183
|
+
#
|
184
|
+
# - form_name - the name of the form to retrieve records from
|
185
|
+
# - qual - an optional qualification used to select the records: i.e. "1=1"
|
186
|
+
# - sort - an optional list (Array, or comma-separated String) of field ids to sort the results
|
187
|
+
#--
|
188
|
+
# TODO: Add sort order (ASC | DESC)
|
189
|
+
#++
|
190
|
+
# Returns an array of Request IDs of the records on the form that match the qualification, sorted in the order specified with the sort parameter.
|
191
|
+
#
|
192
|
+
def self.entries(form_name, qual = nil, sort = nil)
|
193
|
+
self.establish_connection if @@connected == false
|
194
|
+
|
195
|
+
qual ||= ''
|
196
|
+
qualification = "?qualification=#{qual}"
|
197
|
+
|
198
|
+
sort ||= ''
|
199
|
+
sort = options.join(",") if sort.is_a? Array
|
200
|
+
sort.gsub!(' ', '')
|
201
|
+
sort_list = "&sort=#{sort}" unless sort.nil? || sort.empty?
|
202
|
+
|
203
|
+
uri = URI.escape("http://#{@@klink_server}/klink/entries/#{@@user}:#{@@password}@#{@@ar_server}/#{form_name}#{qualification}#{sort_list}")
|
204
|
+
|
205
|
+
response = Net::HTTP.get(URI.parse(uri))
|
206
|
+
xmldoc = Document.new(response)
|
207
|
+
|
208
|
+
ret_val = Array.new
|
209
|
+
|
210
|
+
xmldoc.elements.each('Response/Result/EntryList/Entry') { |id|
|
211
|
+
ret_val << id.attributes['ID']
|
212
|
+
}
|
213
|
+
|
214
|
+
return ret_val
|
215
|
+
|
216
|
+
end
|
217
|
+
|
218
|
+
# Finds all the records from a form that match the qualification. If the fields option is specified, only those fields will be retrieved from the form.
|
219
|
+
# There can be a noticeable performance gain when retrieving only a subset of fields from large forms. If any of the specified fields is a diary
|
220
|
+
# field, or a long character field that cannot be returned with ARGetList, the call will silently fall back to retrieving a list of entry ids,
|
221
|
+
# then retrieving each entry separately.
|
222
|
+
#
|
223
|
+
# - form_name - the name of the form to retrieve records from
|
224
|
+
# - options - an optional hash of additional parameters to use with the query
|
225
|
+
#
|
226
|
+
# Available Options
|
227
|
+
# - :qual - an optional qualification used to select the records: i.e. "1=1"
|
228
|
+
# - :sort - an optional list (Array, or comma-separated String) of field ids to sort the results
|
229
|
+
# - :fields - an optional list (Array, or comma-separated String) of field ids to retrieve (default is no fields)
|
230
|
+
#--
|
231
|
+
# TODO: Add sort order (ASC | DESC)
|
232
|
+
#++
|
233
|
+
# Returns an array of hashes that represent each record that matched the qualification. Each hash in the array contains a mapping of fields id to field value.
|
234
|
+
#
|
235
|
+
def self.entries_with_fields(form_name, options = {})
|
236
|
+
self.establish_connection if @@connected == false
|
237
|
+
|
238
|
+
# build up the qualification as the first parameter - not necessary as the first, but we need to include the ? somewhere.
|
239
|
+
qual = options[:qual] || ''
|
240
|
+
qualification = "?qualification=#{qual}"
|
241
|
+
|
242
|
+
# build up the string of sort fields
|
243
|
+
sort = options[:sort] || ''
|
244
|
+
sort = options.join(",") if sort.is_a? Array
|
245
|
+
sort.gsub!(' ', '')
|
246
|
+
sort_list = "&sort=#{sort}" unless sort.nil? || sort.empty?
|
247
|
+
|
248
|
+
# build up the string of field ids to return
|
249
|
+
fields = options[:fields] || ''
|
250
|
+
fields = fields.join(",") if fields.is_a? Array
|
251
|
+
fields.gsub!(' ', '')
|
252
|
+
field_list = "&items=#{fields}" unless fields.nil? || fields.empty?
|
253
|
+
|
254
|
+
uri = URI.escape("http://#{@@klink_server}/klink/entries/#{@@user}:#{@@password}@#{@@ar_server}/#{form_name}#{qualification}#{sort_list}#{field_list}")
|
255
|
+
|
256
|
+
ret_val = Array.new
|
257
|
+
|
258
|
+
# try to get the results
|
259
|
+
begin
|
260
|
+
response = Net::HTTP.get(URI.parse(uri))
|
261
|
+
xmldoc = Document.new(response)
|
262
|
+
|
263
|
+
# check if there are any errors retrieving dialry fields or character fields that are too long
|
264
|
+
if xmldoc.root.attributes['Success'] == "false"
|
265
|
+
message = xmldoc.elements["Response/Messages/Message"]
|
266
|
+
message_text = message.text if message
|
267
|
+
raise StandardError.new(message_text || "Fall back to retrieving each record individually")
|
268
|
+
end
|
269
|
+
|
270
|
+
xmldoc.elements.each('Response/Result/EntryList/Entry') { |id|
|
271
|
+
entry = { '1' => id.attributes['ID'] }
|
272
|
+
id.elements.each('EntryItem') { |item_id|
|
273
|
+
entry[item_id.attributes['ID']] = item_id.text || ''
|
274
|
+
}
|
275
|
+
ret_val << entry
|
276
|
+
}
|
277
|
+
rescue StandardError => e
|
278
|
+
# if there was a problem, try to get a list of ids, then retrieve each record individually
|
279
|
+
self.entries(form_name, qual, sort).each { |entry_id|
|
280
|
+
ret_val << self.entry(form_name, entry_id, fields)
|
281
|
+
}
|
282
|
+
end
|
283
|
+
|
284
|
+
return ret_val
|
285
|
+
end
|
286
|
+
|
287
|
+
# return a list of statistics
|
288
|
+
# TODO - need to take params
|
289
|
+
def self.statistics(items = {})
|
290
|
+
self.establish_connection if @@connected == false
|
291
|
+
|
292
|
+
param_list = "?items=#{items}" if items.size > 0
|
293
|
+
uri = URI.escape("http://#{@@klink_server}/klink/statistics/#{@@user}:#{@@password}@#{@@ar_server}#{param_list}")
|
294
|
+
|
295
|
+
response = Net::HTTP.get(URI.parse(uri))
|
296
|
+
xmldoc = Document.new(response)
|
297
|
+
|
298
|
+
ret_val = Hash.new
|
299
|
+
|
300
|
+
xmldoc.elements.each('Response/Result/Statistics/Statistic') { |stat|
|
301
|
+
ret_val[stat.attributes['Name']]=stat.text ||=''
|
302
|
+
}
|
303
|
+
|
304
|
+
return ret_val
|
305
|
+
|
306
|
+
end
|
307
|
+
|
308
|
+
# return a list of configurations
|
309
|
+
# TODO - need to take params
|
310
|
+
def self.configurations(items = {})
|
311
|
+
self.establish_connection if @@connected == false
|
312
|
+
|
313
|
+
param_list = "?items=#{items}" if items.size > 0
|
314
|
+
uri = URI.escape("http://#{@@klink_server}/klink/configurations/#{@@user}:#{@@password}@#{@@ar_server}#{param_list}")
|
315
|
+
|
316
|
+
response = Net::HTTP.get(URI.parse(uri))
|
317
|
+
xmldoc = Document.new(response)
|
318
|
+
|
319
|
+
ret_val = Hash.new
|
320
|
+
|
321
|
+
xmldoc.elements.each('Response/Result/Configurations/Configuration') { |conf|
|
322
|
+
ret_val[conf.attributes['Name']]=conf.text ||=''
|
323
|
+
}
|
324
|
+
|
325
|
+
return ret_val
|
326
|
+
|
327
|
+
end
|
328
|
+
|
329
|
+
# return a list of structures
|
330
|
+
def self.structures
|
331
|
+
self.establish_connection if @@connected == false
|
332
|
+
|
333
|
+
uri = URI.escape("http://#{@@klink_server}/klink/structures/#{@@user}:#{@@password}@#{@@ar_server}")
|
334
|
+
|
335
|
+
response = Net::HTTP.get(URI.parse(uri))
|
336
|
+
xmldoc = Document.new(response)
|
337
|
+
|
338
|
+
ret_val = Array.new
|
339
|
+
|
340
|
+
xmldoc.elements.each('Response/Result/Structures/Structure') { |structure|
|
341
|
+
ret_val << structure.attributes['ID'] ||=''
|
342
|
+
}
|
343
|
+
|
344
|
+
return ret_val
|
345
|
+
|
346
|
+
end
|
347
|
+
|
348
|
+
# TODO - make cleaner and make into a library
|
349
|
+
# I just never found it in a library
|
350
|
+
def self.clean_input(v)
|
351
|
+
|
352
|
+
new_v = v.is_a?(String) ? v.clone : v
|
353
|
+
|
354
|
+
if v.class == String then
|
355
|
+
new_v.gsub!(/&/, '&')
|
356
|
+
new_v.gsub!(/\n/, ' ')
|
357
|
+
new_v.gsub!(/\r/, ' ') # TODO - never tested
|
358
|
+
new_v.gsub!(/\</, '<')
|
359
|
+
new_v.gsub!(/\>/, '>')
|
360
|
+
end
|
361
|
+
|
362
|
+
return new_v
|
363
|
+
|
364
|
+
end
|
365
|
+
|
366
|
+
|
367
|
+
def self.structure(form_name)
|
368
|
+
self.establish_connection if @@connected == false
|
369
|
+
|
370
|
+
uri = URI.escape("http://#{@@klink_server}/klink/structure/#{@@user}:#{@@password}@#{@@ar_server}/#{form_name}")
|
371
|
+
|
372
|
+
response = Net::HTTP.get(URI.parse(uri))
|
373
|
+
xmldoc = Document.new(response)
|
374
|
+
|
375
|
+
structure_map = Hash.new
|
376
|
+
xmldoc.elements.each('Response/Result/Structure/StructureItem') { |structure_item|
|
377
|
+
|
378
|
+
# structure_map[structure_item.attributes['ID']] = structure_item.attributes['Name']
|
379
|
+
|
380
|
+
name = structure_item.attributes['Name']
|
381
|
+
id = structure_item.attributes['ID']
|
382
|
+
type = structure_item.attributes['Type'] # DATA/ATTACHMENT
|
383
|
+
|
384
|
+
|
385
|
+
field_hash = Hash.new
|
386
|
+
|
387
|
+
field_hash["Name"] = name
|
388
|
+
field_hash["ID"] = id
|
389
|
+
field_hash["Type"] = type
|
390
|
+
|
391
|
+
structure_item.elements.each('DataType') { |value|
|
392
|
+
field_hash["DataType"] = value.text
|
393
|
+
}
|
394
|
+
|
395
|
+
structure_item.elements.each('DefaultValue') { |value|
|
396
|
+
field_hash["DefaultValue"] = value.text
|
397
|
+
}
|
398
|
+
|
399
|
+
structure_item.elements.each('EntryMode') { |value|
|
400
|
+
field_hash["EntryMode"] = value.text
|
401
|
+
}
|
402
|
+
|
403
|
+
attr = Array.new
|
404
|
+
structure_item.elements.each('Attributes/Attribute') { |value|
|
405
|
+
|
406
|
+
attr << value.text
|
407
|
+
}
|
408
|
+
field_hash["attributes"] = attr
|
409
|
+
|
410
|
+
|
411
|
+
# TODO - store it by name and by id -- easier to find
|
412
|
+
#structure_map[name] = field_hash
|
413
|
+
structure_map[id] = field_hash
|
414
|
+
|
415
|
+
}
|
416
|
+
return structure_map
|
417
|
+
end
|
418
|
+
|
419
|
+
def self.build_connection
|
420
|
+
|
421
|
+
# if port info is included - need to breakup and attach to that port
|
422
|
+
if /:/.match(@@klink_server) then
|
423
|
+
(location,port) = @@klink_server.split ':'
|
424
|
+
http = Net::HTTP.new location, port
|
425
|
+
else
|
426
|
+
http = Net::HTTP.new @@klink_server
|
427
|
+
end
|
428
|
+
|
429
|
+
end
|
430
|
+
|
431
|
+
# TODO - return values of more than just ID
|
432
|
+
def self.write(form_name, record_id, name_values = nil)
|
433
|
+
|
434
|
+
self.establish_connection if @@connected == false
|
435
|
+
|
436
|
+
http = self.build_connection
|
437
|
+
|
438
|
+
headers = {
|
439
|
+
'Content-Type' => 'application/xml',
|
440
|
+
'User-Agent' => @@link_api_version
|
441
|
+
}
|
442
|
+
|
443
|
+
data = ""
|
444
|
+
|
445
|
+
if record_id.nil? then
|
446
|
+
# create
|
447
|
+
data = %|<Entry Structure="#{form_name}">|
|
448
|
+
else
|
449
|
+
# update
|
450
|
+
data = %|<Entry ID="#{record_id}" Structure="#{form_name}">|
|
451
|
+
end
|
452
|
+
|
453
|
+
name_values.each do |n,v|
|
454
|
+
if v != nil then
|
455
|
+
new_v = Link::clean_input(v)
|
456
|
+
data += %|<EntryItem ID="#{n}">#{new_v}</EntryItem>|
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
data += "</Entry>"
|
461
|
+
|
462
|
+
if record_id.nil? then
|
463
|
+
response, data = http.post(URI.escape("/klink/create/#{@@user}:#{@@password}@#{@@ar_server}"), data, headers)
|
464
|
+
else
|
465
|
+
response, data = http.post(URI.escape("/klink/update/#{@@user}:#{@@password}@#{@@ar_server}"), data, headers)
|
466
|
+
end
|
467
|
+
|
468
|
+
xmldoc = Document.new data
|
469
|
+
ret_val = ""
|
470
|
+
|
471
|
+
|
472
|
+
# This is a create - return ID number
|
473
|
+
if record_id.nil? then
|
474
|
+
xmldoc.elements.each('Response/Result/Entry') { |entry|
|
475
|
+
ret_val = entry.attributes['ID'] ||=''
|
476
|
+
}
|
477
|
+
|
478
|
+
raise xmldoc.to_s if ret_val == ''
|
479
|
+
return ret_val
|
480
|
+
end
|
481
|
+
|
482
|
+
# Fall through to update -- were we successful in the actual update?
|
483
|
+
xmldoc.elements.each('Response') { |entry_item|
|
484
|
+
ret_val = entry_item.attributes['Success']
|
485
|
+
# TODO - this will not happen as Klink has a bug in updates
|
486
|
+
# See Redmine#1179
|
487
|
+
if ret_val == 'false' then
|
488
|
+
raise xmldoc.to_s
|
489
|
+
end
|
490
|
+
|
491
|
+
if ret_val == 'true' then
|
492
|
+
|
493
|
+
# Catch bug #1179 -- look for ERROR in message type - if so -- raise an issue
|
494
|
+
xmldoc.elements.each('Response/Messages/Message') {|error_item|
|
495
|
+
if error_item.attributes['Type'] == 'ERROR' then
|
496
|
+
raise xmldoc.to_s
|
497
|
+
end
|
498
|
+
}
|
499
|
+
|
500
|
+
|
501
|
+
end
|
502
|
+
|
503
|
+
|
504
|
+
}
|
505
|
+
|
506
|
+
|
507
|
+
return true
|
508
|
+
|
509
|
+
end
|
510
|
+
|
511
|
+
def self.create(form_name, name_values = nil)
|
512
|
+
self.write(form_name, nil, name_values)
|
513
|
+
end
|
514
|
+
|
515
|
+
def self.update(form_name, record_id, name_values = nil)
|
516
|
+
x = self.write(form_name, record_id, name_values)
|
517
|
+
return x
|
518
|
+
end
|
519
|
+
|
520
|
+
end
|
521
|
+
|
522
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'kinetic', 'link.rb'))
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require File.dirname(__FILE__) +'/../test_helper'
|
2
|
+
|
3
|
+
|
4
|
+
class ConfigurationsTest < Test::Unit::TestCase
|
5
|
+
def test_get_configurations
|
6
|
+
|
7
|
+
assert_nothing_thrown {
|
8
|
+
configs = Kinetic::Link.configurations
|
9
|
+
|
10
|
+
assert_not_nil configs
|
11
|
+
assert_kind_of Hash,configs
|
12
|
+
|
13
|
+
|
14
|
+
}
|
15
|
+
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_get_configuration
|
20
|
+
|
21
|
+
config_name = "HOSTNAME"
|
22
|
+
|
23
|
+
assert_nothing_thrown {
|
24
|
+
config = Kinetic::Link.configurations(config_name)
|
25
|
+
|
26
|
+
assert_not_nil config
|
27
|
+
assert_kind_of Hash,config
|
28
|
+
assert_not_nil config[config_name]
|
29
|
+
assert_kind_of String, config[config_name]
|
30
|
+
|
31
|
+
}
|
32
|
+
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
def test_get_multi_configurations
|
40
|
+
|
41
|
+
config_name = "HOSTNAME,OPERATING_SYSTEM"
|
42
|
+
config_one = "HOSTNAME"
|
43
|
+
|
44
|
+
|
45
|
+
assert_nothing_thrown {
|
46
|
+
config = Kinetic::Link.configurations(config_name)
|
47
|
+
|
48
|
+
assert_not_nil config
|
49
|
+
assert_kind_of Hash,config
|
50
|
+
assert (config.keys.size == 2)
|
51
|
+
assert_not_nil config[config_one]
|
52
|
+
assert_kind_of String, config[config_one]
|
53
|
+
|
54
|
+
}
|
55
|
+
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.dirname(__FILE__) +'/../test_helper'
|
2
|
+
|
3
|
+
class KineticLink_CreateTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_create_simple
|
6
|
+
fields = {'2' => 'Tester', '4' => 'Shayne', '8' => 'Test entry'}
|
7
|
+
assert_nothing_thrown {
|
8
|
+
record = Kinetic::Link.create("KLINK_CanonicalForm", fields)
|
9
|
+
assert_not_nil(record)
|
10
|
+
assert_match(/^\d+$/,record)
|
11
|
+
Kinetic::Link.delete("KLINK_CanonicalForm", record)
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_create_with_missing_required
|
16
|
+
#Missing a required field, 8 is required.
|
17
|
+
fields = {'2' => 'Tester', '4' => 'Shayne','8' => ''}
|
18
|
+
record = nil
|
19
|
+
assert_throws (:runtime_error) {
|
20
|
+
record = Kinetic::Link.create("KLINK_CanonicalForm", fields)
|
21
|
+
}
|
22
|
+
rescue RuntimeError
|
23
|
+
assert_nil(record)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require File.dirname(__FILE__) +'/../test_helper'
|
2
|
+
|
3
|
+
class KineticLink_DeleteTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_delete_simple
|
6
|
+
fields = {'2' => "Klink", '4' => "Shayne", '8' => "Test entry - #{Time.now}"}
|
7
|
+
new_record = Kinetic::Link.create("KLINK_CanonicalForm", fields)
|
8
|
+
success = ''
|
9
|
+
assert_nothing_thrown {
|
10
|
+
success = Kinetic::Link.delete("KLINK_CanonicalForm", new_record)
|
11
|
+
}
|
12
|
+
assert_not_nil(success)
|
13
|
+
assert_match(/^true$/,success)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_delete_record_does_not_exist
|
17
|
+
success = nil
|
18
|
+
assert_nothing_thrown {
|
19
|
+
success = Kinetic::Link.delete("KLINK_CanonicalForm", "DOES_NOT_EXIST")
|
20
|
+
}
|
21
|
+
rescue RuntimeError
|
22
|
+
assert_nil(success)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_delete_record_with_error
|
26
|
+
fields = {'2' => "Klink", '4' => "Shayne", '8' => "No can delete"}
|
27
|
+
#TODO create this filter
|
28
|
+
# this creates a record that will have a filter against it preventing delete
|
29
|
+
new_record = Kinetic::Link.create("KLINK_CanonicalForm", fields)
|
30
|
+
success = nil
|
31
|
+
assert_throws (:runtime_error) {
|
32
|
+
success = Kinetic::Link.delete("KLINK_CanonicalForm", new_record)
|
33
|
+
}
|
34
|
+
rescue RuntimeError
|
35
|
+
assert_nil(success)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.dirname(__FILE__) +'/../test_helper'
|
2
|
+
|
3
|
+
class KineticLink_EntriesTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_entries_simple
|
6
|
+
entries = nil
|
7
|
+
assert_nothing_thrown {
|
8
|
+
entries = Kinetic::Link::entries('User')
|
9
|
+
}
|
10
|
+
assert_not_nil(entries)
|
11
|
+
assert_instance_of(Array,entries)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_entries_param_001
|
15
|
+
entries = nil
|
16
|
+
param = %|'Request ID'!="0"|
|
17
|
+
assert_nothing_thrown {
|
18
|
+
entries = Kinetic::Link::entries('User', param)
|
19
|
+
}
|
20
|
+
assert_not_nil(entries)
|
21
|
+
assert_instance_of(Array,entries)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_entries_param_002
|
25
|
+
entries = nil
|
26
|
+
param = %|'request_id'="000000000000027"|
|
27
|
+
assert_nothing_thrown {
|
28
|
+
entries = Kinetic::Link::entries('User', param)
|
29
|
+
}
|
30
|
+
assert_not_nil(entries)
|
31
|
+
assert_instance_of(Array,entries)
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_entries_param_003
|
35
|
+
entries = nil
|
36
|
+
param = %|1=1|
|
37
|
+
assert_nothing_thrown {
|
38
|
+
entries = Kinetic::Link::entries('User', param)
|
39
|
+
}
|
40
|
+
assert_not_nil(entries)
|
41
|
+
assert_instance_of(Array,entries)
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|