vayacondios-server 0.1.12 → 0.2.1

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.
data/Rakefile CHANGED
@@ -1,5 +1,9 @@
1
+ # -*- ruby -*-
2
+
1
3
  require 'bundler' ; Bundler.setup
2
4
 
5
+ require 'configliere'
6
+
3
7
  # App-specific tasks
4
8
  Dir[File.dirname(__FILE__)+'/lib/tasks/**/*.rake'].sort.each{|f| load f }
5
9
 
@@ -2,3 +2,6 @@ mongo:
2
2
  host: localhost
3
3
  port: 27017
4
4
  database: vayacondios_dev
5
+
6
+ vayacondios:
7
+ legacy: false
@@ -2,3 +2,6 @@ mongo:
2
2
  host: localhost
3
3
  port: 27017
4
4
  database: vayacondios_dev
5
+
6
+ vayacondios:
7
+ legacy: false
data/lib/tasks/spec.rake CHANGED
@@ -1,3 +1,5 @@
1
+ # -*- ruby -*-
2
+
1
3
  require 'rspec/core/rake_task'
2
4
 
3
5
  RSpec::Core::RakeTask.new
@@ -0,0 +1,38 @@
1
+ class Vayacondios
2
+ # Are we operating on JSON Hashes (Vayacondios) or on JSON arrays
3
+ # (Vayacondios Legacy)? These classes determine which to use.
4
+
5
+ class StandardContentsHandler
6
+ def wrap_contents(contents) {contents: contents} end
7
+ def extract_contents(document) document['contents'] end
8
+ def proper_request(document)
9
+ result = document.is_a?(Hash) and document.fetch('_json', {}).is_a?(Hash)
10
+ result
11
+ end
12
+ end
13
+
14
+ class LegacyContentsHandler
15
+ def wrap_contents(contents) contents end
16
+ def extract_contents(document) document.fetch('_json', {}) end
17
+ def proper_request(document)
18
+ result = document.is_a?(Array) or document.fetch('_json', {}).is_a?(Array)
19
+ puts "proper legacy request? #{document.inspect}: #{result.inspect}"
20
+ result
21
+ end
22
+ end
23
+
24
+ def self.legacy_switch
25
+ @@legacy_switch ||= get_legacy_switch(Settings[:vayacondios][:legacy])
26
+ end
27
+
28
+ def self.force_legacy_mode on
29
+ @@legacy_switch = get_legacy_switch on
30
+ end
31
+
32
+ private
33
+
34
+ def self.get_legacy_switch on
35
+ (on ? LegacyContentsHandler : StandardContentsHandler).new
36
+ end
37
+ end
38
+
@@ -1,4 +1,5 @@
1
1
  require 'vayacondios/server/model/document'
2
+ require 'vayacondios/legacy_switch'
2
3
 
3
4
  # The configuration model
4
5
  #
@@ -21,6 +22,8 @@ class Vayacondios::ItemsetDocument < Vayacondios::Document
21
22
  @body = nil
22
23
  @mongo = mongodb
23
24
 
25
+ @handler = Vayacondios.legacy_switch
26
+
24
27
  collection_name = [organization.to_s, topic, 'itemset'].join('.')
25
28
  @collection = @mongo.collection(collection_name)
26
29
  end
@@ -34,7 +37,7 @@ class Vayacondios::ItemsetDocument < Vayacondios::Document
34
37
  end
35
38
 
36
39
  def body
37
- {contents: @body}
40
+ @handler.wrap_contents(@body)
38
41
  end
39
42
 
40
43
  def find
@@ -50,9 +53,9 @@ class Vayacondios::ItemsetDocument < Vayacondios::Document
50
53
  end
51
54
 
52
55
  def update(document)
53
- raise Vayacondios::Error::BadRequest.new unless document.is_a?(Hash)
56
+ raise Vayacondios::Error::BadRequest.new unless @handler.proper_request(document)
54
57
 
55
- @body = document['contents']
58
+ @body = extract_contents(document)
56
59
 
57
60
 
58
61
  @collection.update({:_id => @id}, {:_id => @id, 'd' => @body }, {upsert: true})
