keen 0.3.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,40 @@
1
+ module Keen
2
+ module HTTP
3
+ class Sync
4
+ def initialize(host, port, options={})
5
+ require 'net/https'
6
+ @http = Net::HTTP.new(host, port)
7
+ options.each_pair { |key, value| @http.send "#{key}=", value }
8
+ end
9
+
10
+ def post(options)
11
+ path, headers, body = options.values_at(
12
+ :path, :headers, :body)
13
+ @http.post(path, body, headers)
14
+ end
15
+ end
16
+
17
+ class Async
18
+ def initialize(host, port, options={})
19
+ if defined?(EventMachine) && EventMachine.reactor_running?
20
+ require 'em-http-request'
21
+ else
22
+ raise Error, "An EventMachine loop must be running to use publish_async calls"
23
+ end
24
+
25
+ @host, @port, @http_options = host, port, options
26
+ end
27
+
28
+ def post(options)
29
+ path, headers, body = options.values_at(
30
+ :path, :headers, :body)
31
+ uri = "https://#{@host}:#{@port}#{path}"
32
+ http_client = EventMachine::HttpRequest.new(uri, @http_options)
33
+ http_client.post(
34
+ :body => body,
35
+ :head => headers
36
+ )
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,19 +1,3 @@
1
- require 'keen'
2
- require 'yaml'
3
-
4
- # parse VERSION.yml
5
- yaml_path = File.join(File.expand_path(File.dirname(__FILE__)), '..', '..', 'VERSION.yml')
6
- version_info = File.open( yaml_path ) { |file| YAML::load( file ) }
7
-
8
- # build the version string
9
- version_string = ""
10
- version_string += "#{version_info[:major]}"
11
- version_string += "#{version_info[:minor]}"
12
- version_string += "#{version_info[:patch]}"
13
-
14
- if version_info[:build]
15
- version_string += "#{version_info[:build]}"
1
+ module Keen
2
+ VERSION = "0.4.1"
16
3
  end
