vayacondios-server 0.0.11 → 0.1.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/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/Gemfile CHANGED
@@ -2,3 +2,10 @@ source 'http://rubygems.org'
2
2
 
3
3
  gemspec name: 'vayacondios-server'
4
4
  gemspec name: 'vayacondios-client'
5
+
6
+ group :hadoop_monitor do
7
+ gem 'mongo'
8
+ gem 'bson_ext'
9
+ gem 'gorillib', require: 'gorillib/hash/slice'
10
+ gem 'json'
11
+ end
data/Procfile CHANGED
@@ -1,2 +1,2 @@
1
- listener: ./app/http_shim.rb -sv -p 8000 -c $PWD/config/http_shim.rb
1
+ listener: bundle exec ./app/http_shim.rb -sv -p 8000 -c $PWD/config/http_shim.rb
2
2
  mongod: mongod
data/app/http_shim.rb CHANGED
@@ -1,98 +1,53 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'vayacondios-server'
4
- require 'multi_json'
5
4
 
6
5
  class HttpShim < Goliath::API
7
- use Goliath::Rack::Tracer, 'X-Tracer' # log trace statistics
8
- use Goliath::Rack::DefaultMimeType # cleanup accepted media types
9
- use Goliath::Rack::Formatters::JSON # JSON output formatter
10
- use Goliath::Rack::Render # auto-negotiate response format
11
- use Goliath::Rack::Heartbeat # respond to /status with 200, OK (monitoring, etc)
6
+ use Goliath::Rack::Tracer, 'X-Tracer' # log trace statistics
7
+ # /v1/infochimps/itemset/foo/1 -d '["foo","bar","baz"]'
8
+ # use Vayacondios::Rack::Versionator
9
+ # /v1/infochimps/itemset/foo/1 -d '{"items":["foo","bar","baz"]}' ... env[:vayacondios_version] = 1
10
+ # post_process()
11
+ # extract results = results[:results] from body for legacy
12
+ use Goliath::Rack::Params # parse query string and message body into params hash
13
+ use Goliath::Rack::Validation::RequestMethod, %w[GET PUT PATCH DELETE] # only allow these methods
14
+ use Vayacondios::Rack::ExtractMethods # interpolate GET, PUT into :create, :update, etc
15
+ use Vayacondios::Rack::Path # parse path into parameterized pieces
16
+ use Vayacondios::Rack::PathValidation # validate the existence of env[:vayacondios_path]
17
+ use Goliath::Rack::Formatters::JSON # JSON output formatter
18
+ use Goliath::Rack::Render # auto-negotiate response format
19
+ use Goliath::Rack::Heartbeat # respond to /status with 200, OK (monitoring, etc)
12
20
 
13
21
  def response(env)
14
- # Validate path_params
15
- path_params = parse_path(env[Goliath::Request::REQUEST_PATH])
16
- return [400, {}, MultiJson.dump({error: "Bad Request"})] if !path_params.present? || method_name(env).nil?
17
-
18
- # TODO refactor a middlware
19
- # Decode the document body
20
- body = nil
21
- begin
22
- if env['rack.input']
23
- body = env['rack.input'].read
24
- body = MultiJson.decode(body) if !body.blank?
25
- env['rack.input'].rewind
26
- end
27
- rescue MultiJson::DecodeError => ex
28
- return [400, {}, MultiJson.dump({error: "Bad Request"})]
29
- end
30
- # Look up handler using inflection
22
+ path_params = env[:vayacondios_path]
31
23
  klass = ('vayacondios/' + path_params[:type] + '_handler').camelize.constantize
32
24
 
33
25
  begin
34
- case method_name(env)
35
-
26
+ case env[:vayacondios_method]
27
+
36
28
  when :show
37
29
  record = klass.find(mongo, path_params)
38
30
  [200, {}, MultiJson.dump(record.body)]
39
31
 
40
32
  when :update
41
- record = klass.new(mongo).update(body, path_params)
33
+ record = klass.new(mongo).update(env['params'], path_params)
42
34
  [200, {}, nil]
43
35
 
44
36
  when :patch
45
- record = klass.new(mongo).patch(body, path_params)
37
+ record = klass.new(mongo).patch(env['params'], path_params)
46
38
  [200, {}, nil]
47
39
 
48
40
  when :delete
49
- record = klass.find(mongo, path_params).destroy(body)
41
+ record = klass.find(mongo, path_params).destroy(env['params'])
50
42
  [200, {}, MultiJson.dump(record.body)]
51
-
52
- when :create
53
- return [405, ({'Allow' => "GET PUT PATCH DELETE"}), nil]
54
43
  end
55
44
  rescue Vayacondios::Error::NotFound => ex
56
- return [404, {}, MultiJson.dump({error: "Not Found"})]
45
+ return [404, {}, MultiJson.dump({ error: "Not Found" })]
57
46
  rescue Vayacondios::Error::BadRequest => ex
58
- return [400, {}, MultiJson.dump({error: "Bad Request"})]
47
+ return [400, {}, MultiJson.dump({ error: "Bad Request" })]
59
48
  rescue StandardError => ex
60
49
  puts ex
61
- ex.backtrace.each{|l| puts l}
62
- end
63
- end
64
-
65
- private
66
-
67
- # Determine the organization, type of action (config or event), the topic,
68
- # id, and format for the request.
69
- def parse_path path
70
- path_regex = /^\/v1\/(?<organization>[a-z]\w+)\/(?<type>config|event|itemset)(\/(?<topic>\w+)(\/(?<id>(\w+\/?)+))?)?(\/|\.(?<format>json))?$/i
71
- if (match = path_regex.match(path))
72
- {}.tap do |segments|
73
- match.names.each do |segment|
74
- segments[segment.to_sym] = match[segment]
75
- end
76
- end
77
- end
78
- end
79
-
80
- def method_name env
81
- case env['REQUEST_METHOD'].upcase
82
- when "GET"
83
- :show
84
- when "PUT"
85
- if env['HTTP_X_METHOD'] && env['HTTP_X_METHOD'].upcase == 'PATCH'
86
- :patch
87
- else
88
- :update
89
- end
90
- when "POST"
91
- :create
92
- when "PATCH"
93
- :patch
94
- when "DELETE"
95
- :delete
50
+ ex.backtrace.each{ |l| puts l }
96
51
  end
