solutious-stella 0.6.0 → 0.7.0.001

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/CHANGES.txt +3 -15
  2. data/LICENSE.txt +1 -1
  3. data/README.rdoc +90 -60
  4. data/Rakefile +32 -42
  5. data/bin/stella +138 -0
  6. data/examples/basic/listing_ids.csv +7 -0
  7. data/examples/basic/plan.rb +71 -0
  8. data/lib/stella.rb +57 -104
  9. data/lib/stella/cli.rb +66 -0
  10. data/lib/stella/client.rb +197 -0
  11. data/lib/stella/config.rb +87 -0
  12. data/lib/stella/data.rb +85 -0
  13. data/lib/stella/data/http.rb +2 -257
  14. data/lib/stella/data/http/body.rb +15 -0
  15. data/lib/stella/data/http/request.rb +116 -0
  16. data/lib/stella/data/http/response.rb +92 -0
  17. data/lib/stella/dsl.rb +5 -0
  18. data/lib/stella/engine.rb +55 -0
  19. data/lib/stella/engine/functional.rb +39 -0
  20. data/lib/stella/engine/load.rb +106 -0
  21. data/lib/stella/exceptions.rb +15 -0
  22. data/lib/stella/guidelines.rb +18 -0
  23. data/lib/stella/mixins.rb +2 -0
  24. data/lib/stella/stats.rb +3 -7
  25. data/lib/stella/testplan.rb +95 -220
  26. data/lib/stella/testplan/stats.rb +26 -0
  27. data/lib/stella/testplan/usecase.rb +67 -0
  28. data/lib/stella/utils.rb +126 -0
  29. data/lib/{util → stella/utils}/httputil.rb +0 -0
  30. data/lib/stella/version.rb +15 -0
  31. data/lib/threadify.rb +0 -6
  32. data/stella.gemspec +43 -49
  33. data/support/example_webapp.rb +246 -0
  34. data/support/useragents.txt +75 -0
  35. metadata +66 -31
  36. data/bin/example_test.rb +0 -82
  37. data/bin/example_webapp.rb +0 -63
  38. data/lib/logger.rb +0 -79
  39. data/lib/stella/clients.rb +0 -161
  40. data/lib/stella/command/base.rb +0 -20
  41. data/lib/stella/command/form.rb +0 -36
  42. data/lib/stella/command/get.rb +0 -44
  43. data/lib/stella/common.rb +0 -53
  44. data/lib/stella/crypto.rb +0 -88
  45. data/lib/stella/data/domain.rb +0 -82
  46. data/lib/stella/environment.rb +0 -66
  47. data/lib/stella/functest.rb +0 -105
  48. data/lib/stella/loadtest.rb +0 -186
  49. data/lib/stella/testrunner.rb +0 -64
  50. data/lib/storable.rb +0 -280
  51. data/lib/timeunits.rb +0 -65
  52. data/tryouts/drb/drb_test.rb +0 -65
  53. data/tryouts/drb/open4.rb +0 -19
  54. data/tryouts/drb/slave.rb +0 -27
  55. data/tryouts/oo_tryout.rb +0 -30
