keen 0.8.0 → 0.8.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.
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