97
52
  end
98
53
  end
@@ -1,10 +1,10 @@
1
1
  class Vayacondios
2
2
  class HttpClient
3
- include Gorillib::Builder
3
+ include Gorillib::Model
4
4
 
5
- field :host, String, :default => 'localhost'
6
- field :port, Integer, :default => 8000
7
- field :organization, String, :default => 'infochimps'
5
+ field :host, String, :default => 'localhost'
6
+ field :port, String, :default => '8000'
7
+ field :organization, String, :default => 'infochimps'
8
8
 
9
9
  class Error < StandardError; end
10
10
 
@@ -20,6 +20,11 @@ class Vayacondios
20
20
  end
21
21
  end
22
22
 
23
+ class NullNotifier < Notifier
24
+ def notify topic, cargo={}
25
+ end
26
+ end
27
+
23
28
  class LogNotifier < Notifier
24
29
 
25
30
  def initialize(options = {})
@@ -53,27 +58,36 @@ class Vayacondios
53
58
  def self.receive(attrs = {})
54
59
  type = attrs.delete(:type)
55
60
  case type
56
- when 'http' then HttpNotifier.new(attrs)
57
- when 'log' then LogNotifier.new(attrs)
61
+ when 'http' then HttpNotifier.new(attrs)
62
+ when 'log' then LogNotifier.new(attrs)
63
+ when 'none','null' then NullNotifier.new(attrs)
58
64
  else
59
65
  raise ArgumentError, "<#{type}> is not a valid build option"
60
66
  end
61
67
  end
62
68
  end
63
69
 
64
- def self.default_notifier() NotifierFactory.receive(type: 'http') ; end
70
+ def self.default_notifier(log = nil) NotifierFactory.receive(type: 'log', log: log) ; end
65
71
 
66
72
  module Notifications
67
- extend Gorillib::Concern
68
- include Gorillib::Configurable
69
73
 
70
74
  def notify(topic, cargo = {})
71
75
  notifier.notify(topic, cargo)
72
76
  end
73
77
 
74
- included do
75
- class_eval do
76
- config(:notifier, Vayacondios::NotifierFactory, default: Vayacondios.default_notifier)
78
+ def self.included klass
79
+ if klass.ancestors.include? Gorillib::Model
80
+ klass.class_eval do
81
+ field :notifier, Vayacondios::NotifierFactory, default: Vayacondios.default_notifier
82
+
83
+ def receive_notifier params
84
+ params.merge!(log: try(:log)) if params[:type] == 'log'
85
+ @notifier = Vayacondios::NotifierFactory.receive(params)
86
+ end
87
+ end
88
+ else
89
+ klass.class_attribute :notifier
90
+ klass.notifier = Vayacondios.default_notifier try(:log)
77
91
  end
78
92
  end
79
93
 
@@ -12,8 +12,8 @@ class Vayacondios
12
12
  end
13
13
 
14
14
  def update(document, options={})
15
- raise Error::BadRequest.new unless options[:topic] && options[:id]
16
- raise Error::BadRequest.new if /\W/ =~ options[:id]
15
+ raise Vayacondios::Error::BadRequest.new unless options[:topic] && options[:id]
16
+ raise Vayacondios::Error::BadRequest.new if /\W/ =~ options[:id]
17
17
 
18
18
  existing_document = ConfigDocument.find(@mongo, options)
19
19
  if existing_document
@@ -25,8 +25,8 @@ class Vayacondios
25
25
 
26
26
  def self.find(mongodb, options)
27
27
  existing_document = ConfigDocument.find(mongodb, options)
28
- raise Error::NotFound.new unless existing_document
28
+ raise Vayacondios::Error::NotFound.new unless existing_document
29
29
  existing_document
30
30
  end
31
31
  end
32
- end
32
+ end
@@ -48,7 +48,7 @@ class Vayacondios::ConfigDocument < Vayacondios::Document
48
48
  end
49
49
 
50
50
  def update(document)
51
- raise Error::BadRequest.new if !document.is_a?(Hash)
51
+ raise Vayacondios::Error::BadRequest.new if !document.is_a?(Hash)
52
52
 
53
53
  # Merge ourselves
54
54
  document = body.deep_merge(document) if body
@@ -39,20 +39,17 @@ class Vayacondios::ItemsetDocument < Vayacondios::Document
39
39
  if result
40
40
  result.delete("_id")
41
41
  @body = result["d"]
42
- self
42
+ self
43
43
  else
44
44
  nil
45
45
  end
46
46
  end
47
47
 
48
48
  def update(document)
49
- if !document.is_a?(Array)
50
- puts "not an array: #{document}"
51
- end
49
+ raise Vayacondios::Error::BadRequest.new unless document.is_a?(Hash)
52
50
 
53
- raise Vayacondios::Error::BadRequest.new if !document.is_a?(Array)
51
+ @body = document['contents'] # should be items
54
52
 
55
- @body = document
56
53
 
57
54
  @collection.update({:_id => @id}, {:_id => @id, 'd' => @body }, {upsert: true})
58
55
 
@@ -60,19 +57,19 @@ class Vayacondios::ItemsetDocument < Vayacondios::Document
60
57
  end
61
58
 
62
59
  def patch(document)
63
- raise Vayacondios::Error::BadRequest.new if !document.is_a?(Array)
60
+ raise Vayacondios::Error::BadRequest.new unless document.is_a?(Hash)
64
61
 
65
62
  # Merge ourselves
66
63
  if @body
67
- @body = body + document
64
+ @body = body + document['contents']
68
65
  else
69
- @body = document
66
+ @body = document['contents']
70
67
  end
71
68
 
72
69
  @collection.update({:_id => @id}, {
73
70
  '$addToSet' => {
74
71
  'd' => {
75
- '$each'=> document
72
+ '$each'=> document['contents']
76
73
  }
77
74
  }
78
75
  }, {upsert: true})
