oats 0.0.1
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/.gitignore +6 -0
- data/Gemfile +15 -0
- data/README.txt +165 -0
- data/Rakefile +2 -0
- data/bin/agent +204 -0
- data/bin/oats +10 -0
- data/bin/occ +29 -0
- data/bin/results_cleanup +6 -0
- data/doc/COPYING +55 -0
- data/doc/LICENSE +55 -0
- data/doc/OATS_Framework.doc +0 -0
- data/doc/classes/ApplicationLogs.html +239 -0
- data/doc/classes/Campaign.html +843 -0
- data/doc/classes/CommandlineOptions.html +131 -0
- data/doc/classes/Driver.html +182 -0
- data/doc/classes/Hash.html +137 -0
- data/doc/classes/Ide.html +194 -0
- data/doc/classes/MapSelenium.html +197 -0
- data/doc/classes/Net.html +107 -0
- data/doc/classes/Oats/OatsFilterError.html +119 -0
- data/doc/classes/Oats.html +998 -0
- data/doc/classes/OatsAssertError.html +119 -0
- data/doc/classes/OatsBadInput.html +119 -0
- data/doc/classes/OatsData.html +290 -0
- data/doc/classes/OatsError.html +117 -0
- data/doc/classes/OatsExit.html +117 -0
- data/doc/classes/OatsLock.html +254 -0
- data/doc/classes/OatsMain.html +182 -0
- data/doc/classes/OatsMysqlError.html +113 -0
- data/doc/classes/OatsMysqlMissingInput.html +113 -0
- data/doc/classes/OatsReportError.html +113 -0
- data/doc/classes/OatsSetupError.html +119 -0
- data/doc/classes/OatsTestError.html +119 -0
- data/doc/classes/OatsTestExit.html +119 -0
- data/doc/classes/OatsTestLocateError.html +120 -0
- data/doc/classes/OatsVerifyError.html +119 -0
- data/doc/classes/Ragent.html +397 -0
- data/doc/classes/Rclient.html +236 -0
- data/doc/classes/Report.html +368 -0
- data/doc/classes/Reports.html +244 -0
- data/doc/classes/RestApi.html +333 -0
- data/doc/classes/RhttpClient.html +236 -0
- data/doc/classes/Rimap.html +170 -0
- data/doc/classes/Rmysql.html +176 -0
- data/doc/classes/Roptions.html +131 -0
- data/doc/classes/Rselenium.html +233 -0
- data/doc/classes/Rssh.html +138 -0
- data/doc/classes/Runnable.html +174 -0
- data/doc/classes/SFTriggers.html +206 -0
- data/doc/classes/Selenium/Client/Driver.html +211 -0
- data/doc/classes/Selenium/Client.html +107 -0
- data/doc/classes/Selenium.html +107 -0
- data/doc/classes/SystemCapture.html +304 -0
- data/doc/classes/TestCase.html +418 -0
- data/doc/classes/TestData.html +235 -0
- data/doc/classes/TestList.html +264 -0
- data/doc/classes/Tools.html +244 -0
- data/doc/classes/Util.html +201 -0
- data/doc/classes/Variation.html +206 -0
- data/doc/fr_class_index.html +92 -0
- data/doc/fr_method_index.html +465 -0
- data/doc/index.html +23 -0
- data/doc/oats_httpd.conf +32 -0
- data/doc/oats_user.yml +25 -0
- data/doc/rdoc-style.css +208 -0
- data/lib/deep_merge/.gitignore +2 -0
- data/lib/deep_merge/core.rb +195 -0
- data/lib/deep_merge/deep_merge.rb +1 -0
- data/lib/deep_merge/deep_merge_hash.rb +28 -0
- data/lib/deep_merge/rails_compat.rb +27 -0
- data/lib/oats/application_logs.rb +163 -0
- data/lib/oats/build_id.rb +58 -0
- data/lib/oats/commandline_options.rb +128 -0
- data/lib/oats/diff.rb +278 -0
- data/lib/oats/driver.rb +492 -0
- data/lib/oats/ide.rb +227 -0
- data/lib/oats/keywords.rb +67 -0
- data/lib/oats/log4r_init.rb +14 -0
- data/lib/oats/mysql.rb +97 -0
- data/lib/oats/oats.rb +637 -0
- data/lib/oats/oats_data.rb +400 -0
- data/lib/oats/oats_exceptions.rb +25 -0
- data/lib/oats/oats_lock.rb +261 -0
- data/lib/oats/oats_selenium_api.rb +639 -0
- data/lib/oats/oselenium.rb +189 -0
- data/lib/oats/ossh.rb +36 -0
- data/lib/oats/patches_for_eventmachine_12.10.rb +66 -0
- data/lib/oats/ragent.rb +321 -0
- data/lib/oats/rclient.rb +42 -0
- data/lib/oats/report.rb +207 -0
- data/lib/oats/roptions.rb +88 -0
- data/lib/oats/test_case.rb +510 -0
- data/lib/oats/test_data.rb +98 -0
- data/lib/oats/test_list.rb +141 -0
- data/lib/oats/unixdiff.rb +75 -0
- data/lib/oats/util.rb +125 -0
- data/lib/oats/version.rb +3 -0
- data/lib/oats.rb +36 -0
- data/nbproject/configs/agent.properties +0 -0
- data/nbproject/configs/gr.properties +0 -0
- data/nbproject/project.properties +10 -0
- data/nbproject/project.xml +17 -0
- data/oats.gemspec +42 -0
- data/oats_ini.yml +258 -0
- data/oats_tests/Gemfile +18 -0
- data/oats_tests/aut_ini.yml +30 -0
- data/oats_tests/bin/oats +8 -0
- data/oats_tests/environments/qa.yml +4 -0
- data/oats_tests/environments/qa_chrome.yml +4 -0
- data/oats_tests/examples/core/coreExamples.yml +8 -0
- data/oats_tests/examples/core/expectedException.rb +39 -0
- data/oats_tests/examples/core/ok_verify.rb +2 -0
- data/oats_tests/examples/core/ok_verify.rb_ok/out/myfile.txt +1 -0
- data/oats_tests/examples/core/ok_verify.rb_ok/out/myfile2.txt +1 -0
- data/oats_tests/examples/core/ok_verify.rb_ok/rats_test.log +2 -0
- data/oats_tests/examples/core/unexpectedException.rb +30 -0
- data/oats_tests/examples/examples.yml +13 -0
- data/oats_tests/examples/gui/guiExamples.yml +7 -0
- data/oats_tests/examples/gui/seleniumGoogle.rb +10 -0
- data/oats_tests/examples/gui/webdriverGoogle.rb +9 -0
- data/oats_tests/examples/keywords/SampleXlList-1.xls +0 -0
- data/oats_tests/examples/keywords/SampleXlList-2.xls +0 -0
- data/oats_tests/examples/keywords/SampleXlLists.xls +0 -0
- data/oats_tests/examples/keywords/keywordsDriver.rb +1 -0
- data/oats_tests/examples/keywords/keywordsExamples.yml +8 -0
- data/oats_tests/examples/keywords/keywordsTC1.yml +5 -0
- data/oats_tests/examples/keywords/keywordsTestlist.yml +16 -0
- data/oats_tests/examples/needsWork/addTestDynamically.rb +4 -0
- data/oats_tests/examples/needsWork/emailVerify.rb +34 -0
- data/oats_tests/examples/needsWork/testSql/rtest.sql +6 -0
- data/oats_tests/examples/needsWork/testSql/rtest.yml +11 -0
- data/oats_tests/examples/occTest/occTest.rb +13 -0
- data/oats_tests/examples/occTest/occTest_1.rb +1 -0
- data/oats_tests/examples/occTest/occTest_1_1.rb +1 -0
- data/oats_tests/examples/occTest/occTest_1_2.rb +1 -0
- data/oats_tests/examples/occTest/occTest_1_3.rb +1 -0
- data/oats_tests/examples/occTest/occTest_1_4.rb +1 -0
- data/oats_tests/examples/occTest/occTest_2.rb +1 -0
- data/oats_tests/examples/occTest/occTest_2_1.rb +1 -0
- data/oats_tests/examples/occTest/occTest_2_2.rb +1 -0
- data/oats_tests/examples/occTest/occTest_2_3.rb +1 -0
- data/oats_tests/examples/occTest/occTest_2_4.rb +1 -0
- data/oats_tests/examples/occTest/occTest_3.rb +1 -0
- data/oats_tests/examples/occTest/occTest_3_1.rb +1 -0
- data/oats_tests/examples/occTest/occTest_3_2.rb +1 -0
- data/oats_tests/examples/occTest/occTest_3_3.rb +1 -0
- data/oats_tests/examples/occTest/occTest_3_4.rb +1 -0
- data/oats_tests/examples/occTest/occTest_4.rb +1 -0
- data/oats_tests/examples/occTest/occTestlist.yml +9 -0
- data/oats_tests/examples/occTest/occTestlist_1.yml +9 -0
- data/oats_tests/examples/occTest/occTestlist_2.yml +9 -0
- data/oats_tests/examples/occTest/occTestlist_3.yml +9 -0
- data/oats_tests/examples/occTest/variation1.yml +4 -0
- data/oats_tests/examples/occTest/variation2.yml +4 -0
- data/oats_tests/examples/testFileLocationUnitTests/extn_driver.rb +4 -0
- data/oats_tests/examples/testFileLocationUnitTests/folder/oats.yml +3 -0
- data/oats_tests/examples/testFileLocationUnitTests/folder/t1.rb +2 -0
- data/oats_tests/examples/testFileLocationUnitTests/folder1/t1.yml +2 -0
- data/oats_tests/examples/testFileLocationUnitTests/folder1/t1_1.yml +3 -0
- data/oats_tests/examples/testFileLocationUnitTests/folder2/oats.yml +3 -0
- data/oats_tests/examples/testFileLocationUnitTests/folder2/t1.rb +2 -0
- data/oats_tests/examples/testFileLocationUnitTests/folder2/t1.yml +2 -0
- data/oats_tests/examples/testFileLocationUnitTests/no_yaml.rb +3 -0
- data/oats_tests/examples/testFileLocationUnitTests/post_yaml.rb +1 -0
- data/oats_tests/examples/testFileLocationUnitTests/t1.rb +4 -0
- data/oats_tests/examples/testFileLocationUnitTests/t1.yml +2 -0
- data/oats_tests/examples/testFileLocationUnitTests/t1_1.yml +3 -0
- data/oats_tests/examples/testFileLocationUnitTests/testDir/oats.yml +3 -0
- data/oats_tests/examples/testFileLocationUnitTests/testDir/t1.rb +2 -0
- data/oats_tests/examples/testFileLocationUnitTests/testDir/t1.yml +2 -0
- data/oats_tests/examples/testFileLocationUnitTests/testDir2/t1.rb +2 -0
- data/oats_tests/examples/testFileLocationUnitTests/testDir2/t1.yml +2 -0
- data/oats_tests/examples/testFileLocationUnitTests/unitTestList.yml +36 -0
- data/oats_tests/examples/testFileLocationUnitTests/yml_driver.rb +2 -0
- data/oats_tests/lib/business.rb +28 -0
- data/oats_tests/lib/sample_xl_lists.rb +37 -0
- data/test/common_test_unit_setup.rb +21 -0
- data/test/test_basic.rb +16 -0
- data/test/test_selenium.rb +16 -0
- data/test/test_xl_lists.rb +16 -0
- metadata +291 -0
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
#require 'yaml' # http://www.ruby-doc.org/core/classes/YAML.html
|
|
2
|
+
module Oats
|
|
3
|
+
|
|
4
|
+
# Keeps history of YAML files loaded into the global $oats.
|
|
5
|
+
# if omit is true add the yaml name into the result directory hierarchy
|
|
6
|
+
class OatsDataLoadHistoryItem
|
|
7
|
+
attr_accessor :file, :omit, :in_result_dir
|
|
8
|
+
def initialize(file, omit = false)
|
|
9
|
+
@file = file
|
|
10
|
+
@omit = omit
|
|
11
|
+
@in_result_dir = true
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class OatsData
|
|
16
|
+
@@oats_def_file = nil
|
|
17
|
+
@@resolve_path = []
|
|
18
|
+
# Resolves ENV[ entries in a oats_data
|
|
19
|
+
def OatsData.resolve(oats_data = nil)
|
|
20
|
+
oats_data = $oats unless oats_data
|
|
21
|
+
changed = false
|
|
22
|
+
oats_data.each do |key, val|
|
|
23
|
+
if val.instance_of?(String)
|
|
24
|
+
begin
|
|
25
|
+
next unless /Oats\.|ENV\[/ =~ val # skip if no need for change
|
|
26
|
+
new_val = eval(val)
|
|
27
|
+
next if new_val.instance_of?(String) and /Oats\.|ENV\[/ =~ new_val # skip if change did not help
|
|
28
|
+
# new_key = key.sub(/\s*\(wait4definition\)\s*/,'')
|
|
29
|
+
# next unless new_key == key or new_val # skip if wait4defs in effect
|
|
30
|
+
# oats_data[new_key] = new_val
|
|
31
|
+
oats_data[key] = if new_val == 'previous_oats_value'
|
|
32
|
+
oc = @@oats_copy
|
|
33
|
+
@@resolve_path.each { |k| oc = oc[k] }
|
|
34
|
+
oc[key]
|
|
35
|
+
else
|
|
36
|
+
new_val
|
|
37
|
+
end
|
|
38
|
+
changed = true
|
|
39
|
+
# oats_data.delete(key) unless new_key == key
|
|
40
|
+
rescue Exception =>e
|
|
41
|
+
$log.error "While evaluating Oats.data #{key}: #{val}"
|
|
42
|
+
raise e
|
|
43
|
+
end
|
|
44
|
+
elsif val.instance_of?(Array)
|
|
45
|
+
val.each_with_index do | item, index |
|
|
46
|
+
if item.instance_of?(String)
|
|
47
|
+
begin
|
|
48
|
+
next unless /Oats\.|ENV\[/ =~ item # skip if no need for change
|
|
49
|
+
new_val = eval(item)
|
|
50
|
+
next if /Oats\.|ENV\[/ =~ new_val # skip if change did not help
|
|
51
|
+
val[index] = if new_val == 'previous_oats_value'
|
|
52
|
+
oc = @@oats_copy
|
|
53
|
+
@@resolve_path.each { |k| oc = oc[k] }
|
|
54
|
+
oc[key]
|
|
55
|
+
else
|
|
56
|
+
new_val
|
|
57
|
+
end
|
|
58
|
+
changed = true
|
|
59
|
+
rescue Exception =>exc
|
|
60
|
+
$log.error "While evaluating [#{item}] for [#{index}]th entry in Rat.data #{key}: #{val}"
|
|
61
|
+
raise exc
|
|
62
|
+
end
|
|
63
|
+
elsif item.instance_of?(Hash)
|
|
64
|
+
begin
|
|
65
|
+
@@resolve_path.push(key)
|
|
66
|
+
res_return = resolve(item)
|
|
67
|
+
ensure
|
|
68
|
+
@@resolve_path.pop
|
|
69
|
+
end
|
|
70
|
+
changed = res_return || changed
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
elsif val.instance_of?(Hash)
|
|
74
|
+
begin
|
|
75
|
+
@@resolve_path.push(key)
|
|
76
|
+
res_return = resolve(val)
|
|
77
|
+
ensure
|
|
78
|
+
@@resolve_path.pop
|
|
79
|
+
end
|
|
80
|
+
changed = res_return || changed
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
while changed
|
|
84
|
+
changed = resolve(oats_data)
|
|
85
|
+
end
|
|
86
|
+
changed
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# If no input, use default YAML file, overridden by user's HOME or OATS_INI
|
|
90
|
+
# Specified oats_file becomes the overriding file.
|
|
91
|
+
# If specified, oats_default data is used instead of the default YAML contents.
|
|
92
|
+
# Returns loaded data in $oats
|
|
93
|
+
@@define_always = nil
|
|
94
|
+
def OatsData.load(oats_file = ENV['OATS_INI'] , oats_default = nil)
|
|
95
|
+
@@define_always = nil
|
|
96
|
+
@@oats_def_file ||= ENV['OATS_HOME'] + '/oats_ini.yml'
|
|
97
|
+
|
|
98
|
+
if oats_file
|
|
99
|
+
raise(OatsError, "Can not locate: #{oats_file}") unless File.exist?(oats_file)
|
|
100
|
+
else
|
|
101
|
+
oats_file = ENV['HOME'] ? File.join( ENV['HOME'] , 'oats_user.yml') : nil
|
|
102
|
+
oats_file = nil unless oats_file and File.exist?(oats_file)
|
|
103
|
+
end
|
|
104
|
+
if oats_file
|
|
105
|
+
begin
|
|
106
|
+
oats_data = YAML.load_file(oats_file)
|
|
107
|
+
rescue
|
|
108
|
+
raise(OatsError, "While loading [#{oats_file}] " + $!)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
if oats_default # make a deep copy
|
|
113
|
+
oats_default = Marshal.load(Marshal.dump(oats_default))
|
|
114
|
+
else # Only the first time, when reading the _ini files
|
|
115
|
+
begin
|
|
116
|
+
oats_default = YAML.load_file(@@oats_def_file)
|
|
117
|
+
rescue
|
|
118
|
+
raise(OatsError,"Error loading [#{@@oats_def_file}]: " + $!)
|
|
119
|
+
end
|
|
120
|
+
$oats = oats_default # So that resolve can resolve Oats.data calls
|
|
121
|
+
begin
|
|
122
|
+
OatsData.resolve(oats_default)
|
|
123
|
+
rescue
|
|
124
|
+
$log.error "While resolving variables in: " + @@oats_def_file
|
|
125
|
+
# raise(OatsError, $!.to_s)
|
|
126
|
+
raise $!
|
|
127
|
+
end
|
|
128
|
+
# Use this hash to persist internally used oats_data
|
|
129
|
+
oats_default['_'] = {}
|
|
130
|
+
oats_default['_']['load_history'] = [ OatsDataLoadHistoryItem.new(@@oats_def_file) ]
|
|
131
|
+
$oats = oats_default # $oats now has data resolved and has load_history
|
|
132
|
+
# For some reason OCC/Ubuntu needed the environment but not Mac
|
|
133
|
+
aut_dir_test = ENV['OATS_TESTS'] || oats_data['execution']['dir_tests'] || oats_default['execution']['dir_tests']
|
|
134
|
+
if aut_dir_test
|
|
135
|
+
aut_ini = aut_dir_test + '/aut_ini.yml'
|
|
136
|
+
oats_default['include_yaml'] ||= aut_ini if File.exists?(aut_ini)
|
|
137
|
+
end
|
|
138
|
+
OatsData.include_yaml_file(oats_default['include_yaml'], @@oats_def_file) if oats_default['include_yaml']
|
|
139
|
+
oats_default = $oats
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
if oats_data
|
|
143
|
+
incl_yamls = oats_data['include_yaml']
|
|
144
|
+
if incl_yamls and not oats_data['include_yaml_later']
|
|
145
|
+
oats_data['include_yaml'] = nil
|
|
146
|
+
OatsData.include_yaml_file(incl_yamls, oats_file)
|
|
147
|
+
end
|
|
148
|
+
begin
|
|
149
|
+
@@oats_copy = Marshal.load(Marshal.dump($oats))
|
|
150
|
+
merged = OatsData.merge($oats,oats_data)
|
|
151
|
+
rescue OatsError
|
|
152
|
+
$log.error "While merging: " + oats_file
|
|
153
|
+
raise(OatsError, $!.to_s)
|
|
154
|
+
rescue
|
|
155
|
+
$log.error "While merging: " + oats_file
|
|
156
|
+
raise
|
|
157
|
+
end
|
|
158
|
+
merged['_']['load_history'] << OatsDataLoadHistoryItem.new(oats_file)
|
|
159
|
+
$oats = merged
|
|
160
|
+
if incl_yamls and oats_data['include_yaml_later']
|
|
161
|
+
merged['include_yaml'] = nil
|
|
162
|
+
OatsData.include_yaml_file(incl_yamls, oats_file)
|
|
163
|
+
end
|
|
164
|
+
begin
|
|
165
|
+
OatsData.resolve(merged)
|
|
166
|
+
rescue
|
|
167
|
+
$log.error "While resolving variables in: " + oats_file
|
|
168
|
+
raise $!
|
|
169
|
+
end
|
|
170
|
+
result = $oats
|
|
171
|
+
else
|
|
172
|
+
$log.warn("Could not find oats-user.yml via OATS_INI or HOME definition. Using the system default.")
|
|
173
|
+
result = oats_default
|
|
174
|
+
end
|
|
175
|
+
return result
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
@@include_hist = []
|
|
179
|
+
# Handles include_yaml files. Calls OatsData.overlay to modify $oats. Returns nothing.
|
|
180
|
+
def OatsData.include_yaml_file(incl_yamls, oats_file = nil)
|
|
181
|
+
return unless incl_yamls
|
|
182
|
+
if incl_yamls
|
|
183
|
+
incl_yamls = [incl_yamls] if incl_yamls.instance_of?(String)
|
|
184
|
+
incl_yamls.each do |incl_yaml|
|
|
185
|
+
begin
|
|
186
|
+
incl_yaml_file = TestData.locate(incl_yaml, File.dirname(oats_file))
|
|
187
|
+
Oats.assert incl_yaml_file, "Can not locate file: #{incl_yaml}"
|
|
188
|
+
|
|
189
|
+
hist = Oats.data['_']['load_history'].collect{|i| i.file} + @@include_hist
|
|
190
|
+
Oats.assert ! hist.include?(incl_yaml_file), "Attempt to re-include #{incl_yaml_file} into #{hist.inspect}"
|
|
191
|
+
begin
|
|
192
|
+
@@include_hist.push(incl_yaml_file)
|
|
193
|
+
OatsData.overlay(incl_yaml_file)
|
|
194
|
+
ensure
|
|
195
|
+
Oats.assert_equal incl_yaml_file, @@include_hist.pop
|
|
196
|
+
end
|
|
197
|
+
rescue
|
|
198
|
+
msg = "While including [#{incl_yaml}]"
|
|
199
|
+
msg += " from: " + oats_file if oats_file
|
|
200
|
+
# raise(OatsError, msg + $!)
|
|
201
|
+
$log.error msg
|
|
202
|
+
raise $!
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
return
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Returns Oats.data history files in an array.
|
|
210
|
+
def OatsData.history(omit=false)
|
|
211
|
+
if omit
|
|
212
|
+
Oats.data['_']['load_history'].select{|i| i.omit and i.in_result_dir}.collect{|i| i.file}
|
|
213
|
+
else
|
|
214
|
+
Oats.data['_']['load_history'].collect{|i| i.file}
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Overrides config_ini hash tree with custom_ini.
|
|
219
|
+
# At each level keep only the items specified by the include_list array
|
|
220
|
+
def OatsData.merge(config_ini, custom_ini)
|
|
221
|
+
merged_config = config_ini
|
|
222
|
+
raise(OatsError, "Original YAML is not a hash: " + config_ini.inspect) unless config_ini.class == Hash
|
|
223
|
+
return config_ini unless custom_ini # If input YAML is empty
|
|
224
|
+
raise(OatsError, "Override YAML is not a hash: " + custom_ini.inspect) unless custom_ini.class == Hash
|
|
225
|
+
include_array = []
|
|
226
|
+
include_list_exists = false
|
|
227
|
+
@@define_always = custom_ini['define_always'] if custom_ini.include?('define_always')
|
|
228
|
+
custom_ini.each do |key, val|
|
|
229
|
+
if config_ini.has_key?(key)
|
|
230
|
+
old_val = config_ini[key]
|
|
231
|
+
unless old_val.nil? or val.nil?
|
|
232
|
+
if (old_val.class != val.class)
|
|
233
|
+
if val.instance_of?(FalseClass) # If new value is different and false set it to nil
|
|
234
|
+
val = nil
|
|
235
|
+
elsif not ( (val.instance_of?(TrueClass) or val.instance_of?(FalseClass)) and
|
|
236
|
+
(old_val.instance_of?(TrueClass) or old_val.instance_of?(FalseClass)) )
|
|
237
|
+
$log.error "Entry [#{key}] was previously set to [#{old_val}] with type [" + old_val.class.to_s + "]"
|
|
238
|
+
$log.error " now being set to [#{val}] with type [" + val.class.to_s + "]"
|
|
239
|
+
$log.error " entry [#{old_val}] of the original YAML entry is part of: " + config_ini.inspect
|
|
240
|
+
$log.error " entry [#{val}] of over-ride YAML entry is part of: " + custom_ini.inspect
|
|
241
|
+
raise(OatsError, "Attempt to override OATS data with a different type.")
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
else
|
|
246
|
+
if key == "include_list"
|
|
247
|
+
raise(OatsError, "The include_list " + val.inspect + " is not an Array") unless val.class == Array
|
|
248
|
+
include_array = val
|
|
249
|
+
include_list_exists = true
|
|
250
|
+
else
|
|
251
|
+
add_key = key.sub(/\s*\(define\)\s*/,'')
|
|
252
|
+
if add_key == key and ! @@define_always
|
|
253
|
+
raise(OatsError, "Override YAML key [#{key}] is not defined in the master YAML: " + @@oats_def_file)
|
|
254
|
+
else
|
|
255
|
+
if merged_config.has_key?(add_key)
|
|
256
|
+
key = add_key
|
|
257
|
+
old_val = config_ini[key]
|
|
258
|
+
else
|
|
259
|
+
merged_config[add_key] = val
|
|
260
|
+
merged_config.delete(key) unless add_key == key
|
|
261
|
+
next
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
case val
|
|
267
|
+
when Hash then merged_config[key] = merge( old_val, val) # Deep copy for Hashes
|
|
268
|
+
when Array then # Only shallow copy for Arrays
|
|
269
|
+
new_arr = []
|
|
270
|
+
val.each { |e| new_arr << e }
|
|
271
|
+
merged_config[key] = new_arr
|
|
272
|
+
when String then merged_config[key] = val.dup
|
|
273
|
+
else
|
|
274
|
+
unless (val.nil? and (old_val.class == Hash) ) || key == "include_list"
|
|
275
|
+
merged_config[key] = val
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
if include_list_exists
|
|
280
|
+
return nil if include_array.nil?
|
|
281
|
+
merged_config.delete_if { |key,value| not include_array.include?(key) }
|
|
282
|
+
end
|
|
283
|
+
merged_config
|
|
284
|
+
end
|
|
285
|
+
# Overlays $oats with contents of oats_file. Performs no compatibility checking.
|
|
286
|
+
def OatsData.overlay(oats_file)
|
|
287
|
+
if oats_file.instance_of?(Hash)
|
|
288
|
+
oats_overlay = oats_file
|
|
289
|
+
oats_file = oats_overlay.keys.first + '_' + oats_overlay.values.first.keys.first
|
|
290
|
+
else
|
|
291
|
+
if oats_file
|
|
292
|
+
raise(OatsError, "Can not locate [#{oats_file}]") unless File.exist?(oats_file)
|
|
293
|
+
else
|
|
294
|
+
raise(OatsError, "Must specify a oats_file")
|
|
295
|
+
end
|
|
296
|
+
begin
|
|
297
|
+
oats_overlay = YAML.load_file(oats_file)
|
|
298
|
+
rescue
|
|
299
|
+
raise(OatsError, "While loading [#{oats_file}] " + $!)
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
incl_yamls = oats_overlay['include_yaml']
|
|
303
|
+
if incl_yamls and not oats_overlay['include_yaml_later']
|
|
304
|
+
oats_overlay['include_yaml'] = nil
|
|
305
|
+
OatsData.include_yaml_file(incl_yamls, oats_file)
|
|
306
|
+
end
|
|
307
|
+
# Clone it, don't change the original
|
|
308
|
+
oats_new = Marshal.load(Marshal.dump($oats))
|
|
309
|
+
begin
|
|
310
|
+
OatsData.overlay_data(oats_overlay, oats_new)
|
|
311
|
+
rescue OatsError
|
|
312
|
+
$log.error "While overlaying: " + oats_file
|
|
313
|
+
raise(OatsError, $!.to_s)
|
|
314
|
+
rescue Exception
|
|
315
|
+
$log.error "While overlaying: " + oats_file
|
|
316
|
+
raise
|
|
317
|
+
end
|
|
318
|
+
oats_new['_']['load_history'] << OatsDataLoadHistoryItem.new(oats_file)
|
|
319
|
+
|
|
320
|
+
$oats = oats_new
|
|
321
|
+
if incl_yamls and oats_overlay['include_yaml_later']
|
|
322
|
+
oats_overlay['include_yaml'] = nil
|
|
323
|
+
OatsData.include_yaml_file(incl_yamls, oats_file)
|
|
324
|
+
end
|
|
325
|
+
begin
|
|
326
|
+
OatsData.resolve(oats_new)
|
|
327
|
+
rescue
|
|
328
|
+
$log.error "While resolving variables in: " + oats_file
|
|
329
|
+
raise $!
|
|
330
|
+
end
|
|
331
|
+
oats_new = $oats
|
|
332
|
+
return oats_new
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
# Recurse thru matching hash only, replace rest by overlay
|
|
336
|
+
def OatsData.overlay_data(overlay, oats_data)
|
|
337
|
+
overlay.each do |key, val|
|
|
338
|
+
default_key = key.sub(/\s*\((default|define)\)\s*/,'')
|
|
339
|
+
if default_key == key
|
|
340
|
+
default_key = nil
|
|
341
|
+
else
|
|
342
|
+
key = default_key
|
|
343
|
+
end
|
|
344
|
+
if val.instance_of?(Hash)
|
|
345
|
+
if oats_data[key].instance_of?(Hash)
|
|
346
|
+
OatsData.overlay_data(val, oats_data[key])
|
|
347
|
+
else
|
|
348
|
+
oats_data[key] = val if oats_data[key] == nil
|
|
349
|
+
OatsData.overlay_data(val, oats_data[key])
|
|
350
|
+
end
|
|
351
|
+
else
|
|
352
|
+
if default_key
|
|
353
|
+
oats_data[key] = val unless oats_data[key]
|
|
354
|
+
else
|
|
355
|
+
oats_data[key] = val
|
|
356
|
+
end
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
# Regenerates input file based on YAML. Assumes input is absolute path and exists.
|
|
362
|
+
# Return generated file path or nil if nothing is generated.
|
|
363
|
+
def OatsData.regenerate_file(file_in)
|
|
364
|
+
file_in_root = file_in.sub(/(.*)\..*$/,'\1')
|
|
365
|
+
file_in_extn = File.extname(file_in)
|
|
366
|
+
yaml_in = file_in_root + '.yml'
|
|
367
|
+
return nil unless File.exist?(yaml_in)
|
|
368
|
+
file_gen = file_in_root + '.gen' + file_in_extn
|
|
369
|
+
yml_out = file_in_root + '.gen.yml'
|
|
370
|
+
$log.debug "Regenerating [#{file_in}] into [#{file_gen}] based on [#{yaml_in}]"
|
|
371
|
+
file_contents = IO.read(file_in)
|
|
372
|
+
test_data = YAML.load_file(yaml_in)
|
|
373
|
+
if OatsData.map_file_contents(Oats.data, test_data, file_contents)
|
|
374
|
+
File.open( file_gen, 'w' ) { |out| out.print file_contents }
|
|
375
|
+
File.open( yml_out, 'w' ) { |out| YAML.dump( test_data, out ) }
|
|
376
|
+
return file_gen
|
|
377
|
+
else
|
|
378
|
+
return nil
|
|
379
|
+
end
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
# Helper method to replace HTML file contents based on oats and test data mappings.
|
|
383
|
+
# Returns true if substitutions are made
|
|
384
|
+
def OatsData.map_file_contents(oats_data, test_data, file_contents)
|
|
385
|
+
return false unless test_data
|
|
386
|
+
changed = false
|
|
387
|
+
test_data.each do |key,val|
|
|
388
|
+
repVal = oats_data[key]
|
|
389
|
+
next if val.nil? or repVal.nil?
|
|
390
|
+
if val.class == Hash
|
|
391
|
+
changed = changed or map_file_contents( repVal, val, file_contents)
|
|
392
|
+
else
|
|
393
|
+
changed = changed or file_contents.sub!(val, repVal)
|
|
394
|
+
test_data[key] = repVal
|
|
395
|
+
end
|
|
396
|
+
end
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
end
|
|
400
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Defines general exception classes used in OATS.
|
|
2
|
+
|
|
3
|
+
# Not an error, but a request to exit gracefully from deep within OATS code.
|
|
4
|
+
class OatsExit < StandardError ; end
|
|
5
|
+
|
|
6
|
+
# Unclassified exceptions used by OATS framework
|
|
7
|
+
class OatsError < StandardError ; end
|
|
8
|
+
|
|
9
|
+
# Errors related to Oats Setup
|
|
10
|
+
class OatsSetupError < OatsError ; end
|
|
11
|
+
|
|
12
|
+
# Commandline or related oats-user.yml value errors
|
|
13
|
+
class OatsBadInput < OatsError ; end
|
|
14
|
+
|
|
15
|
+
# Assertion of failure of an individual OATS test
|
|
16
|
+
class OatsTestError < OatsError ; end
|
|
17
|
+
|
|
18
|
+
# Raised by Oats.assert_* methods
|
|
19
|
+
class OatsAssertError < OatsTestError ; end
|
|
20
|
+
|
|
21
|
+
# Assertion of failure during verification of test output
|
|
22
|
+
class OatsVerifyError < OatsTestError ; end
|
|
23
|
+
|
|
24
|
+
# Not an error, but a way to escape a OatsTest from the middle of it.
|
|
25
|
+
class OatsTestExit < OatsTestError ; end
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# Manages a lock file indicating a OATS session is in process
|
|
2
|
+
require 'win32ole' if ENV['OS'] == 'Windows_NT'
|
|
3
|
+
module Oats
|
|
4
|
+
|
|
5
|
+
module OatsLock
|
|
6
|
+
@@file_handle = nil
|
|
7
|
+
@@is_locked = false
|
|
8
|
+
|
|
9
|
+
# Returns true if able to set the lock.
|
|
10
|
+
def OatsLock.set(verbose = nil)
|
|
11
|
+
if OatsLock.locked?(true)
|
|
12
|
+
return false
|
|
13
|
+
else
|
|
14
|
+
@@file_handle = File.open(in_progress_file, 'w')
|
|
15
|
+
my_pid = Process.pid.to_s
|
|
16
|
+
@@file_handle.puts my_pid
|
|
17
|
+
if ENV['OS'] != 'Windows_NT' or ENV['TEMP'] =~ /^\/cygdrive/
|
|
18
|
+
# Leave file handle open for windows to detect and kill associated java, etc.
|
|
19
|
+
# processes using file handles.
|
|
20
|
+
@@file_handle.close
|
|
21
|
+
@@file_handle = nil
|
|
22
|
+
end
|
|
23
|
+
@@is_locked = true
|
|
24
|
+
return true
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Returns the locked state after the last check
|
|
29
|
+
# verify: true will verify the true state of the lock
|
|
30
|
+
def OatsLock.locked?(verify = nil)
|
|
31
|
+
return @@is_locked unless verify
|
|
32
|
+
@@is_locked = false
|
|
33
|
+
if ENV['OS'] != 'Windows_NT' or ENV['TEMP'] =~ /^\/cygdrive/
|
|
34
|
+
if File.exist?(in_progress_file)
|
|
35
|
+
pids = IO.readlines(in_progress_file)
|
|
36
|
+
ruby_pid = pids.shift
|
|
37
|
+
return @@is_locked unless ruby_pid
|
|
38
|
+
ps_line = `ps -p #{ruby_pid} `
|
|
39
|
+
if ps_line =~ /bin\/ruby/
|
|
40
|
+
@@is_locked = true
|
|
41
|
+
$log.error "Another oats session is possibly in progress:"
|
|
42
|
+
$log.error ">> #{ps_line}"
|
|
43
|
+
$log.error "Please kill locking processes or remove #{in_progress_file}."
|
|
44
|
+
else
|
|
45
|
+
pids.each { |pid| OatsLock.kill_pid(pid.chomp) }
|
|
46
|
+
FileUtils.rm(in_progress_file)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
else
|
|
50
|
+
begin
|
|
51
|
+
FileUtils.rm(in_progress_file)
|
|
52
|
+
rescue Errno::ENOENT # No such File or Directory
|
|
53
|
+
rescue Errno::EACCES # unlink Permission denied
|
|
54
|
+
@@is_locked = true
|
|
55
|
+
return @@is_locked if verify == :handles_are_cleared
|
|
56
|
+
# Attempt to kill all dangling processes that prevent removal of the lock
|
|
57
|
+
proc_array = nil
|
|
58
|
+
hstring = lock_file
|
|
59
|
+
ok_to_kill = /(java)|(mysql)||(chromedriver)|(firefox)||(chrome)|(iexplore)\.exe/
|
|
60
|
+
pid, proc_name, handle_string, line = nil
|
|
61
|
+
matches = IO.popen("handle #{hstring}").readlines
|
|
62
|
+
oats_is_alive = false
|
|
63
|
+
matches.each do |lvar|
|
|
64
|
+
line = lvar.chomp
|
|
65
|
+
proc_array = parse_windows_handle_process_line(line)
|
|
66
|
+
pid, proc_name, handle_string = proc_array
|
|
67
|
+
next unless pid
|
|
68
|
+
if proc_name =~ /ruby/
|
|
69
|
+
# if pid = $$.to_s
|
|
70
|
+
# @@is_locked = false
|
|
71
|
+
# return false
|
|
72
|
+
# end
|
|
73
|
+
oats_is_alive = line
|
|
74
|
+
$log.error "Another oats session is possibly in progress:"
|
|
75
|
+
$log.error ">> #{line}"
|
|
76
|
+
$log.error "Please kill locking processes and remove this file if the oats session is defunct."
|
|
77
|
+
break
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
@@is_locked = oats_is_alive
|
|
81
|
+
unless oats_is_alive
|
|
82
|
+
matches.each do |lvar|
|
|
83
|
+
line = lvar.chomp
|
|
84
|
+
pid, proc_name, handle_string = parse_windows_handle_process_line(line)
|
|
85
|
+
next unless pid
|
|
86
|
+
raise "Handle error for [#{hstring}] Please notify OATS administrator." unless handle_string =~ /#{hstring}/
|
|
87
|
+
$log.warn "Likely locking process: [#{line}]"
|
|
88
|
+
if proc_name =~ ok_to_kill
|
|
89
|
+
$log.warn "Will attempt to kill [#{proc_name}] with PID #{pid}"
|
|
90
|
+
signal = 'KILL'
|
|
91
|
+
killed = Process.kill(signal,pid.to_i)
|
|
92
|
+
if RUBY_VERSION =~ /^1.9/
|
|
93
|
+
if killed.empty?
|
|
94
|
+
killed = 0
|
|
95
|
+
else
|
|
96
|
+
killed = 1
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
if killed == 0
|
|
100
|
+
$log.warn "Failed to kill the process"
|
|
101
|
+
else
|
|
102
|
+
$log.warn "Successfully killed [#{proc_name}]"
|
|
103
|
+
end
|
|
104
|
+
else
|
|
105
|
+
$log.warn "Oats is configured not to auto-kill process [#{proc_name}]"
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
sleep 2 # Need time to clear the process handles
|
|
109
|
+
@@is_locked = OatsLock.locked?(:handles_are_cleared) # Still locked?
|
|
110
|
+
end
|
|
111
|
+
@@is_locked = proc_array if @@is_locked and proc_array
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
return @@is_locked
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def OatsLock.kill_pid(pid,info_line=nil)
|
|
118
|
+
signal = 'KILL'
|
|
119
|
+
no_such_process = false
|
|
120
|
+
begin
|
|
121
|
+
killed = Process.kill(signal,pid.to_i)
|
|
122
|
+
rescue Errno::ESRCH # OK if the process is gone
|
|
123
|
+
no_such_process = true
|
|
124
|
+
end
|
|
125
|
+
if RUBY_VERSION =~ /^1.9/
|
|
126
|
+
if killed.empty?
|
|
127
|
+
killed = 0
|
|
128
|
+
else
|
|
129
|
+
killed = 1
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
if no_such_process
|
|
133
|
+
# $log.debug "No such process #{info_line||pid}"
|
|
134
|
+
elsif killed == 0
|
|
135
|
+
$log.warn "Failed to kill [#{info_line||pid}]"
|
|
136
|
+
else
|
|
137
|
+
$log.warn "Successfully killed [#{info_line||pid}]"
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def OatsLock.find_matching_processes(proc_names)
|
|
142
|
+
matched = []
|
|
143
|
+
if ENV['OS'] == 'Windows_NT'
|
|
144
|
+
processes = WIN32OLE.connect("winmgmts://").ExecQuery("select * from win32_process")
|
|
145
|
+
# for process in processes do
|
|
146
|
+
# for property in process.Properties_ do
|
|
147
|
+
# puts property.Name
|
|
148
|
+
# end
|
|
149
|
+
# break
|
|
150
|
+
# end
|
|
151
|
+
processes.each do |process|
|
|
152
|
+
if process.Commandline =~ proc_names
|
|
153
|
+
matched.push [process.ProcessId,process.Name,nil, process.CommandLine]
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
else
|
|
157
|
+
pscom = ENV['OS'] == 'Linux' ? 'ps lxww' : 'ps -ef'
|
|
158
|
+
`#{pscom}`.split("\n").each do |lvar|
|
|
159
|
+
line = lvar.chomp
|
|
160
|
+
case ENV['OS']
|
|
161
|
+
when 'Darwin' # ps -ef output
|
|
162
|
+
pid = line[5..11]
|
|
163
|
+
next if pid.to_i == 0
|
|
164
|
+
ppid = line[12..16]
|
|
165
|
+
proc_name = line[50..-1]
|
|
166
|
+
when 'Linux' # ps ww output
|
|
167
|
+
pid = line[7..12]
|
|
168
|
+
next if pid.to_i == 0
|
|
169
|
+
ppid = line[13..18]
|
|
170
|
+
proc_name = line[69..-1]
|
|
171
|
+
else
|
|
172
|
+
raise OatError, "Do not know how to parse ps output from #{ENV['OS']}"
|
|
173
|
+
end
|
|
174
|
+
next unless pid
|
|
175
|
+
matched.push [pid.strip, proc_name.strip, ppid.strip, line.strip] if proc_name =~ proc_names
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
return matched
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def OatsLock.kill_webdriver_browsers
|
|
182
|
+
match = "ruby.*oats/lib/oats_main.rb"
|
|
183
|
+
# Not tested on agents on Windows_NT
|
|
184
|
+
if $oats_execution['agent']
|
|
185
|
+
nickname = $oats_execution['agent']['execution:occ:agent_nickname']
|
|
186
|
+
port = $oats_execution['agent']['execution:occ:agent_port']
|
|
187
|
+
match += " -p #{port} -n #{nickname}"
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Kill all selenium automation chrome jobs on MacOS. Assumes MacOS is for development only, not OCC.
|
|
191
|
+
# Will cause problems if multiple agents are run on MacOS
|
|
192
|
+
if ENV['OS'] == 'Darwin'
|
|
193
|
+
chrome_automation_procs = OatsLock.find_matching_processes(/ Chrome .* --dom-automation/)
|
|
194
|
+
chrome_automation_procs.each do |pid,proc_name,ppid|
|
|
195
|
+
OatsLock.kill_pid pid
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
oats_procs = OatsLock.find_matching_processes(/#{match}\z/)
|
|
200
|
+
chromedriver_procs = OatsLock.find_matching_processes(/IEXPLORE.EXE\" -noframemerging|(chromedriver|firefox(-bin|\.exe\") -no-remote)/)
|
|
201
|
+
webdriver_procs = OatsLock.find_matching_processes(/webdriver/)
|
|
202
|
+
oats_procs.each do |opid,oproc_name,oppid|
|
|
203
|
+
chromedriver_procs.each do |cpid,cproc_name,cppid|
|
|
204
|
+
if cppid == opid
|
|
205
|
+
webdriver_procs.each do |wpid,wproc_name,wppid|
|
|
206
|
+
OatsLock.kill_pid wpid if wppid == cpid
|
|
207
|
+
end
|
|
208
|
+
OatsLock.kill_pid cpid
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
# If parent ruby dies, ppid reverts to "1"
|
|
213
|
+
(chromedriver_procs + webdriver_procs).each do |pid,proc_name,ppid|
|
|
214
|
+
OatsLock.kill_pid pid if ppid == "1" and proc_name !~ /defunct/
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Removes lock
|
|
219
|
+
def OatsLock.reset
|
|
220
|
+
if @@file_handle # Only for Windows
|
|
221
|
+
@@file_handle.close
|
|
222
|
+
@@file_handle = nil
|
|
223
|
+
@@is_locked = true
|
|
224
|
+
else # Doesn't return status properly for non-windows, just resets the lock
|
|
225
|
+
if $oats_execution['agent'].nil? and ENV['OS'] != 'Windows_NT' and File.exist?(in_progress_file)
|
|
226
|
+
pids = IO.readlines(in_progress_file)
|
|
227
|
+
current_pid = pids.shift
|
|
228
|
+
pids.each { |pid| OatsLock.kill_pid(pid.chomp) } # Legacy firefox
|
|
229
|
+
end
|
|
230
|
+
@@is_locked = false
|
|
231
|
+
end
|
|
232
|
+
FileUtils.rm_f in_progress_file
|
|
233
|
+
return @@is_locked
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
class << self
|
|
237
|
+
private
|
|
238
|
+
def lock_file
|
|
239
|
+
file = 'oats_in_progress.lock'
|
|
240
|
+
if $oats_execution['agent'] && $oats_execution['agent']['execution:occ:agent_nickname']
|
|
241
|
+
file = $oats_execution['agent']['execution:occ:agent_nickname'] + '_' + file
|
|
242
|
+
end
|
|
243
|
+
return file
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def in_progress_file
|
|
247
|
+
return ENV['HOME'] + '/' + lock_file
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def parse_windows_handle_process_line(line)
|
|
251
|
+
line =~ /(.*) pid:(.*) .*: (.*)/
|
|
252
|
+
return nil unless $1
|
|
253
|
+
proc_name = $1
|
|
254
|
+
pid = $2
|
|
255
|
+
handle_string = $3
|
|
256
|
+
return pid.strip, proc_name.strip, handle_string.strip
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
end
|
|
261
|
+
end
|