simply_stored 0.3.9 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (132) hide show
  1. data/CHANGELOG.md +38 -0
  2. data/README.md +45 -24
  3. data/lib/simply_stored/couch/association_property.rb +27 -0
  4. data/lib/simply_stored/couch/belongs_to.rb +5 -7
  5. data/lib/simply_stored/couch/finders.rb +5 -1
  6. data/lib/simply_stored/couch/has_and_belongs_to_many.rb +202 -0
  7. data/lib/simply_stored/couch/has_many.rb +6 -51
  8. data/lib/simply_stored/couch/has_one.rb +4 -29
  9. data/lib/simply_stored/couch/properties.rb +11 -0
  10. data/lib/simply_stored/couch.rb +38 -2
  11. data/lib/simply_stored/instance_methods.rb +68 -29
  12. data/lib/simply_stored.rb +3 -1
  13. data/test/{couchdb/couch_active_model_compatibility_test.rb → active_model_compatibility_test.rb} +2 -2
  14. data/test/{couchdb/couch_belongs_to_test.rb → belongs_to_test.rb} +13 -3
  15. data/test/{couchdb/couch_conflict_handling_test.rb → conflict_handling_test.rb} +3 -3
  16. data/test/{couchdb/couch_finder_test.rb → finder_test.rb} +8 -3
  17. data/test/fixtures/couch.rb +55 -0
  18. data/test/has_and_belongs_to_many_test.rb +639 -0
  19. data/test/{couchdb/couch_has_many_test.rb → has_many_test.rb} +13 -3
  20. data/test/{couchdb/couch_has_one_test.rb → has_one_test.rb} +13 -3
  21. data/test/{couchdb/couch_instance_lifecycle_test.rb → instance_lifecycle_test.rb} +3 -3
  22. data/test/{couchdb/couch_mass_assignment_protection_test.rb → mass_assignment_protection_test.rb} +3 -3
  23. data/test/{couchdb/couch_s3_test.rb → s3_test.rb} +3 -3
  24. data/test/{couchdb/couch_soft_deletable_test.rb → soft_deletable_test.rb} +3 -3
  25. data/test/test_helper.rb +1 -5
  26. data/test/{couchdb/couch_validations_test.rb → validations_test.rb} +3 -3
  27. data/test/{couchdb/custom_views_test.rb → views_test.rb} +3 -3
  28. metadata +36 -234
  29. data/lib/simply_stored/simpledb/associations.rb +0 -215
  30. data/lib/simply_stored/simpledb/attributes.rb +0 -173
  31. data/lib/simply_stored/simpledb/storag.rb +0 -85
  32. data/lib/simply_stored/simpledb/validations.rb +0 -88
  33. data/lib/simply_stored/simpledb.rb +0 -216
  34. data/test/fixtures/simpledb/item.rb +0 -11
  35. data/test/fixtures/simpledb/item_daddy.rb +0 -8
  36. data/test/fixtures/simpledb/log_item.rb +0 -3
  37. data/test/fixtures/simpledb/namespace_bar.rb +0 -5
  38. data/test/fixtures/simpledb/namespace_foo.rb +0 -7
  39. data/test/fixtures/simpledb/protected_item.rb +0 -3
  40. data/test/simply_stored_simpledb_test.rb +0 -1376
  41. data/test/vendor/dhaka-2.2.1/lib/dhaka/dot/dot.rb +0 -29
  42. data/test/vendor/dhaka-2.2.1/lib/dhaka/evaluator/evaluator.rb +0 -133
  43. data/test/vendor/dhaka-2.2.1/lib/dhaka/grammar/closure_hash.rb +0 -15
  44. data/test/vendor/dhaka-2.2.1/lib/dhaka/grammar/grammar.rb +0 -240
  45. data/test/vendor/dhaka-2.2.1/lib/dhaka/grammar/grammar_symbol.rb +0 -27
  46. data/test/vendor/dhaka-2.2.1/lib/dhaka/grammar/precedence.rb +0 -19
  47. data/test/vendor/dhaka-2.2.1/lib/dhaka/grammar/production.rb +0 -36
  48. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/accept_actions.rb +0 -36
  49. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/alphabet.rb +0 -21
  50. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/compiled_lexer.rb +0 -46
  51. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/dfa.rb +0 -121
  52. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/lexeme.rb +0 -32
  53. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/lexer.rb +0 -70
  54. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/lexer_run.rb +0 -78
  55. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/regex_grammar.rb +0 -392
  56. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/regex_parser.rb +0 -2010
  57. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/regex_tokenizer.rb +0 -14
  58. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/specification.rb +0 -96
  59. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/state.rb +0 -68
  60. data/test/vendor/dhaka-2.2.1/lib/dhaka/lexer/state_machine.rb +0 -37
  61. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/action.rb +0 -55
  62. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/channel.rb +0 -58
  63. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/compiled_parser.rb +0 -51
  64. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/conflict.rb +0 -54
  65. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/item.rb +0 -42
  66. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/parse_result.rb +0 -50
  67. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/parse_tree.rb +0 -66
  68. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/parser.rb +0 -165
  69. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/parser_methods.rb +0 -11
  70. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/parser_run.rb +0 -39
  71. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/parser_state.rb +0 -74
  72. data/test/vendor/dhaka-2.2.1/lib/dhaka/parser/token.rb +0 -22
  73. data/test/vendor/dhaka-2.2.1/lib/dhaka/runtime.rb +0 -51
  74. data/test/vendor/dhaka-2.2.1/lib/dhaka/tokenizer/tokenizer.rb +0 -190
  75. data/test/vendor/dhaka-2.2.1/lib/dhaka.rb +0 -62
  76. data/test/vendor/dhaka-2.2.1/test/all_tests.rb +0 -5
  77. data/test/vendor/dhaka-2.2.1/test/arithmetic/arithmetic_evaluator.rb +0 -64
  78. data/test/vendor/dhaka-2.2.1/test/arithmetic/arithmetic_evaluator_test.rb +0 -43
  79. data/test/vendor/dhaka-2.2.1/test/arithmetic/arithmetic_grammar.rb +0 -41
  80. data/test/vendor/dhaka-2.2.1/test/arithmetic/arithmetic_grammar_test.rb +0 -9
  81. data/test/vendor/dhaka-2.2.1/test/arithmetic/arithmetic_test_methods.rb +0 -9
  82. data/test/vendor/dhaka-2.2.1/test/arithmetic/arithmetic_tokenizer.rb +0 -39
  83. data/test/vendor/dhaka-2.2.1/test/arithmetic/arithmetic_tokenizer_test.rb +0 -38
  84. data/test/vendor/dhaka-2.2.1/test/arithmetic_precedence/arithmetic_precedence_evaluator.rb +0 -43
  85. data/test/vendor/dhaka-2.2.1/test/arithmetic_precedence/arithmetic_precedence_grammar.rb +0 -24
  86. data/test/vendor/dhaka-2.2.1/test/arithmetic_precedence/arithmetic_precedence_grammar_test.rb +0 -30
  87. data/test/vendor/dhaka-2.2.1/test/arithmetic_precedence/arithmetic_precedence_lexer_specification.rb +0 -23
  88. data/test/vendor/dhaka-2.2.1/test/arithmetic_precedence/arithmetic_precedence_parser_test.rb +0 -33
  89. data/test/vendor/dhaka-2.2.1/test/brackets/bracket_grammar.rb +0 -23
  90. data/test/vendor/dhaka-2.2.1/test/brackets/bracket_tokenizer.rb +0 -22
  91. data/test/vendor/dhaka-2.2.1/test/brackets/brackets_test.rb +0 -28
  92. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_driver.rb +0 -46
  93. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_driver_test.rb +0 -276
  94. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_evaluator.rb +0 -284
  95. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_evaluator_test.rb +0 -38
  96. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_grammar.rb +0 -104
  97. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_lexer.rb +0 -109
  98. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_lexer_specification.rb +0 -37
  99. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_lexer_test.rb +0 -58
  100. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_parser.rb +0 -879
  101. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_parser_test.rb +0 -55
  102. data/test/vendor/dhaka-2.2.1/test/chittagong/chittagong_test.rb +0 -170
  103. data/test/vendor/dhaka-2.2.1/test/core/another_lalr_but_not_slr_grammar.rb +0 -20
  104. data/test/vendor/dhaka-2.2.1/test/core/compiled_parser_test.rb +0 -44
  105. data/test/vendor/dhaka-2.2.1/test/core/dfa_test.rb +0 -170
  106. data/test/vendor/dhaka-2.2.1/test/core/evaluator_test.rb +0 -22
  107. data/test/vendor/dhaka-2.2.1/test/core/grammar_test.rb +0 -83
  108. data/test/vendor/dhaka-2.2.1/test/core/lalr_but_not_slr_grammar.rb +0 -19
  109. data/test/vendor/dhaka-2.2.1/test/core/lexer_test.rb +0 -139
  110. data/test/vendor/dhaka-2.2.1/test/core/malformed_grammar.rb +0 -7
  111. data/test/vendor/dhaka-2.2.1/test/core/malformed_grammar_test.rb +0 -8
  112. data/test/vendor/dhaka-2.2.1/test/core/nullable_grammar.rb +0 -21
  113. data/test/vendor/dhaka-2.2.1/test/core/parse_result_test.rb +0 -44
  114. data/test/vendor/dhaka-2.2.1/test/core/parser_state_test.rb +0 -24
  115. data/test/vendor/dhaka-2.2.1/test/core/parser_test.rb +0 -131
  116. data/test/vendor/dhaka-2.2.1/test/core/precedence_grammar.rb +0 -17
  117. data/test/vendor/dhaka-2.2.1/test/core/precedence_grammar_test.rb +0 -9
  118. data/test/vendor/dhaka-2.2.1/test/core/rr_conflict_grammar.rb +0 -21
  119. data/test/vendor/dhaka-2.2.1/test/core/simple_grammar.rb +0 -22
  120. data/test/vendor/dhaka-2.2.1/test/core/sr_conflict_grammar.rb +0 -16
  121. data/test/vendor/dhaka-2.2.1/test/dhaka_test_helper.rb +0 -17
  122. data/test/vendor/dhaka-2.2.1/test/fake_logger.rb +0 -17
  123. data/test/vendor/simplerdb-0.2/lib/simplerdb/client_exception.rb +0 -10
  124. data/test/vendor/simplerdb-0.2/lib/simplerdb/db.rb +0 -146
  125. data/test/vendor/simplerdb-0.2/lib/simplerdb/query_language.rb +0 -266
  126. data/test/vendor/simplerdb-0.2/lib/simplerdb/server.rb +0 -33
  127. data/test/vendor/simplerdb-0.2/lib/simplerdb/servlet.rb +0 -191
  128. data/test/vendor/simplerdb-0.2/lib/simplerdb.rb +0 -3
  129. data/test/vendor/simplerdb-0.2/test/functional_test.rb +0 -81
  130. data/test/vendor/simplerdb-0.2/test/query_evaluator_test.rb +0 -73
  131. data/test/vendor/simplerdb-0.2/test/query_parser_test.rb +0 -64
  132. data/test/vendor/simplerdb-0.2/test/simplerdb_test.rb +0 -80