@@ -81,13 +78,13 @@ class Vayacondios::ItemsetDocument < Vayacondios::Document
81
78
  end
82
79
 
83
80
  def destroy(document)
84
- raise Vayacondios::Error::BadRequest.new if !document.is_a?(Array)
81
+ raise Vayacondios::Error::BadRequest.new unless document.is_a?(Hash)
85
82
 
86
- @body -= document
83
+ @body -= document['contents']
87
84
 
88
85
  @collection.update({:_id => @id}, {
89
86
  '$pullAll' => {
90
- 'd' => document
87
+ 'd' => document['contents']
91
88
  }
92
89
  })
93
90
 
@@ -0,0 +1,25 @@
1
+ class Vayacondios
2
+ module Rack
3
+ class ExtractMethods
4
+ include Goliath::Rack::AsyncMiddleware
5
+
6
+ def call(env)
7
+ method_name = extract_method(env)
8
+ super env.merge(vayacondios_method: method_name)
9
+ end
10
+
11
+ def extract_method env
12
+ return unless env['REQUEST_METHOD']
13
+ case env['REQUEST_METHOD'].upcase
14
+ when 'PUT' then
15
+ (env['HTTP_X_METHOD'] && env['HTTP_X_METHOD'].upcase == 'PATCH') ? :patch : :update
16
+ when 'GET' then :show
17
+ when 'POST' then :create
18
+ when 'PATCH' then :patch
19
+ when 'DELETE' then :delete
20
+ else nil
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,23 @@
1
+ class Vayacondios
2
+ module Rack
3
+ class Path
4
+ include Goliath::Rack::AsyncMiddleware
5
+
6
+ def call(env)
7
+ path_params = parse_path(env[Goliath::Request::REQUEST_PATH])
8
+ super env.merge(vayacondios_path: path_params)
9
+ end
10
+
11
+ def parse_path(path)
12
+ path_regex = /^\/v1\/(?<organization>[a-z]\w+)\/(?<type>config|event|itemset)(\/(?<topic>\w+)(\/(?<id>(\w+\/?)+))?)?(\/|\.(?<format>json))?$/i
13
+ if (match = path_regex.match(path))
14
+ {}.tap do |segments|
15
+ match.names.each do |segment|
16
+ segments[segment.to_sym] = match[segment]
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,22 @@
1
+ class Vayacondios
2
+ module Rack
3
+ class PathValidation
4
+ include Goliath::Rack::AsyncMiddleware
5
+
6
+ def initialize(app, opts = {})
7
+ @app = app ; @opts = opts
8
+ end
9
+
10
+ def call(env)
11
+ return [400, {}, MultiJson.dump({ error: "Bad Request. Format path is <host>/v1/<org>/event/<topic>" })] unless valid_paths? env[:vayacondios_path]
12
+ @app.call(env)
13
+ end
14
+
15
+ def valid_paths?(path)
16
+ # use @opts for validation later
17
+ path.nil? ? false : true
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -1,3 +1,3 @@
1
1
  class Vayacondios
2
- VERSION = '0.0.11'
2
+ VERSION = '0.1.1'
3
3
  end
@@ -20,4 +20,8 @@ require 'vayacondios/server/model/itemset_document'
20
20
 
21
21
  require 'vayacondios/server/handlers/config_handler'
22
22
  require 'vayacondios/server/handlers/event_handler'
23
- require 'vayacondios/server/handlers/itemset_handler'
23
+ require 'vayacondios/server/handlers/itemset_handler'
24
+
25
+ require 'vayacondios/server/rack/extract_methods'
26
+ require 'vayacondios/server/rack/path'
27
+ require 'vayacondios/server/rack/path_validation'
@@ -26,10 +26,12 @@ module Vayacondios
26
26
 
27
27
  def init_settings
28
28
  return if defined? @settings
29
-
29
+
30
30
  @settings = Configliere::Param.new
31
31
  @settings.use :env_var, :config_file, :commandline
32
-
32
+
33
+ @settings.define(:config_file,
34
+ description: "Config file location")
33
35
  @settings.define(:sleep_seconds,
34
36
  default: 5,
35
37
  description: "Time to sleep in main loops")
@@ -60,9 +62,14 @@ module Vayacondios
60
62
  @settings.define(:machine_stats_size,
61
63
  default: 100 * (1 << 20),
62
64
  description: ("Size (in bytes) of machine stats collection"))
63
-
65
+
64
66
  @settings.resolve!
65
67
 
68
+ if @settings.config_file
69
+ @settings.read(@settings.config_file)
70
+ @settings.resolve!
71
+ end
72
+
66
73
  @logger = Logger.new(STDERR)
67
74
  @logger.level = Logger.const_get(@settings.log_level.upcase.to_sym)
68
75
 
@@ -14,7 +14,8 @@ describe HttpShim do
14
14
  with_api(HttpShim) do |api|
15
15
  put_request({
16
16
  :path => '/v1/infochimps/config/',
17
- :body => MultiJson.dump({:level=>"awesome"})
17
+ :body => MultiJson.dump({:level=>"awesome"}),
18
+ :head => { :content_type => 'application/json' }
18
19
  }, err) do |c|
19
20
  c.response_header.status.should == 400
20
21
  end
@@ -25,7 +26,8 @@ describe HttpShim do
25
26
  with_api(HttpShim) do |api|
26
27
  put_request({
27
28
  :path => '/v1/infochimps/config/power',
28
- :body => MultiJson.dump({:level=>"awesome"})
29
+ :body => MultiJson.dump({:level=>"awesome"}),
30
+ :head => { :content_type => 'application/json' }
29
31
  }, err) do |c|
30
32
  c.response_header.status.should == 400
31
33
  end
@@ -36,7 +38,8 @@ describe HttpShim do
36
38
  with_api(HttpShim) do |api|
37
39
  put_request({
38
40
  :path => '/v1/infochimps/config/power/level',
39
- :body => MultiJson.dump({:level=>"awesome"})
41
+ :body => MultiJson.dump({:level=>"awesome"}),
42
+ :head => { :content_type => 'application/json' }
40
43
  }, err) do |c|
