strelka 0.0.1pre4

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 (40) hide show
  1. data/.gemtest +0 -0
  2. data/History.rdoc +4 -0
  3. data/IDEAS.textile +174 -0
  4. data/Manifest.txt +38 -0
  5. data/README.rdoc +66 -0
  6. data/Rakefile +64 -0
  7. data/bin/leash +403 -0
  8. data/data/strelka/apps/strelka-admin +65 -0
  9. data/data/strelka/apps/strelka-setup +26 -0
  10. data/data/strelka/bootstrap-config.rb +34 -0
  11. data/data/strelka/templates/admin/console.tmpl +21 -0
  12. data/data/strelka/templates/layout.tmpl +30 -0
  13. data/lib/strelka/app/defaultrouter.rb +85 -0
  14. data/lib/strelka/app/filters.rb +70 -0
  15. data/lib/strelka/app/parameters.rb +64 -0
  16. data/lib/strelka/app/plugins.rb +205 -0
  17. data/lib/strelka/app/routing.rb +140 -0
  18. data/lib/strelka/app/templating.rb +157 -0
  19. data/lib/strelka/app.rb +175 -0
  20. data/lib/strelka/behavior/plugin.rb +36 -0
  21. data/lib/strelka/constants.rb +53 -0
  22. data/lib/strelka/httprequest.rb +52 -0
  23. data/lib/strelka/logging.rb +241 -0
  24. data/lib/strelka/mixins.rb +143 -0
  25. data/lib/strelka/process.rb +19 -0
  26. data/lib/strelka.rb +40 -0
  27. data/spec/data/layout.tmpl +3 -0
  28. data/spec/data/main.tmpl +1 -0
  29. data/spec/lib/constants.rb +32 -0
  30. data/spec/lib/helpers.rb +134 -0
  31. data/spec/strelka/app/defaultrouter_spec.rb +215 -0
  32. data/spec/strelka/app/parameters_spec.rb +74 -0
  33. data/spec/strelka/app/plugins_spec.rb +167 -0
  34. data/spec/strelka/app/routing_spec.rb +139 -0
  35. data/spec/strelka/app/templating_spec.rb +169 -0
  36. data/spec/strelka/app_spec.rb +160 -0
  37. data/spec/strelka/httprequest_spec.rb +54 -0
  38. data/spec/strelka/logging_spec.rb +72 -0
  39. data/spec/strelka_spec.rb +27 -0
  40. metadata +226 -0
