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.
Files changed (181) hide show
  1. data/.gitignore +6 -0
  2. data/Gemfile +15 -0
  3. data/README.txt +165 -0
  4. data/Rakefile +2 -0
  5. data/bin/agent +204 -0
  6. data/bin/oats +10 -0
  7. data/bin/occ +29 -0
  8. data/bin/results_cleanup +6 -0
  9. data/doc/COPYING +55 -0
  10. data/doc/LICENSE +55 -0
  11. data/doc/OATS_Framework.doc +0 -0
  12. data/doc/classes/ApplicationLogs.html +239 -0
  13. data/doc/classes/Campaign.html +843 -0
  14. data/doc/classes/CommandlineOptions.html +131 -0
  15. data/doc/classes/Driver.html +182 -0
  16. data/doc/classes/Hash.html +137 -0
  17. data/doc/classes/Ide.html +194 -0
  18. data/doc/classes/MapSelenium.html +197 -0
  19. data/doc/classes/Net.html +107 -0
  20. data/doc/classes/Oats/OatsFilterError.html +119 -0
  21. data/doc/classes/Oats.html +998 -0
  22. data/doc/classes/OatsAssertError.html +119 -0
  23. data/doc/classes/OatsBadInput.html +119 -0
  24. data/doc/classes/OatsData.html +290 -0
  25. data/doc/classes/OatsError.html +117 -0
  26. data/doc/classes/OatsExit.html +117 -0
  27. data/doc/classes/OatsLock.html +254 -0
  28. data/doc/classes/OatsMain.html +182 -0
  29. data/doc/classes/OatsMysqlError.html +113 -0
  30. data/doc/classes/OatsMysqlMissingInput.html +113 -0
  31. data/doc/classes/OatsReportError.html +113 -0
  32. data/doc/classes/OatsSetupError.html +119 -0
  33. data/doc/classes/OatsTestError.html +119 -0
  34. data/doc/classes/OatsTestExit.html +119 -0
  35. data/doc/classes/OatsTestLocateError.html +120 -0
  36. data/doc/classes/OatsVerifyError.html +119 -0
  37. data/doc/classes/Ragent.html +397 -0
  38. data/doc/classes/Rclient.html +236 -0
  39. data/doc/classes/Report.html +368 -0
  40. data/doc/classes/Reports.html +244 -0
  41. data/doc/classes/RestApi.html +333 -0
  42. data/doc/classes/RhttpClient.html +236 -0
  43. data/doc/classes/Rimap.html +170 -0
  44. data/doc/classes/Rmysql.html +176 -0
  45. data/doc/classes/Roptions.html +131 -0
  46. data/doc/classes/Rselenium.html +233 -0
  47. data/doc/classes/Rssh.html +138 -0
  48. data/doc/classes/Runnable.html +174 -0
  49. data/doc/classes/SFTriggers.html +206 -0
  50. data/doc/classes/Selenium/Client/Driver.html +211 -0
  51. data/doc/classes/Selenium/Client.html +107 -0
  52. data/doc/classes/Selenium.html +107 -0
  53. data/doc/classes/SystemCapture.html +304 -0
  54. data/doc/classes/TestCase.html +418 -0
  55. data/doc/classes/TestData.html +235 -0
  56. data/doc/classes/TestList.html +264 -0
  57. data/doc/classes/Tools.html +244 -0
  58. data/doc/classes/Util.html +201 -0
  59. data/doc/classes/Variation.html +206 -0
  60. data/doc/fr_class_index.html +92 -0
  61. data/doc/fr_method_index.html +465 -0
  62. data/doc/index.html +23 -0
  63. data/doc/oats_httpd.conf +32 -0
  64. data/doc/oats_user.yml +25 -0
  65. data/doc/rdoc-style.css +208 -0
  66. data/lib/deep_merge/.gitignore +2 -0
  67. data/lib/deep_merge/core.rb +195 -0
  68. data/lib/deep_merge/deep_merge.rb +1 -0
  69. data/lib/deep_merge/deep_merge_hash.rb +28 -0
  70. data/lib/deep_merge/rails_compat.rb +27 -0
  71. data/lib/oats/application_logs.rb +163 -0
  72. data/lib/oats/build_id.rb +58 -0
  73. data/lib/oats/commandline_options.rb +128 -0
  74. data/lib/oats/diff.rb +278 -0
  75. data/lib/oats/driver.rb +492 -0
  76. data/lib/oats/ide.rb +227 -0
  77. data/lib/oats/keywords.rb +67 -0
  78. data/lib/oats/log4r_init.rb +14 -0
  79. data/lib/oats/mysql.rb +97 -0
  80. data/lib/oats/oats.rb +637 -0
  81. data/lib/oats/oats_data.rb +400 -0
  82. data/lib/oats/oats_exceptions.rb +25 -0
  83. data/lib/oats/oats_lock.rb +261 -0
  84. data/lib/oats/oats_selenium_api.rb +639 -0
  85. data/lib/oats/oselenium.rb +189 -0
  86. data/lib/oats/ossh.rb +36 -0
  87. data/lib/oats/patches_for_eventmachine_12.10.rb +66 -0
  88. data/lib/oats/ragent.rb +321 -0
  89. data/lib/oats/rclient.rb +42 -0
  90. data/lib/oats/report.rb +207 -0
  91. data/lib/oats/roptions.rb +88 -0
  92. data/lib/oats/test_case.rb +510 -0
  93. data/lib/oats/test_data.rb +98 -0
  94. data/lib/oats/test_list.rb +141 -0
  95. data/lib/oats/unixdiff.rb +75 -0
  96. data/lib/oats/util.rb +125 -0
  97. data/lib/oats/version.rb +3 -0
  98. data/lib/oats.rb +36 -0
  99. data/nbproject/configs/agent.properties +0 -0
  100. data/nbproject/configs/gr.properties +0 -0
  101. data/nbproject/project.properties +10 -0
  102. data/nbproject/project.xml +17 -0
  103. data/oats.gemspec +42 -0
  104. data/oats_ini.yml +258 -0
  105. data/oats_tests/Gemfile +18 -0
  106. data/oats_tests/aut_ini.yml +30 -0
  107. data/oats_tests/bin/oats +8 -0
  108. data/oats_tests/environments/qa.yml +4 -0
  109. data/oats_tests/environments/qa_chrome.yml +4 -0
  110. data/oats_tests/examples/core/coreExamples.yml +8 -0
  111. data/oats_tests/examples/core/expectedException.rb +39 -0
  112. data/oats_tests/examples/core/ok_verify.rb +2 -0
  113. data/oats_tests/examples/core/ok_verify.rb_ok/out/myfile.txt +1 -0
  114. data/oats_tests/examples/core/ok_verify.rb_ok/out/myfile2.txt +1 -0
  115. data/oats_tests/examples/core/ok_verify.rb_ok/rats_test.log +2 -0
  116. data/oats_tests/examples/core/unexpectedException.rb +30 -0
  117. data/oats_tests/examples/examples.yml +13 -0
  118. data/oats_tests/examples/gui/guiExamples.yml +7 -0
  119. data/oats_tests/examples/gui/seleniumGoogle.rb +10 -0
  120. data/oats_tests/examples/gui/webdriverGoogle.rb +9 -0
  121. data/oats_tests/examples/keywords/SampleXlList-1.xls +0 -0
  122. data/oats_tests/examples/keywords/SampleXlList-2.xls +0 -0
  123. data/oats_tests/examples/keywords/SampleXlLists.xls +0 -0
  124. data/oats_tests/examples/keywords/keywordsDriver.rb +1 -0
  125. data/oats_tests/examples/keywords/keywordsExamples.yml +8 -0
  126. data/oats_tests/examples/keywords/keywordsTC1.yml +5 -0
  127. data/oats_tests/examples/keywords/keywordsTestlist.yml +16 -0
  128. data/oats_tests/examples/needsWork/addTestDynamically.rb +4 -0
  129. data/oats_tests/examples/needsWork/emailVerify.rb +34 -0
  130. data/oats_tests/examples/needsWork/testSql/rtest.sql +6 -0
  131. data/oats_tests/examples/needsWork/testSql/rtest.yml +11 -0
  132. data/oats_tests/examples/occTest/occTest.rb +13 -0
  133. data/oats_tests/examples/occTest/occTest_1.rb +1 -0
  134. data/oats_tests/examples/occTest/occTest_1_1.rb +1 -0
  135. data/oats_tests/examples/occTest/occTest_1_2.rb +1 -0
  136. data/oats_tests/examples/occTest/occTest_1_3.rb +1 -0
  137. data/oats_tests/examples/occTest/occTest_1_4.rb +1 -0
  138. data/oats_tests/examples/occTest/occTest_2.rb +1 -0
  139. data/oats_tests/examples/occTest/occTest_2_1.rb +1 -0
  140. data/oats_tests/examples/occTest/occTest_2_2.rb +1 -0
  141. data/oats_tests/examples/occTest/occTest_2_3.rb +1 -0
  142. data/oats_tests/examples/occTest/occTest_2_4.rb +1 -0
  143. data/oats_tests/examples/occTest/occTest_3.rb +1 -0
  144. data/oats_tests/examples/occTest/occTest_3_1.rb +1 -0
  145. data/oats_tests/examples/occTest/occTest_3_2.rb +1 -0
  146. data/oats_tests/examples/occTest/occTest_3_3.rb +1 -0
  147. data/oats_tests/examples/occTest/occTest_3_4.rb +1 -0
  148. data/oats_tests/examples/occTest/occTest_4.rb +1 -0
  149. data/oats_tests/examples/occTest/occTestlist.yml +9 -0
  150. data/oats_tests/examples/occTest/occTestlist_1.yml +9 -0
  151. data/oats_tests/examples/occTest/occTestlist_2.yml +9 -0
  152. data/oats_tests/examples/occTest/occTestlist_3.yml +9 -0
  153. data/oats_tests/examples/occTest/variation1.yml +4 -0
  154. data/oats_tests/examples/occTest/variation2.yml +4 -0
  155. data/oats_tests/examples/testFileLocationUnitTests/extn_driver.rb +4 -0
  156. data/oats_tests/examples/testFileLocationUnitTests/folder/oats.yml +3 -0
  157. data/oats_tests/examples/testFileLocationUnitTests/folder/t1.rb +2 -0
  158. data/oats_tests/examples/testFileLocationUnitTests/folder1/t1.yml +2 -0
  159. data/oats_tests/examples/testFileLocationUnitTests/folder1/t1_1.yml +3 -0
  160. data/oats_tests/examples/testFileLocationUnitTests/folder2/oats.yml +3 -0
  161. data/oats_tests/examples/testFileLocationUnitTests/folder2/t1.rb +2 -0
  162. data/oats_tests/examples/testFileLocationUnitTests/folder2/t1.yml +2 -0
  163. data/oats_tests/examples/testFileLocationUnitTests/no_yaml.rb +3 -0
  164. data/oats_tests/examples/testFileLocationUnitTests/post_yaml.rb +1 -0
  165. data/oats_tests/examples/testFileLocationUnitTests/t1.rb +4 -0
  166. data/oats_tests/examples/testFileLocationUnitTests/t1.yml +2 -0
  167. data/oats_tests/examples/testFileLocationUnitTests/t1_1.yml +3 -0
  168. data/oats_tests/examples/testFileLocationUnitTests/testDir/oats.yml +3 -0
  169. data/oats_tests/examples/testFileLocationUnitTests/testDir/t1.rb +2 -0
  170. data/oats_tests/examples/testFileLocationUnitTests/testDir/t1.yml +2 -0
  171. data/oats_tests/examples/testFileLocationUnitTests/testDir2/t1.rb +2 -0
  172. data/oats_tests/examples/testFileLocationUnitTests/testDir2/t1.yml +2 -0
  173. data/oats_tests/examples/testFileLocationUnitTests/unitTestList.yml +36 -0
  174. data/oats_tests/examples/testFileLocationUnitTests/yml_driver.rb +2 -0
  175. data/oats_tests/lib/business.rb +28 -0
  176. data/oats_tests/lib/sample_xl_lists.rb +37 -0
  177. data/test/common_test_unit_setup.rb +21 -0
  178. data/test/test_basic.rb +16 -0
  179. data/test/test_selenium.rb +16 -0
  180. data/test/test_xl_lists.rb +16 -0
  181. metadata +291 -0