@@ -0,0 +1,126 @@
1
+
2
+ require 'socket'
3
+ require 'open-uri'
4
+ require 'date'
5
+
6
+ require 'timeout'
7
+
8
+ module Stella
9
+
10
+ # A motley collection of methods that Stella loves to call!
11
+ module Utils
12
+ extend self
13
+ include Socket::Constants
14
+
15
+ # Return the external IP address (the one seen by the internet)
16
+ def external_ip_address
17
+ ip = nil
18
+ begin
19
+ %w{solutious.heroku.com/ip}.each do |sponge|
20
+ ipstr = Net::HTTP.get(URI.parse("http://#{sponge}")) || ''
21
+ ip = /([0-9]{1,3}\.){3}[0-9]{1,3}/.match(ipstr).to_s
22
+ break if ip && !ip.empty?
23
+ end
24
+ rescue SocketError, Errno::ETIMEDOUT => ex
25
+ Stella.le "Connection Error. Check your internets!"
26
+ end
27
+ ip
28
+ end
29
+
30
+ # Return the local IP address which receives external traffic
31
+ # from: http://coderrr.wordpress.com/2008/05/28/get-your-local-ip-address/
32
+ # NOTE: This <em>does not</em> open a connection to the IP address.
33
+ def internal_ip_address
34
+ # turn off reverse DNS resolution temporarily
35
+ orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true
36
+ ip = UDPSocket.open {|s| s.connect('75.101.137.7', 1); s.addr.last } # Solutious IP
37
+ ip
38
+ ensure
39
+ Socket.do_not_reverse_lookup = orig
40
+ end
41
+
42
+
43
+ # <tt>require</tt> a glob of files.
44
+ # * +path+ is a list of path elements which is sent to File.join
45
+ # and then to Dir.glob. The list of files found are sent to require.
46
+ # Nothing is returned but LoadError exceptions are caught. The message
47
+ # is printed to STDERR and the program exits with 7.
48
+ def require_glob(*path)
49
+ begin
50
+ Dir.glob(File.join(*path.flatten)).each do |path|
51
+ require path
52
+ end
53
+ rescue LoadError => ex
54
+ puts "Error: #{ex.message}"
55
+ exit 7
56
+ end
57
+ end
58
+
59
+ # Checks whether something is listening to a socket.
60
+ # * +host+ A hostname
61
+ # * +port+ The port to check
62
+ # * +wait+ The number of seconds to wait for before timing out.
63
+ #
64
+ # Returns true if +host+ allows a socket connection on +port+.
65
+ # Returns false if one of the following exceptions is raised:
66
+ # Errno::EAFNOSUPPORT, Errno::ECONNREFUSED, SocketError, Timeout::Error
67
+ #
68
+ def service_available?(host, port, wait=3)
69
+ if Stella.sysinfo.vm == :java
70
+ begin
71
+ iadd = Java::InetSocketAddress.new host, port
72
+ socket = Java::Socket.new
73
+ socket.connect iadd, wait * 1000 # milliseconds
74
+ success = !socket.isClosed && socket.isConnected
75
+ rescue NativeException => ex
76
+ puts ex.message, ex.backtrace if Stella.debug?
77
+ false
78
+ end
79
+ else
80
+ begin
81
+ status = Timeout::timeout(wait) do
82
+ socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
83
+ sockaddr = Socket.pack_sockaddr_in( port, host )
84
+ socket.connect( sockaddr )
85
+ end
86
+ true
87
+ rescue Errno::EAFNOSUPPORT, Errno::ECONNREFUSED, SocketError, Timeout::Error => ex
88
+ puts ex.class, ex.message, ex.backtrace if Stella.debug?
89
+ false
90
+ end
91
+ end
92
+ end
93
+
94
+ # A basic file writer
95
+ def write_to_file(filename, content, mode, chmod=600)
96
+ mode = (mode == :append) ? 'a' : 'w'
97
+ f = File.open(filename,mode)
98
+ f.puts content
99
+ f.close
100
+ return unless Stella.sysinfo.os == :unix
101
+ raise "Provided chmod is not a Fixnum (#{chmod})" unless chmod.is_a?(Fixnum)
102
+ File.chmod(chmod, filename)
103
+ end
104
+
105
+ #
106
+ # Generates a string of random alphanumeric characters.
107
+ # * +len+ is the length, an Integer. Default: 8
108
+ # * +safe+ in safe-mode, ambiguous characters are removed (default: true):
109
+ # i l o 1 0
110
+ def strand( len=8, safe=true )
111
+ chars = ("a".."z").to_a + ("0".."9").to_a
112
+ chars.delete_if { |v| %w(i l o 1 0).member?(v) } if safe
113
+ str = ""
114
+ 1.upto(len) { |i| str << chars[rand(chars.size-1)] }
115
+ str
116
+ end
117
+
118
+ # Returns +str+ with the leading indentation removed.
119
+ # Stolen from http://github.com/mynyml/unindent/ because it was better.
120
+ def noindent(str)
121
+ indent = str.split($/).each {|line| !line.strip.empty? }.map {|line| line.index(/[^\s]/) }.compact.min
122
+ str.gsub(/^[[:blank:]]{#{indent}}/, '')
123
+ end
124
+
125
+ end
126
+ end
File without changes
@@ -0,0 +1,15 @@
1
+
2
+
3
+ module Stella
4
+ module Version
5
+ unless defined?(MAJOR)
6
+ MAJOR = 0.freeze
7
+ MINOR = 7.freeze
8
+ TINY = 0.freeze
9
+ PATCH = '001'.freeze
10
+ end
11
+ def self.to_s; [MAJOR, MINOR, TINY].join('.'); end
12
+ def self.to_f; self.to_s.to_f; end
13
+ def self.patch; PATCH; end
14
+ end
15
+ end
@@ -137,12 +137,6 @@ class Thread
137
137
  end
138
138
  end
139
139
 
140
- class Object
141
- def threadify! *values
142
- throw :threadify, *values
143
- end
144
- end
145
-
146
140
 
147
141
  if __FILE__ == $0
148
142
  require 'open-uri'
@@ -1,69 +1,63 @@
1
1
  @spec = Gem::Specification.new do |s|
2
- s.name = "stella"
3
- s.rubyforge_project = "stella"
4
- s.version = "0.6.0"
5
- s.summary = "Your friend in performance testing"
6
- s.description = s.summary
7
- s.author = "Delano Mandelbaum"
8
- s.email = "delano@solutious.com"
9
- s.homepage = "http://github.com/solutious/stella"
2
+ s.name = "stella"
3
+ s.rubyforge_project = 'stella'
4
+ s.version = "0.7.0.001"
5
+ s.summary = "Stella: Your friend in performance testing."
6
+ s.description = s.summary
7
+ s.author = "Delano Mandelbaum"
8
+ s.email = "delano@solutious.com"
9
+ s.homepage = "http://solutious.com/projects/stella/"
10
10
 
11
- # = DEPENDENCIES =
12
- # Add all gem dependencies
13
- s.add_dependency 'httpclient'
11
+ s.extra_rdoc_files = %w[README.rdoc LICENSE.txt CHANGES.txt]
12
+ s.has_rdoc = true
13
+ s.rdoc_options = ["--line-numbers", "--title", s.summary, "--main", "README.rdoc"]
14
+ s.require_paths = %w[lib]
14
15
 
16
+ s.executables = %w[stella]
17
+
18
+ s.add_dependency 'drydock', '>= 0.6.7'
19
+ s.add_dependency 'gibbler', '>= 0.6.2'
20
+ s.add_dependency 'storable', '>= 0.5.7'
21
+ s.add_dependency 'httpclient', '>= 2.1.5'
15
22
 
16
23
  # = MANIFEST =
17
- # The complete list of files to be included in the release. When GitHub packages your gem,
18
- # it doesn't allow you to run any command that accesses the filesystem. You will get an
19
- # error. You can ask your VCS for the list of versioned files:
20
24
  # git ls-files
21
- # svn list -R
22
25
  s.files = %w(
23
26
  CHANGES.txt
24
27
  LICENSE.txt
25
28
  README.rdoc
26
29
  Rakefile
27
- bin/example_test.rb
28
- bin/example_webapp.rb
29
- lib/logger.rb
30
+ bin/stella
31
+ examples/basic/listing_ids.csv
32
+ examples/basic/plan.rb
30
33
  lib/stella.rb
31
- lib/stella/clients.rb
32
- lib/stella/command/base.rb
33
- lib/stella/command/form.rb
34
- lib/stella/command/get.rb
35
- lib/stella/common.rb
36
- lib/stella/crypto.rb
37
- lib/stella/data/domain.rb
34
+ lib/stella/cli.rb
35
+ lib/stella/client.rb
36
+ lib/stella/config.rb
37
+ lib/stella/data.rb
38
38
  lib/stella/data/http.rb
39
- lib/stella/environment.rb
40
- lib/stella/functest.rb
41
- lib/stella/loadtest.rb
39
+ lib/stella/data/http/body.rb
40
+ lib/stella/data/http/request.rb
41
+ lib/stella/data/http/response.rb
42
+ lib/stella/dsl.rb
43
+ lib/stella/engine.rb
44
+ lib/stella/engine/functional.rb
45
+ lib/stella/engine/load.rb
46
+ lib/stella/exceptions.rb
47
+ lib/stella/guidelines.rb
48
+ lib/stella/mixins.rb
42
49
  lib/stella/stats.rb
43
50
  lib/stella/testplan.rb
44
- lib/stella/testrunner.rb
45
- lib/storable.rb
51
+ lib/stella/testplan/stats.rb
52
+ lib/stella/testplan/usecase.rb
53
+ lib/stella/utils.rb
54
+ lib/stella/utils/httputil.rb
55
+ lib/stella/version.rb
46
56
  lib/threadify.rb
47
- lib/timeunits.rb
48
- lib/util/httputil.rb
49
57
  stella.gemspec
50
- tryouts/drb/drb_test.rb
51
- tryouts/drb/open4.rb
52
- tryouts/drb/slave.rb
53
- tryouts/oo_tryout.rb
58
+ support/example_webapp.rb
59
+ support/useragents.txt
54
60
  )
55
-
56
- # = EXECUTABLES =
57
- # The list of executables in your project (if any). Don't include the path,
58
- # just the base filename.
59
- s.executables = %w[]
60
-
61
- s.extra_rdoc_files = %w[README.rdoc LICENSE.txt]
62
- s.rdoc_options = ["--line-numbers", "--title", s.summary, "--main", "README.rdoc"]
63
-
64
- s.has_rdoc = true
65
- s.require_paths = %w[lib]
66
- s.rubygems_version = '1.1.1'
67
61
 
68
62
 
69
- end
63
+ end
@@ -0,0 +1,246 @@
1
+ #!/usr/bin/ruby
2
+
3
+ # Use Ruby 1.8
4
+
5
+ require "rubygems"
6
+ require "rack"
7
+ require "sinatra"
8
+
9
+ require 'yaml'
10
+
11
+ set :run => true
12
+ set :environment => :development
13
+ set :dump_errors => true
14
+ set :port => 3114
15
+ set :reload => true
16
+ set :max_listings => 1000
17
+
18
+ #log = File.new("/dev/null", "a")
19
+ #STDOUT.reopen(log)
20
+ #STDERR.reopen(log)
21
+
22
+ #use Rack::Auth::Basic do |username, password|
23
+ # username == 'stella' && password == 'stella'
24
+ #end
25
+
26
+ before do
27
+ @title = "Business Finder"
28
+ end
29
+
30
+ get '/' do
31
+ @title << " - Search"
32
+ erb :search_form
33
+ end
34
+
35
+
36
+ get '/search/?' do
37
+ redirect '/' if blank?(params[:what]) && blank?(params[:where])
38
+ params[:what] ||= ''
39
+ params[:where] ||= ''
40
+ @title << " - Search Results"
41
+ @listings = filter_name(params[:what], options.listings)
42
+ if !blank?(params[:where])
43
+ @listings = filter_city(params[:where], @listings)
44
+ end
45
+ if @listings.empty?
46
+ status 404
47
+ erb :search_error
48
+ else
49
+ erb :search_results
50
+ end
51
+ end
52
+
53
+ get '/listing/add' do
54
+ erb :add_form
55
+ end
56
+
57
+ post '/listing/add' do
58
+ @title = "Add a Business"
59
+ if blank?(params[:name]) || blank?(params[:city])
60
+ status 500
61
+ @msg = blank?(params[:city]) ? "Must specify city" : "Must specify name"
62
+ erb :add_form
63
+ else
64
+ @listings = options.listings
65
+ if find_name(params[:name], @listings).empty?
66
+ @listings.shift if @listings.size >= options.max_listings
67
+ @listings << { :name => params[:name], :id => rand(100000), :city => params[:city] }
68
+ redirect '/listings'
69
+ else
70
+ status 500
71
+ @msg = "That business exists (#{params[:name]})"
72
+ erb :add_form
73
+ end
74
+ end
75
+ end
76
+
77
+ get '/listing/:id.yaml' do
78
+ content_type "text/yaml"
79
+ listing = filter_id params[:id], options.listings
80
+ listing.to_yaml
81
+ end
82
+
83
+ get '/listing/:id' do
84
+ @listings = filter_id(params[:id], options.listings)
85
+ redirect '/' if @listings.empty?
86
+ @title = "Business Listing - #{@listings.first[:name]}"
87
+ erb :listings
88
+ end
89
+
90
+ get '/listings' do
91
+ @listings = options.listings
92
+ @title = "Business Listings"
93
+ erb :listings
94
+ end
95
+
96
+ get '/listings.yaml' do
97
+ content_type "text/yaml"
98
+ @listings = options.listings
99
+ @title = "Business Listings"
100
+ @listings.to_yaml
101
+ end
102
+
103
+ set :listings => [
104
+ { :id => 1000, :name => 'John West Smoked Oysters', :city => 'Toronto' },
105
+ { :id => 1001, :name => 'Fire Town Lightning Rods', :city => 'Toronto' },
106
+ { :id => 1002, :name => 'Oversized Pen and Ink Co', :city => 'Toronto' },
107
+ { :id => 1003, :name => 'The Rathzenburg Brothers', :city => 'Toronto' },
108
+ { :id => 1004, :name => 'Forever and Always Beads', :city => 'Montreal' },
109
+ { :id => 1005, :name => "Big Al's Flavour Country", :city => 'Montreal' },
110
+ { :id => 1006, :name => 'Big Time Furniture World', :city => 'Montreal' },
111
+ { :id => 1007, :name => 'High-End Keyboard Makers', :city => 'Montreal' }
112
+ ]
113
+
114
+ before do
115
+ @cookie = request.cookies["bff-history"]
116
+ @cookie = blank?(@cookie) ? {} : YAML.load(@cookie)
117
+ @cookie[:history] ||= []
118
+ if params[:clear] == 'true'
119
+ @cookie[:history] = []
120
+ @cookie[:location] = ''
121
+ end
122
+ @cookie[:history].delete params[:what]
123
+ @cookie[:history].unshift params[:what] unless blank?(params[:what])
124
+ @cookie[:history].pop if @cookie[:history].size > 5
125
+ @cookie[:location] = params[:where] unless blank?(params[:where])
126
+ response.set_cookie "bff-history", :path => '/', :value => @cookie.to_yaml
127
+ end
128
+
129
+ helpers do
130
+
131
+ def blank?(v)
132
+ v.nil? || v.empty?
133
+ end
134
+
135
+ def filter_id(id, listings)
136
+ listings.select { |l| l[:id] == id.to_i }
137
+ end
138
+
139
+ def filter_name(name, listings)
140
+ listings.select { |l| l[:name].match(/#{name}/i) }
141
+ end
142
+
143
+ def find_name(name, listings)
144
+ listings.select { |l| l[:name] == name }
145
+ end
146
+
147
+ def filter_city(city, listings)
148
+ listings.select { |l| l[:city].match(/#{city}/i) }
149
+ end
150
+
151
+ def format_listing(lid, name, city)
152
+ listing = %Q{<div class="listing" id="listing-#{lid}">}
153
+ listing << %Q{<a href="/listing/#{lid}.yaml">#{name}</a> }
154
+ listing << %Q{#{city}</div>}
155
+ end
156
+
157
+ # Generates a string of random alphanumeric characters
158
+ # These are used as IDs throughout the system
159
+ def strand( len )
160
+ chars = ("a".."z").to_a + ("0".."9").to_a
161
+ newpass = ""
162
+ 1.upto(len) { |i| newpass << chars[rand(chars.size-1)] }
163
+ return newpass
164
+ end
165
+
166
+ end
167
+
168
+ __END__
169
+
170
+ @@layout
171
+ <html>
172
+ <head>
173
+ <title><%= @title %></title>
174
+ <style>
175
+ .hilite { background-color: #FEE00B; font-weight: bold; }
176
+ .footer { color: #ccc; font-weight: lighter; font-size: 80%; margin-top: 30px; }
177
+ .footer a { color: #69c;}
178
+ </style>
179
+ </head>
180
+ <body>
181
+ <h1>Business Finder</h1>
182
+ <p style="margin-left: 50px; margin-top: 20px;"><em>
183
+ <a href="/">New Search</a> -
184
+ <a href="/listing/add?name=<%= params[:what] %>&amp;city=<%= params[:where] %>">Add Listing</a> -
185
+ <a href="/?clear=true">!!</a> -
186
+ <a href="/listings">View All</a>
187
+ </em></p>
188
+ <%= yield %>
189
+ <div class="footer">
190
+ A <a href="http://solutious.com/projects/stella/">Stella</a> demo by <a href="http://solutious.com/">Solutious</a>.
191
+ </div>
192
+ </body>
193
+ </html>
194
+
195
+ @@add_form
196
+ <% city = blank?(params[:city]) ? 'Toronto' : params[:city] %>
197
+ <% if !blank?(@msg) %>
198
+ <p style="color: red"><em>Error: <%= @msg %></em></p>
199
+ <% end %>
200
+ <form method="post">
201
+ Name: <input name="name" value="<%= params[:name] %>"/><br/>
202
+ City: <input name="city" value="<%= city %>" /><br/>
203
+ <input type="submit" />
204
+ </form>
205
+
206
+ @@listings
207
+ <% for l in @listings %>
208
+ <%= format_listing(l[:id], l[:name], l[:city]) %>
209
+ <% end %>
210
+
211
+ @@search_form
212
+ <form action="/search">
213
+ What: <input name="what" value="" /><br/>
214
+ Where: <input name="where" value="<%= @cookie[:location] %>" /><br/>
215
+ <input type="submit" />
216
+ </form>
217
+ <ul id="history">
218
+ <% unless @cookie[:history].empty? %>
219
+ <h3>Previous Searches</h3>
220
+ <% end %>
221
+ <% for what in @cookie[:history] %>
222
+ <li><em><a href="/search/?what=<%= what %>&amp;where=<%= @cookie[:location] %>"><%= what %></a></em></li>
223
+ <% end %>
224
+ </ul>
225
+
226
+ @@search_results
227
+ Looking
228
+ <% if !blank?(params[:what]) %>
229
+ for "<b><%= params[:what] %></b>"
230
+ <% end %>
231
+ <% if !blank?(params[:where]) %>
232
+ in "<b><%= params[:where] %></b>"
233
+ <% end %>
234
+ <br/><br/>
235
+ <% for l in @listings %>
236
+ <% name = l[:name].gsub(/(#{params[:what]})/i, "<span class='hilite'>\\1</span>") %>
237
+ <% city = l[:city].gsub(/(#{params[:where]})/i, "<span class='hilite'>\\1</span>") %>
238
+ <%= format_listing(l[:id], name, city) %>
239
+ <% end %>
240
+
241
+ @@search_error
242
+ Looking for "<b><%= params[:what] %></b>"
243
+ <% if !blank?(params[:where]) %>
244
+ in "<b><%= params[:where] %></b>"
245
+ <% end %>
246
+ <p><i>Nothing found</i></p>