@@ -61,19 +64,19 @@ class Vayacondios::ItemsetDocument < Vayacondios::Document
61
64
  end
62
65
 
63
66
  def patch(document)
64
- raise Vayacondios::Error::BadRequest.new unless document.is_a?(Hash)
67
+ raise Vayacondios::Error::BadRequest.new unless @handler.proper_request(document)
65
68
 
66
69
  # Merge ourselves
67
70
  if @body
68
- @body = @body + document['contents']
71
+ @body = @body + extract_contents(document)
69
72
  else
70
- @body = document['contents']
73
+ @body = extract_contents(document)
71
74
  end
72
75
 
73
76
  @collection.update({:_id => @id}, {
74
77
  '$addToSet' => {
75
78
  'd' => {
76
- '$each'=> document['contents']
79
+ '$each'=> extract_contents(document)
77
80
  }
78
81
  }
79
82
  }, {upsert: true})
@@ -82,13 +85,13 @@ class Vayacondios::ItemsetDocument < Vayacondios::Document
82
85
  end
83
86
 
84
87
  def destroy(document)
85
- raise Vayacondios::Error::BadRequest.new unless document.is_a?(Hash)
88
+ raise Vayacondios::Error::BadRequest.new unless @handler.proper_request(document)
86
89
 
87
- @body -= document['contents']
90
+ @body -= extract_contents(document)
88
91
 
89
92
  @collection.update({:_id => @id}, {
90
93
  '$pullAll' => {
91
- 'd' => document['contents']
94
+ 'd' => extract_contents(document)
92
95
  }
93
96
  })
94
97
 
@@ -97,6 +100,11 @@ class Vayacondios::ItemsetDocument < Vayacondios::Document
97
100
 
98
101
  protected
99
102
 
103
+ def extract_contents(document)
104
+ puts "doc = #{document}. contents = #{result = @handler.extract_contents(document)}"
105
+ result
106
+ end
107
+
100
108
  def sanitize_options(options)
101
109
  options = options.symbolize_keys
102
110
 
@@ -1,3 +1,3 @@
1
1
  class Vayacondios
2
- VERSION = '0.1.12'
2
+ VERSION = '0.2.1'
3
3
  end
data/pom.xml CHANGED
@@ -4,7 +4,7 @@
4
4
  <groupId>com.infochimps</groupId>
5
5
  <artifactId>vayacondios</artifactId>
6
6
  <packaging>jar</packaging>
7
- <version>1.0.1-SNAPSHOT</version>
7
+ <version>1.0.2-SNAPSHOT</version>
8
8
  <name>java-common</name>
9
9
  <url>http://maven.apache.org</url>
10
10
 
@@ -14,6 +14,10 @@
14
14
  <version>1.0.0-SNAPSHOT</version>
15
15
  </parent>
16
16
 
17
+ <properties>
18
+ <test.logLevel>info</test.logLevel>
19
+ </properties>
20
+
17
21
  <reporting>
18
22
  <plugins>
19
23
  <plugin>
@@ -63,6 +67,16 @@
63
67
  </arguments>
64
68
  </configuration>
65
69
  </plugin>
70
+ <plugin>
71
+ <groupId>org.apache.maven.plugins</groupId>
72
+ <artifactId>maven-surefire-plugin</artifactId>
73
+ <version>2.14.1</version>
74
+ <configuration>
75
+ <systemPropertyVariables>
76
+ <org.slf4j.simpleLogger.defaultLogLevel>${test.logLevel}</org.slf4j.simpleLogger.defaultLogLevel>
77
+ </systemPropertyVariables>
78
+ </configuration>
79
+ </plugin>
66
80
  </plugins>
67
81
  </build>
68
82
 
@@ -100,10 +114,16 @@
100
114
  <artifactId>slf4j-api</artifactId>
101
115
  <version>1.7.2</version>
102
116
  </dependency>
117
+ <dependency>
118
+ <groupId>org.slf4j</groupId>
119
+ <artifactId>slf4j-simple</artifactId>
120
+ <version>1.7.2</version>
121
+ <scope>test</scope>
122
+ </dependency>
103
123
  <dependency>
