restforce-db 0.1.6 → 0.2.3

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 (24) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +11 -8
  3. data/lib/generators/templates/migration.rb.tt +2 -0
  4. data/lib/restforce/db/command.rb +17 -4
  5. data/lib/restforce/db/instances/active_record.rb +16 -0
  6. data/lib/restforce/db/instances/base.rb +12 -2
  7. data/lib/restforce/db/instances/salesforce.rb +8 -0
  8. data/lib/restforce/db/record_types/active_record.rb +7 -7
  9. data/lib/restforce/db/record_types/base.rb +17 -5
  10. data/lib/restforce/db/record_types/salesforce.rb +2 -1
  11. data/lib/restforce/db/synchronizer.rb +1 -1
  12. data/lib/restforce/db/tracker.rb +44 -0
  13. data/lib/restforce/db/version.rb +1 -1
  14. data/lib/restforce/db/worker.rb +47 -16
  15. data/lib/restforce/db.rb +3 -1
  16. data/test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/when_synchronization_is_stale/updates_the_database_record.yml +197 -0
  17. data/test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_associated_database_record/when_synchronization_is_up-to-date/does_not_update_the_database_record.yml +234 -0
  18. data/test/lib/restforce/db/instances/active_record_test.rb +4 -0
  19. data/test/lib/restforce/db/record_types/active_record_test.rb +12 -8
  20. data/test/lib/restforce/db/synchronizer_test.rb +45 -14
  21. data/test/lib/restforce/db/tracker_test.rb +50 -0
  22. data/test/support/active_record.rb +4 -3
  23. metadata +6 -3
  24. data/test/cassettes/Restforce_DB_Synchronizer/_run/given_a_Salesforce_record_with_an_existing_record_in_the_database/updates_the_database_record.yml +0 -158
