klink-ruby-api 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|