41
44
  c.response_header.status.should == 200
42
45
  end
@@ -51,7 +54,8 @@ describe HttpShim do
51
54
  with_api(HttpShim) do |api|
52
55
  put_request({
53
56
  :path => '/v1/infochimps/config/power/level/is/invalid',
54
- :body => MultiJson.dump({:level=>"awesome"})
57
+ :body => MultiJson.dump({:level=>"awesome"}),
58
+ :head => { :content_type => 'application/json' }
55
59
  }, err) do |c|
56
60
  c.response_header.status.should == 400
57
61
  end
@@ -66,7 +70,8 @@ describe HttpShim do
66
70
  with_api(HttpShim) do |api|
67
71
  put_request({
68
72
  :path => '/v1/infochimps/config/power/level',
69
- :body => MultiJson.dump({:level=>"awesome"})
73
+ :body => MultiJson.dump({:level=>"awesome"}),
74
+ :head => { :content_type => 'application/json' }
70
75
  }, err)
71
76
  end
72
77
  with_api(HttpShim) do |api|
@@ -81,13 +86,15 @@ describe HttpShim do
81
86
  with_api(HttpShim) do |api|
82
87
  put_request({
83
88
  :path => '/v1/infochimps/config/merge/test',
84
- :body => MultiJson.dump({ :foo => { :bar => 3 } })
89
+ :body => MultiJson.dump({ :foo => { :bar => 3 } }),
90
+ :head => { :content_type => 'application/json' }
85
91
  }, err)
86
92
  end
87
93
  with_api(HttpShim) do |api|
88
94
  put_request({
89
95
  :path => '/v1/infochimps/config/merge/test',
90
- :body => MultiJson.dump({ :foo => { :baz => 7 } })
96
+ :body => MultiJson.dump({ :foo => { :baz => 7 } }),
97
+ :head => { :content_type => 'application/json' }
91
98
  }, err)
92
99
  end
93
100
  with_api(HttpShim) do |api|
@@ -103,4 +110,4 @@ describe HttpShim do
103
110
  end
104
111
  end
105
112
  end
106
- end
113
+ end
@@ -8,13 +8,14 @@ describe HttpShim do
8
8
  include Goliath::TestHelper
9
9
 
10
10
  let(:err) { Proc.new{ |c| fail "HTTP Request Failed #{c.response}" } }
11
-
11
+
12
12
  context 'Event tracking' do
13
13
  it 'requires a topic' do
14
14
  with_api(HttpShim) do |api|
15
15
  put_request({
16
16
  :path => '/v1/infochimps/event/',
17
- :body => MultiJson.dump({:level=>"awesome"})
17
+ :body => MultiJson.dump({:level=>"awesome"}),
18
+ :head => { :content_type => 'application/json' }
18
19
  }, err) do |c|
19
20
  c.response_header.status.should == 400
20
21
  end
@@ -25,7 +26,8 @@ describe HttpShim do
25
26
  with_api(HttpShim) do |api|
26
27
  put_request({
27
28
  :path => '/v1/infochimps/event/power',
28
- :body => MultiJson.dump({:level=>"awesome"})
29
+ :body => MultiJson.dump({:level=>"awesome"}),
30
+ :head => { :content_type => 'application/json' }
29
31
  }, err) do |c|
30
32
  c.response_header.status.should == 200
31
33
  end
@@ -36,7 +38,8 @@ describe HttpShim do
36
38
  with_api(HttpShim) do |api|
37
39
  put_request({
38
40
  :path => '/v1/infochimps/event/power/level',
39
- :body => MultiJson.dump({:level=>"awesome"})
41
+ :body => MultiJson.dump({:level=>"awesome"}),
42
+ :head => { :content_type => 'application/json' }
40
43
  }, err) do |c|
41
44
  c.response_header.status.should == 200
42
45
  end
@@ -47,7 +50,8 @@ describe HttpShim do
47
50
  with_api(HttpShim) do |api|
48
51
  put_request({
49
52
  :path => '/v1/infochimps/event/power/level/is/invalid',
50
- :body => MultiJson.dump({:level=>"awesome"})
53
+ :body => MultiJson.dump({:level=>"awesome"}),
54
+ :head => { :content_type => 'application/json' }
51
55
  }, err) do |c|
52
56
  c.response_header.status.should == 400
53
57
  end
@@ -62,7 +66,8 @@ describe HttpShim do
62
66
  with_api(HttpShim) do |api|
63
67
  put_request({
64
68
  :path => '/v1/infochimps/event/power/level',
65
- :body => MultiJson.dump({:level=>"awesome"})
69
+ :body => MultiJson.dump({:level=>"awesome"}),
70
+ :head => { :content_type => 'application/json' }
66
71
  }, err) do |c|
67
72
  c.response_header.status.should == 200
68
73
  end
@@ -81,7 +86,8 @@ describe HttpShim do
81
86
  with_api(HttpShim) do |api|
82
87
  put_request({
83
88
  :path => '/v1/infochimps/event/power/level',
84
- :body => MultiJson.dump({:level=>"awesome", :_timestamp => current_time})
89
+ :body => MultiJson.dump({:level=>"awesome", :_timestamp => current_time}),
90
+ :head => { :content_type => 'application/json' }
85
91
  }, err) do |c|
86
92
  c.response_header.status.should == 200
87
93
  end
@@ -94,4 +100,4 @@ describe HttpShim do
94
100
  end
95
101
  end
96
102
  end
97
- end
103
+ end
@@ -14,7 +14,8 @@ describe HttpShim do
14
14
  with_api(HttpShim) do |api|
15
15
  put_request({
16
16
  :path => '/v1/infochimps/itemset/',
17
- :body => MultiJson.dump(["foo"])
17
+ :body => MultiJson.dump({:contents =>["foo"]}),
18
+ :head => { :content_type => 'application/json' }
18
19
  }, err) do |c|
19
20
  c.response_header.status.should == 400
20
21
  end
@@ -25,7 +26,8 @@ describe HttpShim do
25
26
  with_api(HttpShim) do |api|