@@ -0,0 +1,197 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://<host>/services/oauth2/token
6
+ body:
7
+ encoding: US-ASCII
8
+ string: grant_type=password&client_id=<client_id>&client_secret=<client_secret>&username=<username>&password=<password><security_token>
9
+ headers:
10
+ User-Agent:
11
+ - Faraday v0.9.1
12
+ Content-Type:
13
+ - application/x-www-form-urlencoded
14
+ Accept-Encoding:
15
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
16
+ Accept:
17
+ - "*/*"
18
+ response:
19
+ status:
20
+ code: 200
21
+ message: OK
22
+ headers:
23
+ Date:
24
+ - Tue, 24 Mar 2015 20:01:29 GMT
25
+ Set-Cookie:
26
+ - BrowserId=d0G0Guz1Qb2zbGglgG-bpg;Path=/;Domain=.salesforce.com;Expires=Sat,
27
+ 23-May-2015 20:01:29 GMT
28
+ Expires:
29
+ - Thu, 01 Jan 1970 00:00:00 GMT
30
+ Pragma:
31
+ - no-cache
32
+ Cache-Control:
33
+ - no-cache, no-store
34
+ Content-Type:
35
+ - application/json;charset=UTF-8
36
+ Transfer-Encoding:
37
+ - chunked
38
+ body:
39
+ encoding: ASCII-8BIT
40
+ string: '{"id":"https://login.salesforce.com/id/00D1a000000H3O9EAK/0051a000000UGT8AAO","issued_at":"1427227289790","token_type":"Bearer","instance_url":"https://<host>","signature":"UOEfBh3JWDC/YB0aeGuqptZD4XM3RB62QBkis2zhaZk=","access_token":"00D1a000000H3O9!AQ4AQLW7LvL9F5lVipVJl8BHs21lRfayiAsI3XyWdaLNmdGsBgdOTwyLzmSBrmoKxyILlRDx._h5Oz.OpUoj6pYbfHsCYjrQ"}'
41
+ http_version:
42
+ recorded_at: Tue, 24 Mar 2015 20:01:29 GMT
43
+ - request:
44
+ method: post
45
+ uri: https://<host>/services/data/v26.0/sobjects/CustomObject__c
46
+ body:
47
+ encoding: UTF-8
48
+ string: '{"Name":"Custom object","Example_Field__c":"Some sample text"}'
49
+ headers:
50
+ User-Agent:
51
+ - Faraday v0.9.1
52
+ Content-Type:
53
+ - application/json
54
+ Authorization:
55
+ - OAuth 00D1a000000H3O9!AQ4AQLW7LvL9F5lVipVJl8BHs21lRfayiAsI3XyWdaLNmdGsBgdOTwyLzmSBrmoKxyILlRDx._h5Oz.OpUoj6pYbfHsCYjrQ
56
+ Accept-Encoding:
57
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
58
+ Accept:
59
+ - "*/*"
60
+ response:
61
+ status:
62
+ code: 201
63
+ message: Created
64
+ headers:
65
+ Date:
66
+ - Tue, 24 Mar 2015 20:01:30 GMT
67
+ Set-Cookie:
68
+ - BrowserId=S3WYcky7SpSBvnqYKq6sLg;Path=/;Domain=.salesforce.com;Expires=Sat,
69
+ 23-May-2015 20:01:30 GMT
70
+ Expires:
71
+ - Thu, 01 Jan 1970 00:00:00 GMT
72
+ Sforce-Limit-Info:
73
+ - api-usage=143/15000
74
+ Location:
75
+ - "/services/data/v26.0/sobjects/CustomObject__c/a001a000001IyUmAAK"
76
+ Content-Type:
77
+ - application/json;charset=UTF-8
78
+ Transfer-Encoding:
79
+ - chunked
80
+ body:
81
+ encoding: ASCII-8BIT
82
+ string: '{"id":"a001a000001IyUmAAK","success":true,"errors":[]}'
83
+ http_version:
84
+ recorded_at: Tue, 24 Mar 2015 20:01:30 GMT
85
+ - request:
86
+ method: get
87
+ uri: https://<host>/services/data/v26.0/query?q=select%20Id,%20SystemModstamp,%20Name,%20Example_Field__c%20from%20CustomObject__c%20where%20Id%20=%20%27a001a000001IyUmAAK%27
88
+ body:
89
+ encoding: US-ASCII
90
+ string: ''
91
+ headers:
92
+ User-Agent:
93
+ - Faraday v0.9.1
94
+ Authorization:
95
+ - OAuth 00D1a000000H3O9!AQ4AQLW7LvL9F5lVipVJl8BHs21lRfayiAsI3XyWdaLNmdGsBgdOTwyLzmSBrmoKxyILlRDx._h5Oz.OpUoj6pYbfHsCYjrQ
96
+ Accept-Encoding:
97
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
98
+ Accept:
99
+ - "*/*"
100
+ response:
101
+ status:
102
+ code: 200
103
+ message: OK
104
+ headers:
105
+ Date:
106
+ - Tue, 24 Mar 2015 20:01:31 GMT
107
+ Set-Cookie:
108
+ - BrowserId=iCZa-rO2Qze8bD7-w5DqCw;Path=/;Domain=.salesforce.com;Expires=Sat,
109
+ 23-May-2015 20:01:31 GMT
110
+ Expires:
111
+ - Thu, 01 Jan 1970 00:00:00 GMT
112
+ Sforce-Limit-Info:
113
+ - api-usage=144/15000
114
+ Content-Type:
115
+ - application/json;charset=UTF-8
116
+ Transfer-Encoding:
117
+ - chunked
118
+ body:
119
+ encoding: ASCII-8BIT
120
+ string: '{"totalSize":1,"done":true,"records":[{"attributes":{"type":"CustomObject__c","url":"/services/data/v26.0/sobjects/CustomObject__c/a001a000001IyUmAAK"},"Id":"a001a000001IyUmAAK","SystemModstamp":"2015-03-24T20:01:30.000+0000","Name":"Custom
121
+ object","Example_Field__c":"Some sample text"}]}'
122
+ http_version:
123
+ recorded_at: Tue, 24 Mar 2015 20:01:31 GMT
124
+ - request:
125
+ method: get
126
+ uri: https://<host>/services/data/v26.0/query?q=select%20Id,%20SystemModstamp,%20Name,%20Example_Field__c%20from%20CustomObject__c%20where%20SystemModstamp%20%3C=%202015-03-24T20:01:31Z
127
+ body:
128
+ encoding: US-ASCII
129
+ string: ''
130
+ headers:
131
+ User-Agent:
132
+ - Faraday v0.9.1
133
+ Authorization:
134
+ - OAuth 00D1a000000H3O9!AQ4AQLW7LvL9F5lVipVJl8BHs21lRfayiAsI3XyWdaLNmdGsBgdOTwyLzmSBrmoKxyILlRDx._h5Oz.OpUoj6pYbfHsCYjrQ
135
+ Accept-Encoding:
136
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
137
+ Accept:
138
+ - "*/*"
139
+ response:
140
+ status:
141
+ code: 200
142
+ message: OK
143
+ headers:
144
+ Date:
145
+ - Tue, 24 Mar 2015 20:01:32 GMT
146
+ Set-Cookie:
147
+ - BrowserId=6IY41Rg2TMWpO_MnI-4K6w;Path=/;Domain=.salesforce.com;Expires=Sat,
148
+ 23-May-2015 20:01:32 GMT
149
+ Expires:
150
+ - Thu, 01 Jan 1970 00:00:00 GMT
151
+ Sforce-Limit-Info:
152
+ - api-usage=144/15000
153
+ Content-Type:
154
+ - application/json;charset=UTF-8
155
+ Transfer-Encoding:
156
+ - chunked
157
+ body:
158
+ encoding: ASCII-8BIT
159
+ string: '{"totalSize":3,"done":true,"records":[{"attributes":{"type":"CustomObject__c","url":"/services/data/v26.0/sobjects/CustomObject__c/a001a000001IjCFAA0"},"Id":"a001a000001IjCFAA0","SystemModstamp":"2015-03-24T08:25:04.000+0000","Name":"andrew@tablexi.com","Example_Field__c":null},{"attributes":{"type":"CustomObject__c","url":"/services/data/v26.0/sobjects/CustomObject__c/a001a000001IjP2AAK"},"Id":"a001a000001IjP2AAK","SystemModstamp":"2015-03-24T08:27:33.000+0000","Name":"somebody+new@example.com","Example_Field__c":null},{"attributes":{"type":"CustomObject__c","url":"/services/data/v26.0/sobjects/CustomObject__c/a001a000001IyUmAAK"},"Id":"a001a000001IyUmAAK","SystemModstamp":"2015-03-24T20:01:30.000+0000","Name":"Custom
160
+ object","Example_Field__c":"Some sample text"}]}'
161
+ http_version:
162
+ recorded_at: Tue, 24 Mar 2015 20:01:32 GMT
163
+ - request:
164
+ method: delete
165
+ uri: https://<host>/services/data/v26.0/sobjects/CustomObject__c/a001a000001IyUmAAK
166
+ body:
167
+ encoding: US-ASCII
168
+ string: ''
169
+ headers:
170
+ User-Agent:
171
+ - Faraday v0.9.1
172
+ Authorization:
173
+ - OAuth 00D1a000000H3O9!AQ4AQLW7LvL9F5lVipVJl8BHs21lRfayiAsI3XyWdaLNmdGsBgdOTwyLzmSBrmoKxyILlRDx._h5Oz.OpUoj6pYbfHsCYjrQ
174
+ Accept-Encoding:
175
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
176
+ Accept:
177
+ - "*/*"
178
+ response:
179
+ status:
180
+ code: 204
181
+ message: No Content
182
+ headers:
183
+ Date:
184
+ - Tue, 24 Mar 2015 20:01:34 GMT
185
+ Set-Cookie:
186
+ - BrowserId=MErmNS95SD62_a5q9qw3DA;Path=/;Domain=.salesforce.com;Expires=Sat,
187
+ 23-May-2015 20:01:34 GMT
188
+ Expires:
189
+ - Thu, 01 Jan 1970 00:00:00 GMT
190
+ Sforce-Limit-Info:
191
+ - api-usage=143/15000
192
+ body:
193
+ encoding: UTF-8
194
+ string: ''
195
+ http_version:
196
+ recorded_at: Tue, 24 Mar 2015 20:01:34 GMT
197
+ recorded_with: VCR 2.9.3
@@ -0,0 +1,234 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://<host>/services/oauth2/token
6
+ body:
7
+ encoding: US-ASCII
8
+ string: grant_type=password&client_id=<client_id>&client_secret=<client_secret>&username=<username>&password=<password><security_token>
9
+ headers:
10
+ User-Agent:
11
+ - Faraday v0.9.1
12
+ Content-Type:
13
+ - application/x-www-form-urlencoded
14
+ Accept-Encoding:
15
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
16
+ Accept:
17
+ - "*/*"
18
+ response:
19
+ status:
20
+ code: 200
21
+ message: OK
22
+ headers:
23
+ Date:
24
+ - Tue, 24 Mar 2015 20:01:22 GMT
25
+ Set-Cookie:
26
+ - BrowserId=66vMVxWoT9GxGXx0f_L2PA;Path=/;Domain=.salesforce.com;Expires=Sat,
27
+ 23-May-2015 20:01:22 GMT
28
+ Expires:
29
+ - Thu, 01 Jan 1970 00:00:00 GMT
30
+ Pragma:
31
+ - no-cache
32
+ Cache-Control:
33
+ - no-cache, no-store
34
+ Content-Type:
35
+ - application/json;charset=UTF-8
36
+ Transfer-Encoding:
37
+ - chunked
38
+ body:
39
+ encoding: ASCII-8BIT
40
+ string: '{"id":"https://login.salesforce.com/id/00D1a000000H3O9EAK/0051a000000UGT8AAO","issued_at":"1427227282626","token_type":"Bearer","instance_url":"https://<host>","signature":"nl501aqDiCh/Z5v8a3yRZ50Ft8S1uv7xIxbradmSMjY=","access_token":"00D1a000000H3O9!AQ4AQLW7LvL9F5lVipVJl8BHs21lRfayiAsI3XyWdaLNmdGsBgdOTwyLzmSBrmoKxyILlRDx._h5Oz.OpUoj6pYbfHsCYjrQ"}'
41
+ http_version:
42
+ recorded_at: Tue, 24 Mar 2015 20:01:22 GMT
43
+ - request:
44
+ method: post
45
+ uri: https://<host>/services/data/v26.0/sobjects/CustomObject__c
46
+ body:
47
+ encoding: UTF-8
48
+ string: '{"Name":"Custom object","Example_Field__c":"Some sample text"}'
49
+ headers:
50
+ User-Agent:
51
+ - Faraday v0.9.1
52
+ Content-Type:
53
+ - application/json
54
+ Authorization:
55
+ - OAuth 00D1a000000H3O9!AQ4AQLW7LvL9F5lVipVJl8BHs21lRfayiAsI3XyWdaLNmdGsBgdOTwyLzmSBrmoKxyILlRDx._h5Oz.OpUoj6pYbfHsCYjrQ
56
+ Accept-Encoding:
57
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
58
+ Accept:
59
+ - "*/*"
60
+ response:
61
+ status:
62
+ code: 201
63
+ message: Created
64
+ headers:
65
+ Date:
66
+ - Tue, 24 Mar 2015 20:01:23 GMT
67
+ Set-Cookie:
68
+ - BrowserId=gxq8laTeS4a7aMtwB1kg7w;Path=/;Domain=.salesforce.com;Expires=Sat,
69
+ 23-May-2015 20:01:23 GMT
70
+ Expires:
71
+ - Thu, 01 Jan 1970 00:00:00 GMT
72
+ Sforce-Limit-Info:
73
+ - api-usage=143/15000
74
+ Location:
75
+ - "/services/data/v26.0/sobjects/CustomObject__c/a001a000001IyUhAAK"
76
+ Content-Type:
77
+ - application/json;charset=UTF-8
78
+ Transfer-Encoding:
79
+ - chunked
80
+ body:
81
+ encoding: ASCII-8BIT
82
+ string: '{"id":"a001a000001IyUhAAK","success":true,"errors":[]}'
83
+ http_version:
84
+ recorded_at: Tue, 24 Mar 2015 20:01:23 GMT
85
+ - request:
86
+ method: get
87
+ uri: https://<host>/services/data/v26.0/query?q=select%20Id,%20SystemModstamp,%20Name,%20Example_Field__c%20from%20CustomObject__c%20where%20SystemModstamp%20%3C=%202015-03-24T20:01:23Z
88
+ body:
89
+ encoding: US-ASCII
90
+ string: ''
91
+ headers:
92
+ User-Agent:
93
+ - Faraday v0.9.1
94
+ Authorization:
95
+ - OAuth 00D1a000000H3O9!AQ4AQLW7LvL9F5lVipVJl8BHs21lRfayiAsI3XyWdaLNmdGsBgdOTwyLzmSBrmoKxyILlRDx._h5Oz.OpUoj6pYbfHsCYjrQ
96
+ Accept-Encoding:
97
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
98
+ Accept:
99
+ - "*/*"
100
+ response:
101
+ status:
102
+ code: 200
103
+ message: OK
104
+ headers:
105
+ Date:
106
+ - Tue, 24 Mar 2015 20:01:24 GMT
107
+ Set-Cookie:
108
+ - BrowserId=32lYUckHSQeMtLFmz9K8Tg;Path=/;Domain=.salesforce.com;Expires=Sat,
109
+ 23-May-2015 20:01:24 GMT
110
+ Expires:
111
+ - Thu, 01 Jan 1970 00:00:00 GMT
112
+ Sforce-Limit-Info:
113
+ - api-usage=143/15000
114
+ Content-Type:
115
+ - application/json;charset=UTF-8
116
+ Transfer-Encoding:
117
+ - chunked
118
+ body:
119
+ encoding: ASCII-8BIT
120
+ string: '{"totalSize":3,"done":true,"records":[{"attributes":{"type":"CustomObject__c","url":"/services/data/v26.0/sobjects/CustomObject__c/a001a000001IjCFAA0"},"Id":"a001a000001IjCFAA0","SystemModstamp":"2015-03-24T08:25:04.000+0000","Name":"andrew@tablexi.com","Example_Field__c":null},{"attributes":{"type":"CustomObject__c","url":"/services/data/v26.0/sobjects/CustomObject__c/a001a000001IjP2AAK"},"Id":"a001a000001IjP2AAK","SystemModstamp":"2015-03-24T08:27:33.000+0000","Name":"somebody+new@example.com","Example_Field__c":null},{"attributes":{"type":"CustomObject__c","url":"/services/data/v26.0/sobjects/CustomObject__c/a001a000001IyUhAAK"},"Id":"a001a000001IyUhAAK","SystemModstamp":"2015-03-24T20:01:23.000+0000","Name":"Custom
121
+ object","Example_Field__c":"Some sample text"}]}'
122
+ http_version:
123
+ recorded_at: Tue, 24 Mar 2015 20:01:24 GMT
124
+ - request:
125
+ method: get
126
+ uri: https://<host>/services/data/v26.0/query?q=select%20Id,%20SystemModstamp,%20Name,%20Example_Field__c%20from%20CustomObject__c%20where%20Id%20=%20%27a001a000001IyUhAAK%27
127
+ body:
128
+ encoding: US-ASCII
129
+ string: ''
130
+ headers:
131
+ User-Agent:
132
+ - Faraday v0.9.1
133
+ Authorization:
134
+ - OAuth 00D1a000000H3O9!AQ4AQLW7LvL9F5lVipVJl8BHs21lRfayiAsI3XyWdaLNmdGsBgdOTwyLzmSBrmoKxyILlRDx._h5Oz.OpUoj6pYbfHsCYjrQ
135
+ Accept-Encoding:
136
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
137
+ Accept:
138
+ - "*/*"
139
+ response:
140
+ status:
141
+ code: 200
142
+ message: OK
143
+ headers:
144
+ Date:
145
+ - Tue, 24 Mar 2015 20:01:25 GMT
146
+ Set-Cookie:
147
+ - BrowserId=Vw8J1bAaRYuZY_Jnw1nTIg;Path=/;Domain=.salesforce.com;Expires=Sat,
148
+ 23-May-2015 20:01:25 GMT
149
+ Expires:
150
+ - Thu, 01 Jan 1970 00:00:00 GMT
151
+ Sforce-Limit-Info:
152
+ - api-usage=143/15000
153
+ Content-Type:
154
+ - application/json;charset=UTF-8
155
+ Transfer-Encoding:
156
+ - chunked
157
+ body:
158
+ encoding: ASCII-8BIT
159
+ string: '{"totalSize":1,"done":true,"records":[{"attributes":{"type":"CustomObject__c","url":"/services/data/v26.0/sobjects/CustomObject__c/a001a000001IyUhAAK"},"Id":"a001a000001IyUhAAK","SystemModstamp":"2015-03-24T20:01:23.000+0000","Name":"Custom
160
+ object","Example_Field__c":"Some sample text"}]}'
161
+ http_version:
162
+ recorded_at: Tue, 24 Mar 2015 20:01:25 GMT
163
+ - request:
164
+ method: patch
165
+ uri: https://<host>/services/data/v26.0/sobjects/CustomObject__c/a001a000001IyUhAAK
166
+ body:
167
+ encoding: UTF-8
168
+ string: '{"Name":"Some existing name","Example_Field__c":"Some existing sample
169
+ text"}'
170
+ headers:
171
+ User-Agent:
172
+ - Faraday v0.9.1
173
+ Content-Type:
174
+ - application/json
175
+ Authorization:
176
+ - OAuth 00D1a000000H3O9!AQ4AQLW7LvL9F5lVipVJl8BHs21lRfayiAsI3XyWdaLNmdGsBgdOTwyLzmSBrmoKxyILlRDx._h5Oz.OpUoj6pYbfHsCYjrQ
177
+ Accept-Encoding:
178
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
179
+ Accept:
180
+ - "*/*"
181
+ response:
182
+ status:
183
+ code: 204
184
+ message: No Content
185
+ headers:
186
+ Date:
187
+ - Tue, 24 Mar 2015 20:01:27 GMT
188
+ Set-Cookie:
189
+ - BrowserId=mrm2T-eMR3iEiP-JY4RxEg;Path=/;Domain=.salesforce.com;Expires=Sat,
190
+ 23-May-2015 20:01:27 GMT
191
+ Expires:
192
+ - Thu, 01 Jan 1970 00:00:00 GMT
193
+ Sforce-Limit-Info:
194
+ - api-usage=143/15000
195
+ body:
196
+ encoding: UTF-8
197
+ string: ''
198
+ http_version:
199
+ recorded_at: Tue, 24 Mar 2015 20:01:27 GMT
200
+ - request:
201
+ method: delete
202
+ uri: https://<host>/services/data/v26.0/sobjects/CustomObject__c/a001a000001IyUhAAK
203
+ body:
204
+ encoding: US-ASCII
205
+ string: ''
206
+ headers:
207
+ User-Agent:
208
+ - Faraday v0.9.1
209
+ Authorization:
210
+ - OAuth 00D1a000000H3O9!AQ4AQLW7LvL9F5lVipVJl8BHs21lRfayiAsI3XyWdaLNmdGsBgdOTwyLzmSBrmoKxyILlRDx._h5Oz.OpUoj6pYbfHsCYjrQ
211
+ Accept-Encoding:
212
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
213
+ Accept:
214
+ - "*/*"
215
+ response:
216
+ status:
217
+ code: 204
218
+ message: No Content
219
+ headers:
220
+ Date:
221
+ - Tue, 24 Mar 2015 20:01:28 GMT
222
+ Set-Cookie:
223
+ - BrowserId=xXw1CTnhQK623u5W_v90nw;Path=/;Domain=.salesforce.com;Expires=Sat,
224
+ 23-May-2015 20:01:28 GMT
225
+ Expires:
226
+ - Thu, 01 Jan 1970 00:00:00 GMT
227
+ Sforce-Limit-Info:
228
+ - api-usage=144/15000
229
+ body:
230
+ encoding: UTF-8
231
+ string: ''
232
+ http_version:
233
+ recorded_at: Tue, 24 Mar 2015 20:01:28 GMT
234
+ recorded_with: VCR 2.9.3
@@ -22,6 +22,10 @@ describe Restforce::DB::Instances::ActiveRecord do
22
22
  it "updates the record in Salesforce with the passed attributes" do
