foundationapi 0.9.9

Sign up to get free protection for your applications and to get access to all the features.
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