26
27
  put_request({
27
28
  :path => '/v1/infochimps/itemset/power',
28
- :body => MultiJson.dump(["foo"])
29
+ :body => MultiJson.dump({:contents =>["foo"]}),
30
+ :head => { :content_type => 'application/json' }
29
31
  }, err) do |c|
30
32
  c.response_header.status.should == 400
31
33
  end
@@ -40,7 +42,8 @@ describe HttpShim do
40
42
  with_api(HttpShim) do |api|
41
43
  put_request({
42
44
  :path => '/v1/infochimps/itemset/power/level/is/invalid',
43
- :body => MultiJson.dump(["foo"])
45
+ :body => MultiJson.dump({:contents =>["foo"]}),
46
+ :head => { :content_type => 'application/json' }
44
47
  }, err) do |c|
45
48
  c.response_header.status.should == 400
46
49
  end
@@ -53,13 +56,14 @@ describe HttpShim do
53
56
  end
54
57
 
55
58
  context 'handles PUT requests' do
56
- it 'only accepts arrays' do
59
+ it 'only accepts hashes' do
57
60
  with_api(HttpShim) do |api|
58
61
  put_request({
59
62
  :path => '/v1/infochimps/itemset/power/level',
60
- :body => {"foo" => "bar"}
63
+ :body => MultiJson.dump(['foo', 'bar']),
64
+ :head => { :content_type => 'application/json' }
61
65
  }, err) do |c|
62
- c.response_header.status.should == 400
66
+ c.response_header.status.should == 500
63
67
  end
64
68
 
65
69
  get_mongo_db do |db|
@@ -69,7 +73,8 @@ describe HttpShim do
69
73
  with_api(HttpShim) do |api|
70
74
  put_request({
71
75
  :path => '/v1/infochimps/itemset/power/level',
72
- :body => "foo"
76
+ :body => "foo",
77
+ :head => { :content_type => 'application/json' }
73
78
  }, err) do |c|
74
79
  c.response_header.status.should == 400
75
80
  end
@@ -84,7 +89,8 @@ describe HttpShim do
84
89
  with_api(HttpShim) do |api|
85
90
  put_request({
86
91
  :path => '/v1/infochimps/itemset/power/level',
87
- :body => MultiJson.dump(["foo", "bar"]).to_s
92
+ :body => MultiJson.dump({:contents =>["foo", "bar"]}),
93
+ :head => { :content_type => 'application/json' }
88
94
  }, err) do |c|
89
95
  c.response_header.status.should == 200 # TODO Make this 201 Created
90
96
  c.response.should eql ""
@@ -100,7 +106,8 @@ describe HttpShim do
100
106
  with_api(HttpShim) do |api|
101
107
  put_request({
102
108
  :path => '/v1/infochimps/itemset/power/level',
103
- :body => MultiJson.dump(["chimpanzee", "bonobo"])
109
+ :body => MultiJson.dump({:contents =>["chimpanzee", "bonobo"]}),
110
+ :head => { :content_type => 'application/json' }
104
111
  }, err) do |c|
105
112
  c.response_header.status.should == 200 # TODO Make this 204 No content
106
113
  c.response.should eql ""
@@ -115,7 +122,8 @@ describe HttpShim do
115
122
  with_api(HttpShim) do |api|
116
123
  put_request({
117
124
  :path => '/v1/infochimps/itemset/power/level',
118
- :body => MultiJson.dump(["foo", "bar"])
125
+ :body => MultiJson.dump({:contents =>["foo", "bar"]}),
126
+ :head => { :content_type => 'application/json' }
119
127
  }, err) do |c|
120
128
  c.response_header.status.should == 200
121
129
  c.response.should eql ""
@@ -142,7 +150,8 @@ describe HttpShim do
142
150
  with_api(HttpShim) do |api|
143
151
  put_request({
144
152
  :path => '/v1/infochimps/itemset/power/level',
145
- :body => MultiJson.dump(["foo", "bar"])
153
+ :body => MultiJson.dump({:contents =>["foo", "bar"]}),
154
+ :head => { :content_type => 'application/json' }
146
155
  }, err)
147
156
  end
148
157
  with_api(HttpShim) do |api|
@@ -159,7 +168,8 @@ describe HttpShim do
159
168
  with_api(HttpShim) do |api|
160
169
  post_request({
161
170
  :path => '/v1/infochimps/itemset/post/unsupported',
162
- :body => MultiJson.dump({ :totally => :ignored })
171
+ :body => MultiJson.dump({ :totally => :ignored }),
172
+ :head => { :content_type => 'application/json' }
163
173
  }, err) do |c|
164
174
  c.response_header.status.should eql 405
165
175
  c.response_header["ALLOW"].should_not be_nil
@@ -173,8 +183,8 @@ describe HttpShim do
173
183
  with_api(HttpShim) do |api|
174
184
  put_request({
175
185
  :path => '/v1/infochimps/itemset/power/level',
176
- :head => ({'X-Method' => 'PATCH'}),
177
- :body => MultiJson.dump(["bar"])
186
+ :head => ({'X-Method' => 'PATCH', :content_type => 'application/json' }),
187
+ :body => MultiJson.dump({:contents =>["bar"]})
178
188
  }, err) do |c|
179
189
  c.response_header.status.should eql 200 # TODO Make this 201 Created
180
190
  c.response.should eql ""
@@ -191,14 +201,15 @@ describe HttpShim do
191
201
  with_api(HttpShim) do |api|
192
202
  put_request({
193
203
  :path => '/v1/infochimps/itemset/merge/test',
194
- :body => MultiJson.dump(["foo"])
204
+ :body => MultiJson.dump({:contents =>["foo"]}),
205
+ :head => { :content_type => 'application/json' }
195
206
  }, err)
196
207
  end
197
208
  with_api(HttpShim) do |api|
198
209
  put_request({
199
210
  :path => '/v1/infochimps/itemset/merge/test',
200
- :head => ({'X-Method' => 'PATCH'}),
201
- :body => MultiJson.dump(["bar"])
211
+ :head => ({'X-Method' => 'PATCH', :content_type => 'application/json' }),
212
+ :body => MultiJson.dump({:contents =>["bar"]})
202
213
  }, err)
