vayacondios-server 0.1.12 → 0.2.1

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