17
-
18
- # set the constant
19
- Keen::VERSION = version_string
@@ -0,0 +1,63 @@
1
+ require File.expand_path("../spec_helper", __FILE__)
2
+
3
+ describe "Keen IO API" do
4
+ let(:project_id) { ENV['KEEN_PROJECT_ID'] }
5
+ let(:api_key) { ENV['KEEN_API_KEY'] }
6
+
7
+ let(:collection) { "users" }
8
+ let(:event_properties) { { "name" => "Bob" } }
9
+ let(:api_success) { { "created" => true } }
10
+
11
+ describe "success" do
12
+
13
+ it "should return a created status for a valid post" do
14
+ Keen.publish(collection, event_properties).should == api_success
15
+ end
16
+ end
17
+
18
+ describe "failure" do
19
+ it "should raise a not found error if an invalid project id" do
20
+ client = Keen::Client.new(
21
+ :api_key => api_key, :project_id => "riker")
22
+ expect {
23
+ client.publish(collection, event_properties)
24
+ }.to raise_error(Keen::NotFoundError)
25
+ end
26
+
27
+ it "should raise authentication error if invalid API Key" do
28
+ client = Keen::Client.new(
29
+ :api_key => "wrong", :project_id => project_id)
30
+ expect {
31
+ client.publish(collection, event_properties)
32
+ }.to raise_error(Keen::AuthenticationError)
33
+ end
34
+
35
+ it "should raise bad request if no JSON is supplied" do
36
+ expect {
37
+ Keen.publish(collection, nil)
38
+ }.to raise_error(Keen::BadRequestError)
39
+ end
40
+
41
+ it "should return not found for an invalid collection name" do
42
+ expect {
43
+ Keen.publish(nil, event_properties)
44
+ }.to raise_error(Keen::NotFoundError)
45
+ end
46
+ end
47
+
48
+ describe "async" do
49
+ # no TLS support in EventMachine on jRuby
50
+ unless defined?(JRUBY_VERSION)
51
+
52
+ it "should publish the event and trigger callbacks" do
53
+ EM.run {
54
+ Keen.publish_async(collection, event_properties).callback { |response|
55
+ response.should == api_success
56
+ EM.stop
57
+ }
58
+ }
59
+ end
60
+
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,8 @@
1
+ require File.expand_path("../../spec_helper", __FILE__)
2
+
3
+ RSpec.configure do |config|
4
+ unless ENV['KEEN_PROJECT_ID'] && ENV['KEEN_API_KEY']
5
+ raise "Please set a KEEN_PROJECT_ID and KEEN_API_KEY on the environment
6
+ before running the integration specs."
7
+ end
8
+ end
@@ -0,0 +1,191 @@
1
+ require File.expand_path("../spec_helper", __FILE__)
2
+
3
+ describe Keen::Client do
4
+ let(:project_id) { "12345" }
5
+ let(:api_key) { "abcde" }
6
+ let(:collection) { "users" }
7
+ let(:event_properties) { { "name" => "Bob" } }
8
+ let(:api_success) { { "created" => true } }
9
+
10
+ def stub_api(url, status, json_body)
11
+ stub_request(:post, url).to_return(
12
+ :status => status,
13
+ :body => MultiJson.encode(json_body))
14
+ end
15
+
16
+ def expect_post(url, event_properties, api_key)
17
+ WebMock.should have_requested(:post, url).with(
18
+ :body => MultiJson.encode(event_properties),
19
+ :headers => { "Content-Type" => "application/json",
20
+ "User-Agent" => "keen-gem v#{Keen::VERSION}",
21
+ "Authorization" => api_key })
22
+ end
23
+
24
+ def api_url(collection)
25
+ "https://api.keen.io/3.0/projects/#{project_id}/events/#{collection}"
26
+ end
27
+
28
+ describe "#initialize" do
29
+ context "deprecated" do
30
+ it "should allow created via project_id and api_key args" do
31
+ client = Keen::Client.new(project_id, api_key)
32
+ client.api_key.should == api_key
33
+ client.project_id.should == project_id
34
+ end
35
+ end
36
+
37
+ it "should initialize with options" do
38
+ client = Keen::Client.new(
39
+ :project_id => project_id,
40
+ :api_key => api_key)
41
+ client.api_key.should == api_key
42
+ client.project_id.should == project_id
43
+ end
44
+ end
45
+
46
+ describe "with a unconfigured client" do
47
+ [:publish, :publish_async].each do |_method|
48
+ describe "##{_method}" do
49
+ it "should raise an exception if no project_id" do
50
+ expect {
51
+ Keen::Client.new(:api_key => api_key).
52
+ send(_method, collection, event_properties)
53
+ }.to raise_error(Keen::ConfigurationError)
54
+ end
55
+
56
+ it "should raise an exception if no api_key" do
57
+ expect {
58
+ Keen::Client.new(:project_id => project_id).
59
+ send(_method, collection, event_properties)
60
+ }.to raise_error(Keen::ConfigurationError)
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ describe "with a configured client" do
67
+ before do
68
+ @client = Keen::Client.new(
69
+ :project_id => project_id,
70
+ :api_key => api_key)
71
+ end
72
+
73
+ describe "#publish" do
74
+ it "should post using the collection and properties" do
75
+ stub_api(api_url(collection), 201, "")
76
+ @client.publish(collection, event_properties)
77
+ expect_post(api_url(collection), event_properties, api_key)
78
+ end
79
+
80
+ it "should return the proper response" do
81
+ api_response = { "created" => true }
82
+ stub_api(api_url(collection), 201, api_response)
83
+ @client.publish(collection, event_properties).should == api_response
84
+ end
85
+
86
+ it "should wrap exceptions" do
87
+ stub_request(:post, api_url(collection)).to_timeout
88
+ e = nil
89
+ begin
90
+ @client.publish(collection, event_properties)
91
+ rescue Exception => exception
92
+ e = exception
93
+ end
94
+
95
+ e.class.should == Keen::HttpError
96
+ e.original_error.class.should == Timeout::Error
97
+ e.message.should == "Couldn't connect to Keen IO: execution expired"
98
+ end
99
+ end
100
+
101
+ describe "#publish_async" do
102
+
103
+ # no TLS support in EventMachine on jRuby
104
+ unless defined?(JRUBY_VERSION)
105
+ it "should require a running event loop" do
106
+ expect {
107
+ @client.publish_async(collection, event_properties)
108
+ }.to raise_error(Keen::Error)
109
+ end
110
+
111
+ it "should post the event data" do
112
+ stub_api(api_url(collection), 201, api_success)
113
+ EM.run {
114
+ @client.publish_async(collection, event_properties).callback {
115
+ expect_post(api_url(collection), event_properties, api_key)
116
+ EM.stop
117
+ }
118
+ }
119
+ end
120
+
121
+ describe "deferrable callbacks" do
122
+ it "should trigger callbacks" do
123
+ stub_api(api_url(collection), 201, api_success)
124
+ EM.run {
125
+ @client.publish_async(collection, event_properties).callback { |response|
126
+ response.should == api_success
127
+ EM.stop
128
+ }
129
+ }
130
+ end
131
+
132
+ it "should trigger errbacks" do
133
+ stub_request(:post, api_url(collection)).to_timeout
134
+ EM.run {
135
+ @client.publish_async(collection, event_properties).errback { |error|
136
+ error.should_not be_nil
137
+ error.message.should == "Couldn't connect to Keen IO: WebMock timeout error"
138
+ EM.stop
139
+ }
140
+ }
141
+ end
142
+ end
143
+ end
144
+
145
+ end
146
+
147
+ describe "response handling" do
148
+ def stub_status_and_publish(code, api_response=nil)
149
+ stub_api(api_url(collection), code, api_response)
150
+ @client.publish(collection, event_properties)
151
+ end
152
+
153
+ it "should return the json body for a 200-201" do
154
+ api_response = { "created" => "true" }
155
+ stub_status_and_publish(200, api_response).should == api_response
156
+ stub_status_and_publish(201, api_response).should == api_response
157
+ end
158
+
159
+ it "should raise a bad request error for a 400" do
160
+ expect {
161
+ stub_status_and_publish(400)
162
+ }.to raise_error(Keen::BadRequestError)
163
+ end
164
+
165
+ it "should raise a authentication error for a 401" do
166
+ expect {
167
+ stub_status_and_publish(401)
168
+ }.to raise_error(Keen::AuthenticationError)
169
+ end
170
+
171
+ it "should raise a not found error for a 404" do
172
+ expect {
173
+ stub_status_and_publish(404)
174
+ }.to raise_error(Keen::NotFoundError)
175
+ end
176
+
177
+ it "should raise an http error otherwise" do
178
+ expect {
179
+ stub_status_and_publish(420)
180
+ }.to raise_error(Keen::HttpError)
181
+ end
182
+ end
183
+
184
+ describe "#add_event" do
185
+ it "should alias to publish" do
186
+ @client.should_receive(:publish).with("users", {:a => 1}, {:b => 2})
187
+ @client.add_event("users", {:a => 1}, {:b => 2})
188
+ end
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,61 @@
1
+ require File.expand_path("../spec_helper", __FILE__)
2
+
3
+ describe Keen do
4
+ describe "default client" do
5
+ describe "configuring from the environment" do
6
+ before do
7
+ ENV["KEEN_PROJECT_ID"] = "12345"
8
+ ENV["KEEN_API_KEY"] = "abcde"
9
+ end
10
+
11
+ let(:client) { Keen.send(:default_client) }
12
+
13
+ it "should set a project id from the environment" do
14
+ client.project_id.should == "12345"
15
+ end
16
+
17
+ it "should set a project id from the environment" do
18
+ client.api_key.should == "abcde"
19
+ end
20
+
21
+ after do
22
+ ENV["KEEN_PROJECT_ID"] = nil
23
+ ENV["KEEN_API_KEY"] = nil
24
+ end
25
+ end
26
+ end
27
+
28
+ describe "forwardable" do
29
+ before do
30
+ @default_client = double("client")
31
+ Keen.stub(:default_client).and_return(@default_client)
32
+ end
33
+
34
+ [:project_id, :api_key].each do |_method|
35
+ it "should forward the #{_method} method" do
36
+ @default_client.should_receive(_method)
37
+ Keen.send(_method)
38
+ end
39
+ end
40
+
41
+ [:project_id=, :api_key=].each do |_method|
42
+ it "should forward the #{_method} method" do
43
+ @default_client.should_receive(_method).with("12345")
44
+ Keen.send(_method, "12345")
45
+ end
46
+ end
47
+
48
+ [:publish, :publish_async].each do |_method|
49
+ it "should forward the #{_method} method" do
50
+ @default_client.should_receive(_method).with("users", {})
51
+ Keen.send(_method, "users", {})
52
+ end
53
+ end
54
+ end
55
+
56
+ describe "logger" do
57
+ it "should be set to info" do
58
+ Keen.logger.level.should == Logger::INFO
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,10 @@
1
+ require File.expand_path("../../spec_helper", __FILE__)
2
+
3
+ require 'webmock/rspec'
4
+
5
+ RSpec.configure do |config|
6
+ config.before(:each) do
7
+ WebMock.disable_net_connect!
8
+ WebMock.reset!
9
+ end
10
+ end
@@ -0,0 +1,16 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'Use of Bundler is recommended'
5
+ end
6
+
7
+ require 'rspec'
8
+ require 'net/https'
9
+ require 'em-http'
10
+
11
+ require File.expand_path("../../lib/keen", __FILE__)
12
+
13
+ RSpec.configure do |config|
14
+ config.before(:all) do
15
+ end
16
+ end
metadata CHANGED
@@ -1,153 +1,87 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: keen
3
- version: !ruby/object:Gem::Version
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.1
4
5
  prerelease:
5
- version: 0.3.0
6
6
  platform: ruby
7
- authors:
8
- - dorkitude
7
+ authors:
8
+ - Kyle Wild
9
+ - Josh Dzielak
9
10
  autorequire:
10
11
  bindir: bin
11
12
  cert_chain: []
12
-
13
- date: 2012-11-26 00:00:00 Z
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: json
17
- requirement: &id001 !ruby/object:Gem::Requirement
13
+ date: 2013-01-07 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: multi_json
17
+ requirement: !ruby/object:Gem::Requirement
18
18
  none: false
19
- requirements:
20
- - - ">="
21
- - !ruby/object:Gem::Version
22
- version: 1.6.5
23
- type: :runtime
24
- prerelease: false
25
- version_requirements: *id001
26
- - !ruby/object:Gem::Dependency
27
- name: shoulda
28
- requirement: &id002 !ruby/object:Gem::Requirement
29
- none: false
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: "0"
34
- type: :development
35
- prerelease: false
36
- version_requirements: *id002
37
- - !ruby/object:Gem::Dependency
38
- name: rdoc
39
- requirement: &id003 !ruby/object:Gem::Requirement
40
- none: false
41
- requirements:
19
+ requirements:
42
20
  - - ~>
43
- - !ruby/object:Gem::Version
44
- version: "3.12"
45
- type: :development
46
- prerelease: false
47
- version_requirements: *id003
48
- - !ruby/object:Gem::Dependency
49
- name: bundler
50
- requirement: &id004 !ruby/object:Gem::Requirement
51
- none: false
52
- requirements:
53
- - - ">="
54
- - !ruby/object:Gem::Version
55
- version: 1.1.4
56
- type: :development
21
+ - !ruby/object:Gem::Version
22
+ version: '1.0'
23
+ type: :runtime
57
24
  prerelease: false