104
124
  <groupId>junit</groupId>
105
125
  <artifactId>junit</artifactId>
106
- <version>3.8.1</version>
126
+ <version>4.10</version>
107
127
  <scope>test</scope>
108
128
  </dependency>
109
129
  </dependencies>
@@ -0,0 +1,320 @@
1
+ require 'spec_helper'
2
+
3
+ require 'multi_json'
4
+
5
+ require File.join(File.dirname(__FILE__), '../../', 'app/http_shim')
6
+
7
+ describe HttpShim do
8
+ include Goliath::TestHelper
9
+
10
+ let(:err) { Proc.new{ |c| fail "HTTP Request Failed #{c.response}" } }
11
+
12
+ context 'Basic requirements' do
13
+ it 'requires a topic' do
14
+ Vayacondios.force_legacy_mode(true)
15
+ with_api(HttpShim) do |api|
16
+ put_request({
17
+ :path => '/v1/infochimps/itemset/',
18
+ :body => MultiJson.dump(["foo"]),
19
+ :head => { :content_type => 'application/json' }
20
+ }, err) do |c|
21
+ c.response_header.status.should == 400
22
+ end
23
+ end
24
+ end
25
+
26
+ it 'requires an id' do
27
+ with_api(HttpShim) do |api|
28
+ put_request({
29
+ :path => '/v1/infochimps/itemset/power',
30
+ :body => MultiJson.dump(["foo"]),
31
+ :head => { :content_type => 'application/json' }
32
+ }, err) do |c|
33
+ c.response_header.status.should == 400
34
+ end
35
+
36
+ get_mongo_db do |db|
37
+ db.collection("infochimps.power.itemset").find_one().should be_nil
38
+ end
39
+ end
40
+ end
41
+
42
+ it 'rejects deep IDs' do
43
+ with_api(HttpShim) do |api|
44
+ put_request({
45
+ :path => '/v1/infochimps/itemset/power/level/is/invalid',
46
+ :body => MultiJson.dump(["foo"]),
47
+ :head => { :content_type => 'application/json' }
48
+ }, err) do |c|
49
+ c.response_header.status.should == 400
50
+ end
51
+
52
+ get_mongo_db do |db|
53
+ db.collection("infochimps.power.itemset").find_one({:_id => "level"}).should be_nil
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+
60
+ context 'can handle GET requests' do
61
+ Vayacondios.force_legacy_mode(true)
62
+
63
+ it 'and return 404 for missing resources' do
64
+ with_api(HttpShim) do |api|
65
+ Vayacondios.force_legacy_mode(true)
66
+
67
+ get_request({:path => '/v1/infochimps/itemset/missing/resource'}, err) do |c|
68
+ c.response_header.status.should == 404
69
+ end
70
+ end
71
+ end
72
+
73
+ it 'and return an array for valid resources' do
74
+
75
+ with_api(HttpShim) do |api|
76
+ put_request({
77
+ :path => '/v1/infochimps/itemset/power/level',
78
+ :body => MultiJson.dump(["foo", "bar"]),
79
+ :head => { :content_type => 'application/json' }
80
+ }, err)
81
+ end
82
+ with_api(HttpShim) do |api|
83
+ get_request({:path => '/v1/infochimps/itemset/power/level'}, err) do |c|
84
+ c.response_header.status.should == 200
85
+ MultiJson.load(c.response).should eql(["foo", "bar"])
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ context "will not handle POST requests" do
92
+ it 'fails on POST' do
93
+ with_api(HttpShim) do |api|
94
+ post_request({
95
+ :path => '/v1/infochimps/itemset/post/unsupported',
96
+ :body => MultiJson.dump({ :totally => :ignored }),
97
+ :head => { :content_type => 'application/json' }
98
+ }, err) do |c|
99
+ c.response_header.status.should eql 405
100
+ c.response_header["ALLOW"].should_not be_nil
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ context 'handles PUT requests in legacy mode' do
107
+ Vayacondios.force_legacy_mode(true)
108
+ it 'only accepts arrays' do
109
+ with_api(HttpShim) do |api|
110
+ put_request({
111
+ :path => '/v1/infochimps/itemset/power/level',
112
+ :body => MultiJson.dump({'foo' => 'bar'}),
113
+ :head => { :content_type => 'application/json' }
114
+ }, err) do |c|
115
+ c.response_header.status.should == 400 # geometrid: changed from 500
116
+ end
117
+
118
+ get_mongo_db do |db|
119
+ db.collection("infochimps.itemset").find_one({:_id => "power"}).should be_nil
120
+ end
121
+ end
122
+ with_api(HttpShim) do |api|
123
+ put_request({
124
+ :path => '/v1/infochimps/itemset/power/level',
125
+ :body => "foo",
126
+ :head => { :content_type => 'application/json' }
127
+ }, err) do |c|
128
+ c.response_header.status.should == 400
129
+ end
130
+
131
+ get_mongo_db do |db|
132
+ db.collection("infochimps.itemset").find_one({:_id => "power"}).should be_nil
133
+ end
134
+ end
135
+ end
136
+ it "stores the array when the resource doesn't exist" do
137
+ with_api(HttpShim) do |api|
138
+ put_request({
139
+ :path => '/v1/infochimps/itemset/power/level',
140
+ :body => MultiJson.dump(["foo", "bar"]),
141
+ :head => { :content_type => 'application/json' }
142
+ }, err) do |c|
143
+ c.response_header.status.should == 200 # TODO Make this 201 Created
144
+ c.response.should eql ""
145
+ end
146
+
147
+ get_mongo_db do |db|
148
+ db.collection("infochimps.power.itemset").find_one({:_id => "level"})["d"].should eql ["foo", "bar"]
149
+ end
150
+ end
151
+ end
152
+ it "clobbers the previous array when the resource does exist" do
153
+ with_api(HttpShim) do |api|
154
+ put_request({
155
+ :path => '/v1/infochimps/itemset/power/level',
156
+ :body => MultiJson.dump(["chimpanzee", "bonobo"]),
157
+ :head => { :content_type => 'application/json' }
158
+ }, err) do |c|
159
+ c.response_header.status.should == 200 # TODO Make this 204 No content
160
+ c.response.should eql ""
161
+ end
162
+ end
163
+
164
+ # Verify the first was created
165
+ get_mongo_db do |db|
166
+ db.collection("infochimps.power.itemset").find_one({:_id => "level"})["d"].should eql ["chimpanzee", "bonobo"]
167
+ end
168
+
169
+ with_api(HttpShim) do |api|
170
+ put_request({
171
+ :path => '/v1/infochimps/itemset/power/level',
172
+ :body => MultiJson.dump(["foo", "bar"]),
173
+ :head => { :content_type => 'application/json' }
174
+ }, err) do |c|
175
+ c.response_header.status.should == 200
176
+ c.response.should eql ""
177
+ end
178
+
179
+ # Verify the first was clobbered
180
+ get_mongo_db do |db|
181
+ db.collection("infochimps.power.itemset").find_one({:_id => "level"})["d"].should eql ["foo", "bar"]
182
+ end
183
+ end
184
+ end
185
+ end
186
+
187
+ context "handles PATCH requests in legacy mode" do
188
+ Vayacondios.force_legacy_mode(true)
189
+ it 'creates a missing resource' do
190
+ with_api(HttpShim) do |api|
191
+ put_request({
192
+ :path => '/v1/infochimps/itemset/power/level',
193
+ :head => ({'X-Method' => 'PATCH', :content_type => 'application/json' }),
194
+ :body => MultiJson.dump(["bar"])
195
+ }, err) do |c|
196
+ c.response_header.status.should eql 200 # TODO Make this 201 Created
197
+ c.response.should eql ""
198
+ end
199
+
200
+ # Verify the resource was created
201
+ get_mongo_db do |db|
202
+ db.collection("infochimps.power.itemset").find_one({:_id => "level"})["d"].should eql ["bar"]
203
+ end
204
+ end
205
+ end
206
+
207
+ it 'merges with PATCH' do
208
+ with_api(HttpShim) do |api|
209
+ put_request({
210
+ :path => '/v1/infochimps/itemset/merge/test',
211
+ :body => MultiJson.dump(["foo"]),
212
+ :head => { :content_type => 'application/json' }
213
+ }, err)
214
+ end
215
+ with_api(HttpShim) do |api|
216
+ put_request({
217
+ :path => '/v1/infochimps/itemset/merge/test',
218
+ :head => ({'X-Method' => 'PATCH', :content_type => 'application/json' }),
219
+ :body => MultiJson.dump(["bar"])
220
+ }, err)
221
+ end
222
+ with_api(HttpShim) do |api|
223
+ get_request({:path => '/v1/infochimps/itemset/merge/test'}, err) do |c|
224
+ c.response_header.status.should == 200
225
+ MultiJson.load(c.response).should eql(["foo", "bar"])
226
+ end
227
+ end
228
+ end
229
+ end
230
+
231
+ context "will handle DELETE requests in legacy mode" do
232
+ Vayacondios.force_legacy_mode(true)
233
+ it 'will not delete a missing resource' do
234
+ with_api(HttpShim) do |api|
235
+ delete_request({
236
+ :path => '/v1/infochimps/itemset/merge/test',
237
+ :body => MultiJson.dump(["bar"]),
238
+ :head => { :content_type => 'application/json' }
239
+ }, err) do |c|
240
+ c.response_header.status.should == 404
241
+ end
242
+ end
243
+ end
244
+
245
+ it "will be ok to delete items that don't exist" do
246
+ with_api(HttpShim) do |api|
247
+ put_request({
248
+ :path => '/v1/infochimps/itemset/power/level',
249
+ :body => MultiJson.dump(["foo"]),
250
+ :head => { :content_type => 'application/json' }
251
+ }, err) do |c|
252
+ c.response_header.status.should == 200 # TODO Make this 201 Created
253
+ end
254
+ end
255
+ with_api(HttpShim) do |api|
256
+ delete_request({
257
+ :path => '/v1/infochimps/itemset/power/level',
258
+ :body => MultiJson.dump(["bar"]),
259
+ :head => { :content_type => 'application/json' }
260
+ }, err) do |c|
261
+ c.response_header.status.should == 200 # TODO Make this 204 No content
262
+ end
263
+ end
264
+ end
265
+
266
+ it "will delete items that do exist" do
267
+ with_api(HttpShim) do |api|
268
+ put_request({
269
+ :path => '/v1/infochimps/itemset/power/level',
270
+ :body => MultiJson.dump(["foo", "bar"]),
271
+ :head => { :content_type => 'application/json' }
272
+ }, err) do |c|
273
+ c.response_header.status.should == 200 # TODO Makes this 201 Created
274
+ end
275
+ end
276
+ with_api(HttpShim) do |api|
277
+ delete_request({
278
+ :path => '/v1/infochimps/itemset/power/level',
279
+ :body => MultiJson.dump(["bar"]),
280
+ :head => { :content_type => 'application/json' }
281
+ }, err) do |c|
282
+ c.response_header.status.should == 200 # TODO Make this 204 No content
283
+ end
284
+ end
285
+ with_api(HttpShim) do |api|
286
+ get_request({:path => '/v1/infochimps/itemset/power/level'}, err) do |c|
287
+ c.response_header.status.should == 200
288
+ MultiJson.load(c.response).should eql(["foo"])
289
+ end
290
+ end
291
+ end
292
+
293
+ it "leaves behind an empty array if everything is deleted" do
294
+ with_api(HttpShim) do |api|
295
+ put_request({
296
+ :path => '/v1/infochimps/itemset/power/level',
297
+ :body => MultiJson.dump(["foo", "bar"]),
298
+ :head => { :content_type => 'application/json' }
299
+ }, err) do |c|
300
+ c.response_header.status.should == 200 # TODO Makes this 201 Created
301
+ end
302
+ end
303
+ with_api(HttpShim) do |api|
304
+ delete_request({
305
+ :path => '/v1/infochimps/itemset/power/level',
306
+ :body => MultiJson.dump(["foo", "bar"]),
307
+ :head => { :content_type => 'application/json' }
308
+ }, err) do |c|
309
+ c.response_header.status.should == 200 # TODO Make this 204 No content
310
+ end
311
+ end
312
+ with_api(HttpShim) do |api|
313
+ get_request({:path => '/v1/infochimps/itemset/power/level'}, err) do |c|
314
+ c.response_header.status.should == 200
315
+ MultiJson.load(c.response).should eql([])
316
+ end
317
+ end
318
+ end
319
+ end
320
+ end
@@ -47,25 +47,29 @@ describe HttpShim do
47
47
  }, err) do |c|
