apes 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.rubocop.yml +82 -0
  4. data/.travis-gemfile +15 -0
  5. data/.travis.yml +15 -0
  6. data/.yardopts +1 -0
  7. data/CHANGELOG.md +3 -0
  8. data/Gemfile +22 -0
  9. data/README.md +177 -0
  10. data/Rakefile +44 -0
  11. data/apes.gemspec +34 -0
  12. data/doc/Apes.html +130 -0
  13. data/doc/Apes/Concerns.html +127 -0
  14. data/doc/Apes/Concerns/Errors.html +1089 -0
  15. data/doc/Apes/Concerns/Pagination.html +636 -0
  16. data/doc/Apes/Concerns/Request.html +766 -0
  17. data/doc/Apes/Concerns/Response.html +940 -0
  18. data/doc/Apes/Controller.html +1100 -0
  19. data/doc/Apes/Errors.html +125 -0
  20. data/doc/Apes/Errors/AuthenticationError.html +133 -0
  21. data/doc/Apes/Errors/BadRequestError.html +157 -0
  22. data/doc/Apes/Errors/BaseError.html +320 -0
  23. data/doc/Apes/Errors/InvalidDataError.html +157 -0
  24. data/doc/Apes/Errors/MissingDataError.html +157 -0
  25. data/doc/Apes/Model.html +378 -0
  26. data/doc/Apes/PaginationCursor.html +2138 -0
  27. data/doc/Apes/RuntimeConfiguration.html +909 -0
  28. data/doc/Apes/Serializers.html +125 -0
  29. data/doc/Apes/Serializers/JSON.html +389 -0
  30. data/doc/Apes/Serializers/JWT.html +452 -0
  31. data/doc/Apes/Serializers/List.html +347 -0
  32. data/doc/Apes/UrlsParser.html +1432 -0
  33. data/doc/Apes/Validators.html +125 -0
  34. data/doc/Apes/Validators/BaseValidator.html +278 -0
  35. data/doc/Apes/Validators/BooleanValidator.html +494 -0
  36. data/doc/Apes/Validators/EmailValidator.html +350 -0
  37. data/doc/Apes/Validators/PhoneValidator.html +375 -0
  38. data/doc/Apes/Validators/ReferenceValidator.html +372 -0
  39. data/doc/Apes/Validators/TimestampValidator.html +640 -0
  40. data/doc/Apes/Validators/UuidValidator.html +372 -0
  41. data/doc/Apes/Validators/ZipCodeValidator.html +372 -0
  42. data/doc/Apes/Version.html +189 -0
  43. data/doc/ApplicationController.html +547 -0
  44. data/doc/Concerns.html +128 -0
  45. data/doc/Concerns/ErrorHandling.html +826 -0
  46. data/doc/Concerns/PaginationHandling.html +463 -0
  47. data/doc/Concerns/RequestHandling.html +512 -0
  48. data/doc/Concerns/ResponseHandling.html +579 -0
  49. data/doc/Errors.html +126 -0
  50. data/doc/Errors/AuthenticationError.html +123 -0
  51. data/doc/Errors/BadRequestError.html +147 -0
  52. data/doc/Errors/BaseError.html +289 -0
  53. data/doc/Errors/InvalidDataError.html +147 -0
  54. data/doc/Errors/MissingDataError.html +147 -0
  55. data/doc/Model.html +315 -0
  56. data/doc/PaginationCursor.html +764 -0
  57. data/doc/Serializers.html +126 -0
  58. data/doc/Serializers/JSON.html +253 -0
  59. data/doc/Serializers/JWT.html +253 -0
  60. data/doc/Serializers/List.html +245 -0
  61. data/doc/Validators.html +126 -0
  62. data/doc/Validators/BaseValidator.html +209 -0
  63. data/doc/Validators/BooleanValidator.html +391 -0
  64. data/doc/Validators/EmailValidator.html +298 -0
  65. data/doc/Validators/PhoneValidator.html +313 -0
  66. data/doc/Validators/ReferenceValidator.html +284 -0
  67. data/doc/Validators/TimestampValidator.html +476 -0
  68. data/doc/Validators/UuidValidator.html +310 -0
  69. data/doc/Validators/ZipCodeValidator.html +310 -0
  70. data/doc/_index.html +435 -0
  71. data/doc/class_list.html +58 -0
  72. data/doc/css/common.css +1 -0
  73. data/doc/css/full_list.css +57 -0
  74. data/doc/css/style.css +339 -0
  75. data/doc/file.README.html +252 -0
  76. data/doc/file_list.html +60 -0
  77. data/doc/frames.html +26 -0
  78. data/doc/index.html +252 -0
  79. data/doc/js/app.js +219 -0
  80. data/doc/js/full_list.js +181 -0
  81. data/doc/js/jquery.js +4 -0
  82. data/doc/method_list.html +615 -0
  83. data/doc/top-level-namespace.html +112 -0
  84. data/lib/apes.rb +40 -0
  85. data/lib/apes/concerns/errors.rb +111 -0
  86. data/lib/apes/concerns/pagination.rb +81 -0
  87. data/lib/apes/concerns/request.rb +237 -0
  88. data/lib/apes/concerns/response.rb +74 -0
  89. data/lib/apes/controller.rb +77 -0
  90. data/lib/apes/errors.rb +38 -0
  91. data/lib/apes/model.rb +94 -0
  92. data/lib/apes/pagination_cursor.rb +152 -0
  93. data/lib/apes/runtime_configuration.rb +80 -0
  94. data/lib/apes/serializers.rb +88 -0
  95. data/lib/apes/urls_parser.rb +233 -0
  96. data/lib/apes/validators.rb +234 -0
  97. data/lib/apes/version.rb +24 -0
  98. data/spec/apes/concerns/errors_spec.rb +141 -0
  99. data/spec/apes/concerns/pagination_spec.rb +114 -0
  100. data/spec/apes/concerns/request_spec.rb +244 -0
  101. data/spec/apes/concerns/response_spec.rb +79 -0
  102. data/spec/apes/controller_spec.rb +54 -0
  103. data/spec/apes/errors_spec.rb +14 -0
  104. data/spec/apes/models_spec.rb +148 -0
  105. data/spec/apes/pagination_cursor_spec.rb +113 -0
  106. data/spec/apes/runtime_configuration_spec.rb +100 -0
  107. data/spec/apes/serializers_spec.rb +70 -0
  108. data/spec/apes/urls_parser_spec.rb +150 -0
  109. data/spec/apes/validators_spec.rb +237 -0
  110. data/spec/spec_helper.rb +30 -0
  111. data/views/_included.json.jbuilder +9 -0
  112. data/views/_pagination.json.jbuilder +9 -0
  113. data/views/collection.json.jbuilder +4 -0
  114. data/views/errors/400.json.jbuilder +9 -0
  115. data/views/errors/403.json.jbuilder +7 -0
  116. data/views/errors/404.json.jbuilder +6 -0
  117. data/views/errors/422.json.jbuilder +19 -0
  118. data/views/errors/500.json.jbuilder +12 -0
  119. data/views/errors/501.json.jbuilder +7 -0
  120. data/views/layouts/general.json.jbuilder +36 -0
  121. data/views/object.json.jbuilder +4 -0
  122. metadata +262 -0