58
- version_requirements: *id004
59
- - !ruby/object:Gem::Dependency
60
- name: jeweler
61
- requirement: &id005 !ruby/object:Gem::Requirement
25
+ version_requirements: !ruby/object:Gem::Requirement
62
26
  none: false
63
- requirements:
27
+ requirements:
64
28
  - - ~>
65
- - !ruby/object:Gem::Version
66
- version: 1.8.3
67
- type: :development
68
- prerelease: false
69
- version_requirements: *id005
70
- - !ruby/object:Gem::Dependency
71
- name: rspec
72
- requirement: &id006 !ruby/object:Gem::Requirement
73
- none: false
74
- requirements:
75
- - - ">="
76
- - !ruby/object:Gem::Version
77
- version: 2.9.0
78
- type: :development
79
- prerelease: false
80
- version_requirements: *id006
81
- - !ruby/object:Gem::Dependency
82
- name: cucumber
83
- requirement: &id007 !ruby/object:Gem::Requirement
84
- none: false
85
- requirements:
86
- - - ">="
87
- - !ruby/object:Gem::Version
88
- version: 1.2.1
89
- type: :development
90
- prerelease: false
91
- version_requirements: *id007
92
- description: See the github repo or examples.rb for usage information.
93
- email: kyle@keen.io
29
+ - !ruby/object:Gem::Version
30
+ version: '1.0'
31
+ description: Batch and send events to the Keen IO API. Supports asychronous requests.
32
+ email: josh@keen.io
94
33
  executables: []