48
48
  c.response_header.status.should == 400
49
49
  end
50
-
50
+
51
51
  get_mongo_db do |db|
52
52
  db.collection("infochimps.power.itemset").find_one({:_id => "level"}).should be_nil
53
53
  end
54
54
  end
55
55
  end
56
56
  end
57
-
57
+
58
58
  context 'handles PUT requests' do
59
59
  it 'only accepts hashes' do
60
+ # note: due to unknown class variable handling by rspec,
61
+ # force_legacy_mode must be set inside the it block to
62
+ # get all tests to pass at once
63
+ Vayacondios.force_legacy_mode(false)
60
64
  with_api(HttpShim) do |api|
61
65
  put_request({
62
66
  :path => '/v1/infochimps/itemset/power/level',
63
67
  :body => MultiJson.dump(['foo', 'bar']),
64
68
  :head => { :content_type => 'application/json' }
65
69
  }, err) do |c|
66
- c.response_header.status.should == 500
70
+ c.response_header.status.should == 400 # geometrid: changed from 500
67
71
  end
68
-
72
+
69
73
  get_mongo_db do |db|
70
74
  db.collection("infochimps.itemset").find_one({:_id => "power"}).should be_nil
71
75
  end
@@ -177,8 +181,8 @@ describe HttpShim do
177
181
  end
