keen 0.8.0 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c3cf3ae16e58f3c518d668690727dee634e620ec
4
- data.tar.gz: bb8e8adde18854b35095b90017dc468900e28201
3
+ metadata.gz: bfa6893d4994089e26e547221cd8471568335ec6
4
+ data.tar.gz: c353a3635a5656b6b9e0a4840d1bd88de8beac21
5
5
  SHA512:
6
- metadata.gz: 097d04970b5ce6c0779b96655cd29aa747d1df5eeb4506dfc4763546fae08c7bd3b6f7ed48f5b4f2dcbd3a4caeb433778fda7bfa67d5871c9f9d3c2ffa4d48e2
7
- data.tar.gz: 732360e3dd2873579493eb08f407055929cc9d27a5285ef8d592dcfd94f69999d66f4d62787a0557b96b485409bdb2cb35a5233ff270b81b73e057c0e1247cdf
6
+ metadata.gz: 75adf0c282766b84c1d7be3fc5dab6567951b36f0d63456c12406a7845ccc401f1fb258b93de6e6e150c4fea2c5349bf50eee4719e8f7eeab40979a7b9cd86db
7
+ data.tar.gz: d9ed4ec4656056f296bdacab25b8ab980164330f62477c0333a1a3d4c7a0874665cde88e0c9e172cae11c0e1d4b0df323b0a9a5626f657e92681a7577320af70
data/README.md CHANGED
@@ -154,7 +154,7 @@ Keen.delete(:signups) # => true
154
154
 
155
155
  # Or just delete an event corresponding to a particular user
156
156
  Keen.delete(:signups, filters: [{
157
- :property_name => 'username', ;operator => 'eq', :property_value => "Bob"
157
+ :property_name => 'username', :operator => 'eq', :property_value => "Bob"
158
158
  }]) # => true
