foundationapi 0.9.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. data/Rakefile +37 -0
  2. data/lib/foundation_api.rb +9 -0
  3. data/lib/foundation_api/errors.rb +34 -0
  4. data/lib/foundation_api/event.rb +6 -0
  5. data/lib/foundation_api/event/client.rb +105 -0
  6. data/lib/foundation_api/event/exceptions.rb +20 -0
  7. data/lib/foundation_api/json_rpc.rb +6 -0
  8. data/lib/foundation_api/json_rpc/client.rb +80 -0
  9. data/lib/foundation_api/json_rpc/exceptions.rb +47 -0
  10. data/lib/foundation_api/model.rb +7 -0
  11. data/lib/foundation_api/model/attribute_methods.rb +85 -0
  12. data/lib/foundation_api/model/cached.rb +13 -0
  13. data/lib/foundation_api/model/mapping.rb +24 -0
  14. data/lib/foundation_api/request.rb +29 -0
  15. data/lib/foundation_api/service.rb +56 -0
  16. data/lib/foundation_api/shoulda_matcher.rb +15 -0
  17. data/lib/foundation_api/shoulda_matcher/attribute_alias_matcher.rb +32 -0
  18. data/lib/foundation_api/shoulda_matcher/persistence_method_matcher.rb +91 -0
  19. data/lib/foundation_api/table.rb +6 -0
  20. data/lib/foundation_api/table/persistence.rb +115 -0
  21. data/lib/foundation_api/table/record.rb +143 -0
  22. data/lib/foundation_api/test_helper.rb +53 -0
  23. data/lib/foundation_api/version.rb +27 -0
  24. data/test/foundation_api_test.rb +31 -0
  25. data/test/test_helper.rb +31 -0
  26. data/test/unit/foundation_api/event/client_test.rb +129 -0
  27. data/test/unit/foundation_api/json_rpc/client_test.rb +143 -0
  28. data/test/unit/foundation_api/model/attribute_methods_test.rb +96 -0
  29. data/test/unit/foundation_api/model/cached_test.rb +20 -0
  30. data/test/unit/foundation_api/model/mapping_test.rb +22 -0
  31. data/test/unit/foundation_api/request_test.rb +33 -0
  32. data/test/unit/foundation_api/service_test.rb +54 -0
  33. data/test/unit/foundation_api/table/persistence_test.rb +182 -0
  34. data/test/unit/foundation_api/table/record_test.rb +176 -0
  35. metadata +209 -0