@@ -0,0 +1,139 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ BEGIN {
4
+ require 'pathname'
5
+ basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
6
+ $LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
7
+ }
8
+
9
+ require 'rspec'
10
+
11
+ require 'spec/lib/helpers'
12
+
13
+ require 'strelka'
14
+ require 'strelka/app/plugins'
15
+ require 'strelka/app/routing'
16
+
17
+ require 'strelka/behavior/plugin'
18
+
19
+
20
+ #####################################################################
21
+ ### C O N T E X T S
22
+ #####################################################################
23
+
24
+ describe Strelka::App::Routing do
25
+
26
+ before( :all ) do
27
+ setup_logging( :fatal )
28
+ end
29
+
30
+ after( :all ) do
31
+ reset_logging()
32
+ end
33
+
34
+
35
+ it_should_behave_like( "A Strelka::App Plugin" )
36
+
37
+
38
+ describe "an including App" do
39
+
40
+ before( :each ) do
41
+ Strelka.log.debug "Creating a new Strelka::App"
42
+ @app = Class.new( Strelka::App ) do
43
+ plugin :routing
44
+ end
45
+ Strelka.log.debug " new instance is: %p, routes array: 0x%016x" %
46
+ [ @app, @app.routes.object_id * 2 ]
47
+ end
48
+
49
+
50
+ it "has an Array of raw routes" do
51
+ @app.routes.should be_a( Array )
52
+ end
53
+
54
+ it "can declare a GET route" do
55
+ @app.routes.should be_empty()
56
+
57
+ @app.class_eval do
58
+ get do |req|
59
+ end
60
+ end
61
+
62
+ @app.routes.should == [[ :GET, [], @app.instance_method(:GET), {} ]]
63
+ end
64
+
65
+ it "allows a route to specify a path" do
66
+ @app.routes.should be_empty()
67
+
68
+ @app.class_eval do
69
+ get '/info' do |req|
70
+ end
71
+ end
72
+
73
+ @app.routes.should == [[ :GET, ['info'], @app.instance_method(:GET_info), {} ]]
74
+ end
75
+
76
+ it "allows a route to omit the leading '/' when specifying a path" do
77
+ @app.class_eval do
78
+ get 'info' do |req|
79
+ end
80
+ end
81
+
82
+ @app.routes.should == [[ :GET, ['info'], @app.instance_method(:GET_info), {} ]]
83
+ end
84
+
85
+
86
+ it "uses the Strelka::App::DefaultRouter as it's router by default" do
87
+ @app.routerclass.should equal( Strelka::App::DefaultRouter )
88
+ end
89
+
90
+ it "can specify a different Router class than the default" do
91
+ class MyRouter < Strelka::App::DefaultRouter; end
92
+ @app.class_eval do
93
+ router MyRouter
94
+ end
95
+ @app.routerclass.should equal( MyRouter )
96
+ end
97
+
98
+
99
+ describe "that also uses the :parameters plugin" do
100
+
101
+ before( :each ) do
102
+ @app.plugin( :parameters )
103
+ end
104
+
105
+ it "allows a route to have parameters in it" do
106
+ @app.class_eval do
107
+ param :username, /[a-z]\w+/i
108
+ post '/userinfo/:username' do |req|
109
+ end
110
+ end
111
+
112
+ @app.routes.should ==
113
+ [[ :POST, ['userinfo', /(?<username>(?i-mx:[a-z]\w+))/],
114
+ @app.instance_method(:POST_userinfo__username), {} ]]
115
+ end
116
+
117
+
118
+ it "raises a ScriptError if a route is defined with a param without it having first " +
119
+ "been set up" do
120
+ # RSpec's expect {},to only rescues RuntimeErrors, so we have to do this ourselves.
121
+ begin
122
+ @app.get( '/userinfo/:username' ) {}
123
+ rescue ScriptError => err
124
+ Strelka.log.error "%p: %s" % [ err.class, err.message ]
125
+ :pass
126
+ rescue ::Exception => err
127
+ fail "Expected to raise a ScriptError, but raised a %p instead" % [ err ]
128
+ else
129
+ fail "Expected to raise a ScriptError, but nothing was raised."
130
+ end
131
+
132
+ end
133
+ end
134
+
135
+ end
136
+
137
+
138
+ end
139
+
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ BEGIN {
4
+ require 'pathname'
5
+ basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
6
+ $LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
7
+ }
8
+
9
+ require 'rspec'
10
+ require 'inversion'
11
+
12
+ require 'spec/lib/helpers'
13
+
14
+ require 'strelka'
15
+ require 'strelka/app/plugins'
16
+ require 'strelka/app/templating'
17
+
18
+ require 'strelka/behavior/plugin'
19
+
20
+
21
+ #####################################################################
22
+ ### C O N T E X T S
23
+ #####################################################################
24
+
25
+ describe Strelka::App::Templating do
26
+
27
+ before( :all ) do
28
+ setup_logging( :fatal )
29
+ @request_factory = Mongrel2::RequestFactory.new( route: '/user' )
30
+ end
31
+
32
+ after( :all ) do
33
+ reset_logging()
34
+ end
35
+
36
+
37
+ it_should_behave_like( "A Strelka::App Plugin" )
38
+
39
+
40
+ describe "an including App" do
41
+
42
+ before( :each ) do
43
+ @app = Class.new( Strelka::App ) do
44
+ plugin :templating
45
+ templates :main => 'main.tmpl'
46
+
47
+ def initialize( appid=TEST_APPID, sspec=TEST_SEND_SPEC, rspec=TEST_RECV_SPEC )
48
+ super
49
+ end
50
+ end
51
+ @req = @request_factory.get( '/user/info' )
52
+ end
53
+
54
+
55
+ it "has a Hash of templates" do
56
+ @app.templates.should be_a( Hash )
57
+ end
58
+
59
+ it "can add templates that it wants to use to its templates hash" do
60
+ @app.class_eval do
61
+ templates :main => 'main.tmpl'
62
+ end
63
+
64
+ @app.templates.should == { :main => 'main.tmpl' }
65
+ end
66
+
67
+ it "can declare a layout template" do
68
+ @app.class_eval do
69
+ layout 'layout.tmpl'
70
+ end
71
+
72
+ @app.layout.should == 'layout.tmpl'
73
+ end
74
+
75
+ describe "instance" do
76
+
77
+ before( :all ) do
78
+ basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
79
+ specdir = basedir + 'spec'
80
+ specdata = specdir + 'data'
81
+
82
+ tmpl_paths = [ specdata ]
83
+ Inversion::Template.configure( :template_paths => tmpl_paths )
84
+ end
85
+
86
+ before( :each ) do
87
+ @app.class_eval do
88
+ templates :main => 'main.tmpl'
89
+ end
90
+ @instance = @app.new( 'template-test', 'tcp://127.0.0.1:9999', 'tcp://127.0.0.1:9998' )
91
+ end
92
+
93
+
94
+ it "can load declared templates by mentioning the symbol" do
95
+ @instance.template( :main ).should be_a( Inversion::Template )
96
+ end
97
+
98
+ it "can respond with just a template name" do
99
+ @app.class_eval do
100
+ def handle_request( req )
101
+ super { :main }
102
+ end
103
+ end
104
+
105
+ res = @app.new.handle( @req )
106
+
107
+ res.body.should == "A template for testing the Templating plugin.\n"
108
+ res.status.should == 200
109
+ end
110
+
111
+ it "can respond with just a template instance" do
112
+ @app.class_eval do
113
+ def handle_request( req )
114
+ super { self.template(:main) }
115
+ end
116
+ end
117
+
118
+ res = @app.new.handle( @req )
119
+
120
+ res.body.should == "A template for testing the Templating plugin.\n"
121
+ res.status.should == 200
122
+ end
123
+
124
+ it "can respond with a Mongrel2::HTTPResponse with a template instance as its body" do
125
+ @app.class_eval do
126
+ def handle_request( req )
127
+ super do
128
+ res = req.response
129
+ res.body = self.template( :main )
130
+ res
131
+ end
132
+ end
133
+ end
134
+
135
+ res = @app.new.handle( @req )
136
+
137
+ res.body.should == "A template for testing the Templating plugin.\n"
138
+ res.status.should == 200
139
+ end
140
+
141
+
142
+ it "wraps the layout template around whatever gets returned if one is set" do
143
+ @app.class_eval do
144
+ layout 'layout.tmpl'
145
+
146
+ def handle_request( req )
147
+ # Super through the plugins and then load the template into the response
148
+ super do
149
+ res = req.response
150
+ res.body = self.template( :main )
151
+ res
152
+ end
153
+ end
154
+ end
155
+
156
+ res = @app.new.handle( @req )
157
+
158
+ res.body.should == "A minimal layout template.\n" +
159
+ "A template for testing the Templating plugin.\n\n"
160
+ res.status.should == 200
161
+ end
162
+
163
+ end
164
+
165
+ end
166
+
167
+
168
+ end
169
+
@@ -0,0 +1,160 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ BEGIN {
4
+ require 'pathname'
5
+ basedir = Pathname.new( __FILE__ ).dirname.parent.parent
6
+ $LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
7
+ }
8
+
9
+ require 'rspec'
10
+ require 'zmq'
11
+ require 'mongrel2'
12
+
13
+ require 'spec/lib/helpers'
14
+
15
+ require 'strelka'
16
+ require 'strelka/app'
17
+
18
+
19
+ #####################################################################
20
+ ### C O N T E X T S
21
+ #####################################################################
22
+
23
+ describe Strelka::App do
24
+
25
+ before( :all ) do
26
+ setup_logging( :fatal )
27
+ @request_factory = Mongrel2::RequestFactory.new( route: '/mail' )
28
+ end
29
+
30
+ before( :each ) do
31
+ @app = Class.new( Strelka::App ) do
32
+ def initialize( appid=TEST_APPID, sspec=TEST_SEND_SPEC, rspec=TEST_RECV_SPEC )
33
+ super
34
+ end
35
+ end
36
+ @req = @request_factory.get( '/mail/inbox' )
37
+ end
38
+
39
+ after( :all ) do
40
+ reset_logging()
41
+ end
42
+
43
+
44
+ it "returns a No Content response by default" do
45
+
46
+ res = @app.new.handle( @req )
47
+
48
+ res.should be_a( Mongrel2::HTTPResponse )
49
+ res.status_line.should == 'HTTP/1.1 204 No Content'
50
+ res.body.should == ''
51
+ end
52
+
53
+
54
+ it "provides a mechanism for aborting with a status" do
55
+
56
+ # make a plugin that always 304s and install it
57
+ not_modified_plugin = Module.new do
58
+ extend Strelka::App::Plugin
59
+ def handle_request( r )
60
+ finish_with( HTTP::NOT_MODIFIED, "Unchanged." )
61
+ fail "Shouldn't be reached."
62
+ end
63
+ end
64
+ @app.plugin( not_modified_plugin )
65
+
66
+ res = @app.new.handle( @req )
67
+
68
+ res.should be_a( Mongrel2::HTTPResponse )
69
+ res.status_line.should == 'HTTP/1.1 304 Not Modified'
70
+ res.body.should == ''
71
+ end
72
+
73
+
74
+ it "creates a simple response body for status responses that can have them" do
75
+ # make an auth plugin that always denies requests
76
+ forbidden_plugin = Module.new do
77
+ extend Strelka::App::Plugin
78
+ def handle_request( r )
79
+ finish_with( HTTP::FORBIDDEN, "You aren't allowed to look at that." )
80
+ fail "Shouldn't be reached."
81
+ end
82
+ end
83
+ @app.plugin( forbidden_plugin )
84
+
85
+ res = @app.new.handle( @req )
86
+
87
+ res.should be_a( Mongrel2::HTTPResponse )
88
+ res.status_line.should == 'HTTP/1.1 403 Forbidden'
89
+ res.content_type.should == 'text/plain'
90
+ res.body.should == "You aren't allowed to look at that.\n"
91
+ end
92
+
93
+
94
+ it "provides a declarative for setting the default content type of responses" do
95
+ @app.class_eval do
96
+ default_content_type 'text/css'
97
+ def handle_request( r )
98
+ r.response.puts( "body { font-family: monospace }" )
99
+ r.response
100
+ end
101
+ end
102
+
103
+ res = @app.new.handle( @req )
104
+
105
+ res.should be_a( Mongrel2::HTTPResponse )
106
+ res.content_type.should == 'text/css'
107
+ end
108
+
109
+
110
+ it "provides a plugin hook for plugins to manipulate the request before handling it" do
111
+ # make a fixup plugin that adds a custom x- header to the request
112
+ header_fixup_plugin = Module.new do
113
+ extend Strelka::App::Plugin
114
+ def fixup_request( r )
115
+ r.headers[:x_funted_by] = 'Cragnux/1.1.3'
116
+ super
117
+ end
118
+ def handle_request( r )
119
+ res = r.response
120
+ res.puts( "Request was funted by %s!" % [r.headers.x_funted_by] )
121
+ res.status = HTTP::OK
122
+ return res
123
+ end
124
+ end
125
+ @app.plugin( header_fixup_plugin )
126
+
127
+ res = @app.new.handle( @req )
128
+
129
+ res.should be_a( Mongrel2::HTTPResponse )
130
+ res.status_line.should == 'HTTP/1.1 200 OK'
131
+ res.body.should == "Request was funted by Cragnux/1.1.3!\n"
132
+ end
133
+
134
+
135
+ it "provides a plugin hook for plugins to manipulate the response before it's returned to Mongrel2" do
136
+ # make a fixup plugin that adds a custom x- header to the response
137
+ header_fixup_plugin = Module.new do
138
+ extend Strelka::App::Plugin
139
+ def fixup_response( req, res )
140
+ res.headers.x_funted_by = 'Cragnux/1.1.3'
141
+ super
142
+ end
143
+ def handle_request( r )
144
+ res = r.response
145
+ res.puts( "Funt this" )
146
+ res.status = HTTP::OK
147
+ return res
148
+ end
149
+ end
150
+ @app.plugin( header_fixup_plugin )
151
+
152
+ res = @app.new.handle( @req )
153
+
154
+ res.should be_a( Mongrel2::HTTPResponse )
155
+ res.status_line.should == 'HTTP/1.1 200 OK'
156
+ res.header_data.should =~ %r{X-Funted-By: Cragnux/1.1.3}
157
+ end
158
+
159
+ end
160
+
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ BEGIN {
4
+ require 'pathname'
5
+ basedir = Pathname.new( __FILE__ ).dirname.parent.parent
6
+
7
+ $LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
8
+ }
9
+
10
+ require 'rspec'
11
+ require 'spec/lib/helpers'
12
+ require 'strelka/httprequest'
13
+
14
+
15
+ #####################################################################
16
+ ### C O N T E X T S
17
+ #####################################################################
18
+
19
+ describe Strelka::HTTPRequest do
20
+
21
+ before( :all ) do
22
+ setup_logging( :fatal )
23
+ @request_factory = Mongrel2::RequestFactory.new( route: '/directory' )
24
+ end
25
+
26
+ after( :all ) do
27
+ reset_logging()
28
+ end
29
+
30
+
31
+ before( :each ) do
32
+ @req = @request_factory.get( '/directory/userinfo/ged' )
33
+ end
34
+
35
+ it "knows what the request's parsed URI is" do
36
+ @req.uri.should be_a( URI )
37
+ @req.uri.path.should == '/directory/userinfo/ged'
38
+ @req.uri.query.should be_nil()
39
+ end
40
+
41
+ it "knows what Mongrel2 route it followed" do
42
+ @req.pattern.should == '/directory'
43
+ end
44
+
45
+ it "knows what the path of the request past its route is" do
46
+ @req.app_path.should == '/userinfo/ged'
47
+ end
48
+
49
+ it "knows what HTTP verb the request used" do
50
+ @req.verb.should == :GET
51
+ end
52
+
53
+ end
54
+
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ BEGIN {
4
+ require 'pathname'
5
+ basedir = Pathname.new( __FILE__ ).dirname.parent.parent
6
+ $LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
7
+ }
8
+
9
+ require 'rspec'
10
+ require 'stringio'
11
+
12
+ require 'spec/lib/helpers'
13
+
14
+ require 'strelka'
15
+ require 'strelka/logging'
16
+
17
+
18
+ #####################################################################
19
+ ### C O N T E X T S
20
+ #####################################################################
21
+
22
+ describe Strelka::Logging, "-extended module" do
23
+
24
+ before( :each ) do
25
+ @extended_module = Module.new do
26
+ extend Strelka::Logging
27
+ end
28
+ end
29
+
30
+ it "should have a default Logger" do
31
+ @extended_module.logger.should be_a( Logger )
32
+ @extended_module.default_logger.should equal( @extended_module.logger )
33
+ end
34
+
35
+ it "should know if its default logger is replaced" do
36
+ @extended_module.should be_using_default_logger
37
+ @extended_module.logger = Logger.new( $stderr )
38
+ @extended_module.should_not be_using_default_logger
39
+ end
40
+
41
+ it "has the default logger instance after being reset" do
42
+ @extended_module.reset_logger
43
+ @extended_module.logger.should equal( @extended_module.default_logger )
44
+ end
45
+
46
+ it "has the default log formatter instance after being reset" do
47
+ @extended_module.reset_logger
48
+ @extended_module.logger.formatter.should equal( @extended_module.default_log_formatter )
49
+ end
50
+
51
+
52
+ context "with new defaults" do
53
+
54
+ before( :each ) do
55
+ @sink = StringIO.new
56
+ @logger = Logger.new( @sink )
57
+ @formatter = Strelka::Logging::ColorFormatter.new( @logger )
58
+
59
+ @extended_module.default_logger = @logger
60
+ @extended_module.default_log_formatter = @formatter
61
+ end
62
+
63
+ it "uses the new defaults when the logging subsystem is reset" do
64
+ @extended_module.reset_logger
65
+ @extended_module.logger.should equal( @logger )
66
+ end
67
+
68
+ end
69
+
70
+
71
+ end
72
+
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env rspec -cfd -b
2
+
3
+ BEGIN {
4
+ require 'pathname'
5
+ basedir = Pathname( __FILE__ ).dirname.parent
6
+ $LOAD_PATH.unshift( basedir.to_s ) unless $LOAD_PATH.include?( basedir.to_s )
7
+ }
8
+
9
+ require 'rspec'
10
+ require 'spec/lib/helpers'
11
+ require 'strelka'
12
+
13
+ describe Strelka do
14
+
15
+ describe "version methods" do
16
+ it "returns a version string if asked" do
17
+ described_class.version_string.should =~ /\w+ [\d.]+/
18
+ end
19
+
20
+
21
+ it "returns a version string with a build number if asked" do
22
+ described_class.version_string(true).should =~ /\w+ [\d.]+ \(build [[:xdigit:]]+\)/
23
+ end
24
+ end
25
+
26
+ end
27
+