203
214
  end
204
215
  with_api(HttpShim) do |api|
@@ -215,18 +226,20 @@ describe HttpShim do
215
226
  with_api(HttpShim) do |api|
216
227
  delete_request({
217
228
  :path => '/v1/infochimps/itemset/merge/test',
218
- :body => MultiJson.dump(["bar"])
229
+ :body => MultiJson.dump({:contents =>["bar"]}),
230
+ :head => { :content_type => 'application/json' }
219
231
  }, err) do |c|
220
232
  c.response_header.status.should == 404
221
233
  end
222
234
  end
223
235
  end
224
236
 
225
- it "will be ok to delete items that are don't exist" do
237
+ it "will be ok to delete items that don't exist" do
226
238
  with_api(HttpShim) do |api|
227
239
  put_request({
228
240
  :path => '/v1/infochimps/itemset/power/level',
229
- :body => MultiJson.dump(["foo"])
241
+ :body => MultiJson.dump({:contents =>["foo"]}),
242
+ :head => { :content_type => 'application/json' }
230
243
  }, err) do |c|
231
244
  c.response_header.status.should == 200 # TODO Make this 201 Created
232
245
  end
@@ -234,18 +247,20 @@ describe HttpShim do
234
247
  with_api(HttpShim) do |api|
235
248
  delete_request({
236
249
  :path => '/v1/infochimps/itemset/power/level',
237
- :body => MultiJson.dump(["bar"])
250
+ :body => MultiJson.dump({:contents =>["bar"]}),
251
+ :head => { :content_type => 'application/json' }
238
252
  }, err) do |c|
239
253
  c.response_header.status.should == 200 # TODO Make this 204 No content
240
254
  end
241
255
  end
242
256
  end
243
257
 
244
- it "will be delete items that exist" do
258
+ it "will delete items that do exist" do
245
259
  with_api(HttpShim) do |api|
246
260
  put_request({
247
261
  :path => '/v1/infochimps/itemset/power/level',
248
- :body => MultiJson.dump(["foo", "bar"])
262
+ :body => MultiJson.dump({:contents =>["foo", "bar"]}),
263
+ :head => { :content_type => 'application/json' }
249
264
  }, err) do |c|
250
265
  c.response_header.status.should == 200 # TODO Makes this 201 Created
251
266
  end
@@ -253,7 +268,8 @@ describe HttpShim do
253
268
  with_api(HttpShim) do |api|
254
269
  delete_request({
255
270
  :path => '/v1/infochimps/itemset/power/level',
256
- :body => MultiJson.dump(["bar"])
271
+ :body => MultiJson.dump({:contents =>["bar"]}),
272
+ :head => { :content_type => 'application/json' }
257
273
  }, err) do |c|
258
274
  c.response_header.status.should == 200 # TODO Make this 204 No content
259
275
  end
@@ -265,12 +281,13 @@ describe HttpShim do
265
281
  end
266
282
  end
267
283
  end
268
- #
284
+
269
285
  it "leaves behind an empty array if everything is deleted" do
270
286
  with_api(HttpShim) do |api|
271
287
  put_request({
272
288
  :path => '/v1/infochimps/itemset/power/level',
273
- :body => MultiJson.dump(["foo", "bar"])
289
+ :body => MultiJson.dump({:contents =>["foo", "bar"]}),
290
+ :head => { :content_type => 'application/json' }
274
291
  }, err) do |c|
275
292
  c.response_header.status.should == 200 # TODO Makes this 201 Created
276
293
  end
@@ -278,7 +295,8 @@ describe HttpShim do
278
295
  with_api(HttpShim) do |api|
279
296
  delete_request({
280
297
  :path => '/v1/infochimps/itemset/power/level',
281
- :body => MultiJson.dump(["foo", "bar"])
298
+ :body => MultiJson.dump({:contents =>["foo", "bar"]}),
299
+ :head => { :content_type => 'application/json' }
282
300
  }, err) do |c|
283
301
  c.response_header.status.should == 200 # TODO Make this 204 No content
284
302
  end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+ require 'vayacondios/server/rack/extract_methods'
