qa_robusta 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. data/.autotest +23 -0
  2. data/.gemtest +0 -0
  3. data/History.txt +6 -0
  4. data/Manifest.txt +101 -0
  5. data/README.txt +48 -0
  6. data/Rakefile +18 -0
  7. data/bin/qa_robusta +14 -0
  8. data/common/Rakefile +95 -0
  9. data/common/conf/monkey_patch.yaml +8 -0
  10. data/common/conf/monkey_patch.yaml.ex +10 -0
  11. data/common/lib/array.rb +9 -0
  12. data/common/lib/cache.rb +12 -0
  13. data/common/lib/constants.rb +35 -0
  14. data/common/lib/error_defns.rb +13 -0
  15. data/common/lib/format_html_tmp.html +34 -0
  16. data/common/lib/formatters.rb +18 -0
  17. data/common/lib/gem_helpers.rb +29 -0
  18. data/common/lib/gems/.svn/entries +43 -0
  19. data/common/lib/gems/cache/.svn/entries +28 -0
  20. data/common/lib/gems/doc/.svn/entries +28 -0
  21. data/common/lib/gems/gems/.svn/entries +28 -0
  22. data/common/lib/gems/installed/.svn/entries +40 -0
  23. data/common/lib/gems/installed/cache/.svn/entries +28 -0
  24. data/common/lib/gems/installed/doc/.svn/entries +28 -0
  25. data/common/lib/gems/installed/gems/.svn/entries +28 -0
  26. data/common/lib/gems/installed/specifications/.svn/entries +28 -0
  27. data/common/lib/gems/specifications/.svn/entries +28 -0
  28. data/common/lib/gen_suite_doc.rb +52 -0
  29. data/common/lib/load_test_data.rb +18 -0
  30. data/common/lib/monkey_patch.rb +149 -0
  31. data/common/lib/navigate_mech.rb +79 -0
  32. data/common/lib/update_element.rb +12 -0
  33. data/common/monkey_patches/mechanize.rb +589 -0
  34. data/common/monkey_patches/table.rb +363 -0
  35. data/common/monkey_patches/telnet.rb +420 -0
  36. data/common/monkey_patches/unit.rb +538 -0
  37. data/demo/demo_site.rb +38 -0
  38. data/demo/public/javascripts/jquery-1.6.2.min.js +18 -0
  39. data/demo/views/index.erb +35 -0
  40. data/lib/monkey_patch.rb +26 -0
  41. data/lib/qa_robusta.rb +3 -0
  42. data/mechanize_interface/conf/app.yaml +10 -0
  43. data/mechanize_interface/lib/agent.rb +18 -0
  44. data/mechanize_interface/lib/app_require.rb +19 -0
  45. data/mechanize_interface/lib/get_page.rb +20 -0
  46. data/mechanize_interface/lib/login.rb +30 -0
  47. data/mechanize_interface/lib/navigation_paths.rb +12 -0
  48. data/mechanize_interface/test/lib/mech_unit_test.rb +19 -0
  49. data/qa_observer/conf/dev_users.yaml +9 -0
  50. data/qa_observer/conf/development.yaml +3 -0
  51. data/qa_observer/conf/qa_observer_links.yaml +10 -0
  52. data/qa_observer/generators/site/site_generator.rb +61 -0
  53. data/qa_observer/generators/site/templates/base_urls.yaml.erb +6 -0
  54. data/qa_observer/generators/site/templates/create_flow.rb.erb +54 -0
  55. data/qa_observer/generators/site/templates/elements.rb.erb +61 -0
  56. data/qa_observer/generators/site/templates/html_elements.yaml +22 -0
  57. data/qa_observer/generators/site/templates/navigate.rb +32 -0
  58. data/qa_observer/generators/site/templates/reports.rb +7 -0
  59. data/qa_observer/generators/site/templates/users_list.yaml +21 -0
  60. data/qa_observer/generators/test_case/templates/test_case.rb.erb +62 -0
  61. data/qa_observer/generators/test_case/test_case_generator.rb +29 -0
  62. data/qa_observer/lib/doc.rb +103 -0
  63. data/qa_observer/lib/env_details.rb +2 -0
  64. data/qa_observer/lib/error_defns.rb +3 -0
  65. data/qa_observer/lib/form_helpers.rb +52 -0
  66. data/qa_observer/lib/reports.rb +7 -0
  67. data/qa_observer/lib/requires.rb +23 -0
  68. data/qa_observer/lib/system_test.rb +146 -0
  69. data/qa_observer/lib/test_extention.rb +29 -0
  70. data/qa_observer/lib/update_element.rb +12 -0
  71. data/qa_observer/lib/watir.rb +42 -0
  72. data/qa_observer/script/destroy +14 -0
  73. data/qa_observer/script/generate +14 -0
  74. data/qa_observer/sites/demo/conf/base_urls.yaml +6 -0
  75. data/qa_observer/sites/demo/conf/html_elements.yaml +22 -0
  76. data/qa_observer/sites/demo/conf/remote_machine.yaml +12 -0
  77. data/qa_observer/sites/demo/conf/users_list.yaml +21 -0
  78. data/qa_observer/sites/demo/elements/demo_elements.rb +9 -0
  79. data/qa_observer/sites/demo/flows/demo_flows.rb +37 -0
  80. data/qa_observer/sites/demo/helpers/.placeholder +0 -0
  81. data/qa_observer/sites/demo/lib/navigate.rb +32 -0
  82. data/qa_observer/sites/demo/lib/reports.rb +7 -0
  83. data/qa_observer/sites/demo/results/.placeholder +0 -0
  84. data/qa_observer/sites/demo/results/images/.placeholder +0 -0
  85. data/qa_observer/sites/demo/test_cases/home_page.rb +106 -0
  86. data/qa_observer/suites/demo_lg_chrome/lg.yaml +11 -0
  87. data/qa_observer/suites/demo_md_chrome/md.yaml +11 -0
  88. data/qa_observer/suites/demo_sm_chrome/sm.yaml +11 -0
  89. data/qa_observer/suites/init.rb +41 -0
  90. data/qa_observer/test_runner.rb +125 -0
  91. data/remote_unix/helpers/constants.rb +8 -0
  92. data/remote_unix/helpers/out_xforms.rb +48 -0
  93. data/remote_unix/lib/common.rb +52 -0
  94. data/remote_unix/lib/error_defn.rb +4 -0
  95. data/remote_unix/lib/general_unix.rb +308 -0
  96. data/remote_unix/lib/network_commands.rb +41 -0
  97. data/remote_unix/lib/network_info.rb +98 -0
  98. data/remote_unix/lib/postfix_commands.rb +87 -0
  99. data/remote_unix/lib/postfix_info.rb +30 -0
  100. data/remote_unix/lib/requires.rb +25 -0
  101. data/remote_unix/lib/scp.rb +22 -0
  102. data/remote_unix/lib/ssh.rb +46 -0
  103. data/test/test_qa_robusta.rb +8 -0
  104. metadata +219 -0