159
159
  ```
160
160
 
@@ -180,6 +180,23 @@ Keen.publish_batch(
180
180
  This call would publish 2 `signups` events and 2 `purchases` events - all in just one API call.
181
181
  Batch publishing is ideal for loading historical events into Keen IO.
182
182
 
183
+ #### Asynchronous batch publishing
184
+
185
+ Ensuring the above guidance is followed for asynchronous publishing, batch publishing logic can used asynchronously with `publish_batch_async`:
186
+
187
+ ```ruby
188
+ Keen.publish_batch_async(
189
+ :signups => [
190
+ { :name => "Bob" },
191
+ { :name => "Mary" }
192
+ ],
193
+ :purchases => [
194
+ { :price => 10 },
195
+ { :price => 20 }
196
+ ]
197
+ )
198
+ ```
199
+
183
200
  #### Configurable and per-client authentication
184
201
 
185
202
  To configure keen-gem in code, do as follows:
@@ -266,6 +283,9 @@ EventMachine itself won't do this because it runs in a different thread. Here's
266
283
 
267
284
  ### Changelog
268
285
 
286
+ ##### 0.8.1
287
+ + Add support for asynchronous batch publishing
288
+
269
289
  ##### 0.8.0
270
290
  + **UPGRADE WARNING** Do you use spaces in collection names? Or other special characters? Read [this post](https://groups.google.com/forum/?fromgroups#!topic/keen-io-devs/VtCgPuNKrgY) from the mailing list to make sure your collection names don't change.
271
291
  + Add support for generating [scoped keys](https://keen.io/docs/security/#scoped-key).
data/keen.gemspec CHANGED
@@ -12,9 +12,7 @@ Gem::Specification.new do |s|
12
12
  s.description = "Send events and build analytics features into your Ruby applications."
13
13
  s.license = "MIT"
14
14
 
15
- s.post_install_message = "**UPGRADE WARNING** Do you use spaces in collection names? Or other special characters? Read https://groups.google.com/forum/?fromgroups#!topic/keen-io-devs/VtCgPuNKrgY from the mailing list to make sure your collection names don't change!"
16
-
17
- s.add_dependency "multi_json", "~> 1.0"
15
+ s.add_dependency "multi_json", "~> 1.3"
18
16
  s.add_dependency "addressable", "~> 2.3.5"
19
17
  s.add_dependency "jruby-openssl" if defined?(JRUBY_VERSION)
20
18
 
data/lib/keen.rb CHANGED
@@ -39,7 +39,7 @@ module Keen
39
39
 
40
40
  def_delegators :default_client,
41
41
  :publish, :publish_async, :publish_batch,
42
- :beacon_url, :redirect_url
42
+ :publish_batch_async, :beacon_url, :redirect_url
43
43
 
44
44
  def_delegators :default_client,
45
45
  :count, :count_unique, :minimum, :maximum,
@@ -77,6 +77,26 @@ module Keen
77
77
  end
78
78
  end
79
79
 
80
+ def publish_batch_async(events)
81
+ ensure_project_id!
82
+ ensure_write_key!
83
+
84
+ http_client = Keen::HTTP::Async.new(
85
+ self.api_url,
86
+ {:proxy_url => self.proxy_url, :proxy_type => self.proxy_type})
87
+
88
+ http = http_client.post(
89
+ :path => api_events_resource_path,
90
+ :headers => api_headers(self.write_key, "async"),
91
+ :body => MultiJson.encode(events)
92
+ )
93
+ if defined?(EM::Synchrony)
94
+ process_with_synchrony(http)
95
+ else
96
+ process_with_callbacks(http)
97
+ end
98
+ end
99
+
80
100
  # Returns an encoded URL that will record an event. Useful in email situations.
81
101
  # See detailed documentation here
82
102
  # https://keen.io/docs/api/reference/#event-collection-resource
data/lib/keen/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Keen
2
- VERSION = "0.8.0"
2
+ VERSION = "0.8.1"
3
3
  end
@@ -4,6 +4,15 @@ describe "Keen IO API" do
4
4
  let(:project_id) { ENV['KEEN_PROJECT_ID'] }
5
5
  let(:write_key) { ENV['KEEN_WRITE_KEY'] }
6
6
 
7
+ def wait_for_count(event_collection, count)
8
+ attempts = 0
9
+ while attempts < 30
10
+ break if Keen.count(event_collection) == count
11
+ attempts += 1
12
+ sleep(1)
13
+ end
14
+ end
15
+
7
16
  describe "publishing" do
8
17
  let(:collection) { "User posts.new" }
9
18
  let(:event_properties) { { "name" => "Bob" } }
@@ -85,6 +94,35 @@ describe "Keen IO API" do
85
94
  end
86
95
  end
87
96
 
97
+ describe "batch_async" do
98
+ # no TLS support in EventMachine on jRuby
99
+ unless defined?(JRUBY_VERSION)
100
+ let(:api_success) { {"batch_purchases"=>[{"success"=>true}, {"success"=>true}], "batch_signups"=>[{"success"=>true}, {"success"=>true}]} }
101
+ it "should publish the event and trigger callbacks" do
102
+ EM.run {
103
+ Keen.publish_batch_async(
104
+ :batch_signups => [
105
+ { :name => "bob" },
106
+ { :name => "ted" }
107
+ ],
108
+ :batch_purchases => [
109
+ { :price => 30 },
110
+ { :price => 40 }
111
+ ]).callback { |response|
112
+ begin
113
+ response.should == api_success
114
+ ensure
115
+ EM.stop
116
+ end
117
+ }.errback { |error|
118
+ EM.stop
119
+ fail error
120
+ }
121
+ }
122
+ end
123
+ end
124
+ end
125
+
88
126
  describe "queries" do
89
127
  let(:read_key) { ENV['KEEN_READ_KEY'] }
90
128
  let(:event_collection) { @event_collection }
@@ -106,26 +144,25 @@ describe "Keen IO API" do
106
144
  :username => "bob",
107
145
  :price => 30
108
146
  })
109
- sleep(5)
110
- end
111
147
 
112
- it "should return a valid count" do
113
- Keen.count(event_collection).should == 2
148
+ # poll the count to know when to continue
149
+ wait_for_count(@event_collection, 2)
150
+ wait_for_count(@returns_event_collection, 1)
114
151
  end
115
152
 
116
153
  it "should return a valid count_unique" do
117
154
  Keen.count_unique(event_collection, :target_property => "price").should == 2
118
155
  end
119
-
120
- it "should return a valid count with group_by" do
156
+
157
+ it "should return a valid count with group_by" do
121
158
  response = Keen.average(event_collection, :group_by => "username", :target_property => "price")
122
159
  bobs_response = response.select { |result| result["username"] == "bob" }.first
123
160
  bobs_response["result"].should == 10
124
161
  teds_response = response.select { |result| result["username"] == "ted" }.first
125
- teds_response["result"].should == 20
162
+ teds_response["result"].should == 20
126
163
  end
127
-
128
- it "should return a valid count with multi-group_by" do
164
+
165
+ it "should return a valid count with multi-group_by" do
129
166
  response = Keen.average(event_collection, :group_by => ["username", "price"], :target_property => "price")
130
167
  bobs_response = response.select { |result| result["username"] == "bob" }.first
131
168
  bobs_response["result"].should == 10
@@ -189,15 +226,14 @@ describe "Keen IO API" do
189
226
  before do
190
227
  Keen.publish(event_collection, :delete => "me")
191
228
  Keen.publish(event_collection, :delete => "you")
192
- sleep(10)
229
+ wait_for_count(event_collection, 2)
193
230
  end
194
231
 
195
232
  it "should delete the event" do
196
- Keen.count(event_collection).should == 2
197
233
  Keen.delete(event_collection, :filters => [
198
234
  { :property_name => "delete", :operator => "eq", :property_value => "me" }
199
235
  ])
200
- sleep(3)
236
+ wait_for_count(event_collection, 1)
201
237
  results = Keen.extraction(event_collection)
202
238
  results.length.should == 1
203
239
  results.first["delete"].should == "you"
@@ -130,7 +130,7 @@ describe Keen::Client::PublishingMethods do
130
130
  ensure
131
131
  EM.stop
132
132
  end
133
- }.errback {
133
+ }.errback {
134
134
  EM.stop
135
135
  fail
136
136
  }
@@ -211,6 +211,84 @@ describe Keen::Client::PublishingMethods do
211
211
  end
212
212
  end
213
213
 
214
+ describe "publish_batch_async" do
215
+ unless defined?(JRUBY_VERSION)
216
+ let(:multi) { EventMachine::MultiRequest.new }
217
+ let(:events) {
218
+ {
219
+ :purchases => [
220
+ { :price => 10 },
221
+ { :price => 11 }
222
+ ],
223
+ :signups => [
224
+ { :name => "bob" },
225
+ { :name => "bill" }
226
+ ]
227
+ }
228
+ }
229
+
230
+ it "should raise an exception if client has no project_id" do
231
+ expect {
232
+ Keen::Client.new(
233
+ :write_key => "abcde"
234
+ ).publish_batch_async(events)
235
+ }.to raise_error(Keen::ConfigurationError, "Keen IO Exception: Project ID must be set")
236
+ end
237
+
238
+ it "should raise an exception if client has no write_key" do
239
+ expect {
240
+ Keen::Client.new(
241
+ :project_id => "12345"
242
+ ).publish_batch_async(events)
243
+ }.to raise_error(Keen::ConfigurationError, "Keen IO Exception: Write Key must be set for sending events")
244
+ end
245
+
246
+ describe "deferrable callbacks" do
247
+ it "should trigger callbacks" do
248
+ stub_keen_post(api_event_resource_url(api_url), 201, api_success)
249
+ EM.run {
250
+ client.publish_batch_async(events).callback { |response|
251
+ begin
252
+ response.should == api_success
253
+ ensure
254
+ EM.stop
255
+ end
256
+ }
257
+ }
258
+ end
259
+
260
+ it "should trigger errbacks" do
261
+ stub_request(:post, api_event_resource_url(api_url)).to_timeout
262
+ EM.run {
263
+ client.publish_batch_async(events).errback { |error|
264
+ begin
265
+ error.should_not be_nil
266
+ error.message.should == "Keen IO Exception: HTTP publish_async failure: WebMock timeout error"
267
+ ensure
268
+ EM.stop
269
+ end
270
+ }
271
+ }
272
+ end
273
+
274
+ it "should not trap exceptions in the client callback" do
275
+ stub_keen_post(api_event_resource_url(api_url), 201, api_success)
276
+ expect {
277
+ EM.run {
278
+ client.publish_batch_async(events).callback {
279
+ begin
280
+ blowup
281
+ ensure
282
+ EM.stop
283
+ end
284
+ }
285
+ }
286
+ }.to raise_error
287
+ end
288
+ end
289
+ end
290
+ end
291
+
214
292
  it "should raise an exception if client has no project_id" do
215
293
  expect {
216
294
  Keen::Client.new.publish_async(collection, event_properties)
@@ -237,4 +315,5 @@ describe Keen::Client::PublishingMethods do
237
315
  "#{api_url}/3.0/projects/12345/events/sign_ups?api_key=#{write_key}&data=eyJuYW1lIjoiQm9iIn0=&redirect=http://keen.io/?foo=bar&bar=baz"
238
316
  end
239
317
  end
318
+
240
319
  end
@@ -84,7 +84,7 @@ describe Keen do
84
84
  end
85
85
  end
86
86
 
87
- [:publish, :publish_async, :publish_batch].each do |_method|
87
+ [:publish, :publish_async, :publish_batch, :publish_batch_async].each do |_method|
88
88
  it "should forward the #{_method} method" do
89
89
  @default_client.should_receive(_method).with("users", {})
90
90
  Keen.send(_method, "users", {})
@@ -7,6 +7,19 @@ describe Keen::HTTP::Async do
7
7
  let(:api_url) { "https://fake.keen.io" }
8
8
  let(:event_properties) { { "name" => "Bob" } }
9
9
  let(:api_success) { { "created" => true } }
10
+ let(:batch_api_success) { { "created" => true } }
11
+ let(:events) {
12
+ {
13
+ :purchases => [
14
+ { :price => 10 },
15
+ { :price => 11 }
16
+ ],
17
+ :signups => [
18
+ { :name => "bob" },
19
+ { :name => "bill" }
20
+ ]
21
+ }
22
+ }
10
23
 
11
24
  describe "synchrony" do
12
25
  before do
@@ -25,7 +38,7 @@ describe Keen::HTTP::Async do
25
38
  }
26
39
  end
27
40
 
28
- it "should recieve the right response 'synchronously'" do
41
+ it "should receive the right response 'synchronously'" do
29
42
  stub_keen_post(api_event_collection_resource_url(api_url, collection), 201, api_success)
30
43
  EM.synchrony {
31
44
  @client.publish_async(collection, event_properties).should == api_success
@@ -34,6 +47,25 @@ describe Keen::HTTP::Async do
34
47
  end
35
48
  end
36
49
 
50
+ describe "batch success" do
51
+ it "should post the event data" do
52
+ stub_keen_post(api_event_resource_url(api_url), 201, api_success)
53
+ EM.synchrony {
54
+ @client.publish_batch_async(events)
55
+ expect_keen_post(api_event_resource_url(api_url), events, "async", write_key)
56
+ EM.stop
57
+ }
58
+ end
59
+
60
+ it "should receive the right response 'synchronously'" do
61
+ stub_keen_post(api_event_resource_url(api_url), 201, api_success)
62
+ EM.synchrony {
63
+ @client.publish_batch_async(events).should == api_success
64
+ EM.stop
65
+ }
66
+ end
67
+ end
68
+
37
69
  describe "failure" do
38
70
  it "should raise an exception" do
39
71
  stub_request(:post, api_event_collection_resource_url(api_url, collection)).to_timeout
@@ -50,5 +82,22 @@ describe Keen::HTTP::Async do
50
82
  }
51
83
  end
52
84
  end
85
+
86
+ describe "batch failure" do
87
+ it "should raise an exception" do
88
+ stub_request(:post, api_event_resource_url(api_url)).to_timeout
89
+ e = nil
90
+ EM.synchrony {
91
+ begin
92
+ @client.publish_batch_async(events).should == api_success
93
+ rescue Exception => exception
94
+ e = exception
95
+ end
96
+ e.class.should == Keen::HttpError
97
+ e.message.should == "Keen IO Exception: HTTP em-synchrony publish_async error: WebMock timeout error"
98
+ EM.stop
99
+ }
100
+ end
101
+ end
53
102
  end
54
103
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: keen
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kyle Wild
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2014-01-09 00:00:00.000000000 Z
13
+ date: 2014-04-04 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: multi_json
@@ -18,14 +18,14 @@ dependencies:
18
18
  requirements:
19
19
  - - ~>
20
20
  - !ruby/object:Gem::Version
21
- version: '1.0'
21
+ version: '1.3'
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - ~>
27
27
  - !ruby/object:Gem::Version
28
- version: '1.0'
28
+ version: '1.3'
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: addressable
31
31
  requirement: !ruby/object:Gem::Requirement
@@ -179,9 +179,7 @@ homepage: https://github.com/keenlabs/keen-gem
179
179
  licenses:
180
180
  - MIT
181
181
  metadata: {}
182
- post_install_message: '**UPGRADE WARNING** Do you use spaces in collection names?
183
- Or other special characters? Read https://groups.google.com/forum/?fromgroups#!topic/keen-io-devs/VtCgPuNKrgY
184
- from the mailing list to make sure your collection names don''t change!'
182
+ post_install_message:
185
183
  rdoc_options: []
186
184
  require_paths:
187
185
  - lib