@@ -0,0 +1,79 @@
1
+ require "spec_helper"
2
+
3
+ describe Apes::Concerns::Response do
4
+ class ResponseHandlingMockContainer
5
+ include Apes::Concerns::Response
6
+ end
7
+
8
+ module Mockspace
9
+ class NameMockController
10
+ end
11
+ end
12
+
13
+ subject { ResponseHandlingMockContainer.new }
14
+
15
+ describe "#response_template_for" do
16
+ it "should return the right template" do
17
+ expect(subject.response_template_for(Mockspace::NameMockController.new)).to eq("mockspace_name_mock_controller")
18
+ expect(subject.response_template_for([Mockspace::NameMockController.new])).to eq("mockspace_name_mock_controller")
19
+ end
20
+ end
21
+
22
+ describe "#response_meta" do
23
+ it "should return the right meta" do
24
+ expect(subject.response_meta).to be_a(HashWithIndifferentAccess)
25
+ expect(subject.response_meta("FOO")).to eq("FOO")
26
+
27
+ subject.instance_variable_set(:@meta, "BAR")
28
+ expect(subject.response_meta).to eq("BAR")
29
+ end
30
+ end
31
+
32
+ describe "#response_data" do
33
+ it "should return the right data" do
34
+ expect(subject.response_data).to be_a(HashWithIndifferentAccess)
35
+ expect(subject.response_data("FOO")).to eq("FOO")
36
+
37
+ subject.instance_variable_set(:@data, "BAR")
38
+ expect(subject.response_data).to eq("BAR")
39
+ end
40
+ end
41
+
42
+ describe "#response_links" do
43
+ it "should return the right links" do
44
+ expect(subject.response_links).to be_a(HashWithIndifferentAccess)
45
+ expect(subject.response_links("FOO")).to eq("FOO")
46
+
47
+ subject.instance_variable_set(:@links, "BAR")
48
+ expect(subject.response_links).to eq("BAR")
49
+ end
50
+ end
51
+
52
+ describe "#response_included" do
53
+ it "should return the right included data" do
54
+ allow(subject).to receive(:controller).and_return(OpenStruct.new(included: nil))
55
+ expect(subject.response_included).to be_a(HashWithIndifferentAccess)
56
+ expect(subject.response_included("FOO")).to eq("FOO")
57
+
58
+ allow(subject).to receive(:controller).and_return(OpenStruct.new(included: "BAR"))
59
+ subject.instance_variable_set(:@links, "BAR")
60
+ expect(subject.response_links).to eq("BAR")
61
+ end
62
+ end
63
+
64
+ describe "#response_include" do
65
+ it "should add included data" do
66
+ data = {}
67
+ allow(subject).to receive(:controller).and_return(OpenStruct.new(included: data))
68
+
69
+ subject.response_include("DATA")
70
+ expect(data).to eq({"string:DATA"=>["DATA", nil]})
71
+ end
72
+ end
73
+
74
+ describe "#response_timestamp" do
75
+ it "should return the right timestamp" do
76
+ expect(subject.response_timestamp(DateTime.civil(2024, 12, 6, 3, 2, 1, "+7"))).to eq("2024-12-06T03:02:01.000+0700")
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,54 @@
1
+ #
2
+ # This file is part of the apes gem. Copyright (C) 2016 and above Shogun <shogun@cowtech.it>.
3
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
4
+ #
5
+
6
+ require "spec_helper"
7
+
8
+ describe Apes::Controller do
9
+ describe "#handle_cors", type: :controller do
10
+ it "should render the right content" do
11
+ expect(subject).to receive(:render).with(nothing: true, status: :no_content)
12
+ subject.handle_cors
13
+ end
14
+ end
15
+
16
+ describe "#default_url_options" do
17
+ it "should always mark the host as needed in URLs" do
18
+ allow(Apes::RuntimeConfiguration).to receive(:development?).and_return(true)
19
+ expect(subject).to receive(:request).and_return(OpenStruct.new(url: "http://localhost"))
20
+ expect(subject.default_url_options[:only_path]).to be_falsey
21
+ end
22
+ end
23
+
24
+ describe "#render_error" do
25
+ it "should render the right template" do
26
+ expect(subject).to receive(:render).with("errors/403", status: :forbidden)
27
+ subject.render_error(:forbidden, ["1", "2"])
28
+ expect(subject.instance_variable_get(:@errors)).to eq(["1", "2"])
29
+
30
+ expect(subject).to receive(:render).with("errors/404", status: 404)
31
+ subject.render_error(404, ["3", "4"])
32
+ expect(subject.instance_variable_get(:@errors)).to eq(["3", "4"])
33
+ end
34
+ end
35
+
36
+ describe "#render_default_views (private)" do
37
+ it "should render the object template if a object is set" do
38
+ subject.instance_variable_set(:@object, "FOO")
39
+ expect(subject).to receive(:render).with("/object")
40
+ subject.send(:render_default_views, RuntimeError.new)
41
+ end
42
+
43
+ it "should render the collection template if a collection is set" do
44
+ subject.instance_variable_set(:@objects, "FOO")
45
+ expect(subject).to receive(:render).with("/collection")
46
+ subject.send(:render_default_views, RuntimeError.new)
47
+ end
48
+
49
+ it "should fallback to the default handler otherwise" do
50
+ expect(subject).to receive(:error_handle_exception).with(an_instance_of(RuntimeError))
51
+ subject.send(:render_default_views, RuntimeError.new)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,14 @@
1
+ #
2
+ # This file is part of the apes gem. Copyright (C) 2016 and above Shogun <shogun@cowtech.it>.
3
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
4
+ #
5
+
6
+ require "spec_helper"
7
+
8
+ describe Apes::Errors::BaseError do
9
+ it "should save details" do
10
+ subject = Apes::Errors::BaseError.new({a: 1})
11
+ expect(subject.message).to eq("")
12
+ expect(subject.details).to eq({a: 1})
13
+ end
14
+ end
@@ -0,0 +1,148 @@
1
+ #
2
+ # This file is part of the apes gem. Copyright (C) 2016 and above Shogun <shogun@cowtech.it>.
3
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
4
+ #
5
+
6
+ require "spec_helper"
7
+
8
+ describe Apes::Model do
9
+ class MockBaseModel < ActiveRecord::Base
10
+ include Apes::Model
11
+
12
+ self.abstract_class = true
13
+ end
14
+
15
+ class MockQueryingModel < MockBaseModel
16
+ SECONDARY_QUERY = "name = :id"
17
+
18
+ def self.table_name
19
+ "querying_temp_table"
20
+ end
21
+
22
+ attr_reader :field
23
+ validates :field, "presence" => true
24
+ end
25
+
26
+ class MockQueryingOtherModel < MockBaseModel
27
+ include Apes::Model
28
+
29
+ SECONDARY_KEY = :handle
30
+
31
+ def self.table_name
32
+ "querying_temp_table"
33
+ end
34
+ end
35
+
36
+ class MockQueryingAnotherModel < MockBaseModel
37
+ include Apes::Model
38
+
39
+ def self.table_name
40
+ "querying_temp_table"
41
+ end
42
+ end
43
+
44
+ subject {
45
+ MockQueryingModel.new(id: SecureRandom.uuid, handle: "HANDLE", name: "NAME")
46
+ }
47
+
48
+ around(:each) do |example|
49
+ db = Tempfile.new("apes-test")
50
+ MockBaseModel.establish_connection(adapter: "sqlite3", database: db.path)
51
+ MockBaseModel.connection.execute("CREATE TABLE IF NOT EXISTS querying_temp_table(id uuid, handle varchar, name varchar);")
52
+ example.call
53
+ db.unlink
54
+ end
55
+
56
+ describe ".find_with_any!" do
57
+ it "should find a record using the primary key when the ID is a UUID" do
58
+ expect(MockQueryingOtherModel).to receive(:find).with(subject.id).and_return(subject)
59
+ expect(MockQueryingOtherModel.find_with_any!(subject.id)).to eq(subject)
60
+ end
61
+
62
+ it "should find a record using the secondary key" do
63
+ expect(MockQueryingOtherModel).to receive(:find_by!).with(handle: subject.handle).and_return(subject)
64
+ expect(MockQueryingOtherModel.find_with_any!(subject.handle)).to eq(subject)
65
+ end
66
+
67
+ it "should find a record using the secondary query" do
68
+ expect(MockQueryingModel).to receive(:find_by!).with("name = :id", {id: subject.name}).and_return(subject)
69
+ expect(MockQueryingModel.find_with_any!(subject.name).id).to eq(subject.id)
70
+ end
71
+
72
+ it "should fallback to a reasonable query" do
73
+ expect(MockQueryingAnotherModel).to receive(:find_by!).with(handle: subject.handle).and_return(subject)
74
+ expect(MockQueryingAnotherModel.find_with_any!(subject.handle).id).to eq(subject.id)
75
+ end
76
+
77
+ it "should raise an exception when nothing is found" do
78
+ expect { MockQueryingOtherModel.find_with_any!("NOTHING") }.to raise_error(ActiveRecord::RecordNotFound)
79
+ end
80
+ end
81
+
82
+ describe ".find_with_any" do
83
+ it "should find a records" do
84
+ expect(MockQueryingOtherModel).to receive(:find_by!).with(handle: subject.handle).and_return(subject)
85
+ expect(MockQueryingOtherModel.find_with_any(subject.handle)).to eq(subject)
86
+ end
87
+
88
+ it "should raise an exception when nothing is found" do
89
+ expect { MockQueryingOtherModel.find_with_any("NOTHING") }.not_to raise_error
90
+ end
91
+ end
92
+
93
+ describe ".search" do
94
+ let(:params) { {filter: {query: "ABC"}} }
95
+ let(:table_name) { "querying_temp_table" }
96
+
97
+ it "should do nothing if no value is present" do
98
+ expect(MockQueryingOtherModel.search().to_sql).to eq("SELECT \"#{table_name}\".* FROM \"#{table_name}\"")
99
+ end
100
+
101
+ it "should perform a query on the fields" do
102
+ expect(MockQueryingOtherModel.search(params: params, fields: [:name, :token, :secret]).to_sql).to eq("SELECT \"#{table_name}\".* FROM \"#{table_name}\" WHERE (name ILIKE '%ABC%' OR token ILIKE '%ABC%' OR secret ILIKE '%ABC%')")
103
+ end
104
+
105
+ it "should allow prefix based queries" do
106
+ expect(MockQueryingOtherModel.search(params: params, start_only: true).to_sql).to eq("SELECT \"#{table_name}\".* FROM \"#{table_name}\" WHERE (name ILIKE 'ABC%')")
107
+ end
108
+
109
+ it "should allow case sensitive searches" do
110
+ expect(MockQueryingOtherModel.search(params: params, case_sensitive: true).to_sql).to eq("SELECT \"#{table_name}\".* FROM \"#{table_name}\" WHERE (name LIKE '%ABC%')")
111
+ end
112
+
113
+ it "should allow to use AND based searches" do
114
+ expect(MockQueryingOtherModel.search(params: params, method: :other).to_sql).to eq("SELECT \"#{table_name}\".* FROM \"#{table_name}\" WHERE (name ILIKE '%ABC%')")
115
+ end
116
+
117
+ it "should extend existing queries" do
118
+ expect(MockQueryingOtherModel.search(params: params, query: MockQueryingOtherModel.where("secret IS NOT NULL")).to_sql).to eq("SELECT \"#{table_name}\".* FROM \"#{table_name}\" WHERE (secret IS NOT NULL) AND (name ILIKE '%ABC%')")
119
+ end
120
+ end
121
+
122
+ describe "#additional_errors" do
123
+ it "should return a ActiveModel::Errors object" do
124
+ expect(MockQueryingModel.new.additional_errors).to be_a(ActiveModel::Errors)
125
+ end
126
+ end
127
+
128
+ describe "#run_validations!" do
129
+ it "should merge errors when validating" do
130
+ subject = MockQueryingModel.new
131
+ subject.additional_errors.add(:field, "ANOTHER")
132
+ subject.validate
133
+ expect(subject.errors.to_hash).to eq({field: ["ANOTHER", "can't be blank"]})
134
+ end
135
+ end
136
+
137
+ describe "#all_validation_errors" do
138
+ it "should allow to add additional errors after validation" do
139
+ subject = MockQueryingModel.new
140
+ expect(subject.all_validation_errors.to_hash).to eq({})
141
+ subject.validate
142
+ expect(subject.all_validation_errors.to_hash).to eq({field: ["can't be blank"]})
143
+ subject.additional_errors.add(:field, "ANOTHER")
144
+ expect(subject.all_validation_errors.to_hash).to eq({field: ["can't be blank", "ANOTHER"]})
145
+ expect(subject.all_validation_errors.to_hash).to eq({field: ["can't be blank", "ANOTHER"]}) # Should not add errors twice
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,113 @@
1
+ #
2
+ # This file is part of the apes gem. Copyright (C) 2016 and above Shogun <shogun@cowtech.it>.
3
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
4
+ #
5
+
6
+ require "spec_helper"
7
+
8
+ describe Apes::PaginationCursor do
9
+ def create_cursor(value = nil, direction = "next", count = nil, use_offset = false)
10
+ Apes::PaginationCursor.new({count: count, page: JWT.encode({aud: "pagination", sub: {value: value, use_offset: use_offset, direction: direction}}, Apes::RuntimeConfiguration.jwt_token, "HS256")})
11
+ end
12
+
13
+ def decode_cursor(cursor)
14
+ JWT.decode(cursor, Apes::RuntimeConfiguration.jwt_token, true, {algorithm: "HS256", verify_aud: true, aud: "pagination"}).dig(0, "sub")
15
+ end
16
+
17
+ describe "#initialize" do
18
+ it "should load a JWT token from data" do
19
+ subject = create_cursor("1", "previous", 3, true)
20
+
21
+ expect(subject.value).to eq("1")
22
+ expect(subject.direction).to eq("previous")
23
+ expect(subject.size).to eq(3)
24
+ expect(subject.use_offset).to be_truthy
25
+ end
26
+
27
+ it "should ensure good defaults" do
28
+ subject = Apes::PaginationCursor.new({count: 3, page: "FOO"})
29
+
30
+ expect(subject.value).to be_nil
31
+ expect(subject.direction).to eq("next")
32
+ expect(subject.size).to eq(3)
33
+ expect(subject.use_offset).to be_falsey
34
+
35
+ end
36
+
37
+ it "should sanitize values" do
38
+ subject = create_cursor("1", "other", -1)
39
+
40
+ expect(subject.direction).to eq("next")
41
+ expect(subject.size).to eq(Apes::PaginationCursor::DEFAULT_SIZE)
42
+ end
43
+ end
44
+
45
+ describe "#operator" do
46
+ it "should return the right operator" do
47
+ subject = create_cursor("", "next", -1)
48
+ expect(subject.operator(:asc)).to eq(">")
49
+ expect(subject.operator(:desc)).to eq("<")
50
+
51
+ subject = create_cursor("", "previous", -1)
52
+ expect(subject.operator(:asc)).to eq("<")
53
+ expect(subject.operator(:desc)).to eq(">")
54
+ end
55
+ end
56
+
57
+ describe "#might_exist?" do
58
+ it "should check if a pagination link might exist" do
59
+ subject = create_cursor("", "next", -1)
60
+ expect(subject.might_exist?("first", [])).to be_truthy
61
+ expect(subject.might_exist?("next", [])).to be_falsey
62
+ expect(subject.might_exist?("prev", [])).to be_falsey
63
+ expect(subject.might_exist?("first", [1])).to be_truthy
64
+ expect(subject.might_exist?("next", [1])).to be_truthy
65
+ expect(subject.might_exist?("prev", [1])).to be_falsey
66
+
67
+ subject = create_cursor("1", "next", -1)
68
+ expect(subject.might_exist?("prev", [1])).to be_truthy
69
+ end
70
+ end
71
+
72
+ describe "#save" do
73
+ describe "when NOT using offset based pagination" do
74
+ it "should generate a valid token for direction next" do
75
+ cursor = create_cursor(1, "next", -1).save([OpenStruct.new(id: 1), OpenStruct.new(id: 2)], "next")
76
+ subject = decode_cursor(cursor)
77
+ expect(subject).to eq({"value" => 2, "use_offset" => false, "direction" => "next", "size" => 25})
78
+ end
79
+
80
+ it "should generate a valid token for direction prev" do
81
+ cursor = create_cursor(1, "next", -1).save([OpenStruct.new(id: 1), OpenStruct.new(id: 2)], "previous")
82
+ subject = decode_cursor(cursor)
83
+ expect(subject).to eq({"value" => 1, "use_offset" => false, "direction" => "previous", "size" => 25})
84
+ end
85
+
86
+ it "should generate a valid token for direction first" do
87
+ cursor = create_cursor(1, "next", -1).save([OpenStruct.new(id: 1), OpenStruct.new(id: 2)], "first")
88
+ subject = decode_cursor(cursor)
89
+ expect(subject).to eq({"value" => nil, "use_offset" => false, "direction" => "next", "size" => 25})
90
+ end
91
+ end
92
+
93
+ describe "when using offset based pagination" do
94
+ it "should generate a valid token for direction next" do
95
+ cursor = create_cursor(30, "next", -1).save([OpenStruct.new(id: 1), OpenStruct.new(id: 2)], "next", use_offset: true)
96
+ subject = decode_cursor(cursor)
97
+ expect(subject).to eq({"value" => 55, "use_offset" => true, "direction" => "next", "size" => 25})
98
+ end
99
+
100
+ it "should generate a valid token for direction prev" do
101
+ cursor = create_cursor(30, "next", -1).save([OpenStruct.new(id: 1), OpenStruct.new(id: 2)], "previous", use_offset: true)
102
+ subject = decode_cursor(cursor)
103
+ expect(subject).to eq({"value" => 5, "use_offset" => true, "direction" => "previous", "size" => 25})
104
+ end
105
+
106
+ it "should generate a valid token for direction first" do
107
+ cursor = create_cursor(30, "next", -1).save([OpenStruct.new(id: 1), OpenStruct.new(id: 2)], "first", use_offset: true)
108
+ subject = decode_cursor(cursor)
109
+ expect(subject).to eq({"value" => nil, "use_offset" => true, "direction" => "next", "size" => 25})
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,100 @@
1
+ #
2
+ # This file is part of the apes gem. Copyright (C) 2016 and above Shogun <shogun@cowtech.it>.
3
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
4
+ #
5
+
6
+ require "spec_helper"
7
+
8
+ describe Apes::RuntimeConfiguration do
9
+ describe ".root" do
10
+ it "should get the information from RubyGems" do
11
+ expect(Apes::RuntimeConfiguration.root).to be_a(String)
12
+ end
13
+ end
14
+
15
+ describe ".rails_root" do
16
+ it "should get the information from Rails" do
17
+ stub_const("Rails", {root: "/ABC"}.ensure_access(:dotted))
18
+ expect(Apes::RuntimeConfiguration.rails_root).to eq("/ABC")
19
+ end
20
+
21
+ it "should fallback to a default" do
22
+ allow(Rails).to receive(:root).and_raise(RuntimeError)
23
+
24
+ expect(Apes::RuntimeConfiguration.rails_root).to be_nil
25
+ expect(Apes::RuntimeConfiguration.rails_root("DEFAULT")).to eq("DEFAULT")
26
+ end
27
+ end
28
+
29
+ describe ".gems_root" do
30
+ it "should get the information from Rails" do
31
+ expect(Apes::RuntimeConfiguration.gems_root).to be_a(String)
32
+ end
33
+
34
+ it "should fallback to a default" do
35
+ allow(Gem).to receive(:loaded_specs).and_raise(RuntimeError)
36
+
37
+ expect(Apes::RuntimeConfiguration.gems_root).to be_nil
38
+ expect(Apes::RuntimeConfiguration.gems_root("DEFAULT")).to eq("DEFAULT")
39
+ end
40
+ end
41
+
42
+ describe ".environment" do
43
+ it "should get the information from Rails secrets" do
44
+ stub_const("Rails", {env: "FOO"}.ensure_access(:dotted))
45
+ expect(Apes::RuntimeConfiguration.environment).to eq("FOO")
46
+ end
47
+
48
+ it "should fallback to a default" do
49
+ allow(Rails).to receive(:env).and_raise(RuntimeError)
50
+ expect(Apes::RuntimeConfiguration.environment).to eq("development")
51
+ expect(Apes::RuntimeConfiguration.environment("DEFAULT")).to eq("DEFAULT")
52
+ end
53
+ end
54
+
55
+ describe ".environment" do
56
+ it "should check if Rails is in development" do
57
+ stub_const("Rails", {env: "development"}.ensure_access(:dotted))
58
+ expect(Apes::RuntimeConfiguration.development?).to be_truthy
59
+
60
+ stub_const("Rails", {env: "FOO"}.ensure_access(:dotted))
61
+ expect(Apes::RuntimeConfiguration.development?).to be_falsey
62
+ end
63
+ end
64
+
65
+ describe ".jwt_token" do
66
+ it "should get the information from Rails secrets" do
67
+ stub_const("Rails", {application: {secrets: {jwt: "SECRET"}}}.ensure_access(:dotted))
68
+ expect(Apes::RuntimeConfiguration.jwt_token).to eq("SECRET")
69
+ end
70
+
71
+ it "should fallback to a default" do
72
+ expect(Apes::RuntimeConfiguration.jwt_token).to eq("secret")
73
+ expect(Apes::RuntimeConfiguration.jwt_token("DEFAULT")).to eq("DEFAULT")
74
+ end
75
+ end
76
+
77
+ describe ".cors_source" do
78
+ it "should get the information from Rails secrets" do
79
+ stub_const("Rails", {application: {secrets: {cors_source: "SOURCE"}}}.ensure_access(:dotted))
80
+ expect(Apes::RuntimeConfiguration.cors_source).to eq("SOURCE")
81
+ end
82
+
83
+ it "should fallback to a default" do
84
+ expect(Apes::RuntimeConfiguration.cors_source).to eq("localhost")
85
+ expect(Apes::RuntimeConfiguration.cors_source("DEFAULT")).to eq("DEFAULT")
86
+ end
87
+ end
88
+
89
+ describe ".timestamp_formats" do
90
+ it "should get the information from Rails secrets" do
91
+ stub_const("Rails", {application: {config: {timestamp_formats: {a: 1}}}}.ensure_access(:dotted))
92
+ expect(Apes::RuntimeConfiguration.timestamp_formats).to eq({a: 1})
93
+ end
94
+
95
+ it "should fallback to a default" do
96
+ expect(Apes::RuntimeConfiguration.timestamp_formats).to eq({})
97
+ expect(Apes::RuntimeConfiguration.timestamp_formats("DEFAULT")).to eq("DEFAULT")
98
+ end
99
+ end
100
+ end