178
182
  end
179
183
  end
180
-
181
- context "handles PATCH requests" do
184
+
185
+ context "handles PATCH requests" do
182
186
  it 'creates a missing resource' do
183
187
  with_api(HttpShim) do |api|
184
188
  put_request({
@@ -222,6 +226,7 @@ describe HttpShim do
222
226
  end
223
227
 
224
228
  context "will handle DELETE requests" do
229
+ Vayacondios.force_legacy_mode(false)
225
230
  it 'will not delete a missing resource' do
226
231
  with_api(HttpShim) do |api|
227
232
  delete_request({
@@ -17,22 +17,22 @@ import java.net.Proxy;
17
17
 
18
18
  public class DebugUtil {
19
19
  public static Proxy useCharles() {
20
- trustAllCerts();
21
- return new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 8888));
20
+ trustAllCerts();
21
+ return new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 8888));
22
22
  }
23
23
 
24
24
  public static void trustAllCerts() {
25
- try {
26
- SSLContext sc = SSLContext.getInstance("SSL");
27
- sc.init(null,
28
- new TrustManager[] {
29
- new X509TrustManager() {
30
- public X509Certificate[] getAcceptedIssuers() { return null;}
31
- public void checkClientTrusted(X509Certificate[] certs, String authType) {}
32
- public void checkServerTrusted(X509Certificate[] certs, String authType) {}
33
- }
34
- }, new SecureRandom());
35
- HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
36
- } catch (GeneralSecurityException e) {}
25
+ try {
26
+ SSLContext sc = SSLContext.getInstance("SSL");
27
+ sc.init(null,
28
+ new TrustManager[] {
29
+ new X509TrustManager() {
30
+ public X509Certificate[] getAcceptedIssuers() { return null;}
31
+ public void checkClientTrusted(X509Certificate[] certs, String authType) {}
32
+ public void checkServerTrusted(X509Certificate[] certs, String authType) {}
33
+ }
34
+ }, new SecureRandom());
35
+ HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
36
+ } catch (GeneralSecurityException e) {}
37
37
  }
38
38
  }