@@ -0,0 +1,363 @@
1
+ module Watir
2
+
3
+ # This class is used for dealing with tables.
4
+ # Normally a user would not need to create this object as it is returned by the Watir::Container#table method
5
+ #
6
+ # many of the methods available to this object are inherited from the Element class
7
+ #
8
+ class Table < Element
9
+ include Container
10
+
11
+ # Returns the table object containing the element
12
+ # * container - an instance of an IE object
13
+ # * anElement - a Watir object (TextField, Button, etc.)
14
+ def Table.create_from_element(container, element)
15
+ element.locate if defined?(element.locate)
16
+ o = element.ole_object.parentElement
17
+ o = o.parentElement until o.tagName == 'TABLE'
18
+ new container, :ole_object, o
19
+ end
20
+
21
+ # Returns an initialized instance of a table object
22
+ # * container - the container
23
+ # * how - symbol - how we access the table
24
+ # * what - what we use to access the table - id, name index etc
25
+ def initialize(container, how, what)
26
+ set_container container
27
+ @how = how
28
+ @what = what
29
+ super nil
30
+ end
31
+
32
+ def locate
33
+ if @how == :xpath
34
+ @o = @container.element_by_xpath(@what)
35
+ elsif @how == :ole_object
36
+ @o = @what
37
+ else
38
+ @o = @container.locate_tagged_element('TABLE', @how, @what)
39
+ end
40
+ end
41
+
42
+ # override the highlight method, as if the tables rows are set to have a background color,
43
+ # this will override the table background color, and the normal flash method won't work
44
+ def highlight(set_or_clear)
45
+ if set_or_clear == :set
46
+ begin
47
+ @original_border = @o.border.to_i
48
+ if @o.border.to_i==1
49
+ @o.border = 2
50
+ else
51
+ @o.border = 1
52
+ end
53
+ rescue
54
+ @original_border = nil
55
+ end
56
+ else
57
+ begin
58
+ @o.border= @original_border unless @original_border == nil
59
+ @original_border = nil
60
+ rescue
61
+ # we could be here for a number of reasons...
62
+ ensure
63
+ @original_border = nil
64
+ end
65
+ end
66
+ super
67
+ end
68
+
69
+ # this method is used to populate the properties in the to_s method
70
+ def table_string_creator
71
+ n = []
72
+ n << "rows:".ljust(TO_S_SIZE) + self.row_count.to_s
73
+ n << "cols:".ljust(TO_S_SIZE) + self.column_count.to_s
74
+ return n
75
+ end
76
+ private :table_string_creator
77
+
78
+ # returns the properties of the object in a string
79
+ # raises an ObjectNotFound exception if the object cannot be found
80
+ def to_s
81
+ assert_exists
82
+ r = string_creator
83
+ r += table_string_creator
84
+ return r.join("\n")
85
+ end
86
+
87
+ # iterates through the rows in the table. Yields a TableRow object
88
+ def each
89
+ assert_exists
90
+ 0.upto(@o.getElementsByTagName("TR").length) do |i|
91
+ yield TableRow.new(@container, :ole_object, _row(i))
92
+ end
93
+ end
94
+
95
+ # Returns a row in the table
96
+ # * index - the index of the row
97
+ def [](index)
98
+ assert_exists
99
+ return TableRow.new(@container, :ole_object, _row(index))
100
+ end
101
+
102
+ # Returns the number of rows inside the table, including rows in nested tables.
103
+ def row_count
104
+ assert_exists
105
+ #return table_body.children.length
106
+ return @o.getElementsByTagName("TR").length
107
+ end
108
+
109
+ # Returns the number of rows in the table, not including rows in nested tables.
110
+ def row_count_excluding_nested_tables
111
+ assert_exists
112
+ return @o.rows.length
113
+ end
114
+
115
+ # This method returns the number of columns in a row of the table.
116
+ # Raises an UnknownObjectException if the table doesn't exist.
117
+ # * index - the index of the row
118
+ def column_count(index=0)
119
+ assert_exists
120
+ _row(index).cells.length
121
+ end
122
+
123
+ # This method returns the table as a 2 dimensional array.
124
+ # Don't expect too much if there are nested tables, colspan etc.
125
+ # Raises an UnknownObjectException if the table doesn't exist.
126
+ # http://www.w3.org/TR/html4/struct/tables.html
127
+ def to_a
128
+ assert_exists
129
+ y = []
130
+ table_rows = @o.getElementsByTagName("TR")
131
+ for row in table_rows
132
+ x = []
133
+ for td in row.getElementsbyTagName("TD")
134
+ x << td.innerText.strip
135
+ end
136
+ y << x
137
+ end
138
+ return y
139
+ end
140
+
141
+ def table_body(index=1)
142
+ return @o.getElementsByTagName('TBODY')[index]
143
+ end
144
+ private :table_body
145
+
146
+ # returns a watir object
147
+ def body(how, what)
148
+ return TableBody.new(@container, how, what, self)
149
+ end
150
+
151
+ # returns a watir object
152
+ def bodies
153
+ assert_exists
154
+ return TableBodies.new(@container, @o)
155
+ end
156
+
157
+ # returns an ole object
158
+ def _row(index)
159
+ return @o.invoke("rows")[(index - 1).to_s]
160
+ end
161
+ private :_row
162
+
163
+ # Returns an array containing all the text values in the specified column
164
+ # Raises an UnknownCellException if the specified column does not exist in every
165
+ # Raises an UnknownObjectException if the table doesn't exist.
166
+ # row of the table
167
+ # * columnnumber - column index to extract values from
168
+ def column_values(columnnumber)
169
+ return (1..row_count).collect {|i| self[i][columnnumber].text}
170
+ end
171
+
172
+ # Returns an array containing all the text values in the specified row
173
+ # Raises an UnknownObjectException if the table doesn't exist.
174
+ # * rownumber - row index to extract values from
175
+ def row_values(rownumber)
176
+ return (1..column_count(rownumber)).collect {|i| self[rownumber][i].text}
177
+ end
178
+
179
+ end
180
+
181
+ # this class is a collection of the table body objects that exist in the table
182
+ # it wouldnt normally be created by a user, but gets returned by the bodies method of the Table object
183
+ # many of the methods available to this object are inherited from the Element class
184
+ #
185
+ class TableBodies < Element
186
+ def initialize(container, parent_table)
187
+ set_container container
188
+ @o = parent_table # in this case, @o is the parent table
189
+ end
190
+
191
+ # returns the number of TableBodies that exist in the table
192
+ def length
193
+ assert_exists
194
+ return @o.tBodies.length
195
+ end
196
+
197
+ # returns the n'th Body as a Watir TableBody object
198
+ def []n
199
+ assert_exists
200
+ return TableBody.new(@container, :ole_object, ole_table_body_at_index(n))
201
+ end
202
+
203
+ # returns an ole table body
204
+ def ole_table_body_at_index(n)
205
+ return @o.tBodies[(n-1).to_s]
206
+ end
207
+
208
+ # iterates through each of the TableBodies in the Table. Yields a TableBody object
209
+ def each
210
+ 1.upto(@o.tBodies.length) do |i|
211
+ yield TableBody.new(@container, :ole_object, ole_table_body_at_index(i))
212
+ end
213
+ end
214
+
215
+ end
216
+
217
+ # this class is a table body
218
+ class TableBody < Element
219
+ def locate
220
+ @o = nil
221
+ if @how == :ole_object
222
+ @o = @what # in this case, @o is the table body
223
+ elsif @how == :index
224
+ @o = @parent_table.bodies.ole_table_body_at_index(@what)
225
+ end
226
+ @rows = []
227
+ if @o
228
+ @o.rows.each do |oo|
229
+ @rows << TableRow.new(@container, :ole_object, oo)
230
+ end
231
+ end
232
+ end
233
+
234
+ def initialize(container, how, what, parent_table=nil)
235
+ set_container container
236
+ @how = how
237
+ @what = what
238
+ @parent_table = parent_table
239
+ super nil
240
+ end
241
+
242
+ # returns the specified row as a TableRow object
243
+ def [](n)
244
+ assert_exists
245
+ return @rows[n - 1]
246
+ end
247
+
248
+ # iterates through all the rows in the table body
249
+ def each
250
+ locate
251
+ 0.upto(@rows.length - 1) { |i| yield @rows[i] }
252
+ end
253
+
254
+ # returns the number of rows in this table body.
255
+ def length
256
+ return @rows.length
257
+ end
258
+ end
259
+
260
+ class TableRow < Element
261
+
262
+ def locate
263
+ @o = nil
264
+ if @how == :ole_object
265
+ @o = @what
266
+ elsif @how == :xpath
267
+ @o = @container.element_by_xpath(@what)
268
+ else
269
+ @o = @container.locate_tagged_element("TR", @how, @what)
270
+ end
271
+ if @o # cant call the assert_exists here, as an exists? method call will fail
272
+ @cells = []
273
+ @o.cells.each do |oo|
274
+ @cells << TableCell.new(@container, :ole_object, oo)
275
+ end
276
+ end
277
+ end
278
+
279
+ # Returns an initialized instance of a table row
280
+ # * o - the object contained in the row
281
+ # * container - an instance of an IE object
282
+ # * how - symbol - how we access the row
283
+ # * what - what we use to access the row - id, index etc. If how is :ole_object then what is a Internet Explorer Raw Row
284
+ def initialize(container, how, what)
285
+ set_container container
286
+ @how = how
287
+ @what = what
288
+ super nil
289
+ end
290
+
291
+ # this method iterates through each of the cells in the row. Yields a TableCell object
292
+ def each
293
+ locate
294
+ 0.upto(@cells.length) { |i| yield @cells[i] }
295
+ end
296
+
297
+ # Returns an element from the row as a TableCell object
298
+ def [](index)
299
+ assert_exists
300
+ if @cells.length < index
301
+ raise UnknownCellException, "Unable to locate a cell at index #{index}"
302
+ end
303
+ return @cells[(index)]
304
+ end
305
+
306
+ # defaults all missing methods to the array of elements, to be able to
307
+ # use the row as an array
308
+ # def method_missing(aSymbol, *args)
309
+ # return @o.send(aSymbol, *args)
310
+ # end
311
+ def column_count
312
+ locate
313
+ @cells.length
314
+ end
315
+ end
316
+
317
+ # this class is a table cell - when called via the Table object
318
+ class TableCell < Element
319
+ include Watir::Exception
320
+ include Container
321
+
322
+ def locate
323
+ if @how == :xpath
324
+ @o = @container.element_by_xpath(@what)
325
+ elsif @how == :ole_object
326
+ @o = @what
327
+ else
328
+ @o = @container.locate_tagged_element("TD", @how, @what)
329
+ end
330
+ end
331
+
332
+ # Returns an initialized instance of a table cell
333
+ # * container - an IE object
334
+ # * how - symbol - how we access the cell
335
+ # * what - what we use to access the cell - id, name index etc
336
+ def initialize(container, how, what)
337
+ set_container container
338
+ @how = how
339
+ @what = what
340
+ super nil
341
+ end
342
+
343
+ def ole_inner_elements
344
+ locate
345
+ return @o.all
346
+ end
347
+ private :ole_inner_elements
348
+
349
+ def document
350
+ locate
351
+ return @o
352
+ end
353
+
354
+ alias to_s text
355
+
356
+ def colspan
357
+ locate
358
+ @o.colSpan
359
+ end
360
+
361
+ end
362
+
363
+ end
@@ -0,0 +1,420 @@
1
+ require 'rubygems'
2
+ require 'net/ssh'
3
+
4
+ module Net
5
+ module SSH
6
+
7
+ # == Net::SSH::Telnet
8
+ #
9
+ # Provides a simple send/expect interface with an API almost
10
+ # identical to Net::Telnet. Please see Net::Telnet for main documentation.
11
+ # Only the differences are documented here.
12
+
13
+ class Telnet
14
+
15
+ CR = "\015"
16
+ LF = "\012"
17
+ EOL = CR + LF
18
+ VERSION = '0.0.1'
19
+
20
+ # Wrapper to emulate the behaviour of Net::Telnet "Proxy" option, where
21
+ # the user passes in an already-open socket
22
+
23
+ class TinyFactory
24
+ def initialize(sock)
25
+ @sock = sock
26
+ end
27
+ def open(host, port)
28
+ s = @sock
29
+ @sock = nil
30
+ s
31
+ end
32
+ end
33
+
34
+ # Creates a new Net::SSH::Telnet object.
35
+ #
36
+ # The API is similar to Net::Telnet, although you will need to pass in
37
+ # either an existing Net::SSH::Session object or a Username and Password,
38
+ # as shown below.
39
+ #
40
+ # Note that unlike Net::Telnet there is no preprocess method automatically
41
+ # setting up options related to proper character translations, so if your
42
+ # remote ptty is configured differently than the typical linux one you may
43
+ # need to pass in a different terminator or call 'stty' remotely to set it
44
+ # into an expected mode. This is better explained by the author of perl's
45
+ # Net::SSH::Expect here:
46
+ #
47
+ # http://search.cpan.org/~bnegrao/Net-SSH-Expect-1.04/lib/Net/SSH/Expect.pod
48
+ # #IMPORTANT_NOTES_ABOUT_DEALING_WITH_SSH_AND_PSEUDO-TERMINALS
49
+ #
50
+ # though for most installs the default LF should be fine. See example 5
51
+ # below.
52
+ #
53
+ # A new option is added to correct a misfeature of Net::Telnet. If you
54
+ # pass "FailEOF" => true, then if the remote end disconnects while you
55
+ # are still waiting for your match pattern then an EOFError is raised.
56
+ # Otherwise, it reverts to the same behaviour as Net::Telnet, which is
57
+ # just to return whatever data was sent so far, or nil if no data was
58
+ # returned so far. (This is a poor design because you can't tell whether
59
+ # the expected pattern was successfully matched or the remote end
60
+ # disconnected unexpectedly, unless you perform a second match on the
61
+ # return string). See
62
+ # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/11373
63
+ # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/11380
64
+ #
65
+ # Example 1 - pass existing Net::SSH::Session object
66
+ #
67
+ # ssh = Net::SSH.start("127.0.0.1",
68
+ # :username=>"test123",
69
+ # :password=>"pass456"
70
+ # )
71
+ # s = Net::SSH::Telnet.new(
72
+ # "Dump_log" => "/dev/stdout",
73
+ # "Session" => ssh
74
+ # )
75
+ # puts "Logged in"
76
+ # p s.cmd("echo hello")
77
+ #
78
+ # This is the most flexible way as it allows you to set up the SSH
79
+ # session using whatever authentication system you like. When done this
80
+ # way, calling Net::SSH::Telnet.new multiple times will create
81
+ # multiple channels, and #close will only close one channel.
82
+ #
83
+ # In all later examples, calling #close will close the entire
84
+ # Net::SSH::Session object (and therefore drop the TCP connection)
85
+ #
86
+ # Example 2 - pass host, username and password
87
+ #
88
+ # s = Net::SSH::Telnet.new(
89
+ # "Dump_log" => "/dev/stdout",
90
+ # "Host" => "127.0.0.1",
91
+ # "Username" => "test123",
92
+ # "Password" => "pass456"
93
+ # )
94
+ # puts "Logged in"
95
+ # puts s.cmd("echo hello")
96
+ #
97
+ # Example 3 - pass open IO object, username and password (this is really
98
+ # just for compatibility with Net::Telnet Proxy feature)
99
+ #
100
+ # require 'socket'
101
+ # sock = TCPSocket.open("127.0.0.1",22)
102
+ # s = Net::SSH::Telnet.new(
103
+ # "Dump_log" => "/dev/stdout",
104
+ # "Proxy" => sock,
105
+ # "Username" => "test123",
106
+ # "Password" => "pass456"
107
+ # )
108
+ # puts "Logged in"
109
+ # puts s.cmd("echo hello")
110
+ #
111
+ # Example 4 - pass a connection factory, host, username and password;
112
+ # Net::SSH will call #open(host,port) on this object. Included just
113
+ # because it was easy :-)
114
+ #
115
+ # require 'socket'
116
+ # s = Net::SSH::Telnet.new(
117
+ # "Dump_log" => "/dev/stdout",
118
+ # "Factory" => TCPSocket,
119
+ # "Host" => "127.0.0.1",
120
+ # "Username" => "test123",
121
+ # "Password" => "pass456"
122
+ # )
123
+ # puts "Logged in"
124
+ # puts s.cmd("echo hello")
125
+ #
126
+ # Example 5 - connection to a SAN device running a customized NetBSD with
127
+ # different ptty defaults, it doesn't convert LF -> CR+LF (see the man
128
+ # page for 'stty') and uses a custom prompt
129
+ #
130
+ # s = Net::SSH::Telnet.new(
131
+ # "Host" => "192.168.1.1",
132
+ # "Username" => "test123",
133
+ # "Password" => "pass456",
134
+ # "Prompt" => %r{^\S+>\s.*$},
135
+ # "Terminator" => "\r"
136
+ # )
137
+ # puts "Logged in"
138
+ # puts s.cmd("show alerts")
139
+
140
+ def initialize(options, &blk) # :yield: mesg
141
+ @options = options
142
+ @options["Host"] = "localhost" unless @options.has_key?("Host")
143
+ @options["Port"] = 22 unless @options.has_key?("Port")
144
+ @options["Prompt"] = /[$%#>] \z/n unless @options.has_key?("Prompt")
145
+ @options["Timeout"] = 10 unless @options.has_key?("Timeout")
146
+ @options["Waittime"] = 0 unless @options.has_key?("Waittime")
147
+ @options["Terminator"] = LF unless @options.has_key?("Terminator")
148
+
149
+ unless @options.has_key?("Binmode")
150
+ @options["Binmode"] = false
151
+ else
152
+ unless (true == @options["Binmode"] or false == @options["Binmode"])
153
+ raise ArgumentError, "Binmode option must be true or false"
154
+ end
155
+ end
156
+
157
+ if @options.has_key?("Output_log")
158
+ @log = File.open(@options["Output_log"], 'a+')
159
+ @log.sync = true
160
+ @log.binmode
161
+ end
162
+
163
+ if @options.has_key?("Dump_log")
164
+ @dumplog = File.open(@options["Dump_log"], 'a+')
165
+ @dumplog.sync = true
166
+ @dumplog.binmode
167
+ def @dumplog.log_dump(dir, x) # :nodoc:
168
+ len = x.length
169
+ addr = 0
170
+ offset = 0
171
+ while 0 < len
172
+ if len < 16
173
+ line = x[offset, len]
174
+ else
175
+ line = x[offset, 16]
176
+ end
177
+ hexvals = line.unpack('H*')[0]
178
+ hexvals += ' ' * (32 - hexvals.length)
179
+ hexvals = format("%s %s %s %s " * 4, *hexvals.unpack('a2' * 16))
180
+ line = line.gsub(/[\000-\037\177-\377]/n, '.')
181
+ printf "%s 0x%5.5x: %s%s\n", dir, addr, hexvals, line
182
+ addr += 16
183
+ offset += 16
184
+ len -= 16
185
+ end
186
+ print "\n"
187
+ end
188
+ end
189
+
190
+ if @options.has_key?("Session")
191
+ @ssh = @options["Session"]
192
+ @close_all = false
193
+ elsif @options.has_key?("Proxy")
194
+ @ssh = Net::SSH.start(nil, nil,
195
+ :host_name => @options["Host"], # ignored
196
+ :port => @options["Port"], # ignored
197
+ :user => @options["Username"],
198
+ :password => @options["Password"],
199
+ :timeout => @options["Timeout"],
200
+ :proxy => TinyFactory.new(@options["Proxy"])
201
+ )
202
+ @close_all = true
203
+ else
204
+ message = "Trying " + @options["Host"] + "...\n"
205
+ yield(message) if block_given?
206
+ @log.write(message) if @options.has_key?("Output_log")
207
+ @dumplog.log_dump('#', message) if @options.has_key?("Dump_log")
208
+
209
+ begin
210
+ @ssh = Net::SSH.start(nil, nil,
211
+ :host_name => @options["Host"],
212
+ :port => @options["Port"],
213
+ :user => @options["Username"],
214
+ :password => @options["Password"],
215
+ :timeout => @options["Timeout"],
216
+ :proxy => @options["Factory"]
217
+ )
218
+ @close_all = true
219
+ rescue TimeoutError
220
+ raise TimeoutError, "timed out while opening a connection to the host"
221
+ rescue
222
+ @log.write($ERROR_INFO.to_s + "\n") if @options.has_key?("Output_log")
223
+ @dumplog.log_dump('#', $ERROR_INFO.to_s + "\n") if @options.has_key?("Dump_log")
224
+ raise
225
+ end
226
+
227
+ message = "Connected to " + @options["Host"] + ".\n"
228
+ yield(message) if block_given?
229
+ @log.write(message) if @options.has_key?("Output_log")
230
+ @dumplog.log_dump('#', message) if @options.has_key?("Dump_log")
231
+ end
232
+
233
+ @buf = ""
234
+ @eof = false
235
+ @channel = nil
236
+ @ssh.open_channel do |channel|
237
+ channel.request_pty { |ch,success|
238
+ if success == false
239
+ raise "Failed to open ssh pty"
240
+ end
241
+ }
242
+ channel.send_channel_request("shell") { |ch, success|
243
+ if success
244
+ @channel = ch
245
+ waitfor(@options['Prompt'], &blk)
246
+ return
247
+ else
248
+ raise "Failed to open ssh shell"
249
+ end
250
+ }
251
+ channel.on_data { |ch,data| @buf << data }
252
+ channel.on_extended_data { |ch,type,data| @buf << data if type == 1 }
253
+ channel.on_close { @eof = true }
254
+ end
255
+ @ssh.loop
256
+ end # initialize
257
+
258
+ # Close the ssh channel, and also the entire ssh session if we
259
+ # opened it.
260
+
261
+ def close
262
+ @channel.close if @channel
263
+ @channel = nil
264
+ @ssh.close if @close_all and @ssh
265
+ end
266
+
267
+ # The ssh session and channel we are using.
268
+ attr_reader :ssh, :channel
269
+
270
+ # Turn newline conversion on (+mode+ == false) or off (+mode+ == true),
271
+ # or return the current value (+mode+ is not specified).
272
+ def binmode(mode = nil)
273
+ case mode
274
+ when nil
275
+ @options["Binmode"]
276
+ when true, false
277
+ @options["Binmode"] = mode
278
+ else
279
+ raise ArgumentError, "argument must be true or false"
280
+ end
281
+ end
282
+
283
+ # Turn newline conversion on (false) or off (true).
284
+ def binmode=(mode)
285
+ if (true == mode or false == mode)
286
+ @options["Binmode"] = mode
287
+ else
288
+ raise ArgumentError, "argument must be true or false"
289
+ end
290
+ end
291
+
292
+ # Read data from the host until a certain sequence is matched.
293
+
294
+ def waitfor(options) # :yield: recvdata
295
+ time_out = @options["Timeout"]
296
+ waittime = @options["Waittime"]
297
+ fail_eof = @options["FailEOF"]
298
+
299
+ if options.kind_of?(Hash)
300
+ prompt = if options.has_key?("Match")
301
+ options["Match"]
302
+ elsif options.has_key?("Prompt")
303
+ options["Prompt"]
304
+ elsif options.has_key?("String")
305
+ Regexp.new( Regexp.quote(options["String"]) )
306
+ end
307
+ time_out = options["Timeout"] if options.has_key?("Timeout")
308
+ waittime = options["Waittime"] if options.has_key?("Waittime")
309
+ fail_eof = options["FailEOF"] if options.has_key?("FailEOF")
310
+ else
311
+ prompt = options
312
+ end
313
+
314
+ if time_out == false
315
+ time_out = nil
316
+ end
317
+ line = ''
318
+ buf = ''
319
+ rest = ''
320
+ sock = @ssh.transport.socket
321
+ init_time = Time.now.tv_sec
322
+ until prompt === line and ((@eof and @buf == "") or not IO::select([sock], nil, nil, waittime))
323
+ while @buf == "" and !@eof
324
+ # timeout is covered by net-ssh
325
+ @channel.connection.process(0.1)
326
+ # if waittime.to_i > 0
327
+ # exec_time = Time.now.tv_sec - init_time
328
+ # raise Timeout::Error if exec_time > waittime
329
+ # end
330
+ end
331
+ if @buf != ""
332
+ # if waittime.to_i > 0
333
+ # exec_time = Time.now.tv_sec - init_time
334
+ # raise Timeout::Error if exec_time > waittime
335
+ # end
336
+
337
+ c = @buf; @buf = ""
338
+ @dumplog.log_dump('<', c) if @options.has_key?("Dump_log")
339
+ buf = c
340
+ buf.gsub!(/#{EOL}/no, "\n") unless @options["Binmode"]
341
+ rest = ''
342
+ @log.print(buf) if @options.has_key?("Output_log")
343
+ line += buf
344
+ yield buf if block_given?
345
+ elsif @eof # End of file reached
346
+ break if prompt === line
347
+ raise EOFError if fail_eof
348
+ if line == ''
349
+ line = nil
350
+ yield nil if block_given?
351
+ end
352
+ break
353
+ end
354
+ end
355
+ line
356
+ end
357
+
358
+ # Write +string+ to the host.
359
+ #
360
+ # Does not perform any conversions on +string+. Will log +string+ to the
361
+ # dumplog, if the Dump_log option is set.
362
+ def write(string)
363
+ @dumplog.log_dump('>', string) if @options.has_key?("Dump_log")
364
+ @channel.send_data string
365
+ end
366
+
367
+ # Sends a string to the host.
368
+ #
369
+ # This does _not_ automatically append a newline to the string. Embedded
370
+ # newlines may be converted depending upon the values of binmode or
371
+ # terminator.
372
+ def print(string)
373
+ terminator = @options["Terminator"]
374
+
375
+ if @options["Binmode"]
376
+ self.write(string)
377
+ else
378
+ self.write(string.gsub(/\n/n, terminator))
379
+ end
380
+ end
381
+
382
+ # Sends a string to the host.
383
+ #
384
+ # Same as #print(), but appends a newline to the string.
385
+ def puts(string)
386
+ self.print(string + "\n")
387
+ end
388
+
389
+ # Send a command to the host.
390
+ #
391
+ # More exactly, sends a string to the host, and reads in all received
392
+ # data until is sees the prompt or other matched sequence.
393
+ #
394
+ # The command or other string will have the newline sequence appended
395
+ # to it.
396
+
397
+ def cmd(options) # :yield: recvdata
398
+ match = @options["Prompt"]
399
+ time_out = @options["Timeout"]
400
+
401
+ if options.kind_of?(Hash)
402
+ string = options["String"]
403
+ match = options["Match"] if options.has_key?("Match")
404
+ time_out = options["Timeout"] if options.has_key?("Timeout")
405
+ waittime = options["Waittime"] if options.has_key?("Waittime")
406
+ else
407
+ string = options
408
+ end
409
+
410
+ self.puts(string)
411
+ if block_given?
412
+ waitfor({"Prompt" => match, "Timeout" => time_out, "Waittime" => waittime}){|c| yield c }
413
+ else
414
+ waitfor({"Prompt" => match, "Timeout" => time_out, "Waittime" => waittime})
415
+ end
416
+ end
417
+
418
+ end # class Telnet
419
+ end # module SSH
420
+ end # module Net