moonrope 1.4.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +9 -0
  3. data/Gemfile.lock +47 -0
  4. data/MIT-LICENCE +20 -0
  5. data/README.md +24 -0
  6. data/bin/moonrope +28 -0
  7. data/docs/authentication.md +114 -0
  8. data/docs/controllers.md +106 -0
  9. data/docs/exceptions.md +27 -0
  10. data/docs/introduction.md +29 -0
  11. data/docs/structures.md +214 -0
  12. data/example/authentication.rb +50 -0
  13. data/example/controllers/meta_controller.rb +14 -0
  14. data/example/controllers/users_controller.rb +92 -0
  15. data/example/structures/pet_structure.rb +12 -0
  16. data/example/structures/user_structure.rb +35 -0
  17. data/html/assets/lock.svg +3 -0
  18. data/html/assets/reset.css +101 -0
  19. data/html/assets/style.css +348 -0
  20. data/html/assets/tool.svg +4 -0
  21. data/html/assets/try.js +151 -0
  22. data/html/authenticators/default.html +191 -0
  23. data/html/controllers/meta/version.html +144 -0
  24. data/html/controllers/meta.html +73 -0
  25. data/html/controllers/users/create.html +341 -0
  26. data/html/controllers/users/list.html +348 -0
  27. data/html/controllers/users/show.html +261 -0
  28. data/html/controllers/users/update.html +387 -0
  29. data/html/controllers/users.html +93 -0
  30. data/html/index.html +166 -0
  31. data/html/moonrope.txt +0 -0
  32. data/html/structures/pet.html +176 -0
  33. data/html/structures/user.html +338 -0
  34. data/lib/moonrope/action.rb +165 -37
  35. data/lib/moonrope/authenticator.rb +39 -0
  36. data/lib/moonrope/base.rb +24 -6
  37. data/lib/moonrope/controller.rb +4 -2
  38. data/lib/moonrope/doc_context.rb +94 -0
  39. data/lib/moonrope/doc_server.rb +123 -0
  40. data/lib/moonrope/dsl/action_dsl.rb +159 -9
  41. data/lib/moonrope/dsl/authenticator_dsl.rb +31 -0
  42. data/lib/moonrope/dsl/base_dsl.rb +21 -18
  43. data/lib/moonrope/dsl/controller_dsl.rb +60 -9
  44. data/lib/moonrope/dsl/filterable_dsl.rb +27 -0
  45. data/lib/moonrope/dsl/structure_dsl.rb +27 -2
  46. data/lib/moonrope/errors.rb +3 -0
  47. data/lib/moonrope/eval_environment.rb +82 -3
  48. data/lib/moonrope/eval_helpers/filter_helper.rb +82 -0
  49. data/lib/moonrope/eval_helpers.rb +28 -5
  50. data/lib/moonrope/guard.rb +35 -0
  51. data/lib/moonrope/html_generator.rb +65 -0
  52. data/lib/moonrope/param_set.rb +11 -1
  53. data/lib/moonrope/rack_middleware.rb +1 -1
  54. data/lib/moonrope/railtie.rb +31 -14
  55. data/lib/moonrope/request.rb +25 -14
  56. data/lib/moonrope/structure.rb +74 -11
  57. data/lib/moonrope/structure_attribute.rb +15 -0
  58. data/lib/moonrope/version.rb +1 -1
  59. data/lib/moonrope.rb +5 -4
  60. data/moonrope.gemspec +21 -0
  61. data/spec/spec_helper.rb +32 -0
  62. data/spec/specs/action_spec.rb +455 -0
  63. data/spec/specs/base_spec.rb +29 -0
  64. data/spec/specs/controller_spec.rb +31 -0
  65. data/spec/specs/param_set_spec.rb +31 -0
  66. data/templates/basic/_action_form.erb +77 -0
  67. data/templates/basic/_errors_table.erb +32 -0
  68. data/templates/basic/_structure_attributes_list.erb +55 -0
  69. data/templates/basic/action.erb +168 -0
  70. data/templates/basic/assets/lock.svg +3 -0
  71. data/templates/basic/assets/reset.css +101 -0
  72. data/templates/basic/assets/style.css +348 -0
  73. data/templates/basic/assets/tool.svg +4 -0
  74. data/templates/basic/assets/try.js +151 -0
  75. data/templates/basic/authenticator.erb +51 -0
  76. data/templates/basic/controller.erb +20 -0
  77. data/templates/basic/index.erb +114 -0
  78. data/templates/basic/layout.erb +46 -0
  79. data/templates/basic/structure.erb +23 -0
  80. data/test/test_helper.rb +81 -0
  81. data/test/tests/action_access_test.rb +63 -0
  82. data/test/tests/actions_test.rb +524 -0
  83. data/test/tests/authenticators_test.rb +87 -0
  84. data/test/tests/base_test.rb +35 -0
  85. data/test/tests/controllers_test.rb +49 -0
  86. data/test/tests/eval_environment_test.rb +136 -0
  87. data/test/tests/evel_helpers_test.rb +60 -0
  88. data/test/tests/examples_test.rb +11 -0
  89. data/test/tests/helpers_test.rb +97 -0
  90. data/test/tests/param_set_test.rb +44 -0
  91. data/test/tests/rack_middleware_test.rb +109 -0
  92. data/test/tests/request_test.rb +232 -0
  93. data/test/tests/structures_param_extensions_test.rb +159 -0
  94. data/test/tests/structures_test.rb +335 -0
  95. 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,11 @@
1
+ class ExamplesTest < Test::Unit::TestCase
2
+
3
+ def setup
4
+ @base = Moonrope::Base.load(File.expand_path('../../../example', __FILE__))
5
+ end
6
+
7
+ def test_examples_are_valid
8
+ assert_equal 2, @base.controllers.size
9
+ end
10
+
11
+ 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