3
+
4
+ describe Vayacondios::Rack::ExtractMethods do
5
+ let(:env){ { 'CONTENT_TYPE' => 'application/x-www-form-urlencoded; charset=utf-8' } }
6
+ let(:app){ mock('app').as_null_object }
7
+ subject { described_class.new(app) }
8
+
9
+ it 'adds a key in env for :vayacondios_method' do
10
+ app.should_receive(:call).with do |app_env|
11
+ app_env.keys.should include(:vayacondios_method)
12
+ end
13
+ subject.call(env)
14
+ end
15
+
16
+ context 'PUT' do
17
+ context 'without http_x_method' do
18
+ it 'correctly extracts :update' do
19
+ env.merge!('REQUEST_METHOD' => 'PUT')
20
+ subject.extract_method(env).should == :update
21
+ end
22
+ end
23
+
24
+ context 'with http_x_method' do
25
+ it 'correctly extracts :patch' do
26
+ env.merge!('REQUEST_METHOD' => 'PUT', 'HTTP_X_METHOD' => 'PATCH')
27
+ subject.extract_method(env).should == :patch
28
+ end
29
+ end
30
+ end
31
+
32
+ context 'GET' do
33
+ it 'correctly extracts :show' do
34
+ env.merge!('REQUEST_METHOD' => 'GET')
35
+ subject.extract_method(env).should == :show
36
+ end
37
+ end
38
+
39
+ context 'POST' do
40
+ it 'correctly extracts :create' do
41
+ env.merge!('REQUEST_METHOD' => 'POST')
42
+ subject.extract_method(env).should == :create
43
+ end
44
+
45
+ end
46
+
47
+ context 'PATCH' do
48
+ it 'correctly extracts :patch' do
49
+ env.merge!('REQUEST_METHOD' => 'PATCH')
50
+ subject.extract_method(env).should == :patch
51
+ end
52
+ end
53
+
54
+ context 'DELETE' do
55
+ it 'correctly extracts :delete' do
56
+ env.merge!('REQUEST_METHOD' => 'DELETE')
57
+ subject.extract_method(env).should == :delete
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+ require 'vayacondios/server/rack/path'
3
+
4
+ describe Vayacondios::Rack::Path do
5
+ let(:env) { { 'CONTENT_TYPE' => 'application/x-www-form-urlencoded; charset=utf-8' } }
6
+ let(:app) { mock('app').as_null_object }
7
+ subject { described_class.new(app) }
8
+
9
+ it 'adds a key in env for :vayacondios_path' do
10
+ app.should_receive(:call).with do |app_env|
11
+ app_env.keys.should include(:vayacondios_path)
12
+ end
13
+ subject.call(env)
14
+ end
15
+
16
+ context 'parse_path' do
17
+ it 'returns nil if the path is unparseable' do
18
+ subject.parse_path('/what/the:f/happened&here?').should be nil
19
+ end
20
+ it 'parses organizations and types correctly' do
21
+ subject.parse_path('/v1/infochimps/event').should include(organization: 'infochimps', type: 'event')
22
+ end
23
+
24
+ it 'parses topics correctly' do
25
+ subject.parse_path('/v1/infochimps/config/foo').should include(topic: 'foo')
26
+ end
27
+
28
+ it 'parses ids correctly' do
29
+ subject.parse_path('/v1/infochimps/itemset/bar/1').should include(id: '1')
30
+ end
31
+
32
+ it 'parses formats correctly' do
33
+ subject.parse_path('/v1/infochimps/event/baz/1.json').should include(format: 'json')
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+ require 'vayacondios/server/rack/path_validation'
3
+
4
+ describe Vayacondios::Rack::PathValidation do
5
+ let(:env){ { 'CONTENT_TYPE' => 'application/x-www-form-urlencoded; charset=utf-8' } }
6
+ let(:app){ mock('app').as_null_object }
7
+ subject { described_class.new(app) }
8
+
9
+ it 'sets @opts when created' do
10
+ subject.instance_variable_get('@opts').should == {}
11
+ end
12
+
13
+ it 'returns a bad request when :vayacondios_path does not exist' do
14
+ subject.call(env).should == [400, {}, '{"error":"Bad Request. Format path is <host>/v1/<org>/event/<topic>"}']
15
+ end
16
+
17
+ context 'valid_paths?' do
18
+ it 'validates the :vayacondios_path' do
19
+ subject.valid_paths?({}).should be_true
20
+ end
21
+ end
22
+ end
@@ -13,8 +13,8 @@ describe HttpShim do
13
13
  with_api(HttpShim) do |api|
14
14
  get_request({}, err) do |c|
15
15
  c.response_header.status.should == 400
16
- MultiJson.load(c.response).should eql({"error" => "Bad Request"})
16
+ MultiJson.load(c.response).should eql({"error" => "Bad Request. Format path is <host>/v1/<org>/event/<topic>"})
17
17
  end
18
18
  end
19
19
  end
20
- end
20
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,7 +1,4 @@
1
- require 'bundler'
2
-
3
- Bundler.setup
4
- Bundler.require
1
+ require 'bundler/setup' ; Bundler.require
5
2
 
6
3
  Dir["spec/support/**/*.rb"].each {|f| require File.join(File.dirname(__FILE__), '..', f) }
7
4
 
@@ -17,7 +17,6 @@ Gem::Specification.new do |gem|
17
17
 
18
18
  gem.add_dependency('configliere', '>= 0.4.16')
19
19
  gem.add_dependency('multi_json', '~> 1.1')
20
- # Gorillib versioning is borked
21
20
  gem.add_dependency('gorillib', '~> 0.4.2')
22
21
 
23
22
  gem.add_development_dependency('rake')
@@ -22,7 +22,6 @@ Gem::Specification.new do |gem|
22
22
  gem.add_dependency('goliath', '~> 1.0')
23
23
  gem.add_dependency('em-http-request', '~> 1.0')
24
24
  gem.add_dependency('em-mongo', '~> 0.4.3')
25
- gem.add_dependency('bson_ext', '~> 1.6')
26
25
  gem.add_dependency('foreman')
27
26
 
28
27
  gem.add_development_dependency('rake')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vayacondios-server
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.11
4
+ version: 0.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -12,11 +12,11 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2012-09-24 00:00:00.000000000 Z
15
+ date: 2012-12-05 00:00:00.000000000Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: configliere
19
- requirement: &70112437436680 !ruby/object:Gem::Requirement
19
+ requirement: &2170198080 !ruby/object:Gem::Requirement
20
20
  none: false
21
21
  requirements:
22
22
  - - ! '>='
@@ -24,10 +24,10 @@ dependencies:
24
24
  version: 0.4.13
25
25
  type: :runtime
26
26
  prerelease: false
27
- version_requirements: *70112437436680
27
+ version_requirements: *2170198080
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: gorillib
30
- requirement: &70112437436160 !ruby/object:Gem::Requirement
30
+ requirement: &2170196740 !ruby/object:Gem::Requirement
31
31
  none: false
32
32
  requirements:
33
33
  - - ~>
@@ -35,10 +35,10 @@ dependencies:
35
35
  version: 0.4.2
36
36
  type: :runtime
37
37
  prerelease: false
38
- version_requirements: *70112437436160
38
+ version_requirements: *2170196740
39
39
  - !ruby/object:Gem::Dependency
40
40
  name: eventmachine
41
- requirement: &70112437435700 !ruby/object:Gem::Requirement
41
+ requirement: &2170190120 !ruby/object:Gem::Requirement
42
42
  none: false
43
43
  requirements:
44
44
  - - ~>
@@ -46,10 +46,10 @@ dependencies:
46
46
  version: 1.0.0.beta.4
47
47
  type: :runtime
48
48
  prerelease: false
49
- version_requirements: *70112437435700
49
+ version_requirements: *2170190120
50
50
  - !ruby/object:Gem::Dependency
51
51
  name: goliath
52
- requirement: &70112437435240 !ruby/object:Gem::Requirement
52
+ requirement: &2170188640 !ruby/object:Gem::Requirement
53
53
  none: false