95
-
96
34
  extensions: []
97
-
98
- extra_rdoc_files:
99
- - LICENSE.txt
100
- - README.md
101
- files:
102
- - .rvmrc
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - .rspec
39
+ - .travis.yml
103
40
  - Gemfile
104
- - LICENSE.txt
41
+ - Guardfile
42
+ - LICENSE
105
43
  - README.md
106
44
  - Rakefile
107
- - VERSION.yml
108
- - conf/cacert.pem
109
- - examples.rb
110
- - features/add_event.feature
111
- - features/step_definitions/keen_steps.rb
112
- - features/support/before_and_after.rb
113
- - features/support/env.rb
45
+ - config/cacert.pem
114
46
  - keen.gemspec
115
- - keen.gemspec.old
116
47
  - lib/keen.rb
117
48
  - lib/keen/client.rb
118
- - lib/keen/event.rb
119
- - lib/keen/keys.rb
120
- - lib/keen/utils.rb
49
+ - lib/keen/http.rb
121
50
  - lib/keen/version.rb
122
- homepage: http://github.com/dorkitude/keen
123
- licenses:
124
- - MIT
51
+ - spec/integration/api_spec.rb
52
+ - spec/integration/spec_helper.rb
53
+ - spec/keen/client_spec.rb
54
+ - spec/keen/keen_spec.rb
55
+ - spec/keen/spec_helper.rb
56
+ - spec/spec_helper.rb
57
+ homepage: https://github.com/keenlabs/keen-gem
58
+ licenses: []
125
59
  post_install_message:
126
60
  rdoc_options: []
127
-
128
- require_paths:
61
+ require_paths:
129
62
  - lib
130
- required_ruby_version: !ruby/object:Gem::Requirement
63
+ required_ruby_version: !ruby/object:Gem::Requirement
131
64
  none: false
132
- requirements:
133
- - - ">="
134
- - !ruby/object:Gem::Version
135
- hash: -1792663848985586478
136
- segments:
137
- - 0
138
- version: "0"
139
- required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
140
70
  none: false
141
- requirements:
142
- - - ">="
143
- - !ruby/object:Gem::Version
144
- version: "0"
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
145
75
  requirements: []
146
-
147
76
  rubyforge_project:
148
- rubygems_version: 1.8.19
77
+ rubygems_version: 1.8.23
149
78
  signing_key:
150
79
  specification_version: 3
151
- summary: A library for batching and sending arbitrary events to the Keen API at http://keen.io
152
- test_files: []
153
-
80
+ summary: Keen IO API Client
81
+ test_files:
82
+ - spec/integration/api_spec.rb
83
+ - spec/integration/spec_helper.rb
84
+ - spec/keen/client_spec.rb
85
+ - spec/keen/keen_spec.rb
86
+ - spec/keen/spec_helper.rb
87
+ - spec/spec_helper.rb