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,189 @@
|
|
|
1
|
+
require 'oats/oats_selenium_api'
|
|
2
|
+
|
|
3
|
+
# Advertised OATS methods to be used from tests
|
|
4
|
+
# Selenium object accessor created on demand by Oat.browser
|
|
5
|
+
|
|
6
|
+
def selenium
|
|
7
|
+
$selenium || Oats.browser
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
module Oats
|
|
11
|
+
|
|
12
|
+
class Oselenium
|
|
13
|
+
@@browsers = []
|
|
14
|
+
attr_reader :browser, :site, :login_base_url, :user
|
|
15
|
+
@@server_started_by_oats = false
|
|
16
|
+
|
|
17
|
+
def Oselenium.browsers
|
|
18
|
+
@@browsers
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def Oselenium.browser(*args)
|
|
22
|
+
if args.include?(true)
|
|
23
|
+
new_browser = true
|
|
24
|
+
args.delete true
|
|
25
|
+
end
|
|
26
|
+
if not args.empty?
|
|
27
|
+
if not new_browser and Oselenium.browsers.last
|
|
28
|
+
return Oselenium.browsers.last.login(*args)
|
|
29
|
+
else
|
|
30
|
+
return Oselenium.new(*args).browser
|
|
31
|
+
end
|
|
32
|
+
elsif Oselenium.browsers.last
|
|
33
|
+
return Oselenium.browsers.last
|
|
34
|
+
else
|
|
35
|
+
return Oselenium.new.browser
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def initialize(*args)
|
|
40
|
+
|
|
41
|
+
browser_type = $oats['selenium']['browser_type']
|
|
42
|
+
# is_webdriver = ! $oats['selenium']['rcdriver']
|
|
43
|
+
|
|
44
|
+
unless $oats_global['download_dir']
|
|
45
|
+
if browser_type == 'firefox'
|
|
46
|
+
$oats_global['download_dir'] = $oats['execution']['dir_results'] + '/downloads'
|
|
47
|
+
elsif Oats.data("selenium.default_downloads")
|
|
48
|
+
$oats_global['download_dir'] = File.join(ENV[ ENV['OS'] == 'Windows_NT' ? 'USERPROFILE' : 'HOME'], 'Downloads')
|
|
49
|
+
$oats_global['download_dir'].gsub!('\\','/') if ENV['OS'] == 'Windows_NT'
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
download_dir = $oats_global['download_dir'].gsub('/','\\\\') if $oats_global['download_dir'] and
|
|
54
|
+
ENV['OS'] == 'Windows_NT'
|
|
55
|
+
download_dir ||= $oats_global['download_dir']
|
|
56
|
+
case browser_type
|
|
57
|
+
when 'firefox'
|
|
58
|
+
profile = $oats['selenium']['firefox_profile']
|
|
59
|
+
$oats_global["browser_path"] ||= ENV[profile] if profile
|
|
60
|
+
# if is_webdriver
|
|
61
|
+
profile = Selenium::WebDriver::Firefox::Profile.from_name profile if profile
|
|
62
|
+
profile = Selenium::WebDriver::Firefox::Profile.new unless profile
|
|
63
|
+
profile['browser.download.dir'] = download_dir
|
|
64
|
+
profile["browser.helperApps.neverAsk.saveToDisk"] = "text/plain, application/vnd.ms-excel, application/pdf, text/csv"
|
|
65
|
+
profile['browser.download.folderList'] = 2
|
|
66
|
+
$oats['selenium']['firefox_profile_set'].each { |method,value| profile.send method+'=', value }
|
|
67
|
+
|
|
68
|
+
when 'chrome'
|
|
69
|
+
profile = Selenium::WebDriver::Chrome::Profile.new
|
|
70
|
+
profile['download.prompt_for_download'] = false
|
|
71
|
+
profile['download.default_directory'] = download_dir
|
|
72
|
+
unless $oats_global['browser_path']
|
|
73
|
+
vpath = File.join($oats['_']['vendor'], ENV['OS'], 'chromedriver' + (ENV['OS'] == 'Windows_NT' ? '.exe' : '') )
|
|
74
|
+
$oats_global['browser_path'] = vpath if File.exist?(vpath)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
FileUtils.rm_f Dir.glob(File.join($oats_global['download_dir'],'*')) if $oats_global['download_dir']
|
|
78
|
+
Oats.info "Browser type: #{browser_type.inspect}, profile: #{profile.inspect}, path: #{$oats_global["browser_path"].inspect}"
|
|
79
|
+
$oats_info['browser'] = $oats['selenium']['browser_type'].sub(/ .*/,'')
|
|
80
|
+
remote_webdriver = $oats['selenium']['remote_webdriver']
|
|
81
|
+
driver_type = $oats['selenium']['browser_type']
|
|
82
|
+
if remote_webdriver
|
|
83
|
+
remote_webdriver = remote_webdriver[browser_type]
|
|
84
|
+
if remote_webdriver
|
|
85
|
+
driver_type = 'remote'
|
|
86
|
+
@remote_webdriver_is_active = true
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
opts = [ driver_type.to_sym ]
|
|
90
|
+
opts_hash ={}
|
|
91
|
+
opts_hash[:profile] = profile if profile and driver_type != 'remote'
|
|
92
|
+
if driver_type == 'remote'
|
|
93
|
+
opts_hash[:url] = "http://"+remote_webdriver+'/wd/hub'
|
|
94
|
+
opts_hash[:desired_capabilities] = $oats['selenium']['browser_type'].to_sym
|
|
95
|
+
end
|
|
96
|
+
case browser_type
|
|
97
|
+
when /firefox/
|
|
98
|
+
Selenium::WebDriver::Firefox.path = $oats_global["browser_path"]
|
|
99
|
+
when /chrome/
|
|
100
|
+
Selenium::WebDriver::Chrome.driver_path = $oats_global['browser_path']
|
|
101
|
+
end if $oats_global['browser_path']
|
|
102
|
+
browser_options = Oats.data "selenium.options.#{browser_type}"
|
|
103
|
+
browser_options.each_pair { |name, val| opts_hash[name.to_sym] = val } if browser_options
|
|
104
|
+
opts.push(opts_hash) unless opts_hash.empty?
|
|
105
|
+
# OatsLock.record_firefox_processes do
|
|
106
|
+
@browser = Selenium::WebDriver.for(*opts)
|
|
107
|
+
# end
|
|
108
|
+
@browser.osel = self
|
|
109
|
+
$selenium = @browser
|
|
110
|
+
@@browsers << @browser
|
|
111
|
+
login(*args)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Stub method/interface for actions to take after instantiating the browser
|
|
115
|
+
def login(*args) #
|
|
116
|
+
selenium.open(args.first)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# True if selenium is running in remote_webdriver mode
|
|
120
|
+
def remote_webdriver?
|
|
121
|
+
@remote_webdriver_is_active
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Fixes the path to Windows if running on windows remote webdriver
|
|
125
|
+
def Oselenium.remote_webdriver_map_file_path(file)
|
|
126
|
+
if $selenium and $selenium.osel.remote_webdriver?
|
|
127
|
+
file.sub!(ENV['OATS_HOME'], $oats['selenium']['remote_webdriver']['oats_dir'])
|
|
128
|
+
file_os = $oats['selenium']['remote_webdriver']['os']
|
|
129
|
+
else
|
|
130
|
+
file_os = ENV['OS']
|
|
131
|
+
end
|
|
132
|
+
file_os == 'Windows_NT' ? file.gsub('/','\\') : file
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def Oselenium.reset
|
|
136
|
+
Oselenium.close
|
|
137
|
+
rescue Timeout::Error
|
|
138
|
+
## Sometimes doesn't die gracefully. It is OK, will be killed below.
|
|
139
|
+
ensure
|
|
140
|
+
@@browsers = []
|
|
141
|
+
$selenium = nil
|
|
142
|
+
OatsLock.kill_webdriver_browsers
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def Oselenium.close
|
|
146
|
+
while browser = Oselenium.browsers.pop
|
|
147
|
+
if browser.osel.site
|
|
148
|
+
browser.oats_debug "Closing browser session from #{browser.osel.site}"
|
|
149
|
+
else
|
|
150
|
+
browser.oats_debug "Closing browser session."
|
|
151
|
+
end
|
|
152
|
+
browser.quit
|
|
153
|
+
end
|
|
154
|
+
$selenium = nil
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def Oselenium.pause_browser
|
|
158
|
+
return if Oselenium.browsers.empty? or ! TestData.pause_after_error
|
|
159
|
+
seconds = 999999
|
|
160
|
+
pause_val = $oats['selenium']['pause_on_exit']
|
|
161
|
+
if not pause_val.integer? or
|
|
162
|
+
pause_val <= 0
|
|
163
|
+
seconds = nil
|
|
164
|
+
elsif pause_val == 1
|
|
165
|
+
seconds = nil unless TestData.current_test.status == 1
|
|
166
|
+
elsif pause_val > 0
|
|
167
|
+
seconds = pause_val
|
|
168
|
+
end
|
|
169
|
+
if seconds
|
|
170
|
+
$stderr.puts "Paused because selenium:pause_on_exit is set to [#{pause_val}]"
|
|
171
|
+
$stderr.puts "PLEASE HIT <ENTER> TO CONTINUE!"
|
|
172
|
+
begin
|
|
173
|
+
# timeout(seconds) { loop { browser.get_title ; sleep 1 } }
|
|
174
|
+
timeout(seconds) { STDIN.readline }
|
|
175
|
+
rescue Timeout::Error
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
TestData.pause_after_error = false
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def Oselenium.port
|
|
182
|
+
# if $oats_execution['agent']
|
|
183
|
+
# '4'+$oats_execution['agent']['execution:occ:agent_port'].to_s
|
|
184
|
+
# else
|
|
185
|
+
$oats['selenium']['port']
|
|
186
|
+
# end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
data/lib/oats/ossh.rb
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#require 'util'
|
|
2
|
+
class OatsOsshMissingInput < OatsTestError ; end
|
|
3
|
+
|
|
4
|
+
module Oats
|
|
5
|
+
|
|
6
|
+
# Implement Oats.rssh and Oats.rput functionality. See Oats.rssh documentation.
|
|
7
|
+
module Ossh
|
|
8
|
+
def Ossh.run(cmd_file, dir = nil , host = nil, username = nil, rput = nil)
|
|
9
|
+
username ||= Oats.data['ssh']['username']
|
|
10
|
+
host ||= Oats.data['ssh']['host']
|
|
11
|
+
raise(OatsOsshMissingInput, "Ossh plink requires a host.") unless host
|
|
12
|
+
if username == 'root'
|
|
13
|
+
cmd = "plink #{host} -l #{Oats.data['ssh']['root_sudo_username']} "
|
|
14
|
+
cmd_file = 'sudo -u root ' + cmd_file
|
|
15
|
+
else
|
|
16
|
+
cmd = "plink #{host} -l #{username} "
|
|
17
|
+
end
|
|
18
|
+
if rput
|
|
19
|
+
source_cmd = 'echo'
|
|
20
|
+
if File.exist?(cmd_file)
|
|
21
|
+
cmd_file.gsub! /\//, '\\'
|
|
22
|
+
source_cmd = 'type'
|
|
23
|
+
end
|
|
24
|
+
cmd = "#{source_cmd} #{cmd_file} | #{cmd}\"/home/levent.atasoy/bin/oats_put_file.sh #{dir}\""
|
|
25
|
+
else
|
|
26
|
+
if dir
|
|
27
|
+
cmd += "\"cd #{dir} ; #{cmd_file} 2>&1\""
|
|
28
|
+
else
|
|
29
|
+
cmd += "\"#{cmd_file} 2>&1\""
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
$log.info cmd
|
|
33
|
+
`#{cmd}`
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
module EventMachine
|
|
2
|
+
|
|
3
|
+
def self.event_callback conn_binding, opcode, data # :nodoc:
|
|
4
|
+
#
|
|
5
|
+
# Changed 27Dec07: Eliminated the hookable error handling.
|
|
6
|
+
# No one was using it, and it degraded performance significantly.
|
|
7
|
+
# It's in original_event_callback, which is dead code.
|
|
8
|
+
#
|
|
9
|
+
# Changed 25Jul08: Added a partial solution to the problem of exceptions
|
|
10
|
+
# raised in user-written event-handlers. If such exceptions are not caught,
|
|
11
|
+
# we must cause the reactor to stop, and then re-raise the exception.
|
|
12
|
+
# Otherwise, the reactor doesn't stop and it's left on the call stack.
|
|
13
|
+
# This is partial because we only added it to #unbind, where it's critical
|
|
14
|
+
# (to keep unbind handlers from being re-entered when a stopping reactor
|
|
15
|
+
# runs down open connections). It should go on the other calls to user
|
|
16
|
+
# code, but the performance impact may be too large.
|
|
17
|
+
#
|
|
18
|
+
if opcode == ConnectionUnbound
|
|
19
|
+
if c = @conns.delete( conn_binding )
|
|
20
|
+
begin
|
|
21
|
+
c.unbind
|
|
22
|
+
rescue
|
|
23
|
+
@wrapped_exception = $!
|
|
24
|
+
stop
|
|
25
|
+
end
|
|
26
|
+
elsif c = @acceptors.delete( conn_binding )
|
|
27
|
+
# no-op
|
|
28
|
+
else
|
|
29
|
+
# raise ConnectionNotBound, "recieved ConnectionUnbound for an unknown signature: #{conn_binding}"
|
|
30
|
+
end
|
|
31
|
+
elsif opcode == ConnectionAccepted
|
|
32
|
+
accep,args,blk = @acceptors[conn_binding]
|
|
33
|
+
raise NoHandlerForAcceptedConnection unless accep
|
|
34
|
+
c = accep.new data, *args
|
|
35
|
+
@conns[data] = c
|
|
36
|
+
blk and blk.call(c)
|
|
37
|
+
c # (needed?)
|
|
38
|
+
elsif opcode == ConnectionCompleted
|
|
39
|
+
c = @conns[conn_binding]
|
|
40
|
+
if c
|
|
41
|
+
c.connection_completed
|
|
42
|
+
# else
|
|
43
|
+
# raise ConnectionNotBound, "received ConnectionCompleted for unknown signature: #{conn_binding}"
|
|
44
|
+
end
|
|
45
|
+
##
|
|
46
|
+
# The remaining code is a fallback for the pure ruby and java reactors.
|
|
47
|
+
# In the C++ reactor, these events are handled in the C event_callback() in rubymain.cpp
|
|
48
|
+
elsif opcode == TimerFired
|
|
49
|
+
t = @timers.delete( data )
|
|
50
|
+
return if t == false # timer cancelled
|
|
51
|
+
t or raise UnknownTimerFired, "timer data: #{data}"
|
|
52
|
+
t.call
|
|
53
|
+
elsif opcode == ConnectionData
|
|
54
|
+
c = @conns[conn_binding] or raise ConnectionNotBound, "received data #{data} for unknown signature: #{conn_binding}"
|
|
55
|
+
c.receive_data data
|
|
56
|
+
elsif opcode == LoopbreakSignalled
|
|
57
|
+
run_deferred_callbacks
|
|
58
|
+
elsif opcode == ConnectionNotifyReadable
|
|
59
|
+
c = @conns[conn_binding] or raise ConnectionNotBound
|
|
60
|
+
c.notify_readable
|
|
61
|
+
elsif opcode == ConnectionNotifyWritable
|
|
62
|
+
c = @conns[conn_binding] or raise ConnectionNotBound
|
|
63
|
+
c.notify_writable
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
data/lib/oats/ragent.rb
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
#require 'eventmachine' # http://eventmachine.rubyforge.org/EventMachine.html#M000486
|
|
2
|
+
#require 'patches_for_eventmachine_12.10'
|
|
3
|
+
require 'em-http-request' # https://github.com/igrigorik/em-http-request/wiki/Issuing-Requests
|
|
4
|
+
require 'json'
|
|
5
|
+
|
|
6
|
+
module Oats
|
|
7
|
+
|
|
8
|
+
class Ragent < EventMachine::Connection
|
|
9
|
+
attr_accessor :job_count, :jid, :occ_reintroduction_wait_time
|
|
10
|
+
attr_reader :request
|
|
11
|
+
@@logger = nil
|
|
12
|
+
@@oats_info_snapshot = {}
|
|
13
|
+
@@job_count = 1
|
|
14
|
+
@@occ_default = nil
|
|
15
|
+
@@logger = Log4r::Logger.new('A')
|
|
16
|
+
include EM::P::ObjectProtocol
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# Non-nil if in the state of requesting for the next job
|
|
20
|
+
def Ragent.in_next_job
|
|
21
|
+
@@in_next_job
|
|
22
|
+
end
|
|
23
|
+
def Ragent.in_next_job=(v)
|
|
24
|
+
@@in_next_job = v
|
|
25
|
+
end
|
|
26
|
+
def Ragent.is_busy=(jid)
|
|
27
|
+
@@is_busy = jid
|
|
28
|
+
end
|
|
29
|
+
# Current/Last jobid worked on, or false
|
|
30
|
+
def Ragent.is_busy
|
|
31
|
+
@@is_busy
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Contains YAML OCC entries if oats is started in agent mode
|
|
35
|
+
def Ragent.occ
|
|
36
|
+
@@occ_default
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def Ragent.start(occ_def)
|
|
40
|
+
@@occ_default = occ_def # This should not change during agent execution
|
|
41
|
+
@@logger.add('console')
|
|
42
|
+
3.times do |count| # In case of unexpected exceptions
|
|
43
|
+
begin
|
|
44
|
+
@@occ_reintroduction_wait_time = nil
|
|
45
|
+
@@is_busy = false # If agent is started from scratch assume previous one is gone
|
|
46
|
+
@@in_next_job = false
|
|
47
|
+
@@logger.info "====================================================================================="
|
|
48
|
+
mach_port = ENV['HOSTNAME'] + ':' + $oats['execution']['occ']['port'].to_s
|
|
49
|
+
@@logger.info "Started OATS Server execution-#{count} on #{mach_port} at #{Time.now} "
|
|
50
|
+
EventMachine::run do
|
|
51
|
+
EventMachine::start_server @@occ_default['agent_host'], @@occ_default['agent_port'].to_i, Ragent
|
|
52
|
+
EventMachine.next_tick do
|
|
53
|
+
Ragent.server_logger nil,'Initiating contact with OCC '
|
|
54
|
+
Ragent.start_next_job unless Ragent.is_busy
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
break # Shutdown requested
|
|
58
|
+
rescue Exception => exc
|
|
59
|
+
@@logger.error exc
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# def Ragent.force_close_connection
|
|
65
|
+
# end
|
|
66
|
+
def Ragent.job_count=(val)
|
|
67
|
+
@@job_count = val
|
|
68
|
+
end
|
|
69
|
+
def Ragent.job_count
|
|
70
|
+
@@job_count
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def Ragent.snapshot_oats_info(oats_info)
|
|
74
|
+
@@oats_info_snapshot = oats_info
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Generates summary data into the input oats_info
|
|
78
|
+
def regen_results_summary!(oats_info)
|
|
79
|
+
return Report.results(oats_info['test_files'],true)
|
|
80
|
+
rescue
|
|
81
|
+
server_logger $!.inspect + "\n" + $!.backtrace.join("\n ")
|
|
82
|
+
false
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Results_status: Early, Partial, Current, Archived, Missing, Error
|
|
86
|
+
def get_oats_info
|
|
87
|
+
if @request[:jobid] == Ragent.is_busy # working on it now
|
|
88
|
+
if @request[:jobid] == @@oats_info_snapshot['jobid'] # first test started processing
|
|
89
|
+
if regen_results_summary!(@@oats_info_snapshot) # summary succeeded
|
|
90
|
+
oats_info = Marshal.load(Marshal.dump(@@oats_info_snapshot))
|
|
91
|
+
oats_info['results_status'] = 'Partial'
|
|
92
|
+
else
|
|
93
|
+
server_logger "[ERROR] Can not regen_results_summary from the snapshot"
|
|
94
|
+
oats_info = {'results_status' => 'Error'}
|
|
95
|
+
end
|
|
96
|
+
elsif @@oats_info_snapshot['jobid']
|
|
97
|
+
msg = "ERROR: Unexpected condition. Request jobid: #{@request[:jobid]} does not match stored job id: #{@@oats_info_snapshot['jobid']}"
|
|
98
|
+
server_logger msg
|
|
99
|
+
oats_info = { 'jobid' => @request[:jobid], 'results_status' => 'Error', 'error_message' => msg }
|
|
100
|
+
else
|
|
101
|
+
oats_info = Marshal.load(Marshal.dump(Oats.context))
|
|
102
|
+
oats_info['results_status'] = 'Early'
|
|
103
|
+
oats_info['jobid'] = Ragent.is_busy
|
|
104
|
+
end
|
|
105
|
+
else # Search for request on disk in archive or results
|
|
106
|
+
res_dir = File.join(Oats.result_archive_dir, @request[:jobid].to_s)
|
|
107
|
+
results_file = File.join( res_dir,'results.dump')
|
|
108
|
+
if File.readable?(results_file) # Archived ones should have summary
|
|
109
|
+
oats_info = Report.oats_info_retrieve(results_file)
|
|
110
|
+
oats_info['results_status'] = 'Archived'
|
|
111
|
+
else # May have to regenerate the summary, in case test had died
|
|
112
|
+
results_file = File.join( $oats['execution']['dir_results'], 'results.dump')
|
|
113
|
+
if File.readable?(results_file)
|
|
114
|
+
oats_info = Report.oats_info_retrieve(results_file)
|
|
115
|
+
if regen_results_summary!(oats_info) and @request[:jobid] == oats_info['jobid']
|
|
116
|
+
oats_info['results_status'] = 'Current'
|
|
117
|
+
else
|
|
118
|
+
oats_info = {} unless oats_info.instance_of?(Hash)
|
|
119
|
+
oats_info['debug_message'] = "request_jobid: #{@request[:jobid]}, current oats_info jobid: #{oats_info['jobid']}"
|
|
120
|
+
oats_info['results_status'] = 'Missing'
|
|
121
|
+
end
|
|
122
|
+
else
|
|
123
|
+
oats_info = { 'results_status' => 'Missing' ,
|
|
124
|
+
'debug_message' => "No readable: #{results_file}" }
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
# Convert object to hash
|
|
129
|
+
oats_info['test_files'] = oats_info['test_files'].testlist_hash if oats_info['test_files']
|
|
130
|
+
return oats_info
|
|
131
|
+
rescue
|
|
132
|
+
server_logger $!.inspect + "\n" + $!.backtrace.join("\n ")
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def receive_object(request)
|
|
136
|
+
@request = request
|
|
137
|
+
password = @request.delete(:password)
|
|
138
|
+
server_logger "Received " + @request.inspect
|
|
139
|
+
@request[:password] = password
|
|
140
|
+
response = {}
|
|
141
|
+
case @request[:command]
|
|
142
|
+
|
|
143
|
+
when 'status'
|
|
144
|
+
EventMachine.next_tick { run_next_job } unless Ragent.is_busy
|
|
145
|
+
|
|
146
|
+
when 'start'
|
|
147
|
+
if Ragent.is_busy
|
|
148
|
+
server_logger "Not getting next job again because Ragent.is_busy: #{Ragent.is_busy}"
|
|
149
|
+
else
|
|
150
|
+
EventMachine.next_tick { run_next_job }
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
when 'results'
|
|
154
|
+
begin
|
|
155
|
+
response[:oats_info] = get_oats_info
|
|
156
|
+
rescue
|
|
157
|
+
server_logger $!.inspect + "\n" + $!.backtrace.join("\n ")
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
when 'run' # only called from oats client, not from OCC
|
|
161
|
+
EventMachine.defer( proc {
|
|
162
|
+
Driver.start(@request[:jobid], @request[:args])
|
|
163
|
+
} ) unless Ragent.is_busy
|
|
164
|
+
|
|
165
|
+
when 'stop' # any further test execution for this jobid
|
|
166
|
+
Oats.context['stop_oats'] = @request[:id] if @request[:stop_jobs].include?(Oats.context['jobid'])
|
|
167
|
+
|
|
168
|
+
when 'shutdown'
|
|
169
|
+
else
|
|
170
|
+
response[:unknown_command] = true
|
|
171
|
+
server_logger "Unknown command #{@request[:command]}"
|
|
172
|
+
end
|
|
173
|
+
response[:is_busy] = Ragent.is_busy
|
|
174
|
+
stop_oats = Oats.context && Oats.context['stop_oats']
|
|
175
|
+
response[:is_signal_oats_to_stop] = stop_oats if stop_oats
|
|
176
|
+
server_logger "Sending " + response.inspect
|
|
177
|
+
response[:password] = password
|
|
178
|
+
send_object(response)
|
|
179
|
+
close_connection_after_writing
|
|
180
|
+
rescue
|
|
181
|
+
server_logger $!.inspect + "\n" + $!.backtrace.join("\n ")
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def unbind
|
|
185
|
+
if @request[:command] == 'shutdown'
|
|
186
|
+
server_logger "Shutting down the server."
|
|
187
|
+
EventMachine::stop_event_loop
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def run_next_job(prev_jobid = nil)
|
|
192
|
+
return unless @request[:occ_host] # Bad input or invoked via client, not occ
|
|
193
|
+
occ = @@occ_default.clone
|
|
194
|
+
occ['server_host'] = @request[:occ_host]
|
|
195
|
+
occ['server_port'] = @request[:occ_port]
|
|
196
|
+
Ragent.start_next_job(occ, self, prev_jobid)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def self.start_next_job(occ = @@occ_default, ra = nil, prev_jobid = nil)
|
|
200
|
+
if Ragent.in_next_job or Ragent.is_busy
|
|
201
|
+
msg = if Ragent.in_next_job
|
|
202
|
+
if Ragent.in_next_job == nil.object_id
|
|
203
|
+
"already getting the initial job."
|
|
204
|
+
else
|
|
205
|
+
"already getting job for #{Ragent.in_next_job}]"
|
|
206
|
+
end
|
|
207
|
+
else
|
|
208
|
+
"became busy with #{Ragent.is_busy}"
|
|
209
|
+
end
|
|
210
|
+
Ragent.server_logger ra, "Not requesting new job since #{msg}"
|
|
211
|
+
return false
|
|
212
|
+
end
|
|
213
|
+
Ragent.in_next_job = ra.object_id
|
|
214
|
+
# Double check that this agent has the busy lock
|
|
215
|
+
if not Ragent.in_next_job or Ragent.in_next_job != ra.object_id
|
|
216
|
+
Ragent.server_logger(ra, "Not requesting new job since " +
|
|
217
|
+
"now another Ragent #{ra.object_id} is requesting next job besides current #{Ragent.in_next_job}")
|
|
218
|
+
return false
|
|
219
|
+
end
|
|
220
|
+
query = {
|
|
221
|
+
'nickname' => occ['agent_nickname'],
|
|
222
|
+
'machine' => occ['agent_host'],
|
|
223
|
+
'port' => occ['agent_port'] }
|
|
224
|
+
query['jobid'] = prev_jobid if prev_jobid
|
|
225
|
+
query['repo'] = ENV['OATS_CODE_VERSION'].to_s if ENV['OATS_CODE_VERSION'] and ENV['OATS_CODE_VERSION'] != ''
|
|
226
|
+
query['logfile'] = File.basename(ENV['OATS_AGENT_LOGFILE']||'agent.log')
|
|
227
|
+
Ragent.server_logger ra, "Getting next OCC job: " + query.inspect
|
|
228
|
+
query['password='] = ra.request[:password] if ra and ra.request[:password]
|
|
229
|
+
# Default inactivity_timeout of 10 is not enough when OCC is restarting too
|
|
230
|
+
# many agents. Agent gives up in 10secs but OCC hands over the job in 20secs.
|
|
231
|
+
# As a result OCC thinks job is received but agent has never seen the job.
|
|
232
|
+
connection_options = { :connect_timeout => 60,:inactivity_timeout => 60}
|
|
233
|
+
http_req = EventMachine::HttpRequest.new('http://' + occ['server_host'] + ":#{occ['server_port']}",connection_options)
|
|
234
|
+
http = http_req.get :path => '/jobs/nxt', :query => query
|
|
235
|
+
http.errback { self.no_response(occ,ra, prev_jobid) }
|
|
236
|
+
http.callback do
|
|
237
|
+
status = http.response_header.status
|
|
238
|
+
if status == 200
|
|
239
|
+
data =http.response
|
|
240
|
+
nxt_job = JSON.parse(data) if data
|
|
241
|
+
if nxt_job['jid']
|
|
242
|
+
Ragent.is_busy = nxt_job['jid']
|
|
243
|
+
Ragent.in_next_job = false
|
|
244
|
+
if ra
|
|
245
|
+
ra.jid = nxt_job['jid']
|
|
246
|
+
ra.occ_reintroduction_wait_time = nil # Reset wait time to default if heard from OCC
|
|
247
|
+
end
|
|
248
|
+
Ragent.server_logger ra, "Job-#{Ragent.job_count} #{nxt_job.inspect}"
|
|
249
|
+
EventMachine.defer do
|
|
250
|
+
begin
|
|
251
|
+
opts= {'execution:environments' => [nxt_job['env']],
|
|
252
|
+
'execution:test_files' => [nxt_job['list']] }
|
|
253
|
+
opts['_:options'] = nxt_job['options'].split(',') if nxt_job['options'] and nxt_job['options'] != ''
|
|
254
|
+
Ragent.snapshot_oats_info({})
|
|
255
|
+
Driver.start(nxt_job['jid'],opts)
|
|
256
|
+
ensure
|
|
257
|
+
Ragent.is_busy = false
|
|
258
|
+
end
|
|
259
|
+
Ragent.job_count += 1
|
|
260
|
+
if ra
|
|
261
|
+
ra.run_next_job(nxt_job['jid'] )
|
|
262
|
+
else
|
|
263
|
+
Ragent.start_next_job(occ,ra,nxt_job['jid'])
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
else
|
|
267
|
+
Ragent.in_next_job = false
|
|
268
|
+
Ragent.server_logger ra, "No more pending jobs at OCC. Pausing processing.\n"
|
|
269
|
+
Ragent.job_count = 1
|
|
270
|
+
Ragent.server_logger ra, "***********************************************************\n"
|
|
271
|
+
end
|
|
272
|
+
else
|
|
273
|
+
self.no_response(occ,ra, prev_jobid)
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
rescue RuntimeError => e.message
|
|
277
|
+
Ragent.in_next_job = false
|
|
278
|
+
if e.message == 'eventmachine not initialized: evma_connect_to_server'
|
|
279
|
+
Ragent.server_logger ra, "Shutting down..."
|
|
280
|
+
else
|
|
281
|
+
Ragent.server_logger ra, $!.inspect + "\n" + $!.backtrace.join("\n ")
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
def self.no_response(occv,ra, prev_jobid)
|
|
286
|
+
Ragent.in_next_job = false
|
|
287
|
+
Ragent.server_logger ra, "OCC did not respond."
|
|
288
|
+
wait = ra ? ra.occ_reintroduction_wait_time : @@occ_reintroduction_wait_time
|
|
289
|
+
wait ||= $oats['execution']['occ']['timeout_waiting_for_occ']
|
|
290
|
+
# Keep retrying to introduce, doubling the intervals
|
|
291
|
+
self.server_logger ra, "Will retry in #{wait} seconds."
|
|
292
|
+
EM.add_timer(wait) do
|
|
293
|
+
Ragent.start_next_job(occv,ra, prev_jobid) unless Ragent.is_busy # by now
|
|
294
|
+
end
|
|
295
|
+
wait *= (1.5 + rand(101)/100.0)
|
|
296
|
+
wait = wait.round
|
|
297
|
+
if ra
|
|
298
|
+
ra.occ_reintroduction_wait_time = wait
|
|
299
|
+
else
|
|
300
|
+
@@occ_reintroduction_wait_time = wait
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
def server_logger(arg)
|
|
305
|
+
Ragent.server_logger self, arg
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def Ragent.server_logger(ra, arg)
|
|
309
|
+
if ra
|
|
310
|
+
req = ra.request
|
|
311
|
+
jid = ra.jid
|
|
312
|
+
rt = ":R#{(req and req[:id]) ? req[:id] : ra.object_id}"
|
|
313
|
+
rt += "#{" J:#{jid}" if jid }"
|
|
314
|
+
end
|
|
315
|
+
@@logger.info "[RS#{rt}] #{arg}"
|
|
316
|
+
rescue
|
|
317
|
+
@@logger.error $!.inspect + "\n" + $!.backtrace.join("\n ")
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
end
|
|
321
|
+
end
|
data/lib/oats/rclient.rb
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module Oats
|
|
2
|
+
|
|
3
|
+
class Rclient < EventMachine::Connection
|
|
4
|
+
attr_reader :response
|
|
5
|
+
include EM::P::ObjectProtocol
|
|
6
|
+
# def serializer
|
|
7
|
+
# YAML
|
|
8
|
+
# end
|
|
9
|
+
#
|
|
10
|
+
def initialize(host, request)
|
|
11
|
+
@host = host
|
|
12
|
+
@request = request
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def receive_object(response)
|
|
16
|
+
@response = response
|
|
17
|
+
password = response.delete(:password)
|
|
18
|
+
length = 500
|
|
19
|
+
resp = response.inspect
|
|
20
|
+
resp = resp[0..length] + ' ..... ' + resp[-length..-1] if resp.size > 2*length
|
|
21
|
+
client_logger "Received " + resp + " from"
|
|
22
|
+
response[:password] = password
|
|
23
|
+
client_logger "Command was not recognized" if response[:unknown_command]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def client_logger(arg)
|
|
27
|
+
$log.info arg + " #{@request[:id]}@#{@host} at " + Time.now.strftime("%y-%m-%d %H:%M:%S")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def post_init
|
|
31
|
+
password = @request.delete(:password)
|
|
32
|
+
client_logger "Sending " + @request.inspect + " to"
|
|
33
|
+
@request[:password] = password
|
|
34
|
+
send_object(@request)
|
|
35
|
+
end
|
|
36
|
+
def unbind
|
|
37
|
+
client_logger "Did not hear from " unless @response
|
|
38
|
+
EventMachine::stop_event_loop
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|