23
23
  expect(record.reload.example).to_equal text
24
24
  end
25
+
26
+ it "bumps the record's synchronized_at timestamp" do
27
+ expect(record.reload.synchronized_at).to_not_be_nil
28
+ end
25
29
  end
26
30
 
27
31
  describe "#copy!" do
@@ -10,8 +10,9 @@ describe Restforce::DB::RecordTypes::ActiveRecord do
10
10
 
11
11
  describe "#sync!" do
12
12
  let(:sync_from) do
13
- Struct.new(:id, :attributes).new(
13
+ Struct.new(:id, :last_update, :attributes).new(
14
14
  salesforce_id,
15
+ Time.now,
15
16
  name: "Some name",
16
17
  example: "Some text",
17
18
  )
@@ -28,32 +29,34 @@ describe Restforce::DB::RecordTypes::ActiveRecord do
28
29
  expect(instance.salesforce_id).to_equal salesforce_id
29
30
  expect(instance.name).to_equal sync_from.attributes[:name]
30
31
  expect(instance.example).to_equal sync_from.attributes[:example]
32
+ expect(instance.synchronized_at).to_not_be_nil
31
33
  end
32
34
  end
33
35
 
34
36
  describe "with an existing database record" do
35
- let(:sync_to) do
37
+ let!(:sync_to) do
36
38
  CustomObject.create!(
37
- name: "Existing name",
38
- example: "Existing sample text",
39
- salesforce_id: salesforce_id,
39
+ name: "Existing name",
40
+ example: "Existing sample text",
41
+ salesforce_id: salesforce_id,
42
+ synchronized_at: Time.now,
40
43
  )
41
44
  end
42
45
 
43
- before { sync_to }
44
-
45
46
  it "updates the existing database record" do
46
47
  expect(instance).to_equal sync_to.reload
47
48
  expect(instance.name).to_equal sync_from.attributes[:name]
48
49
  expect(instance.example).to_equal sync_from.attributes[:example]
50
+ expect(instance.synchronized_at).to_not_be_nil
49
51
  end
50
52
  end
51
53
  end
52
54
 
53
55
  describe "#create!" do
54
56
  let(:create_from) do
55
- Struct.new(:id, :attributes).new(
57
+ Struct.new(:id, :last_update, :attributes).new(
56
58
  salesforce_id,
59
+ Time.now,
57
60
  name: "Some name",
58
61
  example: "Some text",
59
62
  )
@@ -68,6 +71,7 @@ describe Restforce::DB::RecordTypes::ActiveRecord do
68
71
  expect(instance.salesforce_id).to_equal salesforce_id
69
72
  expect(instance.name).to_equal create_from.attributes[:name]
70
73
  expect(instance.example).to_equal create_from.attributes[:example]
74
+ expect(instance.synchronized_at).to_not_be_nil
71
75
  end
72
76
  end
73
77
 
@@ -9,6 +9,15 @@ describe Restforce::DB::Synchronizer do
9
9
  let(:salesforce_type) { Restforce::DB::RecordTypes::Salesforce.new("CustomObject__c", mapping) }
10
10
  let(:synchronizer) { Restforce::DB::Synchronizer.new(database_type, salesforce_type) }
11
11
 
12
+ describe "#initialize" do
13
+ before { Restforce::DB.last_run = Time.now }
14
+ after { Restforce::DB.last_run = nil }
15
+
16
+ it "prefills the Synchronizer's last_run timestamp with the global configuration" do
17
+ expect(synchronizer.last_run).to_equal Restforce::DB.last_run
18
+ end
19
+ end
20
+
12
21
  describe "#run", vcr: { match_requests_on: [:method, VCR.request_matchers.uri_without_param(:q)] } do
13
22
  let(:attributes) do
14
23
  {
@@ -57,26 +66,48 @@ describe Restforce::DB::Synchronizer do
57
66
  end
58
67
  end
59
68
 
60
- describe "given a Salesforce record with an existing record in the database" do
69
+ describe "given a Salesforce record with an associated database record" do
70
+ let!(:database_attributes) do
71
+ {
72
+ name: "Some existing name",
73
+ example: "Some existing sample text",
74
+ synchronized_at: Time.now,
75
+ }
76
+ end
61
77
  let(:database_record) do
62
- CustomObject.create!(
63
- name: "Some existing name",
64
- example: "Some existing sample text",
65
- salesforce_id: salesforce_id,
66
- )
78
+ CustomObject.create!(database_attributes.merge(salesforce_id: salesforce_id))
67
79
  end
68
80
 
69
- before do
70
- database_record
71
- salesforce_id
72
- synchronizer.run
81
+ describe "when synchronization is stale" do
82
+ before do
83
+ # Set the synchronization timestamp to 5 seconds before the Salesforce
84
+ # modification timestamp.
85
+ updated = salesforce_type.find(salesforce_id).last_update
86
+ database_record.update!(synchronized_at: updated - 5)
87
+
88
+ synchronizer.run
89
+ end
90
+
91
+ it "updates the database record" do
92
+ record = database_record.reload
93
+
94
+ expect(record.name).to_equal attributes[:name]
95
+ expect(record.example).to_equal attributes[:example]
96
+ end
73
97
  end
74
98
 
75
- it "updates the database record" do
76
- record = database_record.reload
99
+ describe "when synchronization is up-to-date" do
100
+ before do
101
+ database_record.touch(:synchronized_at)
102
+ synchronizer.run
103
+ end
77
104
 
78
- expect(record.name).to_equal attributes[:name]
79
- expect(record.example).to_equal attributes[:example]
105
+ it "does not update the database record" do
106
+ record = database_record.reload
107
+
108
+ expect(record.name).to_equal database_attributes[:name]
109
+ expect(record.example).to_equal database_attributes[:example]
110
+ end
80
111
  end
81
112
  end
82
113
 
@@ -0,0 +1,50 @@
1
+ require_relative "../../../test_helper"
2
+
3
+ describe Restforce::DB::Tracker do
4
+ let(:file) { Tempfile.new(".restforce-db") }
5
+ let(:tracker) { Restforce::DB::Tracker.new(file.path) }
6
+ let(:runtime) { Time.now }
7
+
8
+ after { Restforce::DB.last_run = nil }
9
+
10
+ describe "#initialize" do
11
+
12
+ describe "when no timestamp has been recorded" do
13
+ before { tracker }
14
+
15
+ it "does not initialize Restforce::DB.last_run" do
16
+ expect(Restforce::DB.last_run).to_be_nil
17
+ end
18
+ end
19
+
20
+ describe "when a timestamp has been recorded in the file" do
21
+ before do
22
+ file.print runtime.iso8601
23
+ file.rewind
24
+
25
+ tracker
26
+ end
27
+
28
+ it "initializes Restforce::DB.last_run to the recorded time" do
29
+ expect(Restforce::DB.last_run.to_i).to_equal runtime.to_i
30
+ end
31
+
32
+ it "initializes the tracker's last_run to the recorded time" do
33
+ expect(tracker.last_run.to_i).to_equal runtime.to_i
34
+ end
35
+ end
36
+ end
37
+
38
+ describe "#track" do
39
+ before { tracker.track runtime }
40
+
41
+ it "records the supplied timestamp in the file" do
42
+ expect(file.read).to_equal runtime.iso8601
43
+ end
44
+
45
+ it "updates the tracker's last_run to the recorded time" do
46
+ expect(tracker.last_run.to_i).to_equal runtime.to_i
47
+ end
48
+ end
49
+
50
+ end
@@ -8,9 +8,10 @@ ActiveRecord::Base.establish_connection(
8
8
 
9
9
  ActiveRecord::Schema.define do
10
10
  create_table :custom_objects do |table|
11
- table.column :name, :string
12
- table.column :example, :string
13
- table.column :salesforce_id, :string
11
+ table.column :name, :string
12
+ table.column :example, :string
13
+ table.column :salesforce_id, :string
14
+ table.column :synchronized_at, :datetime
14
15
  table.timestamps null: false
15
16
  end
16
17