vayacondios-server 0.0.11 → 0.1.1

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