moonrope 1.4.1 → 2.0.0
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.
- checksums.yaml +4 -4
- data/Gemfile +9 -0
- data/Gemfile.lock +47 -0
- data/MIT-LICENCE +20 -0
- data/README.md +24 -0
- data/bin/moonrope +28 -0
- data/docs/authentication.md +114 -0
- data/docs/controllers.md +106 -0
- data/docs/exceptions.md +27 -0
- data/docs/introduction.md +29 -0
- data/docs/structures.md +214 -0
- data/example/authentication.rb +50 -0
- data/example/controllers/meta_controller.rb +14 -0
- data/example/controllers/users_controller.rb +92 -0
- data/example/structures/pet_structure.rb +12 -0
- data/example/structures/user_structure.rb +35 -0
- data/html/assets/lock.svg +3 -0
- data/html/assets/reset.css +101 -0
- data/html/assets/style.css +348 -0
- data/html/assets/tool.svg +4 -0
- data/html/assets/try.js +151 -0
- data/html/authenticators/default.html +191 -0
- data/html/controllers/meta/version.html +144 -0
- data/html/controllers/meta.html +73 -0
- data/html/controllers/users/create.html +341 -0
- data/html/controllers/users/list.html +348 -0
- data/html/controllers/users/show.html +261 -0
- data/html/controllers/users/update.html +387 -0
- data/html/controllers/users.html +93 -0
- data/html/index.html +166 -0
- data/html/moonrope.txt +0 -0
- data/html/structures/pet.html +176 -0
- data/html/structures/user.html +338 -0
- data/lib/moonrope/action.rb +165 -37
- data/lib/moonrope/authenticator.rb +39 -0
- data/lib/moonrope/base.rb +24 -6
- data/lib/moonrope/controller.rb +4 -2
- data/lib/moonrope/doc_context.rb +94 -0
- data/lib/moonrope/doc_server.rb +123 -0
- data/lib/moonrope/dsl/action_dsl.rb +159 -9
- data/lib/moonrope/dsl/authenticator_dsl.rb +31 -0
- data/lib/moonrope/dsl/base_dsl.rb +21 -18
- data/lib/moonrope/dsl/controller_dsl.rb +60 -9
- data/lib/moonrope/dsl/filterable_dsl.rb +27 -0
- data/lib/moonrope/dsl/structure_dsl.rb +27 -2
- data/lib/moonrope/errors.rb +3 -0
- data/lib/moonrope/eval_environment.rb +82 -3
- data/lib/moonrope/eval_helpers/filter_helper.rb +82 -0
- data/lib/moonrope/eval_helpers.rb +28 -5
- data/lib/moonrope/guard.rb +35 -0
- data/lib/moonrope/html_generator.rb +65 -0
- data/lib/moonrope/param_set.rb +11 -1
- data/lib/moonrope/rack_middleware.rb +1 -1
- data/lib/moonrope/railtie.rb +31 -14
- data/lib/moonrope/request.rb +25 -14
- data/lib/moonrope/structure.rb +74 -11
- data/lib/moonrope/structure_attribute.rb +15 -0
- data/lib/moonrope/version.rb +1 -1
- data/lib/moonrope.rb +5 -4
- data/moonrope.gemspec +21 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/specs/action_spec.rb +455 -0
- data/spec/specs/base_spec.rb +29 -0
- data/spec/specs/controller_spec.rb +31 -0
- data/spec/specs/param_set_spec.rb +31 -0
- data/templates/basic/_action_form.erb +77 -0
- data/templates/basic/_errors_table.erb +32 -0
- data/templates/basic/_structure_attributes_list.erb +55 -0
- data/templates/basic/action.erb +168 -0
- data/templates/basic/assets/lock.svg +3 -0
- data/templates/basic/assets/reset.css +101 -0
- data/templates/basic/assets/style.css +348 -0
- data/templates/basic/assets/tool.svg +4 -0
- data/templates/basic/assets/try.js +151 -0
- data/templates/basic/authenticator.erb +51 -0
- data/templates/basic/controller.erb +20 -0
- data/templates/basic/index.erb +114 -0
- data/templates/basic/layout.erb +46 -0
- data/templates/basic/structure.erb +23 -0
- data/test/test_helper.rb +81 -0
- data/test/tests/action_access_test.rb +63 -0
- data/test/tests/actions_test.rb +524 -0
- data/test/tests/authenticators_test.rb +87 -0
- data/test/tests/base_test.rb +35 -0
- data/test/tests/controllers_test.rb +49 -0
- data/test/tests/eval_environment_test.rb +136 -0
- data/test/tests/evel_helpers_test.rb +60 -0
- data/test/tests/examples_test.rb +11 -0
- data/test/tests/helpers_test.rb +97 -0
- data/test/tests/param_set_test.rb +44 -0
- data/test/tests/rack_middleware_test.rb +109 -0
- data/test/tests/request_test.rb +232 -0
- data/test/tests/structures_param_extensions_test.rb +159 -0
- data/test/tests/structures_test.rb +335 -0
- metadata +82 -48
@@ -0,0 +1,136 @@
|
|
1
|
+
class EvalEnvironmentTest < Test::Unit::TestCase
|
2
|
+
|
3
|
+
def setup
|
4
|
+
@auth_user = User.new(:name => 'Admin User')
|
5
|
+
@request = FakeRequest.new(:params => {'page' => '1'}, :version => 2, :identity => @auth_user)
|
6
|
+
@environment = Moonrope::EvalEnvironment.new(Moonrope::Base.new, @request, nil, :accessor1 => 'Hello')
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_version
|
10
|
+
assert_equal 2, @environment.version
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_params
|
14
|
+
assert @environment.params.is_a?(Moonrope::ParamSet)
|
15
|
+
assert_equal '1', @environment.params.page
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_accessors
|
19
|
+
assert_equal 'Hello', @environment.accessor1
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_identity_access
|
23
|
+
assert_equal @auth_user, @environment.identity
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_setting_headers
|
27
|
+
@environment.set_header 'Header1', 'A'
|
28
|
+
assert_equal 'A', @environment.headers['Header1']
|
29
|
+
@environment.set_header 'Header2', 'B'
|
30
|
+
assert_equal 'B', @environment.headers['Header2']
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_setting_flags
|
34
|
+
@environment.set_flag 'Flag1', 'A'
|
35
|
+
assert_equal 'A', @environment.flags['Flag1']
|
36
|
+
@environment.set_flag 'Flag2', 'B'
|
37
|
+
assert_equal 'B', @environment.flags['Flag2']
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_structure_access
|
41
|
+
user_structure = Moonrope::Structure.new(@environment.base, :user) do
|
42
|
+
basic { {:id => o.id} }
|
43
|
+
end
|
44
|
+
structure = @environment.structure(user_structure, User.new)
|
45
|
+
assert structure.is_a?(Hash), "structure was not a Hash, was a #{structure.class}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_structure_access_with_auto_determination
|
49
|
+
user_structure = @environment.base.dsl.structure(:user) do
|
50
|
+
basic { {:id => o.id} }
|
51
|
+
end
|
52
|
+
structure = @environment.structure(UserWithUnderscore.new)
|
53
|
+
assert structure.is_a?(Hash), "structure was not a Hash, was a #{structure.class}"
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_structure_for
|
57
|
+
user_structure = @environment.base.dsl.structure(:user) do
|
58
|
+
basic { {:id => o.id} }
|
59
|
+
end
|
60
|
+
structure = @environment.structure_for(:user)
|
61
|
+
assert_equal structure, user_structure
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_has_structure_for
|
65
|
+
user_structure = @environment.base.dsl.structure(:user) do
|
66
|
+
basic { {:id => o.id} }
|
67
|
+
end
|
68
|
+
assert_equal false, @environment.has_structure_for?(:blah)
|
69
|
+
assert_equal true, @environment.has_structure_for?(:user)
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_copy_attributes_from_param_set_to_an_object
|
73
|
+
base = Moonrope::Base.new
|
74
|
+
controller = Moonrope::Controller.new(base, :users) do
|
75
|
+
action :save do
|
76
|
+
param :username do |object, value|
|
77
|
+
object.username = "#{value}!"
|
78
|
+
end
|
79
|
+
param :id
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
request = FakeRequest.new(:params => {'id' => 123, 'username' => 'adam'})
|
84
|
+
env = Moonrope::EvalEnvironment.new(base, request, controller/:save)
|
85
|
+
user = User.new
|
86
|
+
env.copy_params_to user, :username, :id
|
87
|
+
assert_equal user.id, 123
|
88
|
+
assert_equal user.username, "adam!"
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_copy_attributes_from_share
|
92
|
+
base = Moonrope::Base.new
|
93
|
+
controller = Moonrope::Controller.new(base, :users) do
|
94
|
+
shared_action :crud do
|
95
|
+
param :username
|
96
|
+
param :id
|
97
|
+
end
|
98
|
+
action :save do
|
99
|
+
use :crud
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
request = FakeRequest.new(:params => {'id' => 123, 'username' => 'adam'})
|
104
|
+
env = Moonrope::EvalEnvironment.new(base, request, controller/:save)
|
105
|
+
user = User.new
|
106
|
+
env.copy_params_to user, :from => :crud
|
107
|
+
assert_equal user.id, 123
|
108
|
+
assert_equal user.username, "adam"
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_copy_attribute_from_shared_action_within_shared_action
|
112
|
+
base = Moonrope::Base.new
|
113
|
+
controller = Moonrope::Controller.new(base, :users) do
|
114
|
+
shared_action :private_code do
|
115
|
+
param :private_code
|
116
|
+
end
|
117
|
+
shared_action :crud do
|
118
|
+
param :username
|
119
|
+
param :id
|
120
|
+
use :private_code
|
121
|
+
end
|
122
|
+
action :save do
|
123
|
+
use :crud
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
request = FakeRequest.new(:params => {'id' => 123, 'username' => 'adam', 'private_code' => 'llama'})
|
128
|
+
env = Moonrope::EvalEnvironment.new(base, request, controller/:save)
|
129
|
+
user = User.new
|
130
|
+
env.copy_params_to user, :from => :crud
|
131
|
+
assert_equal user.username, "adam"
|
132
|
+
assert_equal user.private_code, "llama"
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
@@ -0,0 +1,60 @@
|
|
1
|
+
class EvalHelpersTest < Test::Unit::TestCase
|
2
|
+
|
3
|
+
def setup
|
4
|
+
@environment = Moonrope::EvalEnvironment.new(Moonrope::Base.new, FakeRequest.new(:params => {'page' => 1}))
|
5
|
+
@environment.reset
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_errors
|
9
|
+
assert_raises Moonrope::Errors::NotFound do
|
10
|
+
@environment.error(:not_found, "Page not found")
|
11
|
+
end
|
12
|
+
|
13
|
+
assert_raises Moonrope::Errors::AccessDenied do
|
14
|
+
@environment.error(:access_denied, "User not authenticated")
|
15
|
+
end
|
16
|
+
|
17
|
+
assert_raises Moonrope::Errors::ValidationError do
|
18
|
+
@environment.error(:validation_error, [{:field => 'user', :message => 'should not be blank'}])
|
19
|
+
end
|
20
|
+
|
21
|
+
assert_raises Moonrope::Errors::ParameterError do
|
22
|
+
@environment.error(:parameter_error, [{:field => 'page', :message => 'should be present'}])
|
23
|
+
end
|
24
|
+
|
25
|
+
assert_raises Moonrope::Errors::RequestError do
|
26
|
+
@environment.error(:misc_error, "Unknown issue")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_paginate
|
31
|
+
items = PaginationCollection.new
|
32
|
+
result = @environment.paginate(items) { |r| r }
|
33
|
+
assert result.is_a?(Array)
|
34
|
+
assert @environment.flags[:paginated].is_a?(Hash)
|
35
|
+
end
|
36
|
+
|
37
|
+
class PaginationCollection
|
38
|
+
def to_a
|
39
|
+
[1,2,3,4,5,6]
|
40
|
+
end
|
41
|
+
|
42
|
+
def page(page)
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
def per(max_per_page)
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
def total_pages
|
51
|
+
2
|
52
|
+
end
|
53
|
+
|
54
|
+
def total_count
|
55
|
+
34
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
class HelpersTest < Test::Unit::TestCase
|
2
|
+
|
3
|
+
def test_helper_definitions_and_selection
|
4
|
+
base = Moonrope::Base.new do
|
5
|
+
# A global helper
|
6
|
+
helper :say_hello do |name|
|
7
|
+
"Hello #{name}!"
|
8
|
+
end
|
9
|
+
|
10
|
+
# A controller specific helper
|
11
|
+
controller :users do
|
12
|
+
helper :user_helper do |name|
|
13
|
+
"Your name is #{name}!"
|
14
|
+
end
|
15
|
+
|
16
|
+
action :action1 do
|
17
|
+
action do
|
18
|
+
say_hello('David')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
action :action2 do
|
23
|
+
action do
|
24
|
+
user_helper('Michael')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
action :action3 do
|
29
|
+
action do
|
30
|
+
animal_helper('Bob')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Another controller
|
36
|
+
controller :animals do
|
37
|
+
helper :animal_helper do |name|
|
38
|
+
"Animal name is #{name}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
assert_equal 3, base.helpers.size
|
44
|
+
assert_equal Moonrope::Helper, base.helper(:say_hello).class
|
45
|
+
|
46
|
+
# see if the controller-scoped helper is only available to the cobntroller
|
47
|
+
assert_equal nil, base.helper(:user_helper)
|
48
|
+
assert_equal nil, base.helper(:user_helper, base / :animals)
|
49
|
+
assert_equal Moonrope::Helper, base.helper(:user_helper, base/:users).class
|
50
|
+
|
51
|
+
# see if running the actuions will allow usage of helpers
|
52
|
+
result = (base/:users/:action1).execute
|
53
|
+
assert_equal "Hello David!", result.data
|
54
|
+
|
55
|
+
result = (base/:users/:action2).execute
|
56
|
+
assert_equal "Your name is Michael!", result.data
|
57
|
+
|
58
|
+
assert_raises(NoMethodError) { (base/:users/:action3).execute }
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_unloadable_helpers
|
62
|
+
base = Moonrope::Base.new
|
63
|
+
base.dsl.instance_eval do
|
64
|
+
helper :unloadable_helper, :unloadable => false do
|
65
|
+
666
|
66
|
+
end
|
67
|
+
|
68
|
+
helper :normal_helper do
|
69
|
+
111
|
70
|
+
end
|
71
|
+
end
|
72
|
+
# initially they'll both exist
|
73
|
+
assert_equal Moonrope::Helper, base.helper(:unloadable_helper).class
|
74
|
+
assert_equal Moonrope::Helper, base.helper(:normal_helper).class
|
75
|
+
# unload the base
|
76
|
+
base.unload
|
77
|
+
# now only the unloadable helper remains
|
78
|
+
assert_equal Moonrope::Helper, base.helper(:unloadable_helper).class
|
79
|
+
assert_equal nil, base.helper(:normal_helper)
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_ensure_helpers_cant_be_double_loaded
|
83
|
+
base = Moonrope::Base.new do
|
84
|
+
helper :my_helper do
|
85
|
+
123
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
assert_raises Moonrope::Errors::HelperAlreadyDefined do
|
90
|
+
base.dsl.instance_eval do
|
91
|
+
helper :my_helper do
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
class ParamSetTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_param_set
|
6
|
+
set = Moonrope::ParamSet.new('fruit' => 'Banana')
|
7
|
+
# Test that values which aren't included are nil
|
8
|
+
assert_equal nil, set.vegetable
|
9
|
+
assert_equal nil, set[:vegetable]
|
10
|
+
# Test values can be accessed if they are provided
|
11
|
+
assert_equal 'Banana', set.fruit
|
12
|
+
assert_equal 'Banana', set[:fruit]
|
13
|
+
assert_equal 'Banana', set['fruit']
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_default_params
|
17
|
+
set = Moonrope::ParamSet.new('fruit' => 'Banana')
|
18
|
+
set._defaults = {'vegetable' => 'Tomato', 'fruit' => 'Apple'}
|
19
|
+
# Check that the default is provided
|
20
|
+
assert_equal 'Tomato', set.vegetable
|
21
|
+
# Check that the fruit default isn't used.
|
22
|
+
assert_equal 'Banana', set.fruit
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_nilification
|
26
|
+
set = Moonrope::ParamSet.new('fruit' => '')
|
27
|
+
assert_equal nil, set.fruit
|
28
|
+
assert_equal nil, set[:fruit]
|
29
|
+
assert_equal nil, set['fruit']
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_key_presence
|
33
|
+
set = Moonrope::ParamSet.new('fruit' => 'Apple')
|
34
|
+
set._defaults = {'meat' => 'Beef'}
|
35
|
+
assert_equal true, set.has?(:fruit)
|
36
|
+
assert_equal true, set.has?(:meat)
|
37
|
+
assert_equal false, set.has?(:vegetable)
|
38
|
+
end
|
39
|
+
|
40
|
+
class ParamSetCopyTestThing
|
41
|
+
attr_accessor :fruit, :vegetable
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
class RackMiddlewareTest < Test::Unit::TestCase
|
2
|
+
|
3
|
+
include Rack::Test::Methods
|
4
|
+
|
5
|
+
def app
|
6
|
+
@app ||= begin
|
7
|
+
base = Moonrope::Base.new do
|
8
|
+
authenticator :default do
|
9
|
+
error "Denied", "No suitable credentials were provided."
|
10
|
+
lookup do
|
11
|
+
# if there is a x-moonrope-username header, check the auth
|
12
|
+
# or raise access denied.
|
13
|
+
if request.headers['X-Moonrope-Username']
|
14
|
+
if request.headers['X-Moonrope-Username'] == 'user' && request.headers['X-Moonrope-Password'] == 'password'
|
15
|
+
User.new(:admin => true)
|
16
|
+
else
|
17
|
+
error "Denied"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
controller :users do
|
23
|
+
action :list do
|
24
|
+
# return an empty array
|
25
|
+
action { [] }
|
26
|
+
end
|
27
|
+
|
28
|
+
action :echo do
|
29
|
+
param :name, :required => true
|
30
|
+
action { params.name }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
Moonrope::RackMiddleware.new(nil, base)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_non_api_requests_404
|
39
|
+
get "/"
|
40
|
+
assert_equal 404, last_response.status
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_api_request_validation
|
44
|
+
get "/api/"
|
45
|
+
assert_equal 400, last_response.status
|
46
|
+
get "/api/v1"
|
47
|
+
assert_equal 400, last_response.status
|
48
|
+
get "/api/v1/controller"
|
49
|
+
assert_equal 400, last_response.status
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_api_methods
|
53
|
+
params = {:page => 1}.to_json
|
54
|
+
get "/api/v1/users/list", {:params => params}
|
55
|
+
assert_equal 200, last_response.status
|
56
|
+
assert response_json = JSON.parse(last_response.body)
|
57
|
+
assert_equal 'success', response_json['status']
|
58
|
+
assert response_json['data'].is_a?(Array)
|
59
|
+
assert_equal 'application/json', last_response.headers['Content-Type']
|
60
|
+
assert last_response.headers['Content-Length']
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_params_in_body
|
64
|
+
post "/api/v1/users/echo", '{"name":"Adam"}', {'CONTENT_TYPE' => 'application/json'}
|
65
|
+
assert_equal 200, last_response.status
|
66
|
+
assert response_json = JSON.parse(last_response.body)
|
67
|
+
assert_equal 'success', response_json['status']
|
68
|
+
assert_equal 'Adam', response_json['data']
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_passing_invalid_json_renders_a_bad_request
|
72
|
+
get "/api/v1/users/list", {:params => "{invalidjson}"}
|
73
|
+
assert_equal 400, last_response.status
|
74
|
+
assert response_json = JSON.parse(last_response.body)
|
75
|
+
assert_equal 'invalid-json', response_json['status']
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_authenticated_api_methods
|
79
|
+
# correct credential
|
80
|
+
get "/api/v1/users/list", {}, auth_headers('user', 'password')
|
81
|
+
assert response_json = JSON.parse(last_response.body)
|
82
|
+
assert_equal 'success', response_json['status']
|
83
|
+
# invalid password
|
84
|
+
get "/api/v1/users/list", {}, auth_headers('user-invalid', 'password-invalid')
|
85
|
+
assert response_json = JSON.parse(last_response.body)
|
86
|
+
assert_equal 'error', response_json['status']
|
87
|
+
assert_equal 'Denied', response_json['data']['code']
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_request_callback_is_invoked
|
91
|
+
request_count = 0
|
92
|
+
app.base.on_request = Proc.new do |base, env|
|
93
|
+
request_count += 1
|
94
|
+
end
|
95
|
+
assert_equal 0, request_count
|
96
|
+
get "/api/v1/users/list"
|
97
|
+
assert_equal 1, request_count
|
98
|
+
get "/api/v1/users/list"
|
99
|
+
assert_equal 2, request_count
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def auth_headers(username, password)
|
106
|
+
{'HTTP_X_MOONROPE_USERNAME' => username, 'HTTP_X_MOONROPE_PASSWORD' => password}
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
@@ -0,0 +1,232 @@
|
|
1
|
+
class RequestTest < Test::Unit::TestCase
|
2
|
+
|
3
|
+
|
4
|
+
def test_validation
|
5
|
+
# Create a simple API server with just the users & list controller
|
6
|
+
base = Moonrope::Base.new do
|
7
|
+
controller :users do
|
8
|
+
action :list
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
request = base.request(make_rack_env_hash('/api/v1/users/list'))
|
13
|
+
assert_equal true, request.valid?
|
14
|
+
request = base.request(make_rack_env_hash('/api/v1/missing/unknown'))
|
15
|
+
assert_equal false, request.valid?
|
16
|
+
|
17
|
+
request = base.request(make_rack_env_hash('/api/v1'))
|
18
|
+
assert_equal false, request.valid?
|
19
|
+
request = base.request(make_rack_env_hash('/api/v1/users'))
|
20
|
+
assert_equal false, request.valid?
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_version
|
24
|
+
base = Moonrope::Base.new
|
25
|
+
request = base.request(make_rack_env_hash('/api/v0/users/list'))
|
26
|
+
assert_equal 1, request.version
|
27
|
+
request = base.request(make_rack_env_hash('/api/v1/users/list'))
|
28
|
+
assert_equal 1, request.version
|
29
|
+
request = base.request(make_rack_env_hash('/api/v2/users/list'))
|
30
|
+
assert_equal 2, request.version
|
31
|
+
request = base.request(make_rack_env_hash('/api/v100/users/list'))
|
32
|
+
assert_equal 100, request.version
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_controllers_and_actions
|
36
|
+
base = Moonrope::Base.new do
|
37
|
+
controller :users do
|
38
|
+
action :list
|
39
|
+
end
|
40
|
+
end
|
41
|
+
request = base.request(make_rack_env_hash('/api/v1/users/list'))
|
42
|
+
assert request.controller.is_a?(Moonrope::Controller)
|
43
|
+
assert_equal :users, request.controller.name
|
44
|
+
assert request.action.is_a?(Moonrope::Action)
|
45
|
+
assert_equal :list, request.action.name
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_params_are_accessible
|
49
|
+
env = make_rack_env_hash('/api/v1/users/list', {'params' => {'page' => 1}})
|
50
|
+
request = Moonrope::Base.new.request(env)
|
51
|
+
assert request.params.is_a?(Moonrope::ParamSet)
|
52
|
+
assert_equal '1', request.params.page
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_actions_can_be_executed
|
56
|
+
base = Moonrope::Base.new do
|
57
|
+
controller :users do
|
58
|
+
action :list do
|
59
|
+
action { true }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
request = base.request(make_rack_env_hash('/api/v1/users/list'))
|
65
|
+
assert result = request.execute
|
66
|
+
assert result.is_a?(Moonrope::ActionResult), "request.action does not return an ActionResult, was a #{result.class}"
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_headers_are_accessible
|
70
|
+
base = Moonrope::Base.new
|
71
|
+
env = make_rack_env_hash('/api/v1/users/list', {}, {'HTTP_X_EXAMPLE_HEADER' => 'Hello'})
|
72
|
+
request = base.request(env)
|
73
|
+
assert_equal 'Hello', request.headers['X-Example-Header']
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_ip_is_accessible
|
77
|
+
base = Moonrope::Base.new
|
78
|
+
env = make_rack_env_hash('/api/v1/users/list')
|
79
|
+
request = base.request(env)
|
80
|
+
assert_equal '127.0.0.1', request.ip
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_authenticated_requests
|
84
|
+
base = Moonrope::Base.new do
|
85
|
+
authenticator :default do
|
86
|
+
lookup do
|
87
|
+
User.new(:admin => true)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
controller :users do
|
91
|
+
action :list do
|
92
|
+
action { true }
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
# authenticated
|
97
|
+
request = base.request(make_rack_env_hash('/api/v1/users/list'))
|
98
|
+
assert result = request.execute
|
99
|
+
assert_equal User, request.identity.class
|
100
|
+
assert_equal false, request.anonymous?
|
101
|
+
assert_equal true, request.authenticated?
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_authentication_failures
|
105
|
+
base = Moonrope::Base.new do
|
106
|
+
authenticator :default do
|
107
|
+
lookup do
|
108
|
+
error :access_denied, "Not permitted"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
controller :users do
|
113
|
+
action :list do
|
114
|
+
action { true}
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
request = base.request(make_rack_env_hash('/api/v1/users/list'))
|
119
|
+
assert result = request.execute
|
120
|
+
assert_equal "access-denied", result.status
|
121
|
+
assert_equal nil, request.identity
|
122
|
+
assert_equal true, request.anonymous?
|
123
|
+
assert_equal false, request.authenticated?
|
124
|
+
end
|
125
|
+
|
126
|
+
def test_requests_which_authenticator_says_are_anonymous
|
127
|
+
base = Moonrope::Base.new do
|
128
|
+
authenticator :default do
|
129
|
+
lookup { nil }
|
130
|
+
end
|
131
|
+
controller :users do
|
132
|
+
action :list do
|
133
|
+
action { true }
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
request = base.request(make_rack_env_hash('/api/v1/users/list'))
|
138
|
+
assert result = request.execute
|
139
|
+
assert_equal "success", result.status
|
140
|
+
assert_equal nil, request.identity
|
141
|
+
assert_equal true, request.anonymous?
|
142
|
+
assert_equal false, request.authenticated?
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_trying_to_use_invalid_authenticator_raises_error
|
146
|
+
base = Moonrope::Base.new do
|
147
|
+
authenticator :default do
|
148
|
+
lookup do
|
149
|
+
User.new(:admin => true)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
controller :users do
|
153
|
+
action :list do
|
154
|
+
authenticator :blah
|
155
|
+
action { true }
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
request = base.request(make_rack_env_hash('/api/v1/users/list'))
|
161
|
+
assert_raises Moonrope::Errors::MissingAuthenticator do
|
162
|
+
request.execute
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def test_raising_errors_from_the_authenticator_lookup
|
167
|
+
base = Moonrope::Base.new do
|
168
|
+
authenticator :default do
|
169
|
+
error 'InvalidToken', 'Token provided is invalid', :attributes => {:token => 'The token looked up'}
|
170
|
+
lookup do
|
171
|
+
error 'InvalidToken', :token => request.headers['X-Example-Header']
|
172
|
+
end
|
173
|
+
end
|
174
|
+
controller :users do
|
175
|
+
action :list do
|
176
|
+
action { true }
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
request = base.request(make_rack_env_hash('/api/v1/users/list', {}, {"HTTP_X_EXAMPLE_HEADER" => "1234567"}))
|
181
|
+
assert result = request.execute
|
182
|
+
assert_equal "error", result.status
|
183
|
+
assert_equal "InvalidToken", result.data[:code]
|
184
|
+
assert_equal "1234567", result.data[:token]
|
185
|
+
assert_equal "Token provided is invalid", result.data[:message]
|
186
|
+
end
|
187
|
+
|
188
|
+
def test_appropriate_error_is_returned_from_access_checks
|
189
|
+
base = Moonrope::Base.new do
|
190
|
+
authenticator :default do
|
191
|
+
lookup { :admin }
|
192
|
+
rule :default, "CustomError", "Must be authenticated as admin user" do
|
193
|
+
identity == :anonymous
|
194
|
+
end
|
195
|
+
end
|
196
|
+
controller :users do
|
197
|
+
action :list do
|
198
|
+
action { true }
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
request = base.request(make_rack_env_hash('/api/v1/users/list', {}, {"HTTP_X_EXAMPLE_HEADER" => "1234567"}))
|
203
|
+
assert result = request.execute
|
204
|
+
assert_equal "error", result.status
|
205
|
+
assert_equal "CustomError", result.data[:code]
|
206
|
+
assert_equal "Must be authenticated as admin user", result.data[:message]
|
207
|
+
end
|
208
|
+
|
209
|
+
def test_appropriate_error_can_be_returned_from_authenticator_error_hash
|
210
|
+
base = Moonrope::Base.new do
|
211
|
+
authenticator :default do
|
212
|
+
lookup { :admin }
|
213
|
+
error "CustomError", "Some custom error message override"
|
214
|
+
rule :default, "CustomError", "Must be authenticated as admin user" do
|
215
|
+
identity == :anonymous
|
216
|
+
end
|
217
|
+
end
|
218
|
+
controller :users do
|
219
|
+
action :list do
|
220
|
+
action { true }
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
request = base.request(make_rack_env_hash('/api/v1/users/list', {}, {"HTTP_X_EXAMPLE_HEADER" => "1234567"}))
|
225
|
+
assert result = request.execute
|
226
|
+
assert_equal "error", result.status
|
227
|
+
assert_equal "CustomError", result.data[:code]
|
228
|
+
assert_equal "Some custom error message override", result.data[:message]
|
229
|
+
end
|
230
|
+
|
231
|
+
|
232
|
+
end
|