@@ -1,1376 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + "/test_helper")
2
-
3
- require File.dirname(__FILE__) + "/fixtures/simpledb/item_daddy.rb"
4
- require File.dirname(__FILE__) + "/fixtures/simpledb/item.rb"
5
- require File.dirname(__FILE__) + "/fixtures/simpledb/namespace_foo.rb"
6
- require File.dirname(__FILE__) + "/fixtures/simpledb/namespace_bar.rb"
7
- require File.dirname(__FILE__) + "/fixtures/simpledb/log_item.rb"
8
- require File.dirname(__FILE__) + "/fixtures/simpledb/protected_item.rb"
9
-
10
- require 'simplerdb/server'
11
- old_stderr = $stderr
12
- $stderr = File.open("/dev/null","w")
13
-
14
- $server ||= SimplerDB::Server.new(8087)
15
- $thread ||= Thread.new do
16
- trap(:INT) {
17
- exit
18
- }
19
- $server.start
20
- end
21
-
22
- $stderr = old_stderr
23
-
24
-
25
- class SimplyStoredTest < Test::Unit::TestCase
26
- context "The simply stored base class" do
27
- setup do
28
- ItemDaddy.instance_eval do
29
- has_one :item, :clear => :nullify
30
- end
31
-
32
- ItemDaddy.instance_eval do
33
- has_many :items, :clear => :nullify
34
- end
35
-
36
- SimplyStored::Simple.aws_access_key = 'foo'
37
- SimplyStored::Simple.aws_secret_access_key = 'bar'
38
- RightAws::ActiveSdb.establish_connection(SimplyStored::Simple.aws_access_key, SimplyStored::Simple.aws_secret_access_key, :server => 'localhost', :port => '8087', :protocol => 'http', :logger => Logger.new('/dev/null'))
39
- Item.create_domain
40
- ItemDaddy.create_domain
41
- Namespace::Foo.create_domain
42
- Namespace::Bar.create_domain
43
- LogItem.create_domain
44
- ProtectedItem.create_domain
45
- @item = Item.new(:foo_attribute => 'a', :bar_attribute_array => 'goog')
46
- end
47
-
48
- should "use UUIDTools::UUID.random_create to generate the ID" do
49
- UUIDTools::UUID.expects(:random_create).returns('foo')
50
- item = create_item
51
- assert_equal 'foo', item.id
52
- end
53
-
54
- context "attributes" do
55
- should "set the given attributes" do
56
- @item.set_attributes(:foo_attribute => '99', :bar_attribute_array => ['1', '2', '3'])
57
- assert_equal '99', @item.foo_attribute
58
- assert_equal ['1', '2', '3'], @item.bar_attribute_array
59
- end
60
-
61
- should "not nil the other attributes" do
62
- @item.bar_attribute_array = ['99']
63
- @item.set_attributes(:foo_attribute => '66')
64
- assert_equal ['99'], @item.bar_attribute_array
65
- end
66
- end
67
-
68
- context "simpledb getter and setter" do
69
-
70
- should "simpledb_attribute_getter" do
71
- assert @item.respond_to?(:foo_attribute)
72
- @item['foo_attribute'] = 'abc'
73
- assert_equal 'abc', @item.foo_attribute
74
- end
75
-
76
- should "getter when empty" do
77
- @item['bar_attribute_array'] = []
78
- @item['foo_attribute'] = nil
79
- assert_equal nil, @item.foo_attribute
80
- assert_equal [], @item.bar_attribute_array
81
- end
82
-
83
- should "getter when empty after setting using the setter" do
84
- @item.bar_attribute_array = []
85
- @item.foo_attribute = nil
86
- assert_equal nil, @item.foo_attribute
87
- assert_equal [], @item.bar_attribute_array
88
- end
89
-
90
- should "attribute setter" do
91
- assert @item.respond_to?(:foo_attribute=)
92
- @item.foo_attribute = 5
93
- assert_equal 5, @item['foo_attribute'].first
94
- assert_equal 5, @item.foo_attribute
95
- end
96
-
97
- should "attribute definition adds to internal attribute list" do
98
- ['foo_attribute', 'item_daddy_id', 'bar_attribute_array', 'updated_at', 'created_at', 'integer_field'].each do |attr|
99
- assert @item.class.instance_variable_get("@_defined_attributes").include?(attr)
100
- end
101
- end
102
-
103
- should "array_getter" do
104
- assert @item.respond_to?(:bar_attribute_array)
105
- @item['bar_attribute_array'] = ['abc']
106
- assert_equal ['abc'], @item.bar_attribute_array
107
- end
108
-
109
- should "array_setter" do
110
- assert @item.respond_to?(:bar_attribute_array=)
111
- @item.bar_attribute_array = 5
112
- assert_equal [5], @item['bar_attribute_array']
113
- assert_equal [5], @item.bar_attribute_array
114
-
115
- @item.bar_attribute_array << 7
116
- assert_equal [5,7], @item.bar_attribute_array
117
- end
118
-
119
- should "array_setter when given an empty array" do
120
- @item['bar_attribute_array'] = []
121
- assert_equal [], @item.bar_attribute_array
122
- @item.bar_attribute_array << 7
123
- assert_equal [7], @item.bar_attribute_array
124
-
125
- @item.bar_attribute_array << 11
126
- assert_equal [7,11], @item.bar_attribute_array
127
- end
128
-
129
- context "belongs_to" do
130
-
131
- should "getter" do
132
- assert @item.respond_to?(:item_daddy)
133
-
134
- @item[:item_daddy_id] = 'the_id_of_item'
135
- ItemDaddy.expects(:find).with('the_id_of_item', {:auto_load => true}).returns('foo')
136
- assert_equal 'foo', @item.item_daddy
137
- end
138
-
139
- should "setter" do
140
- assert @item.respond_to?(:item_daddy=)
141
-
142
- item_daddy = ItemDaddy.new
143
- item_daddy.expects(:id).returns('item_daddy_id')
144
- @item.expects(:item_daddy_id=).with('item_daddy_id')
145
-
146
- @item.item_daddy = item_daddy
147
- end
148
-
149
- should "check the class when setting" do
150
- assert_raise(ArgumentError, 'expected ItemDaddy got String') do
151
- @item.item_daddy = 'foo'
152
- end
153
- end
154
-
155
- should "use the cache when getting" do
156
- @item[:item_daddy_id] = 'the_id_of_item'
157
- ItemDaddy.expects(:find).with('the_id_of_item', {:auto_load => true}).returns('foo').times(1)
158
- assert_equal 'foo', @item.item_daddy
159
- assert_equal 'foo', @item.item_daddy
160
- end
161
-
162
- should "set the cache when setting" do
163
- @item.instance_variable_set("@_cached_belongs_to_item_daddy", 'foo')
164
- assert_equal 'foo', @item.item_daddy
165
-
166
- daddy = ItemDaddy.new('id' => 'the-ID')
167
- @item.expects(:item_daddy_id=)
168
- @item.expects(:instance_variable_set).with("@_cached_belongs_to_item_daddy", daddy)
169
-
170
- @item.item_daddy = daddy
171
- end
172
-
173
- should "not hit the database when the id column is empty" do
174
- ItemDaddy.expects(:find).never
175
- @item.item_daddy_id = []
176
- @item.item_daddy
177
- end
178
- end
179
-
180
- context "has_one" do
181
-
182
- should "getter" do
183
- daddy = ItemDaddy.new(:id => 'daddy_id')
184
- assert daddy.respond_to?(:item)
185
-
186
- Item.expects(:send).with(:find_by_item_daddy_id, 'daddy_id', {:auto_load => true}).returns('a')
187
- assert_equal 'a', daddy.item
188
- end
189
-
190
- should "use the cache when getting" do
191
- daddy = ItemDaddy.new(:id => 'daddy_id')
192
- Item.expects(:send).with(:find_by_item_daddy_id, 'daddy_id', {:auto_load => true}).returns('a').times(1)
193
- assert_equal 'a', daddy.item
194
- assert_equal 'a', daddy.item
195
- assert_equal 'a', daddy.item
196
- end
197
-
198
- should "setter" do
199
- daddy = ItemDaddy.new(:id => 'daddy_id')
200
- assert daddy.respond_to?(:item=)
201
- item = Item.new
202
- item.expects(:item_daddy_id=).with('daddy_id')
203
-
204
- daddy.item = item
205
- end
206
-
207
- should "set the cache when setting" do
208
- daddy = ItemDaddy.new(:id => 'daddy_id')
209
- item = Item.new
210
- item.expects(:item_daddy_id=).with('daddy_id')
211
-
212
- daddy.item = item
213
- assert_equal item, daddy.instance_variable_get("@_cached_has_one_item")
214
- end
215
-
216
- should "check the class" do
217
- daddy = ItemDaddy.new(:id => 'daddy_id')
218
- assert_raise(ArgumentError, 'expected Item got String') do
219
- daddy.item = 'foo'
220
- end
221
- end
222
-
223
- should "clear relations when depending:nullify" do
224
-
225
- ItemDaddy.instance_eval do
226
- has_one :item, :clear => :nullify
227
- end
228
-
229
- daddy = ItemDaddy.new(:id => 'daddy_id')
230
- old_item = Item.new
231
- old_item.stubs(:item_daddy_id).returns('daddy_id')
232
- old_item.expects(:item_daddy_id=).with(nil)
233
- daddy.expects(:item).returns(old_item)
234
-
235
- new_item = Item.new
236
- new_item.stubs(:item_daddy_id=)
237
- daddy.item = new_item
238
- end
239
-
240
- should "delete relations when depending:destroy" do
241
-
242
- ItemDaddy.instance_eval do
243
- has_one :item, :clear => :destroy
244
- end
245
-
246
- daddy = ItemDaddy.new(:id => 'daddy_id')
247
- old_item = Item.new
248
- old_item.stubs(:item_daddy_id).returns('daddy_id')
249
- old_item.expects(:delete)
250
- daddy.expects(:item).returns(old_item)
251
-
252
- new_item = Item.new
253
- new_item.stubs(:item_daddy_id=)
254
- daddy.item = new_item
255
- end
256
-
257
- end
258
-
259
- context "has_many" do
260
-
261
- should "getter" do
262
- daddy = ItemDaddy.new(:id => 'daddy_id')
263
- assert daddy.respond_to?(:items)
264
-
265
- Item.expects(:send).with(:find_all_by_item_daddy_id, 'daddy_id', {:auto_load => true}).returns(['a'])
266
- assert_equal ['a'], daddy.items
267
- end
268
-
269
- should "use the cache when getting" do
270
- daddy = ItemDaddy.new(:id => 'daddy_id')
271
- Item.expects(:send).with(:find_all_by_item_daddy_id, 'daddy_id', {:auto_load => true}).returns(['a']).times(1)
272
- assert_equal ['a'], daddy.items
273
- assert_equal ['a'], daddy.items
274
- assert_equal ['a'], daddy.items
275
- end
276
-
277
- should "setter" do
278
- daddy = ItemDaddy.new(:id => 'daddy_id')
279
- assert daddy.respond_to?(:add_item)
280
- assert daddy.respond_to?(:remove_item)
281
- assert daddy.respond_to?(:remove_all_items)
282
- end
283
-
284
- should "add_item" do
285
- daddy = ItemDaddy.new(:id => 'daddy_id_')
286
- item = Item.new
287
- item.expects(:item_daddy_id=).with('daddy_id_')
288
-
289
- assert_equal [], daddy.items
290
- daddy.add_item(item)
291
- assert_equal [item], daddy.items
292
- assert_equal [item], daddy.instance_variable_get("@_cached_has_many_items")
293
- end
294
-
295
- should "check the class when using add_item" do
296
- daddy = ItemDaddy.new(:id => 'daddy_id')
297
- assert_raise(ArgumentError, 'excepted Item got String') do
298
- daddy.add_item('foo')
299
- end
300
- end
301
-
302
- should "save when adding an item" do
303
- @item.expects(:save).with(false)
304
-
305
- daddy = ItemDaddy.new(:id => 'daddy_id')
306
- daddy.add_item(@item)
307
- end
308
-
309
- should "remove an item" do
310
- daddy = ItemDaddy.new(:id => 'daddy_id')
311
- item = Item.new
312
- item.expects(:item_daddy_id=).with(nil)
313
- item.expects(:item_daddy_id).returns('daddy_id')
314
- item.expects(:save).with(false)
315
-
316
- daddy.instance_variable_set("@_cached_has_many_items", [item])
317
- assert_equal [item], daddy.items
318
- daddy.remove_item(item)
319
- assert_equal [], daddy.items
320
- assert_equal [], daddy.instance_variable_get("@_cached_has_many_items")
321
- end
322
-
323
- should "check ownership when removing" do
324
- daddy = ItemDaddy.new(:id => 'daddy_id')
325
- my_item = Item.new
326
- my_item.expects(:item_daddy_id=).with(nil)
327
- my_item.expects(:item_daddy_id).returns('daddy_id')
328
-
329
- other_item = Item.new
330
- other_item.expects(:item_daddy_id=).never
331
- other_item.expects(:item_daddy_id).returns('not_daddys_id')
332
-
333
- assert_nothing_raised do
334
- daddy.remove_item(my_item)
335
- end
336
-
337
- assert_raise(ArgumentError, 'cannot remove as not mine') do
338
- daddy.remove_item(other_item)
339
- end
340
- end
341
-
342
- should "remove all items" do
343
- daddy = ItemDaddy.new(:id => 'daddy_id')
344
- item_1 = Item.new
345
- item_1.expects(:item_daddy_id).returns('daddy_id')
346
- item_1.expects(:item_daddy_id=).with(nil)
347
- item_2 = Item.new
348
- item_2.expects(:item_daddy_id).returns('daddy_id')
349
- item_2.expects(:item_daddy_id=).with(nil)
350
-
351
- Item.expects(:find_all_by_item_daddy_id).with('daddy_id').returns([item_1, item_2])
352
-
353
- daddy.remove_all_items
354
-
355
- assert_equal [], daddy.instance_variable_get("@_cached_has_many_items")
356
- end
357
-
358
- should "delete relations if depending:destroy" do
359
- ItemDaddy.instance_eval do
360
- has_many :items, :clear => :destroy
361
- end
362
-
363
- daddy = ItemDaddy.new(:id => 'daddy_id')
364
- item = Item.new
365
- item.expects(:delete)
366
- item.expects(:item_daddy_id).returns('daddy_id')
367
-
368
- daddy.remove_item(item)
369
- assert_equal [], daddy.instance_variable_get("@_cached_has_many_items")
370
- end
371
-
372
- end
373
- end
374
-
375
- context "attribute proctection against mass assignment" do
376
-
377
- context "when using attr_protected" do
378
- setup do
379
- ProtectedItem.instance_eval do
380
- @_accessible_attributes ||= []
381
- attr_protected :a, :b
382
- end
383
- end
384
-
385
- should "not allow to set with mass assignment using attributes=" do
386
- item = ProtectedItem.new
387
- item.attributes = {:a => 'a', :c => 'c'}
388
- assert_equal 'c', item.c
389
- assert_nil item.a
390
- end
391
-
392
- should "not allow to set with mass assignment using attributes= - ignore string vs. symbol" do
393
- item = ProtectedItem.new
394
- item.attributes = {'a' => 'a', 'c' => 'c'}
395
- assert_equal 'c', item.c
396
- assert_nil item.a
397
- end
398
-
399
- should "not allow to set with mass assignment using the constructor" do
400
- item = ProtectedItem.new(:a => 'a', :c => 'c')
401
- assert_equal 'c', item.c
402
- assert_nil item.a
403
- end
404
-
405
- should "allow to set with mass assignment using update_attributes" do
406
- item = ProtectedItem.new
407
- item.update_attributes(:a => 'a', :c => 'c')
408
- item.reload
409
- assert_equal 'c', item.c
410
- assert_equal 'a', item.a
411
- end
412
-
413
- should "not allow to set with mass assignment using set_attributes" do
414
- item = ProtectedItem.new
415
- item.set_attributes(:a => 'a', :c => 'c')
416
- assert_equal 'c', item.c
417
- assert_nil item.a
418
- end
419
- end
420
-
421
- context "attr_accessible" do
422
- setup do
423
- ProtectedItem.instance_eval do
424
- @_protected_attributes ||= []
425
- attr_accessible :c
426
- end
427
- end
428
-
429
- should "not allow to set with mass assignment using attributes=" do
430
- item = ProtectedItem.new
431
- item.attributes = {:a => 'a', :c => 'c'}
432
- assert_equal 'c', item.c
433
- assert_nil item.a
434
- end
435
-
436
- should "not allow to set with mass assignment using the constructor" do
437
- item = ProtectedItem.new(:a => 'a', :c => 'c')
438
- assert_equal 'c', item.c
439
- assert_nil item.a
440
- end
441
-
442
- should "allow to set with mass assignment using update_attributes" do
443
- item = ProtectedItem.new
444
- item.update_attributes(:a => 'a', :c => 'c')
445
- item.reload
446
- assert_equal 'c', item.c
447
- assert_equal 'a', item.a
448
- end
449
-
450
- should "not allow to set with mass assignment using set_attributes" do
451
- item = ProtectedItem.new
452
- item.set_attributes(:a => 'a', :c => 'c')
453
- assert_equal 'c', item.c
454
- assert_nil item.a
455
- end
456
- end
457
-
458
- end
459
-
460
- context "validation and errors" do
461
-
462
- should "get errors" do
463
- @item.send(:add_error, 'foo', 'bar')
464
- assert_equal [['foo', 'bar']], @item.errors
465
- end
466
-
467
- should "valid_if_errors" do
468
- @item.stubs(:errors).returns([true])
469
- assert !@item.valid?
470
- end
471
-
472
- should "valid_if_no_errors" do
473
- @item.stubs(:errors).returns([])
474
- assert @item.valid?
475
- end
476
-
477
- should "clear_errors" do
478
- @item.instance_variable_set("@errors", [true])
479
- assert !@item.errors.blank?
480
- @item.send(:clear_errors)
481
- assert @item.errors.blank?
482
- end
483
-
484
- should "valid_calls_validate" do
485
- @item.expects(:validate)
486
- @item.valid?
487
- end
488
-
489
- should "clears errors on a successful save" do
490
- @item.expects(:valid?).returns(true)
491
- @item.expects(:active_sdb_save).returns(true)
492
- @item.expects(:clear_errors).returns(true)
493
-
494
- assert @item.save
495
- end
496
-
497
- should "clear errors when valid? is true" do
498
- @item.instance_variable_set("@errors", [:am, 'foo'])
499
- assert @item.valid?
500
- assert_equal [], @item.instance_variable_get("@errors")
501
- end
502
-
503
- should "fail the save when there's validation errors" do
504
- @item.instance_variable_set("@errors", [:am, 'foo'])
505
- @item.stubs(:clear_errors)
506
- @item.expects(:active_sdb_save).never
507
- assert !@item.save
508
- end
509
-
510
- should "more_attributes_than_allowed" do
511
- @item[:foo] = 'bar'
512
- assert !@item.valid?, @item.attributes.inspect
513
- assert_equal [['foo', 'is unknown and should not be set']], @item.errors
514
- end
515
-
516
- should "more_attributes_than_allowed_does_not_check_id" do
517
- @item[:id] = '90834980324kjndfaslkjadsfp89'
518
- assert @item.valid?, @item.errors.inspect
519
- end
520
-
521
- should "require presence" do
522
- daddy = ItemDaddy.new
523
- daddy.name = nil
524
- assert !daddy.valid?
525
-
526
- daddy.name = 'foo'
527
- assert daddy.valid?
528
- end
529
-
530
- should "require inclusion" do
531
- @item.foo_attribute = 'd'
532
- assert !@item.valid?
533
-
534
- @item.foo_attribute = 'c'
535
- assert @item.valid?
536
- end
537
-
538
- should "require inclusion and allow_blank" do
539
- Item.instance_eval do
540
- require_inclusion_of :foo_attribute, ['a', 'b', 'c'], :allow_blank => true
541
- end
542
-
543
- item = Item.new(:bar_attribute_array => ['goog'], :foo_attribute => nil)
544
- assert item.valid?, item.errors.inspect
545
-
546
- Item.instance_eval do
547
- require_inclusion_of :foo_attribute, ['a', 'b', 'c'], :allow_blank => false
548
- end
549
-
550
- assert !item.valid?, item.errors.inspect
551
- end
552
-
553
- should "require inclusion should work with array attribute" do
554
- @item.bar_attribute_array = ['foobar']
555
- assert !@item.valid?
556
-
557
- @item.bar_attribute_array = ['goog']
558
- assert @item.valid?
559
- end
560
-
561
- should "save_without_validations" do
562
- item = Item.new(:foo_attribute => nil)
563
- assert !item.valid?
564
- assert !item.save
565
- assert item.save(false)
566
- end
567
-
568
- context "format validation" do
569
- setup do
570
- Item.instance_eval do
571
- simpledb_string :format_attribute
572
- require_format_of :format_attribute, /a/, :allow_blank => true
573
- end
574
-
575
- @item = Item.new(:format_attribute => nil, :foo_attribute => 'a')
576
- end
577
-
578
- should "check format" do
579
- @item.format_attribute = 'b'
580
- assert !@item.valid?
581
-
582
- @item.format_attribute = 'c'
583
- assert !@item.valid?
584
-
585
- @item.format_attribute = 'a'
586
- assert @item.valid?, @item.errors.inspect
587
-
588
- @item.format_attribute = 'abc'
589
- assert @item.valid?
590
- end
591
-
592
- should "allow nil" do
593
- @item.format_attribute = 'b'
594
- assert !@item.valid?
595
-
596
- @item.format_attribute = nil
597
- assert @item.valid?, @item.errors.inspect
598
- end
599
-
600
- end
601
- end
602
-
603
- context "callbacks" do
604
-
605
- should "not call callbacks if none are defined" do
606
- @item.stubs(:active_sdb_save).returns(true)
607
- @item.stubs(:respond_to?).returns(false)
608
-
609
- @item.expects(:before_save).never
610
- @item.expects(:after_save).never
611
- assert @item.save
612
- end
613
-
614
- should "call callbacks if none are defined" do
615
- @item.stubs(:active_sdb_save).returns(true)
616
-
617
- def @item.before_save
618
- end
619
-
620
- def @item.after_save
621
- end
622
-
623
- @item.expects(:before_save)
624
- @item.expects(:after_save)
625
- assert @item.save
626
- end
627
-
628
- should "call after_create and before_create callbacks if we have a new record" do
629
- @item.stubs(:new_record?).returns(true)
630
- @item.stubs(:active_sdb_save).returns(true)
631
-
632
- def @item.before_create
633
- end
634
-
635
- def @item.after_create
636
- end
637
-
638
- @item.expects(:before_create)
639
- @item.expects(:after_create)
640
- assert @item.save
641
- end
642
-
643
- should "not call after_create and before_create callbacks if we have an existing record" do
644
- @item.stubs(:new_record?).returns(false)
645
- @item.stubs(:active_sdb_save).returns(true)
646
-
647
- def @item.before_create
648
- end
649
-
650
- def @item.after_create
651
- end
652
-
653
- @item.expects(:before_create).never
654
- @item.expects(:after_create).never
655
- assert @item.save
656
- end
657
-
658
- should "call before_validation before the validation if defined" do
659
- def @item.before_validation
660
- end
661
-
662
- @item.expects(:before_validation)
663
- assert @item.valid?
664
- end
665
-
666
- should "not call before_validation if it is not defined" do
667
- @item.expects(:respond_to?).with(:before_validation).returns(false)
668
-
669
- @item.expects(:before_validation).never
670
- assert @item.valid?
671
- end
672
-
673
- should "before_delete_callback_not_called_if_no_before_delete_defined" do
674
- @item.id = '5'
675
- assert !@item.respond_to?(:before_delete)
676
- assert_nothing_raised do
677
- @item.delete
678
- end
679
- end
680
-
681
- should "before_delete_callback" do
682
- item_with_callback = Item.create(:foo_attribute => '123', :bar_attribute_array => ['a', 'b'], :id => 5)
683
- def item_with_callback.before_delete
684
- 'foo'
685
- end
686
- item_with_callback.expects(:before_delete)
687
-
688
- item_with_callback.delete
689
- end
690
-
691
- should "after_delete_callback_not_called_if_no_before_delete_defined" do
692
- @item.id = '5'
693
- assert !@item.respond_to?(:after_delete)
694
- assert_nothing_raised do
695
- @item.delete
696
- end
697
- end
698
-
699
- should "after_delete_callback" do
700
- item_with_callback = Item.create(:foo_attribute => '123', :bar_attribute_array => ['a', 'b'], :id => 5)
701
- def item_with_callback.after_delete
702
- 'foo'
703
- end
704
- item_with_callback.expects(:after_delete)
705
-
706
- item_with_callback.delete
707
- end
708
-
709
- end
710
-
711
- context "timestamps" do
712
-
713
- should "timestamps" do
714
- item = Item.new(:foo_attribute => 'a', :bar_attribute_array => ['goog'])
715
- assert_nil item.updated_at
716
- assert_nil item.created_at
717
-
718
- time = Time.now
719
- Time.stubs(:now).returns(time)
720
-
721
- assert item.save, item.errors.inspect
722
- assert_equal time.utc, item.updated_at
723
- assert_equal time.utc, item.created_at
724
- end
725
-
726
- should "timestamps_when_saving_without_validations" do
727
- item = Item.new(:foo_attribute => 'a', :bar_attribute_array => ['goog'])
728
- assert_nil item.updated_at
729
- assert_nil item.created_at
730
-
731
- time = Time.now
732
- Time.stubs(:now).returns(time)
733
-
734
- assert item.save(false)
735
- assert_equal time.utc, item.updated_at
736
- assert_equal time.utc, item.created_at
737
- end
738
-
739
- should "timestamps_when_existing_record" do
740
- item = Item.new(:foo_attribute => 'a', :bar_attribute_array => ['goog'])
741
- item.stubs(:new_record?).returns(false)
742
- assert_nil item.updated_at
743
- assert_nil item.created_at
744
-
745
- time = Time.now
746
- Time.stubs(:now).returns(time)
747
-
748
- assert item.save, item.errors.inspect
749
- assert_equal time.utc, item.updated_at
750
- assert_nil item.created_at
751
- end
752
-
753
- should "timestamps_when_validation_fails" do
754
- item = Item.new(:foo_attribute => 'a', :bar_attribute_array => ['goog'])
755
- item.expects(:valid?).returns(false)
756
- assert_nil item.updated_at
757
- assert_nil item.created_at
758
-
759
- assert !item.save
760
- assert_nil item.updated_at
761
- assert_nil item.created_at
762
- end
763
-
764
- should "timestamp_saves_representation_as_integer" do
765
- @item.updated_at = Time.local(2004, 1, 12, 9, 7, 59)
766
- assert_equal ['20040112090759'], @item['updated_at']
767
- end
768
-
769
- should "timestamp_loads_from_representation_as_integer" do
770
- @item['updated_at'] = '20040112090759'
771
- assert_equal Time.local(2004, 1, 12, 10, 7, 59).utc, @item.updated_at
772
- end
773
- end
774
-
775
- context "integer attributes" do
776
-
777
- should "save representation padded" do
778
- @item.integer_field = 91
779
- assert_equal ['0000000000000091'], @item['integer_field']
780
- end
781
-
782
- should "load representation padded" do
783
- @item['integer_field'] = '0000000000000091'
784
- assert_equal 91, @item.integer_field
785
- end
786
- end
787
-
788
- context "find helper" do
789
-
790
- should "all" do
791
- Item.expects(:find).with(:all, instance_of(Hash))
792
- Item.all
793
- end
794
-
795
- should "all_with_options" do
796
- Item.expects(:find).with do |arg, options|
797
- arg == :all && options[:auto_load] == true
798
- end
799
- Item.all(:auto_load => true)
800
- end
801
-
802
- should "first" do
803
- Item.expects(:find).with(:first, instance_of(Hash))
804
- Item.first
805
- end
806
-
807
- should "first_with_options" do
808
- Item.expects(:find).with do |arg, options|
809
- arg == :first && options[:auto_load] == true
810
- end
811
- Item.first(:auto_load => true)
812
- end
813
- end
814
-
815
- context "when finding an object" do
816
- should "should raise RecordNotFound when the object wasn't found" do
817
- assert_raise(SimplyStored::RecordNotFound) do
818
- Item.find("bla")
819
- end
820
- end
821
-
822
- should "should retry x-times before raising RecordNotFound" do
823
- item = create_item
824
- seq = sequence("find")
825
- Item.expects(:find_from_ids).with([item.id], {:auto_load => true}).raises(RightAws::ActiveSdb::ActiveSdbError, "Couldn't find Item with ID").in_sequence(seq)
826
- Item.expects(:find_from_ids).with([item.id], {:auto_load => true}).returns([item]).in_sequence(seq)
827
- assert_nothing_raised do
828
- assert Item.find(item.id)
829
- end
830
- end
831
-
832
- should "should sleep more and more on each subsequent retry" do
833
- item = create_item
834
- seq = sequence("find")
835
- Item.expects(:find_from_ids).with([item.id],{:auto_load => true}).raises(RightAws::ActiveSdb::ActiveSdbError, "Couldn't find Item with ID").in_sequence(seq)
836
- Item.expects(:find_from_ids).with([item.id],{:auto_load => true}).raises(RightAws::ActiveSdb::ActiveSdbError, "Couldn't find Item with ID").in_sequence(seq)
837
- Item.expects(:find_from_ids).with([item.id],{:auto_load => true}).raises(RightAws::ActiveSdb::ActiveSdbError, "Couldn't find Item with ID").in_sequence(seq)
838
-
839
- sleepy = sequence("sleep")
840
- Item.expects(:sleep).with(0.5).in_sequence(sleepy)
841
- Item.expects(:sleep).with(1.0).in_sequence(sleepy)
842
- assert_raise(SimplyStored::RecordNotFound) do
843
- Item.find(item.id)
844
- end
845
- end
846
-
847
- should "retry on system error" do
848
- item = create_item
849
- seq = sequence("find")
850
- item.stubs(:sleep)
851
- Item.expects(:find_from_ids).with([item.id], {:auto_load => true}).raises(Rightscale::AwsError, "RequestThrottled").in_sequence(seq)
852
- Item.expects(:find_from_ids).with([item.id], {:auto_load => true}).raises(Rightscale::AwsError, "RequestThrottled").in_sequence(seq)
853
- Item.expects(:find_from_ids).with([item.id], {:auto_load => true}).returns([item]).in_sequence(seq)
854
- assert_nothing_raised do
855
- assert Item.find(item.id)
856
- end
857
- end
858
-
859
- should "eventually raise an error on system error" do
860
- item = create_item
861
- item.stubs(:sleep)
862
- Item.expects(:find_from_ids).with([item.id], {:auto_load => true}).raises(Rightscale::AwsError, "RequestThrottled").times(3)
863
- assert_raise(SimplyStored::Error) do
864
- Item.find(item.id)
865
- end
866
- end
867
-
868
- should "not retry on client error" do
869
- item = create_item
870
- Item.expects(:find_from_ids).with([item.id], {:auto_load => true}).raises(Rightscale::AwsError, "NoSuchDomain")
871
- assert_raise(SimplyStored::Error) do
872
- Item.find(item.id)
873
- end
874
- end
875
-
876
- should "should auto load attributes by default" do
877
- item = create_item
878
- item = Item.find(item.id)
879
- assert item.attributes.size > 1
880
- end
881
- end
882
-
883
- context "when saving an instance" do
884
- context "when saving fails due to errors" do
885
- should "retry save when a system error was raised by simpledb" do
886
- item = create_item
887
- sleepy = sequence("sleep")
888
- item.expects(:sleep).with(0.5).in_sequence(sleepy)
889
- item.expects(:sleep).with(1.0).in_sequence(sleepy)
890
-
891
- raiser = sequence("exception")
892
- item.expects(:active_sdb_save).raises(Rightscale::AwsError, "RequestThrottled").in_sequence(raiser)
893
- item.expects(:active_sdb_save).raises(Rightscale::AwsError, "RequestThrottled").in_sequence(raiser)
894
- item.expects(:active_sdb_save).returns(true).in_sequence(raiser)
895
-
896
- item.save
897
- end
898
-
899
- should "not retry when error was a client error" do
900
- item = create_item
901
- item.expects(:sleep).never
902
- item.expects(:active_sdb_save).raises(Rightscale::AwsError, "Ron Telesky")
903
- assert_raise(SimplyStored::Error) {item.save}
904
- end
905
-
906
- should "raise an error when the world has gone bad" do
907
- item = create_item
908
- item.expects(:active_sdb_save).times(3).raises(Rightscale::AwsError, "RequestThrottled")
909
- assert_raise(SimplyStored::Error) {item.save}
910
- end
911
- end
912
- end
913
-
914
- context "when deleting an instance" do
915
- should "actually delete the instance" do
916
- @item.save
917
- @item.delete
918
- @item.reload
919
- assert @item.attributes.empty?
920
- end
921
-
922
- should "retry on system error" do
923
- item = create_item
924
- sleepy = sequence("sleep")
925
- item.expects(:sleep).with(0.5).in_sequence(sleepy)
926
- item.expects(:sleep).with(1.0).in_sequence(sleepy)
927
-
928
- raiser = sequence("exception")
929
- item.expects(:active_sdb_delete).raises(Rightscale::AwsError, "RequestThrottled").in_sequence(raiser)
930
- item.expects(:active_sdb_delete).raises(Rightscale::AwsError, "RequestThrottled").in_sequence(raiser)
931
- item.expects(:active_sdb_delete).returns(true).in_sequence(raiser)
932
-
933
- item.delete
934
- end
935
-
936
- should "not retry on client error" do
937
- item = create_item
938
- item.expects(:sleep).never
939
-
940
- item.expects(:active_sdb_delete).raises(Rightscale::AwsError, "NoSuchDomain")
941
-
942
- assert_raise(SimplyStored::Error) do
943
- item.delete
944
- end
945
- end
946
-
947
- should "eventually raise an error" do
948
- item = create_item
949
- item.stubs(:sleep)
950
-
951
- item.expects(:active_sdb_delete).raises(Rightscale::AwsError, "NoSuchDomain")
952
-
953
- assert_raise(SimplyStored::Error) do
954
- item.delete
955
- end
956
- end
957
-
958
- end
959
-
960
- context "reload" do
961
- should "return itself" do
962
- item = create_item
963
- assert item.reload.is_a?(Item)
964
- assert_equal item, item.reload
965
- end
966
- end
967
-
968
- context "ActiveRecord compatability" do
969
- should "have a to_param helper" do
970
- item = create_item
971
- item.id = 9912
972
- assert item.save
973
- assert_equal "9912", item.id
974
- assert_equal "9912", item.to_param
975
- end
976
- end
977
-
978
- context "when updating attributes" do
979
- setup do
980
- @item = create_item
981
- end
982
-
983
- should "use save_attributes" do
984
- @item.expects(:active_sdb_save_attributes).with('foo_attribute' => 'b')
985
-
986
- @item.update_attributes('foo_attribute' => 'b')
987
- end
988
-
989
- should "nil a nil attribute" do
990
- @item.update_attributes('foo_attribute' => 'hi')
991
- assert_equal 'hi', @item.reload.foo_attribute
992
-
993
- @item.update_attributes('foo_attribute' => nil)
994
- assert_nil @item.reload.foo_attribute
995
- end
996
-
997
- should "nil an empty string attribute" do
998
- @item.update_attributes('foo_attribute' => 'hi')
999
- assert_equal 'hi', @item.reload.foo_attribute
1000
-
1001
- @item.update_attributes('foo_attribute' => '')
1002
- assert_nil @item.reload.foo_attribute
1003
- end
1004
-
1005
- should "retry on system error" do
1006
- sleepy = sequence("sleep")
1007
- @item.expects(:sleep).with(0.5).in_sequence(sleepy)
1008
- @item.expects(:sleep).with(1.0).in_sequence(sleepy)
1009
-
1010
- raiser = sequence("exception")
1011
- @item.expects(:active_sdb_save_attributes).raises(Rightscale::AwsError, "RequestThrottled").in_sequence(raiser)
1012
- @item.expects(:active_sdb_save_attributes).raises(Rightscale::AwsError, "RequestThrottled").in_sequence(raiser)
1013
- @item.expects(:active_sdb_save_attributes).returns(true).in_sequence(raiser)
1014
-
1015
- @item.update_attributes(:foo_attribute => 'a')
1016
- end
1017
-
1018
- should "not retry on client error" do
1019
- @item.expects(:sleep).never
1020
-
1021
- @item.expects(:active_sdb_save_attributes).raises(Rightscale::AwsError, "NoSuchDomain")
1022
-
1023
- assert_raise(SimplyStored::Error) do
1024
- @item.update_attributes(:foo_attribute => 'a')
1025
- end
1026
- end
1027
-
1028
- should "eventually raise an error on system error" do
1029
- item = create_item
1030
- item.stubs(:sleep)
1031
-
1032
- item.expects(:active_sdb_save_attributes).raises(Rightscale::AwsError, "RequestThrottled").times(3)
1033
-
1034
- assert_raise(SimplyStored::Error) do
1035
- item.update_attributes(:foo_attribute => 'a')
1036
- end
1037
- end
1038
-
1039
- end
1040
-
1041
- context "namespaced classes" do
1042
-
1043
- setup do
1044
- ItemDaddy.instance_eval do
1045
- belongs_to 'namespace__foo'
1046
- end
1047
- @foo = Namespace::Foo.new
1048
- assert @foo.save
1049
- end
1050
-
1051
- should "be able to adress them in belongs_to" do
1052
- daddy = ItemDaddy.new(:name => 'abc')
1053
- daddy.namespace__foo = @foo
1054
- assert daddy.save
1055
- end
1056
-
1057
- should "be able to call a has_many relation" do
1058
- daddy = ItemDaddy.new(:name => 'abc')
1059
- daddy.namespace__foo = @foo
1060
- assert daddy.save
1061
-
1062
- assert_equal daddy.id, ItemDaddy.find_by_namespace__foo_id(@foo.id).id
1063
- assert_equal [daddy].map(&:id), @foo.item_daddys.map(&:id)
1064
- end
1065
-
1066
- should "need special prefix inside namespace" do
1067
- bar = Namespace::Bar.new
1068
- assert bar.save
1069
- @foo.namespace__bar = bar
1070
- assert @foo.save
1071
- end
1072
- end
1073
-
1074
- context "attributes longer than 1024 bytes" do
1075
- setup do
1076
- Item.instance_eval do
1077
- simpledb_string :very_long
1078
- end
1079
- @item = create_item
1080
- @item.very_long = '*' * 1600
1081
- assert_equal 1600, @item.very_long.size
1082
- end
1083
-
1084
- should "add partitioned attributes to the class metadata"
1085
-
1086
- should "not raise an error" do
1087
- assert_nothing_raised do
1088
- @item.save
1089
- end
1090
- end
1091
-
1092
- should "split up the string into numbered attributes by 1024 bytes" do
1093
- @item.save
1094
- assert_equal 1024, @item["very_long_0"].first.size
1095
- assert_equal 576, @item["very_long_1"].first.size
1096
- end
1097
-
1098
- should "store all characters and re-retrieve them on load" do
1099
- @item.save
1100
- @item.reload
1101
- assert_equal 1600, @item.very_long.size
1102
- end
1103
-
1104
- should "survive several reloads" do
1105
- 5.times do
1106
- @item.save
1107
- @item.reload
1108
- end
1109
- assert_equal 1600, @item.very_long.size
1110
- assert_equal 1600, @item["very_long"].first.size
1111
- end
1112
-
1113
- should "unset the original attribute after saving" do
1114
- @item.save
1115
- assert_equal nil, @item["very_long"]
1116
- end
1117
-
1118
- should "still make the attribute available through its accessor" do
1119
- @item.save
1120
- assert_not_nil @item.very_long
1121
- end
1122
- end
1123
-
1124
- context "with attachments" do
1125
- should "add a class method to specify an attachment" do
1126
- assert SimplyStored::Simple.respond_to?(:has_s3_attachment)
1127
- end
1128
-
1129
- should 'store the options in a class accessor' do
1130
- assert LogItem.respond_to?(:_s3_options)
1131
- assert_not_nil LogItem._s3_options
1132
- end
1133
-
1134
- should "include an accessor for the _attachments" do
1135
- assert LogItem.public_instance_methods.grep(/_s3_attachments/)
1136
- end
1137
-
1138
- should "add accessors to the including class" do
1139
- @log_item = LogItem.new
1140
- assert @log_item.respond_to?(:log_data)
1141
- assert @log_item.respond_to?(:log_data=)
1142
- end
1143
-
1144
- should "return the assigned value with the accessor" do
1145
- @log_item = LogItem.new
1146
- @log_item.log_data = "Yay! It logged!"
1147
- assert_equal "Yay! It logged!", @log_item.log_data
1148
- end
1149
-
1150
- should "mark the attachment as changed when assigned a new value" do
1151
- @log_item = LogItem.new
1152
- @log_item.log_data = "Yay! It logged!"
1153
- assert @log_item._s3_attachments[:log_data][:dirty]
1154
- end
1155
-
1156
- should "not include the assigned value to the simpledb attributes" do
1157
- @log_item = LogItem.new
1158
- @log_item.log_data = "Yay! It logged!"
1159
- assert_nil @log_item.attributes[:log_data]
1160
- end
1161
-
1162
- should "raise an error when no bucket was specified" do
1163
- assert_raise(ArgumentError, "No bucket name specified") do
1164
- LogItem.class_eval do
1165
- has_s3_attachment :bla
1166
- end
1167
- end
1168
- end
1169
-
1170
- context "with s3 interaction" do
1171
- setup do
1172
- LogItem.instance_variable_set(:@_s3_connection, nil)
1173
- LogItem._s3_options[:log_data][:ca_file] = nil
1174
-
1175
- bucket = stub(:bckt) do
1176
- stubs(:put).returns(true)
1177
- stubs(:get).returns(true)
1178
- end
1179
-
1180
- @bucket = bucket
1181
-
1182
- @s3 = stub(:s3) do
1183
- stubs(:bucket).returns(bucket)
1184
- end
1185
-
1186
- RightAws::S3.stubs(:new).returns @s3
1187
- @log_item = LogItem.new
1188
- end
1189
-
1190
- context "when saving the attachment" do
1191
- should "fetch the collection" do
1192
- @log_item.log_data = "Yay! It logged!"
1193
- RightAws::S3.expects(:new).with('abcdef', 'secret!', :multi_thread => true, :ca_file => nil, :logger => nil).returns(@s3)
1194
- @log_item.save
1195
- end
1196
-
1197
- should "upload the file" do
1198
- @log_item.log_data = "Yay! It logged!"
1199
- @bucket.expects(:put).with(anything, "Yay! It logged!", {}, anything)
1200
- @log_item.save
1201
- end
1202
-
1203
- should "use the specified bucket" do
1204
- @log_item.log_data = "Yay! It logged!"
1205
- LogItem._s3_options[:log_data][:bucket] = 'mybucket'
1206
- @s3.expects(:bucket).with('mybucket').returns(@bucket)
1207
- @log_item.save
1208
- end
1209
-
1210
- should "create the bucket if it doesn't exist" do
1211
- @log_item.log_data = "Yay! log me"
1212
- LogItem._s3_options[:log_data][:bucket] = 'mybucket'
1213
-
1214
- @s3.expects(:bucket).with('mybucket').returns(nil)
1215
- @s3.expects(:bucket).with('mybucket', true, 'private', :location => nil).returns(@bucket)
1216
- @log_item.save
1217
- end
1218
-
1219
- should "accept :us location option but not set it in RightAWS::S3" do
1220
- @log_item.log_data = "Yay! log me"
1221
- LogItem._s3_options[:log_data][:bucket] = 'mybucket'
1222
- LogItem._s3_options[:log_data][:location] = :us
1223
-
1224
- @s3.expects(:bucket).with('mybucket').returns(nil)
1225
- @s3.expects(:bucket).with('mybucket', true, 'private', :location => nil).returns(@bucket)
1226
- @log_item.save
1227
- end
1228
-
1229
- should "raise an error if the bucket is not ours" do
1230
- @log_item.log_data = "Yay! log me too"
1231
- LogItem._s3_options[:log_data][:bucket] = 'mybucket'
1232
-
1233
- @s3.expects(:bucket).with('mybucket').returns(nil)
1234
- @s3.expects(:bucket).with('mybucket', true, 'private', :location => nil).raises(RightAws::AwsError, 'BucketAlreadyExists: The requested bucket name is not available. The bucket namespace is shared by all users of the system. Please select a different name and try again')
1235
-
1236
- assert_raise(ArgumentError) do
1237
- @log_item.save
1238
- end
1239
- end
1240
-
1241
- should "not upload the attachment when it hasn't been changed" do
1242
- @bucket.expects(:put).never
1243
- @log_item.save
1244
- end
1245
-
1246
- should "set the permissions to private by default" do
1247
- class PrivateLogItem < SimplyStored::Simple
1248
- has_s3_attachment :log_data, :bucket => 'mybucket'
1249
- end
1250
- PrivateLogItem.create_domain
1251
-
1252
- @bucket.expects(:put).with(anything, anything, {}, 'private')
1253
- @log_item = PrivateLogItem.new
1254
-
1255
- @log_item.log_data = 'Yay!'
1256
- @log_item.save
1257
- end
1258
-
1259
- should "set the permissions to whatever's specified in the options for the attachment" do
1260
- @log_item.save
1261
- old_perms = LogItem._s3_options[:log_data][:permissions]
1262
- LogItem._s3_options[:log_data][:permissions] = 'public-read'
1263
- @bucket.expects(:put).with(anything, anything, {}, 'public-read')
1264
- @log_item.log_data = 'Yay!'
1265
- @log_item.save
1266
- LogItem._s3_options[:log_data][:permissions] = old_perms
1267
- end
1268
-
1269
- should "use the full class name and the id as key" do
1270
- @log_item.save
1271
- @bucket.expects(:put).with("log_items/log_data/#{@log_item.id}", 'Yay!', {}, anything)
1272
- @log_item.log_data = 'Yay!'
1273
- @log_item.save
1274
- end
1275
-
1276
- should "mark the attachment as not dirty after uploading" do
1277
- @log_item.log_data = 'Yay!'
1278
- @log_item.save
1279
- assert !@log_item.instance_variable_get(:@_s3_attachments)[:log_data][:dirty]
1280
- end
1281
-
1282
- should 'store the attachment when the validations succeeded' do
1283
- @log_item.log_data = 'Yay!'
1284
- @log_item.stubs(:valid?).returns(true)
1285
- @bucket.expects(:put)
1286
- @log_item.save
1287
- end
1288
-
1289
- should "not store the attachment when the validations failed" do
1290
- @log_item.log_data = 'Yay!'
1291
- @log_item.stubs(:valid?).returns(false)
1292
- @bucket.expects(:put).never
1293
- @log_item.save
1294
- end
1295
-
1296
- should "save the attachment status" do
1297
- @log_item.save
1298
- @log_item.attributes["log_data_attachments"]
1299
- end
1300
-
1301
- should "save generate the url for the attachment" do
1302
- @log_item._s3_options[:log_data][:bucket] = 'bucket-for-monsieur'
1303
- @log_item._s3_options[:log_data][:permissions] = 'public-read'
1304
- @log_item.save
1305
- assert_equal "http://bucket-for-monsieur.s3.amazonaws.com/#{@log_item.s3_attachment_key(:log_data)}", @log_item.log_data_url
1306
- end
1307
-
1308
- should "add a short-lived access key for private attachments" do
1309
- @log_item._s3_options[:log_data][:bucket] = 'bucket-for-monsieur'
1310
- @log_item._s3_options[:log_data][:location] = :us
1311
- @log_item._s3_options[:log_data][:permissions] = 'private'
1312
- @log_item.save
1313
- assert @log_item.log_data_url.gsub("%2F", '/').include?("https://bucket-for-monsieur.s3.amazonaws.com:443/#{@log_item.s3_attachment_key(:log_data)}")
1314
- assert @log_item.log_data_url.include?("Signature=")
1315
- assert @log_item.log_data_url.include?("Expires=")
1316
- end
1317
-
1318
- should "serialize data other than strings to json" do
1319
- @log_item.log_data = ['one log entry', 'and another one']
1320
- @bucket.expects(:put).with(anything, '["one log entry","and another one"]', {}, anything)
1321
- @log_item.save
1322
- end
1323
- end
1324
-
1325
- context "when fetching the data" do
1326
- should "fetch the data from s3 and set the attachment attribute" do
1327
- @log_item.instance_variable_set(:@_s3_attachments, {})
1328
- @bucket.expects(:get).with("log_items/log_data/#{@log_item.id}").returns("Yay!")
1329
- assert_equal "Yay!", @log_item.log_data
1330
- end
1331
-
1332
- should "not mark the the attachment as dirty" do
1333
- @log_item.instance_variable_set(:@_s3_attachments, {})
1334
- @bucket.expects(:get).with("log_items/log_data/#{@log_item.id}").returns("Yay!")
1335
- @log_item.log_data
1336
- assert !@log_item._s3_attachments[:log_data][:dirty]
1337
- end
1338
-
1339
- should "not try to fetch the attachment if the value is already set" do
1340
- @log_item.log_data = "Yay!"
1341
- @bucket.expects(:get).never
1342
- assert_equal "Yay!", @log_item.log_data
1343
- end
1344
- end
1345
-
1346
- context "when deleting" do
1347
- setup do
1348
- LogItem._s3_options[:log_data][:after_delete] = :nothing
1349
- @log_item.log_data = 'Yatzzee'
1350
- @log_item.save
1351
- end
1352
-
1353
- should "do nothing to S3" do
1354
- @bucket.expects(:key).never
1355
- @log_item.delete
1356
- end
1357
-
1358
- should "also delete on S3 if configured so" do
1359
- LogItem._s3_options[:log_data][:after_delete] = :delete
1360
- s3_key = mock(:delete => true)
1361
- @bucket.expects(:key).with(@log_item.s3_attachment_key('log_data'), true).returns(s3_key)
1362
- @log_item.delete
1363
- end
1364
-
1365
- end
1366
-
1367
- end
1368
- end
1369
- end
1370
-
1371
- def create_item
1372
- i = Item.new(:foo_attribute => 'a', :bar_attribute_array => ['goog'])
1373
- assert i.save
1374
- i
1375
- end
1376
- end