@@ -0,0 +1,208 @@
1
+
2
+ body {
3
+ font-family: Verdana,Arial,Helvetica,sans-serif;
4
+ font-size: 90%;
5
+ margin: 0;
6
+ margin-left: 40px;
7
+ padding: 0;
8
+ background: white;
9
+ }
10
+
11
+ h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
12
+ h1 { font-size: 150%; }
13
+ h2,h3,h4 { margin-top: 1em; }
14
+
15
+ a { background: #eef; color: #039; text-decoration: none; }
16
+ a:hover { background: #039; color: #eef; }
17
+
18
+ /* Override the base stylesheet's Anchor inside a table cell */
19
+ td > a {
20
+ background: transparent;
21
+ color: #039;
22
+ text-decoration: none;
23
+ }
24
+
25
+ /* and inside a section title */
26
+ .section-title > a {
27
+ background: transparent;
28
+ color: #eee;
29
+ text-decoration: none;
30
+ }
31
+
32
+ /* === Structural elements =================================== */
33
+
34
+ div#index {
35
+ margin: 0;
36
+ margin-left: -40px;
37
+ padding: 0;
38
+ font-size: 90%;
39
+ }
40
+
41
+
42
+ div#index a {
43
+ margin-left: 0.7em;
44
+ }
45
+
46
+ div#index .section-bar {
47
+ margin-left: 0px;
48
+ padding-left: 0.7em;
49
+ background: #ccc;
50
+ font-size: small;
51
+ }
52
+
53
+
54
+ div#classHeader, div#fileHeader {
55
+ width: auto;
56
+ color: white;
57
+ padding: 0.5em 1.5em 0.5em 1.5em;
58
+ margin: 0;
59
+ margin-left: -40px;
60
+ border-bottom: 3px solid #006;
61
+ }
62
+
63
+ div#classHeader a, div#fileHeader a {
64
+ background: inherit;
65
+ color: white;
66
+ }
67
+
68
+ div#classHeader td, div#fileHeader td {
69
+ background: inherit;
70
+ color: white;
71
+ }
72
+
73
+
74
+ div#fileHeader {
75
+ background: #057;
76
+ }
77
+
78
+ div#classHeader {
79
+ background: #048;
80
+ }
81
+
82
+
83
+ .class-name-in-header {
84
+ font-size: 180%;
85
+ font-weight: bold;
86
+ }
87
+
88
+
89
+ div#bodyContent {
90
+ padding: 0 1.5em 0 1.5em;
91
+ }
92
+
93
+ div#description {
94
+ padding: 0.5em 1.5em;
95
+ background: #efefef;
96
+ border: 1px dotted #999;
97
+ }
98
+
99
+ div#description h1,h2,h3,h4,h5,h6 {
100
+ color: #125;;
101
+ background: transparent;
102
+ }
103
+
104
+ div#validator-badges {
105
+ text-align: center;
106
+ }
107
+ div#validator-badges img { border: 0; }
108
+
109
+ div#copyright {
110
+ color: #333;
111
+ background: #efefef;
112
+ font: 0.75em sans-serif;
113
+ margin-top: 5em;
114
+ margin-bottom: 0;
115
+ padding: 0.5em 2em;
116
+ }
117
+
118
+
119
+ /* === Classes =================================== */
120
+
121
+ table.header-table {
122
+ color: white;
123
+ font-size: small;
124
+ }
125
+
126
+ .type-note {
127
+ font-size: small;
128
+ color: #DEDEDE;
129
+ }
130
+
131
+ .xxsection-bar {
132
+ background: #eee;
133
+ color: #333;
134
+ padding: 3px;
135
+ }
136
+
137
+ .section-bar {
138
+ color: #333;
139
+ border-bottom: 1px solid #999;
140
+ margin-left: -20px;
141
+ }
142
+
143
+
144
+ .section-title {
145
+ background: #79a;
146
+ color: #eee;
147
+ padding: 3px;
148
+ margin-top: 2em;
149
+ margin-left: -30px;
150
+ border: 1px solid #999;
151
+ }
152
+
153
+ .top-aligned-row { vertical-align: top }
154
+ .bottom-aligned-row { vertical-align: bottom }
155
+
156
+ /* --- Context section classes ----------------------- */
157
+
158
+ .context-row { }
159
+ .context-item-name { font-family: monospace; font-weight: bold; color: black; }
160
+ .context-item-value { font-size: small; color: #448; }
161
+ .context-item-desc { color: #333; padding-left: 2em; }
162
+
163
+ /* --- Method classes -------------------------- */
164
+ .method-detail {
165
+ background: #efefef;
166
+ padding: 0;
167
+ margin-top: 0.5em;
168
+ margin-bottom: 1em;
169
+ border: 1px dotted #ccc;
170
+ }
171
+ .method-heading {
172
+ color: black;
173
+ background: #ccc;
174
+ border-bottom: 1px solid #666;
175
+ padding: 0.2em 0.5em 0 0.5em;
176
+ }
177
+ .method-signature { color: black; background: inherit; }
178
+ .method-name { font-weight: bold; }
179
+ .method-args { font-style: italic; }
180
+ .method-description { padding: 0 0.5em 0 0.5em; }
181
+
182
+ /* --- Source code sections -------------------- */
183
+
184
+ a.source-toggle { font-size: 90%; }
185
+ div.method-source-code {
186
+ background: #262626;
187
+ color: #ffdead;
188
+ margin: 1em;
189
+ padding: 0.5em;
190
+ border: 1px dashed #999;
191
+ overflow: hidden;
192
+ }
193
+
194
+ div.method-source-code pre { color: #ffdead; overflow: hidden; }
195
+
196
+ /* --- Ruby keyword styles --------------------- */
197
+
198
+ .standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
199
+
200
+ .ruby-constant { color: #7fffd4; background: transparent; }
201
+ .ruby-keyword { color: #00ffff; background: transparent; }
202
+ .ruby-ivar { color: #eedd82; background: transparent; }
203
+ .ruby-operator { color: #00ffee; background: transparent; }
204
+ .ruby-identifier { color: #ffdead; background: transparent; }
205
+ .ruby-node { color: #ffa07a; background: transparent; }
206
+ .ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
207
+ .ruby-regexp { color: #ffa07a; background: transparent; }
208
+ .ruby-value { color: #7fffd4; background: transparent; }
@@ -0,0 +1,2 @@
1
+ pkg/*
2
+ *.gemspec
@@ -0,0 +1,195 @@
1
+ module DeepMerge
2
+
3
+ class InvalidParameter < StandardError; end
4
+
5
+ # DEFAULT_FIELD_KNOCKOUT_PREFIX = '--'
6
+
7
+ # Deep Merge core documentation.
8
+ # deep_merge! method permits merging of arbitrary child elements. The two top level
9
+ # elements must be hashes. These hashes can contain unlimited (to stack limit) levels
10
+ # of child elements. These child elements to not have to be of the same types.
11
+ # Where child elements are of the same type, deep_merge will attempt to merge them together.
12
+ # Where child elements are not of the same type, deep_merge will skip or optionally overwrite
13
+ # the destination element with the contents of the source element at that level.
14
+ # So if you have two hashes like this:
15
+ # source = {:x => [1,2,3], :y => 2}
16
+ # dest = {:x => [4,5,'6'], :y => [7,8,9]}
17
+ # dest.deep_merge!(source)
18
+ # Results: {:x => [1,2,3,4,5,'6'], :y => 2}
19
+ # By default, "deep_merge!" will overwrite any unmergeables and merge everything else.
20
+ # To avoid this, use "deep_merge" (no bang/exclamation mark)
21
+ #
22
+ # Options:
23
+ # Options are specified in the last parameter passed, which should be in hash format:
24
+ # hash.deep_merge!({:x => [1,2]}, {:knockout_prefix => '--'})
25
+ # :preserve_unmergeables DEFAULT: false
26
+ # Set to true to skip any unmergeable elements from source
27
+ # :overwrite_arrays DEFAULT: false
28
+ # Set to true to not merge but overwrite arrays
29
+ # :knockout_prefix DEFAULT: nil
30
+ # Set to string value to signify prefix which deletes elements from existing element
31
+ # :sort_merged_arrays DEFAULT: false
32
+ # Set to true to sort all arrays that are merged together
33
+ # :unpack_arrays DEFAULT: nil
34
+ # Set to string value to run "Array::join" then "String::split" against all arrays
35
+ # :merge_debug DEFAULT: false
36
+ # Set to true to get console output of merge process for debugging
37
+ #
38
+ # Selected Options Details:
39
+ # :knockout_prefix => The purpose of this is to provide a way to remove elements
40
+ # from existing Hash by specifying them in a special way in incoming hash
41
+ # source = {:x => ['--1', '2']}
42
+ # dest = {:x => ['1', '3']}
43
+ # dest.ko_deep_merge!(source)
44
+ # Results: {:x => ['2','3']}
45
+ # Additionally, if the knockout_prefix is passed alone as a string, it will cause
46
+ # the entire element to be removed:
47
+ # source = {:x => '--'}
48
+ # dest = {:x => [1,2,3]}
49
+ # dest.ko_deep_merge!(source)
50
+ # Results: {:x => ""}
51
+ # :unpack_arrays => The purpose of this is to permit compound elements to be passed
52
+ # in as strings and to be converted into discrete array elements
53
+ # irsource = {:x => ['1,2,3', '4']}
54
+ # dest = {:x => ['5','6','7,8']}
55
+ # dest.deep_merge!(source, {:unpack_arrays => ','})
56
+ # Results: {:x => ['1','2','3','4','5','6','7','8'}
57
+ # Why: If receiving data from an HTML form, this makes it easy for a checkbox
58
+ # to pass multiple values from within a single HTML element
59
+ #
60
+ # There are many tests for this library - and you can learn more about the features
61
+ # and usages of deep_merge! by just browsing the test examples
62
+ def self.deep_merge!(source, dest, options = {})
63
+ # turn on this line for stdout debugging text
64
+ merge_debug = options[:merge_debug] || false
65
+ overwrite_unmergeable = !options[:preserve_unmergeables]
66
+ knockout_prefix = options[:knockout_prefix] || nil
67
+ raise InvalidParameter, "knockout_prefix cannot be an empty string in deep_merge!" if knockout_prefix == ""
68
+ raise InvalidParameter, "overwrite_unmergeable must be true if knockout_prefix is specified in deep_merge!" if knockout_prefix && !overwrite_unmergeable
69
+ # if present: we will split and join arrays on this char before merging
70
+ array_split_char = options[:unpack_arrays] || false
71
+ # Don't merge but overwrite arrays
72
+ overwrite_arrays = options[:overwrite_arrays] || false
73
+ # request that we sort together any arrays when they are merged
74
+ sort_merged_arrays = options[:sort_merged_arrays] || false
75
+ di = options[:debug_indent] || ''
76
+ # do nothing if source is nil
77
+ return dest if source.nil? || (source.respond_to?(:blank?) && source.blank?)
78
+ # if dest doesn't exist, then simply copy source to it
79
+ if !(dest) && overwrite_unmergeable
80
+ dest = source; return dest
81
+ end
82
+
83
+ puts "#{di}Source class: #{source.class.inspect} :: Dest class: #{dest.class.inspect}" if merge_debug
84
+ if source.kind_of?(Hash)
85
+ puts "#{di}Hashes: #{source.inspect} :: #{dest.inspect}" if merge_debug
86
+ source.each do |src_key, src_value|
87
+ if dest.kind_of?(Hash)
88
+ puts "#{di} looping: #{src_key.inspect} => #{src_value.inspect} :: #{dest.inspect}" if merge_debug
89
+ if dest[src_key]
90
+ puts "#{di} ==>merging: #{src_key.inspect} => #{src_value.inspect} :: #{dest[src_key].inspect}" if merge_debug
91
+ dest[src_key] = deep_merge!(src_value, dest[src_key], options.merge(:debug_indent => di + ' '))
92
+ else # dest[src_key] doesn't exist so we want to create and overwrite it (but we do this via deep_merge!)
93
+ puts "#{di} ==>merging over: #{src_key.inspect} => #{src_value.inspect}" if merge_debug
94
+ # note: we rescue here b/c some classes respond to "dup" but don't implement it (Numeric, TrueClass, FalseClass, NilClass among maybe others)
95
+ begin
96
+ src_dup = src_value.dup # we dup src_value if possible because we're going to merge into it (since dest is empty)
97
+ rescue TypeError
98
+ src_dup = src_value
99
+ end
100
+ dest[src_key] = deep_merge!(src_value, src_dup, options.merge(:debug_indent => di + ' '))
101
+ end
102
+ else # dest isn't a hash, so we overwrite it completely (if permitted)
103
+ if overwrite_unmergeable
104
+ puts "#{di} overwriting dest: #{src_key.inspect} => #{src_value.inspect} -over-> #{dest.inspect}" if merge_debug
105
+ dest = overwrite_unmergeables(source, dest, options)
106
+ end
107
+ end
108
+ end
109
+ elsif source.kind_of?(Array)
110
+ puts "#{di}Arrays: #{source.inspect} :: #{dest.inspect}" if merge_debug
111
+ # if we are instructed, join/split any source arrays before processing
112
+ if array_split_char
113
+ puts "#{di} split/join on source: #{source.inspect}" if merge_debug
114
+ source = source.join(array_split_char).split(array_split_char)
115
+ if dest.kind_of?(Array)
116
+ dest = dest.join(array_split_char).split(array_split_char)
117
+ end
118
+ end
119
+ # if there's a naked knockout_prefix in source, that means we are to truncate dest
120
+ if source.index(knockout_prefix)
121
+ dest = clear_or_nil(dest); source.delete(knockout_prefix)
122
+ end
123
+ if dest.kind_of?(Array) and ! overwrite_arrays
124
+ if knockout_prefix
125
+ print "#{di} knocking out: " if merge_debug
126
+ # remove knockout prefix items from both source and dest
127
+ source.delete_if do |ko_item|
128
+ retval = false
129
+ item = ko_item.respond_to?(:gsub) ? ko_item.gsub(%r{^#{knockout_prefix}}, "") : ko_item
130
+ if item != ko_item
131
+ print "#{ko_item} - " if merge_debug
132
+ dest.delete(item)
133
+ dest.delete(ko_item)
134
+ retval = true
135
+ end
136
+ retval
137
+ end
138
+ puts if merge_debug
139
+ end
140
+ puts "#{di} merging arrays: #{source.inspect} :: #{dest.inspect}" if merge_debug
141
+ dest = dest | source
142
+ dest.sort! if sort_merged_arrays
143
+ elsif overwrite_unmergeable or overwrite_arrays
144
+ puts "#{di} overwriting dest: #{source.inspect} -over-> #{dest.inspect}" if merge_debug
145
+ dest = overwrite_unmergeables(source, dest, options)
146
+ end
147
+ else # src_hash is not an array or hash, so we'll have to overwrite dest
148
+ puts "#{di}Others: #{source.inspect} :: #{dest.inspect}" if merge_debug
149
+ dest = overwrite_unmergeables(source, dest, options)
150
+ end
151
+ puts "#{di}Returning #{dest.inspect}" if merge_debug
152
+ dest
153
+ end # deep_merge!
154
+
155
+ # allows deep_merge! to uniformly handle overwriting of unmergeable entities
156
+ def self.overwrite_unmergeables(source, dest, options)
157
+ merge_debug = options[:merge_debug] || false
158
+ overwrite_unmergeable = !options[:preserve_unmergeables]
159
+ knockout_prefix = options[:knockout_prefix] || false
160
+ di = options[:debug_indent] || ''
161
+ if knockout_prefix && overwrite_unmergeable
162
+ if source.kind_of?(String) # remove knockout string from source before overwriting dest
163
+ if options[:overwrite_arrays] # Don't knock out strings for OATs
164
+ src_tmp = source
165
+ else
166
+ src_tmp = source.gsub(%r{^#{knockout_prefix}},"")
167
+ end
168
+ elsif source.kind_of?(Array) # remove all knockout elements before overwriting dest
169
+ src_tmp = source.delete_if {|ko_item| ko_item.kind_of?(String) && ko_item.match(%r{^#{knockout_prefix}}) }
170
+ else
171
+ src_tmp = source
172
+ end
173
+ if src_tmp == source # if we didn't find a knockout_prefix then we just overwrite dest
174
+ puts "#{di}#{src_tmp.inspect} -over-> #{dest.inspect}" if merge_debug
175
+ dest = src_tmp
176
+ else # if we do find a knockout_prefix, then we just delete dest
177
+ puts "#{di}\"\" -over-> #{dest.inspect}" if merge_debug
178
+ dest = ""
179
+ end
180
+ elsif overwrite_unmergeable
181
+ dest = source
182
+ end
183
+ dest
184
+ end
185
+
186
+ def self.clear_or_nil(obj)
187
+ if obj.respond_to?(:clear)
188
+ obj.clear
189
+ else
190
+ obj = nil
191
+ end
192
+ obj
193
+ end
194
+
195
+ end # module DeepMerge
@@ -0,0 +1 @@
1
+ require 'deep_merge/deep_merge_hash'
@@ -0,0 +1,28 @@
1
+ require 'deep_merge/core'
2
+
3
+ module DeepMerge
4
+ module DeepMergeHash
5
+ # ko_hash_merge! will merge and knockout elements prefixed with DEFAULT_FIELD_KNOCKOUT_PREFIX
6
+ def ko_deep_merge!(source, options = {})
7
+ default_opts = {:knockout_prefix => "--", :preserve_unmergeables => false}
8
+ DeepMerge::deep_merge!(source, self, default_opts.merge(options))
9
+ end
10
+
11
+ # deep_merge! will merge and overwrite any unmergeables in destination hash
12
+ def deep_merge!(source, options = {})
13
+ default_opts = {:preserve_unmergeables => false}
14
+ DeepMerge::deep_merge!(source, self, default_opts.merge(options))
15
+ end
16
+
17
+ # deep_merge will merge and skip any unmergeables in destination hash
18
+ def deep_merge(source, options = {})
19
+ default_opts = {:preserve_unmergeables => true}
20
+ DeepMerge::deep_merge!(source, self, default_opts.merge(options))
21
+ end
22
+
23
+ end # DeepMergeHashExt
24
+ end
25
+
26
+ class Hash
27
+ include DeepMerge::DeepMergeHash
28
+ end
@@ -0,0 +1,27 @@
1
+ require 'deep_merge/core'
2
+
3
+ module DeepMerge
4
+ module RailsCompat
5
+ # ko_hash_merge! will merge and knockout elements prefixed with DEFAULT_FIELD_KNOCKOUT_PREFIX
6
+ def ko_deeper_merge!(source, options = {})
7
+ default_opts = {:knockout_prefix => "--", :preserve_unmergeables => false}
8
+ DeepMerge::deep_merge!(source, self, default_opts.merge(options))
9
+ end
10
+
11
+ # deep_merge! will merge and overwrite any unmergeables in destination hash
12
+ def deeper_merge!(source, options = {})
13
+ default_opts = {:preserve_unmergeables => false}
14
+ DeepMerge::deep_merge!(source, self, default_opts.merge(options))
15
+ end
16
+
17
+ # deep_merge will merge and skip any unmergeables in destination hash
18
+ def deeper_merge(source, options = {})
19
+ default_opts = {:preserve_unmergeables => true}
20
+ DeepMerge::deep_merge!(source, self, default_opts.merge(options))
21
+ end
22
+ end
23
+ end
24
+
25
+ class Hash
26
+ include ::DeepMerge::RailsCompat
27
+ end
@@ -0,0 +1,163 @@
1
+ require 'timeout'
2
+ require 'oats/ossh'
3
+ # Returns all the matching IPs from the listed logs
4
+
5
+ class ApplicationLogs
6
+
7
+ @@app_logs_error_getter = {} # webHostName => ApplicationLogs objects
8
+ @@ip = nil
9
+ @@plink_cmd_params = {} # webHostName => Extra parameters to connect or ''
10
+ PLINK_TIMEOUT = 5
11
+
12
+ # Call returns only errors occurring after the previous call.
13
+ def ApplicationLogs.new_errors(initial = false)
14
+ logs = $oats['env']['web']['logs']
15
+ logs = nil if logs.nil? or logs.empty?
16
+ return [] unless logs
17
+ host = $oats['env']['web']['host']
18
+ if @@app_logs_error_getter[host]
19
+ return [] if initial
20
+ else
21
+ @@app_logs_error_getter[host] = ApplicationLogs.new(host,logs)
22
+ end
23
+ return @@app_logs_error_getter[host].new_errors
24
+ end
25
+
26
+ def initialize(host,logs)
27
+ ApplicationLogs.set_ip unless @@ip
28
+ @logs = logs
29
+ @log_error_count = []
30
+ @command = "plink #{host} -l loguser sudo grep -i #{@@ip} " + @logs.join(' ')
31
+ ApplicationLogs.set_plink_cmd_params
32
+ @command_issue = @command
33
+ end
34
+
35
+ def new_errors
36
+ $log.debug "Interrogating the application logs: #{@command_issue}"
37
+ errors = IO.popen(@command).readlines
38
+ total_errors = 0
39
+ @log_error_count.each {|i| total_errors += i}
40
+ new_error = []
41
+ return new_error if total_errors == errors.length
42
+ i = 0
43
+ new_error_count = []
44
+ new_error_count[0] = 0
45
+ errors.each do |line|
46
+ prefix = Regexp.new('^'+@logs[i]+':')
47
+ unless prefix =~ line
48
+ @log_error_count[i] = new_error_count[i]
49
+ i += 1
50
+ break if i == @logs.length
51
+ new_error_count[i] = 0
52
+ redo
53
+ end
54
+ new_error_count[i] += 1
55
+ new_error << line if new_error_count[i] > (@log_error_count[i] ? @log_error_count[i] : 0)
56
+ end
57
+ @log_error_count[i] = new_error_count[i]
58
+ return new_error
59
+ end
60
+
61
+ # Tails logs continuously.
62
+ def ApplicationLogs.tail_errors
63
+ tail_ip = $oats['execution']['tail_logs_ip']
64
+ logs = $oats['env']['web']['logs']
65
+ logs = nil if logs.nil? or logs.empty?
66
+ host = $oats['env']['web']['host']
67
+ if tail_ip
68
+ raise(OatsBadInput, "The execution:tail_logs_ip is set to [#{tail_ip}] but env:web:logs is empty.") unless logs
69
+ else
70
+ return
71
+ end
72
+ if tail_ip and tail_ip.instance_of?(String)
73
+ if /^\d\d\.\d\d*\.\d\d*\.\d\d*$/ =~ tail_ip
74
+ @@ip = tail_ip
75
+ else
76
+ raise(OatsBadInput, "Input for execution:tail_logs_ip [#{tail_ip}] is not in proper IP format.")
77
+ end
78
+ else
79
+ ApplicationLogs.set_ip unless @@ip
80
+ end
81
+ ApplicationLogs.set_plink_cmd_params(true)
82
+ command = "plink #{host} -l loguser sudo tail -f " + logs.join(' ')
83
+ command_issue = command
84
+ puts "Filtering for [#{@@ip}] after executing command: #{command}"
85
+ IO.popen(command_issue) do |io|
86
+ while io.gets do
87
+ puts $_ if Regexp.new(@@ip) =~ $_ or /^==>/ =~ $_
88
+ end
89
+ end
90
+ exit 0 # Should never get here. User has to kill the process to quit
91
+ end
92
+
93
+ def ApplicationLogs.set_plink_cmd_params(from_tail = nil)
94
+ host = $oats['env']['web']['host']
95
+ return if @@plink_cmd_params[host]
96
+ # Ossh does not support this option anymore. Must go in via Paegant
97
+ # Clean-up the code below later.
98
+ @@plink_cmd_params = ''
99
+ error = 0
100
+ error_msg = nil
101
+ error_msg2 = nil
102
+ correct_response = false
103
+ cmd_issue = "plink #{host} -l loguser whoami 2>&1"
104
+ cmd_display = cmd_issue
105
+ $log.debug "Issuing: " + cmd_issue
106
+ $log.debug "Please start Paegant with loguser key if there is no response in {PLINK_TIMEOUT} seconds."
107
+ begin
108
+ timeout(PLINK_TIMEOUT) do
109
+ IO.popen(cmd_issue) do |ios|
110
+ while ios.gets(':') do
111
+ if /s password:/ =~ $_
112
+ error = 1
113
+ error_msg = "Received Plink authentication challenge from "
114
+ error_msg2 = "If you have not started Paegant already, please do so."
115
+ elsif /s password:/ =~ $_
116
+ error = 2
117
+ error_msg = "Received Plink authentication challenge from "
118
+ error_msg2 = "If you have not defined an entry for [#{host} on Putty already, please do so."
119
+ elsif /^Password:/ =~ $_
120
+ error = 3
121
+ error_msg = "Received 'sudo root' authentication challenge from "
122
+ error_msg2 = "Sudo password cash has timed out. Please type the following on a shell commandline: #{cmd_display}"
123
+ elsif /^Unable to open connection:/ =~ $_
124
+ error = 4
125
+ error_msg = "Could not connect to "
126
+ error_msg2 = "You need to unset error log interrogation to run this test in this environment."
127
+ # elsif /^root/ =~ $_
128
+ elsif /^loguser/ =~ $_
129
+ correct_response = true
130
+ end
131
+ $log.error $_ unless $_.nil? or correct_response
132
+ ios.gets
133
+ $log.error $_ unless $_.nil? or correct_response
134
+ end
135
+ end
136
+ end
137
+ rescue Timeout::Error
138
+ $log.error "plink command timed out after [#{PLINK_TIMEOUT}] seconds."
139
+ end
140
+ if error == 0 and correct_response
141
+ $log.info "Received proper response from Plink."
142
+ return
143
+ else
144
+ if error_msg
145
+ if error_msg2
146
+ $log.error error_msg + "[#{host}]"
147
+ else
148
+ raise(OatsSetupError,error_msg)
149
+ end
150
+ raise(OatsSetupError,error_msg2)
151
+ end
152
+ end
153
+ end
154
+
155
+ def ApplicationLogs.set_ip
156
+ IO.popen('ipconfig') do |io|
157
+ while io.gets do
158
+ @@ip = $_.chomp.sub(/.*IP Address.*: (\d.*\d).*/,'\1') if /IP Address.*: / =~ $_
159
+ end
160
+ end
161
+ end
162
+
163
+ end
@@ -0,0 +1,58 @@
1
+ # Should be overridden by the user if desired
2
+ module Oats
3
+
4
+ module BuildId
5
+ def BuildId.generate
6
+ return
7
+ dir_results = $oats['execution']['dir_results']
8
+ env_name = $oats['env']['name']
9
+ return unless env_name and $oats['execution']['build_version']
10
+ TestList.current.variations.last.env_name = env_name
11
+ run_info_file = File.join(dir_results,'run_info_' + env_name + '.txt')
12
+ unless File.exist?(run_info_file)
13
+ File.open(run_info_file, 'w') do |f|
14
+ YAML.dump($oats,f)
15
+ end
16
+ end
17
+ if Oats.context['build_version'] # Collected build data previously
18
+ return if Oats.context['build_version']['execution'] == $oats['execution']['build_version'] # no change
19
+ Oats.context['build_version']['execution'] = $oats['execution']['build_version'] # Use the latest, input from test list
20
+ return
21
+ end
22
+ # First time collecting build data
23
+ Oats.context['build_version'] = { 'execution' => $oats['execution']['build_version'] }
24
+ all_build_info = ''
25
+ build_id_file = File.join(dir_results,'buildID_' + env_name + '.txt')
26
+
27
+ for host in $oats['execution']['build_versions'] do
28
+ web_host = $oats['env'][host] && $oats['env'][host]['host']
29
+ next unless web_host
30
+ urls = $oats['env'][host]['buildID_url']
31
+ next unless urls
32
+ urls = [ urls ] unless urls.instance_of? Array
33
+ versions = ''
34
+ urls.each do |url|
35
+ begin
36
+ if RUBY_VERSION =~ /^1.9/
37
+ resp = Net::HTTP.new(web_host, 80).get(url) # 1.9 doesn't like the second parameter
38
+ else
39
+ resp = Net::HTTP.new(web_host, 80).get(url, nil )
40
+ end
41
+ build_info = resp.body if resp.code == '200'
42
+ rescue
43
+ $log.error $!.to_s
44
+ $log.error "Occurred after issuing get request to [http://#{web_host}#{url}]"
45
+ build_info = nil
46
+ end
47
+ if build_info
48
+ versions += ' ' unless versions == ''
49
+ versions += build_info[6..(build_info.index("\n")-1)]
50
+ all_build_info += "--- #{host} #{url} --- \n" + build_info + "\n"
51
+ end
52
+ end
53
+ Oats.context['build_version'][host] = versions
54
+ end if $oats['execution']['build_versions']
55
+ File.open(build_id_file, 'w') { |f| f.puts all_build_info } unless all_build_info == ''
56
+ end
57
+ end
58
+ end