54
54
  requirements:
55
55
  - - ~>
@@ -57,10 +57,10 @@ dependencies:
57
57
  version: '1.0'
58
58
  type: :runtime
59
59
  prerelease: false
60
- version_requirements: *70112437435240
60
+ version_requirements: *2170188640
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: em-http-request
63
- requirement: &70112437434760 !ruby/object:Gem::Requirement
63
+ requirement: &2170187920 !ruby/object:Gem::Requirement
64
64
  none: false
65
65
  requirements:
66
66
  - - ~>
@@ -68,10 +68,10 @@ dependencies:
68
68
  version: '1.0'
69
69
  type: :runtime
70
70
  prerelease: false
71
- version_requirements: *70112437434760
71
+ version_requirements: *2170187920
72
72
  - !ruby/object:Gem::Dependency
73
73
  name: em-mongo
74
- requirement: &70112437450660 !ruby/object:Gem::Requirement
74
+ requirement: &2170187240 !ruby/object:Gem::Requirement
75
75
  none: false
76
76
  requirements:
77
77
  - - ~>
@@ -79,21 +79,10 @@ dependencies:
79
79
  version: 0.4.3
80
80
  type: :runtime
81
81
  prerelease: false
82
- version_requirements: *70112437450660
83
- - !ruby/object:Gem::Dependency
84
- name: bson_ext
85
- requirement: &70112437450200 !ruby/object:Gem::Requirement
86
- none: false
87
- requirements:
88
- - - ~>
89
- - !ruby/object:Gem::Version
90
- version: '1.6'
91
- type: :runtime
92
- prerelease: false
93
- version_requirements: *70112437450200
82
+ version_requirements: *2170187240
94
83
  - !ruby/object:Gem::Dependency
95
84
  name: foreman
96
- requirement: &70112437449820 !ruby/object:Gem::Requirement
85
+ requirement: &2170186560 !ruby/object:Gem::Requirement
97
86
  none: false
98
87
  requirements:
99
88
  - - ! '>='
@@ -101,10 +90,10 @@ dependencies:
101
90
  version: '0'
102
91
  type: :runtime
103
92
  prerelease: false
104
- version_requirements: *70112437449820
93
+ version_requirements: *2170186560
105
94
  - !ruby/object:Gem::Dependency
106
95
  name: rake
107
- requirement: &70112437449360 !ruby/object:Gem::Requirement
96
+ requirement: &2170185580 !ruby/object:Gem::Requirement
108
97
  none: false
109
98
  requirements:
110
99
  - - ! '>='
@@ -112,10 +101,10 @@ dependencies:
112
101
  version: '0'
113
102
  type: :development
114
103
  prerelease: false
115
- version_requirements: *70112437449360
104
+ version_requirements: *2170185580
116
105
  - !ruby/object:Gem::Dependency
117
106
  name: mongo
118
- requirement: &70112437448940 !ruby/object:Gem::Requirement
107
+ requirement: &2170184720 !ruby/object:Gem::Requirement
119
108
  none: false
120
109
  requirements:
121
110
  - - ! '>='
@@ -123,7 +112,7 @@ dependencies:
123
112
  version: '0'
124
113
  type: :development
125
114
  prerelease: false
126
- version_requirements: *70112437448940
115
+ version_requirements: *2170184720
127
116
  description: Simple enough to use in a shell script, performant enough to use everywhere.
128
117
  Dios mío! Record that metric, ese!
129
118
  email:
@@ -132,6 +121,7 @@ extensions: []
132
121
  extra_rdoc_files: []
133
122
  files:
134
123
  - .gitignore
124
+ - .rspec
135
125
  - .travis.yml
136
126
  - .yardopts
137
127
  - CHANGELOG.md
@@ -164,6 +154,9 @@ files:
164
154
  - lib/vayacondios/server/model/document.rb
165
155
  - lib/vayacondios/server/model/event_document.rb
166
156
  - lib/vayacondios/server/model/itemset_document.rb
157
+ - lib/vayacondios/server/rack/extract_methods.rb
158
+ - lib/vayacondios/server/rack/path.rb
159
+ - lib/vayacondios/server/rack/path_validation.rb
167
160
  - lib/vayacondios/version.rb
168
161
  - scripts/hadoop_monitor/configurable.rb
169
162
  - scripts/hadoop_monitor/hadoop_client.rb
@@ -178,6 +171,9 @@ files:
178
171
  - spec/server/config_spec.rb
179
172
  - spec/server/event_spec.rb
180
173
  - spec/server/itemset_spec.rb
174
+ - spec/server/rack/extract_methods_spec.rb
175
+ - spec/server/rack/path_spec.rb
176
+ - spec/server/rack/path_validation_spec.rb
181
177
  - spec/server/server_spec.rb
182
178
  - spec/spec_helper.rb
183
179
  - spec/support/mongo_cleaner.rb
@@ -197,7 +193,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
197
193
  version: '0'
198
194
  segments:
199
195
  - 0
200
- hash: 1278306223902219188
196
+ hash: -3537834639285918956
201
197
  required_rubygems_version: !ruby/object:Gem::Requirement
202
198
  none: false
203
199
  requirements:
@@ -206,10 +202,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
206
202
  version: '0'
207
203
  segments:
208
204
  - 0
209
- hash: 1278306223902219188
205
+ hash: -3537834639285918956
210
206
  requirements: []
211
207
  rubyforge_project:
212
- rubygems_version: 1.8.11
208
+ rubygems_version: 1.8.15
213
209
  signing_key:
214
210
  specification_version: 3
215
211
  summary: Data goes in. The right thing happens
@@ -219,6 +215,9 @@ test_files:
219
215
  - spec/server/config_spec.rb
220
216
  - spec/server/event_spec.rb
221
217
  - spec/server/itemset_spec.rb
218
+ - spec/server/rack/extract_methods_spec.rb
219
+ - spec/server/rack/path_spec.rb
220
+ - spec/server/rack/path_validation_spec.rb
222
221
  - spec/server/server_spec.rb
223
222
  - spec/spec_helper.rb
224
223
  - spec/support/mongo_cleaner.rb