@@ -0,0 +1,20 @@
1
+ require 'test_helper'
2
+
3
+ class FoundationApi::Model::AttributeMethodsTest < ActiveSupport::TestCase
4
+ class Model
5
+ include FoundationApi::Model::Cached
6
+
7
+ end
8
+
9
+ context 'cached_find' do
10
+ should 'be the stuff' do
11
+ Model.expects(:find).with(2)
12
+ Model.cached_find(2)
13
+ end
14
+ should 'call cache' do
15
+ Rails.cache.expects(:fetch).with(['FoundationApi::Model::AttributeMethodsTest::Model', 2])
16
+ Model.cached_find(2)
17
+ end
18
+ end
19
+
20
+ end
@@ -0,0 +1,22 @@
1
+ require 'test_helper'
2
+
3
+
4
+
5
+ class FoundationApi::Model::MappingTest < ActiveSupport::TestCase
6
+
7
+ class Model
8
+ include FoundationApi::Model::Mapping
9
+ end
10
+
11
+ context 'map_from_params' do
12
+ should 'create hash with indifferent access' do
13
+ input = "%%tn_drawHistory_ 4,18,10 %%tn_patternIDsSelected_ 1,2,3,4,5,0 %%tn_prizePhaseEstimatedAmounts_ units=0"
14
+ expected = {'tn_drawHistory' => '4,18,10', 'tn_patternIDsSelected' => '1,2,3,4,5,0', 'tn_prizePhaseEstimatedAmounts' => 'units=0'}
15
+ res = Model.map_from_params(input)
16
+ assert res.is_a? HashWithIndifferentAccess
17
+ assert_equal expected, res
18
+ Model.new.map_from_params(input)
19
+ end
20
+ end
21
+
22
+ end
@@ -0,0 +1,33 @@
1
+ require 'test_helper'
2
+
3
+ class FoundationApi::RequestTest < ActiveSupport::TestCase
4
+ class Model
5
+ include FoundationApi::Request
6
+
7
+ end
8
+
9
+ context 'delegation' do
10
+ should 'call the appropriate interface' do
11
+ FoundationApi::JsonRPC::Client.expects(:request).with(:hurrr).returns(11)
12
+ assert_equal 11, Model.request(:hurrr)
13
+ Model.expects(:request).with(:huffr).returns(22)
14
+ assert_equal 22, Model.new.request(:huffr)
15
+ end
16
+ end
17
+
18
+ context 'conversion' do
19
+ should 'quote string' do
20
+ assert_equal "'aha'", Model.quote('aha')
21
+ end
22
+ should 'not quote numbers' do
23
+ assert_equal "1", Model.quote(1)
24
+ end
25
+ should 'quote date' do
26
+ assert_equal "'2013-08-15'", Model.quote(Date.parse("2013-08-15"))
27
+ end
28
+ should 'quote elements of array if relevant' do
29
+ assert_equal "'2013-08-15', 'aha', 1", Model.quote([Date.parse("2013-08-15"), 'aha', 1])
30
+ end
31
+ end
32
+
33
+ end
@@ -0,0 +1,54 @@
1
+ require 'test_helper'
2
+
3
+ class FoundationApi::ServiceTest < ActiveSupport::TestCase
4
+ class Adapter < FoundationApi::Service
5
+ self.service_name = 'test_service'
6
+ end
7
+
8
+ context 'class method' do
9
+ context 'request_data' do
10
+ should 'pass on the appropriate parameters' do
11
+ Adapter.expects(:request).with('test_service', :hello => :there).returns(:hello_again)
12
+ assert_equal :hello_again, Adapter.send(:request_data, :hello => :there)
13
+ end
14
+ end
15
+ context 'translate_options' do
16
+ should 'translate options correctly' do
17
+ expected = {'a' => 1, 'b' => 2}
18
+ assert_equal expected, Adapter.send( :translate_options, :conditions => {:a => 1, :b => 2})
19
+ end
20
+ end
21
+ context 'all' do
22
+ should 'have appropritate calls' do
23
+ Adapter.expects(:request_data).with({}).returns(:data)
24
+ Adapter.expects(:instantiate_objects).with(:data).returns(:good)
25
+ assert_equal :good, Adapter.all
26
+ end
27
+ should 'not try to instantiate object if no result' do
28
+ Adapter.expects(:request_data).with({}).returns(nil)
29
+ Adapter.expects(:instantiate_objects).never
30
+ assert_nil Adapter.all
31
+ end
32
+ should 'apply default scope' do
33
+ Adapter.default_scope = {:hello => :there}
34
+ Adapter.expects(:request_data).with({:hello => :there}).returns(nil)
35
+ assert_nil Adapter.all
36
+ Adapter.default_scope = {}
37
+ end
38
+ end
39
+ context 'where' do
40
+ should 'support optional condition' do
41
+ Adapter.expects(:translate_options).with(:conditions => {:a => :b}).returns(:good)
42
+ Adapter.expects(:request_data).with(:good).returns([:fine])
43
+ Adapter.expects(:instantiate_objects).with([:fine]).returns([:nice])
44
+ assert_equal [:nice], Adapter.where(:a => :b)
45
+ end
46
+ should 'accept string' do
47
+ Adapter.expects(:translate_options).with('a, b, c').returns(:good)
48
+ Adapter.expects(:request_data).with(:good).returns([:fine])
49
+ Adapter.expects(:instantiate_objects).with([:fine]).returns([:nice])
50
+ assert_equal [:nice], Adapter.where('a, b, c')
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,182 @@
1
+ require 'test_helper'
2
+ require 'foundation_api/test_helper'
3
+
4
+ class FoundationApi::Table::PersistenceTest < ActiveSupport::TestCase
5
+
6
+ class TestClass
7
+ include FoundationApi::Model::AttributeMethods
8
+ include FoundationApi::Table::Persistence
9
+ TestClass.persistence create: :CreateTestObject, update: :ChangeTestObject
10
+
11
+ def initialize(attributes = {})
12
+ @attributes = HashWithIndifferentAccess.new attributes
13
+ end
14
+ end
15
+
16
+ context 'class' do
17
+ setup do
18
+ TestClass.persistence create: :CreateTestObject, update: :ChangeTestObject
19
+ end
20
+ teardown do
21
+ TestClass.persistence_options = {}
22
+ end
23
+ should 'have a persistence inteface' do
24
+ assert TestClass.respond_to?(:persistence)
25
+ assert_equal :CreateTestObject, TestClass.persistence_options[:create]
26
+ assert_equal :ChangeTestObject, TestClass.persistence_options[:update]
27
+ end
28
+
29
+ context 'methods create' do
30
+ should 'instantiate and save object' do
31
+ @object = TestClass.new
32
+ attrs = {:hello => :world, :riding => :on_an_airplane}
33
+ TestClass.expects(:new).with(attrs).returns(@object)
34
+ @object.expects(:save).returns(:success)
35
+ assert_equal :success, TestClass.create(attrs)
36
+ TestClass.expects(:new).with(attrs).returns(@object)
37
+ @object.expects(:save!).returns(:success)
38
+ assert_equal :success, TestClass.create!(attrs)
39
+ end
40
+ end
41
+
42
+ context 'remote_create' do
43
+ setup do
44
+ @attrs = {:still => :on, :a => :plane, :properties => {:hello => :there}}
45
+ @object = TestClass.new(@attrs)
46
+ end
47
+ should 'map attributes when requesting' do
48
+ @object.expects(:map_attributes).returns(:good)
49
+ TestClass.expects(:request).with(:CreateTestObject, :good).returns(:in_the_air)
50
+ assert_equal :in_the_air, TestClass.remote_create(@object)
51
+ end
52
+ should 'support mapping hashes into array' do
53
+ assert_equal ({"still"=>:on, "a"=>:plane, "properties"=>{"hello"=>:there}}), @object.map_attributes
54
+ TestClass.persistence create: :CreateTestObject, :hash_to_array => true
55
+ assert_equal ({"still"=>:on, "a"=>:plane, "properties"=>[["hello",:there]]}), @object.map_attributes
56
+
57
+ end
58
+ should 'check for uniqueness if option specified' do
59
+ TestClass.persistence create: :CreateTestObject, unique: :name
60
+ @object[:name] = 'Ivo'
61
+ TestClass.expects(:where).with(:name => 'Ivo', :deleted => 0).returns([true])
62
+ TestClass.expects(:request).never
63
+ assert_raises FoundationApi::RecordNotUnique do
64
+ @object.save!
65
+ end
66
+ @object.expects(:map_attributes).returns(:good)
67
+ TestClass.expects(:where).with(:name => 'Ivo', :deleted => 0).returns([])
68
+ TestClass.expects(:request).with(:CreateTestObject, :good).returns(:in_the_air)
69
+ assert_nothing_raised do
70
+ @object.save!
71
+ end
72
+ end
73
+ should 'return id' do
74
+ @object.expects(:map_attributes).returns(:good)
75
+ TestClass.expects(:request).with(:CreateTestObject, :good).returns([123])
76
+ assert_equal 123, TestClass.remote_create(@object)
77
+ @object.expects(:map_attributes).returns(:good)
78
+ TestClass.expects(:request).with(:CreateTestObject, :good).returns(234)
79
+ assert_equal 234, TestClass.remote_create(@object)
80
+ end
81
+ end
82
+ context 'remote_update' do
83
+ should_eventually 'be supported' do
84
+ end
85
+ end
86
+ context 'remote_destroy' do
87
+ setup do
88
+ @options = TestClass.persistence_options
89
+ @object = TestClass.new(:in_melon => :office)
90
+ end
91
+ teardown do
92
+ TestClass.persistence_options = @options
93
+ end
94
+ should 'provide proper initialization' do
95
+ TestClass.persistence destroy: :DeleteTestObject
96
+ assert_equal :DeleteTestObject, TestClass.persistence_options[:destroy]
97
+ assert_equal 'testClassId', TestClass.send(:destroy_key)
98
+ TestClass.persistence destroy_key: 'baluba'
99
+ assert_equal 'baluba', TestClass.send(:destroy_key)
100
+ end
101
+ should 'check for support before executing' do
102
+ assert_raises FoundationApi::DestroyNotSupported do
103
+ @object.destroy
104
+ end
105
+ @object[:id] = 14
106
+ assert_raises FoundationApi::DestroyNotSupported do
107
+ @object.destroy!
108
+ end
109
+ end
110
+ should 'perform the appropriate call to the service for named id' do
111
+ TestClass.persistence destroy: :DeleteTestObject
112
+ assert_raises FoundationApi::RecordNotPersistent do
113
+ @object.destroy!
114
+ end
115
+ assert !@object.destroy, 'Should deny to destroy object and should not raise exception'
116
+ @object[:id] = 12
117
+ TestClass.expects(:request).with(:DeleteTestObject, 'testClassId' => 12)
118
+ @object.destroy
119
+ end
120
+ should 'perform the appropriate call to the service for array' do
121
+ TestClass.persistence destroy: :DeleteTestObject, destroy_type: :array
122
+ @object[:id] = 12
123
+ TestClass.expects(:request).with(:DeleteTestObject, [12])
124
+ @object.destroy
125
+ TestClass.expects(:request).with(:DeleteTestObject, [11, 12, 13])
126
+ TestClass.destroy 11, 12, 13
127
+ end
128
+ end
129
+
130
+ end
131
+
132
+
133
+ context 'instance' do
134
+ setup do
135
+ @object = TestClass.new({:still_on => :an_airplane})
136
+ end
137
+ context 'method save' do
138
+ should 'create record remotely and store id' do
139
+ @object.expects(:remote_create).with(@object).returns(:catch && 44)
140
+ @object.save
141
+ assert_equal 44, @object.id
142
+ @object.save(:options => :hello)
143
+ assert_equal 44, @object.id
144
+ end
145
+ end
146
+ context 'persistence support' do
147
+ should 'raise error unless persistence support has been defined' do
148
+ @object.persistence_options = {}
149
+ assert_raises FoundationApi::CreateNotSupported do
150
+ @object.stubs(:persisted?).returns(false)
151
+ @object.save!
152
+ end
153
+ assert_raises FoundationApi::UpdateNotSupported do
154
+ @object.stubs(:persisted?).returns(true)
155
+ @object.save!
156
+ end
157
+ end
158
+ end
159
+ context 'having an id' do
160
+ setup do
161
+ @object[:id] = 1
162
+ end
163
+ should 'tell that record is persisted' do
164
+ assert @object.persisted?
165
+ end
166
+ should 'tell that it is not a new record' do
167
+ assert !@object.new_record?
168
+ end
169
+ end
170
+ context 'missing id' do
171
+ setup do
172
+ @object[:id] = nil
173
+ end
174
+ should 'state that record is not persisted' do
175
+ assert !@object.persisted?
176
+ end
177
+ should 'tell that it might be a new record' do
178
+ assert @object.new_record?
179
+ end
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,176 @@
1
+ require 'test_helper'
2
+ require 'foundation_api/test_helper'
3
+
4
+ class FoundationApi::Table::RecordTest < ActiveSupport::TestCase
5
+ setup do
6
+ FoundationApi::JsonRPC::Client.site = "http://cyber:arts@localhost:4444/api"
7
+ FoundationApi::JsonRPC::Client.auth_token = @auth_token = 'tns5ddd7cc5271c8c6b5fab8aaf9ec492ed'
8
+ end
9
+
10
+ class TestObject < FoundationApi::Table::Record
11
+ alias_attribute :gun, :Pistol
12
+ end
13
+
14
+ def hash_difference(a,b)
15
+ "Expected: #{a.inspect}, but was #{b.inspect}\n" +
16
+ "expected - actual #{(a.reject { |k,v| b[k] == v }).inspect}\n" +
17
+ "actual - expected #{(b.reject { |k,v| a[k] == v }).inspect}\n"
18
+ end
19
+ def assert_json_params_equal(a,b)
20
+ a_params = a.delete('params').first
21
+ b_params = b.delete('params').first
22
+ assert_equal a, b, hash_difference(a, b)
23
+ assert_equal a_params, b_params, hash_difference(a_params, b_params)
24
+ end
25
+
26
+ def expect(method, parameters, options = {}, &block)
27
+ if options[:return] || options[:error]
28
+ Net::HTTP.stubs(:raw_response_data).returns(%Q/{"result": #{options[:return] || 'null'}, "id": "jsonrpc", "error": #{options[:error] || 'null'}}/)
29
+ end
30
+ yield
31
+ request_str = %Q/{"params":[{"authorization":"#{@auth_token}",#{parameters}}],"method":"#{method}","id":"jsonrpc"}/
32
+ #puts request_str
33
+ #puts Net::HTTP.raw_post_body
34
+ assert_json_params_equal JSON.parse(request_str), JSON.parse(Net::HTTP.raw_post_body)
35
+ end
36
+
37
+
38
+ context 'behavior' do
39
+ setup do
40
+ end
41
+ should 'include specific modules' do
42
+ modules = [ActiveModel::Conversion]
43
+ assert_equal modules, FoundationApi::Table::Record.included_modules & modules
44
+ end
45
+ should 'have foundation concerns' do
46
+ modules = [FoundationApi::Model::Mapping, FoundationApi::Model::AttributeMethods, FoundationApi::Request]
47
+ assert_equal modules, FoundationApi::Table::Record.included_modules & modules
48
+ end
49
+ end
50
+
51
+ context 'class methods' do
52
+ should 'know table name from class name' do
53
+ assert_equal 'foundationapi.TestObject', TestObject.send(:fully_qualified_table_name)
54
+ assert_equal 'foundationapi', TestObject.database_name
55
+ assert_equal 'TestObject', TestObject.table_name
56
+ end
57
+ should 'translate options correctly' do
58
+ expected = {:filters => ['a = 1', 'b = 2']}
59
+ assert_equal expected, TestObject.send( :translate_options, :conditions => {:a => 1, :b => 2})
60
+ assert_equal expected, TestObject.send( :translate_options, :conditions => ['a = 1', 'b = 2'])
61
+ expected = {:filters => ['great']}
62
+ assert_equal expected, TestObject.send( :translate_options, :conditions => 'great')
63
+ expected = {:filters => ["a = 'wow'", "b = 'hey'"]}
64
+ assert_equal expected, TestObject.send( :translate_options, :conditions => {:a => 'wow', :b => :hey})
65
+ expected = {:filters => ["a = 'hey'", "cool"]}
66
+ assert_equal expected, TestObject.send( :translate_options, :conditions => {:a => 'hey', :_expression => 'cool'})
67
+ end
68
+ should 'raise exception if parameters cannot be translated' do
69
+ assert_raises FoundationApi::TranslationError do
70
+ assert_equal TestObject.send( :translate_options, :conditions => 1)
71
+ end
72
+ end
73
+ context 'find' do
74
+ should 'handle success' do
75
+ TestObject.expects(:get_table_data).with('foundationapi.TestObject', :filters => ['id = 2']).returns([:good])
76
+ TestObject.expects(:instantiate_objects).with([:good]).returns([:nice])
77
+ assert_equal :nice, TestObject.find(2)
78
+ end
79
+ should 'handle failure' do
80
+ TestObject.expects(:get_table_data).with('foundationapi.TestObject', :filters => ['id = 2']).returns([])
81
+ TestObject.expects(:instantiate_objects).never
82
+ assert_nil TestObject.find(2)
83
+ end
84
+ end
85
+ context 'where' do
86
+ should 'support optional condition' do
87
+ TestObject.expects(:translate_options).with(:conditions => {:a => :b}).returns(:good)
88
+ TestObject.expects(:get_table_data).with('foundationapi.TestObject', :good).returns([:fine])
89
+ TestObject.expects(:instantiate_objects).with([:fine]).returns([:nice])
90
+ assert_equal [:nice], TestObject.where(:a => :b)
91
+ end
92
+ should 'accept string' do
93
+ TestObject.expects(:translate_options).with('a, b, c').returns(:good)
94
+ TestObject.expects(:get_table_data).with('foundationapi.TestObject', :good).returns([:fine])
95
+ TestObject.expects(:instantiate_objects).with([:fine]).returns([:nice])
96
+ assert_equal [:nice], TestObject.where('a, b, c')
97
+ end
98
+ end
99
+ context 'all' do
100
+ should 'handle success' do
101
+ TestObject.expects(:get_table_data).with('foundationapi.TestObject').returns([:good])
102
+ TestObject.expects(:instantiate_objects).with([:good]).returns([:nice])
103
+ assert_equal [:nice], TestObject.all
104
+ end
105
+ end
106
+ context 'get_table_data' do
107
+ should 'send correct format for GetTableData' do
108
+ expect 'GetTableData', '"table":"bingo.Perm","filters":["permId = 1", "permTypeId = 2"], "columns":["numbers","tweek"]',
109
+ :return => '{"columnNames":["numbers","tweek"], "rows":[{"fields":["12,13,14", "ugh"]}, {"fields":["22,13,14", "argh"]}]}' do
110
+ expected = [{'numbers' => "12,13,14", 'tweek' => "ugh"}, {'numbers' => "22,13,14", 'tweek' => "argh"}]
111
+ assert_equal expected, TestObject.send(:get_table_data, 'bingo.Perm', :filters => ['permId = 1', 'permTypeId = 2'], :columns => [:numbers, :tweek])
112
+ end
113
+ end
114
+ should 'return nil if there are no data' do
115
+ expect 'GetTableData', '"table":"bingo.Perm","filters":["permId = 1", "permTypeId = 2"], "columns":["numbers","tweek"]',
116
+ :return => '["numbers","tweek"]' do
117
+ assert_nil TestObject.send(:get_table_data, 'bingo.Perm', :filters => ['permId = 1', 'permTypeId = 2'], :columns => [:numbers, :tweek])
118
+ end
119
+ end
120
+ should_eventually 'take advantage of columns' do
121
+ end
122
+ end
123
+
124
+ context 'error handling' do
125
+ should_eventually 'include raising exception when record not found' do
126
+ end
127
+ end
128
+ end
129
+
130
+ context 'instance methods' do
131
+ should 'be dynamic' do
132
+ @object = TestObject.new
133
+ assert_raises NoMethodError do
134
+ @object.unknown
135
+ end
136
+ @object.attributes = HashWithIndifferentAccess.new({:unknown => 'aha'})
137
+ assert_equal 'aha', @object.unknown
138
+ end
139
+ should 'convert id to integer' do
140
+ @object = TestObject.new(:id => '2')
141
+ assert @object.id.is_a? Fixnum
142
+ assert_equal 2, @object.id
143
+ end
144
+ end
145
+
146
+ context 'caching' do
147
+ context 'enabled' do
148
+ setup do
149
+ TestObject.caching_enabled = true
150
+ end
151
+ teardown do
152
+ TestObject.caching_enabled = false
153
+ end
154
+ should 'cache where clause' do
155
+ Rails.cache.expects(:fetch).with([TestObject.name, :where, 'bark twice'],{}).returns(stub(:first => :expected))
156
+ assert_equal :expected, TestObject.where('bark twice').first
157
+ end
158
+ should 'cache object by id' do
159
+ Rails.cache.expects(:fetch).with([TestObject.name, 1],{}).returns(:expected)
160
+ assert_equal :expected, TestObject.find(1)
161
+ end
162
+ end
163
+ context 'disabled' do
164
+ should 'never call cache' do
165
+ Rails.cache.expects(:fetch).never
166
+ TestObject.expects(:get_table_data).returns([:expected])
167
+ TestObject.expects(:instantiate_objects).with([:expected]).returns([:nice])
168
+ assert_equal [:nice], TestObject.where('bark twice')
169
+ TestObject.expects(:get_table_data).returns([:expected])
170
+ TestObject.expects(:instantiate_objects).with([:expected]).returns([:nice])
171
+ assert_equal :nice, TestObject.find( 1 )
172
+ end
173
+ end
174
+ end
175
+
176
+ end