Skip to content
This repository was archived by the owner on Feb 28, 2023. It is now read-only.

Add bulk tracking #13

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
35 changes: 30 additions & 5 deletions lib/heap/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -109,18 +109,17 @@ def add_user_properties(identity, properties)
def track(event, identity, properties = nil)
ensure_valid_app_id!

event_name = event.to_s
ensure_valid_event_name! event_name
ensure_valid_event_name! event
ensure_valid_identity! identity

body = {
:app_id => @app_id,
:identity => identity.to_s,
:event => event,
:identity => identity,
:event => event
}
ensure_valid_properties! properties
unless properties.nil?
body[:properties] = properties
ensure_valid_properties! properties
end

response = connection.post '/api/track', body,
Expand All @@ -129,6 +128,32 @@ def track(event, identity, properties = nil)
self
end

# Sends a collection of custom events to the Heap API servers.
#
# @param [Enumerable<Hash<:event=>String,:identity=>String(,:properties=>Hash)>] events a collection that responds to #each,
# which will yield Hashes containing the following key-value pairs:
# :event => String the name of the server-side event; limited to 1024 characters
# :identity => String an e-mail, handle, or Heap-generated user ID
# :properties => Hash<String, String|Number> key-value properties
# associated with the event; each key must have fewer than 1024 characters;
# each value must be a Number or String with fewer than 1024 characters
# @return [HeapAPI::Client] self
# @see https://heapanalytics.com/docs/server-side#bulk-track
def bulk_track(events)
ensure_valid_app_id!

events.each do |event_hash|
ensure_valid_event_name! event_hash[:event]
ensure_valid_identity! event_hash[:identity]
ensure_valid_properties! event_hash[:properties]
end

response = connection.post '/api/track', { :app_id => @app_id, :events => events },
'User-Agent' => user_agent
raise HeapAPI::ApiError.new(response) unless response.success?
self
end

# The underlying Faraday connection used to make HTTP requests.
#
# @return [Faraday::Connection] a Faraday connection object
Expand Down
27 changes: 16 additions & 11 deletions lib/heap/validations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def ensure_valid_app_id!
# @raise ArgumentError if the event name is invalid
# @return [HeapAPI::Client] self
def ensure_valid_event_name!(event)
event = event.to_s
raise ArgumentError, 'Missing or empty event name' if event.empty?
raise ArgumentError, 'Event name too long' if event.length > 1024
self
Expand All @@ -29,17 +30,17 @@ def ensure_valid_event_name!(event)
# @raise ArgumentError if identity is of an invalid type or too long.
# @return [HeapAPI::Client] self
def ensure_valid_identity!(identity)
identity = identity.to_s if identity.kind_of?(Integer)

if identity.kind_of?(String) || identity.kind_of?(Symbol)
if identity.to_s.length > 255
raise ArgumentError, "Identity field too long; " +
"#{identity.to_s.length} is above the 255-character limit"
if identity.kind_of?(Integer) || identity.kind_of?(String) || identity.kind_of?(Symbol)
identity = identity.to_s
if identity.length > 255
raise ArgumentError, "Identity field too long; #{identity.length} is above the 255-character limit"
end
else
raise ArgumentError,
"Unsupported type for identity value #{identity.inspect}"
end

self
end
private :ensure_valid_identity!

Expand All @@ -51,27 +52,31 @@ def ensure_valid_identity!(identity)
# @raise ArgumentError if the property bag is invalid
# @return [HeapAPI::Client] self
def ensure_valid_properties!(properties)
return self if properties.nil?
unless properties.respond_to?(:each)
raise ArgumentError, 'Properties object does not implement #each'
end

properties.each do |key, value|
if key.to_s.length > 1024
raise ArgumentError, "Property name #{key} too long; " +
"#{key.to_s.length} is above the 1024-character limit"
key_length = key.to_s.length
if key_length > 1024
raise ArgumentError, "Property name #{key} too long; #{key_length} is above the 1024-character limit"
end
if value.kind_of? Numeric
# TODO(pwnall): Check numerical limits, if necessary.
elsif value.kind_of?(String) || value.kind_of?(Symbol)
if value.to_s.length > 1024
value_length = value.to_s.length
if value_length > 1024
raise ArgumentError, "Property #{key} value #{value.inspect} too " +
"long; #{value.to_s.length} is above the 1024-character limit"
"long; #{value_length} is above the 1024-character limit"
end
else
raise ArgumentError,
"Unsupported type for property #{key} value #{value.inspect}"
end
end

self
end
private :ensure_valid_properties!
end
2 changes: 1 addition & 1 deletion test/client_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ def setup
end

def test_default_app_id
assert_equal nil, @heap.app_id
assert_nil @heap.app_id
end

def test_default_stubbed
Expand Down
39 changes: 38 additions & 1 deletion test/client_track_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ def test_track_with_integer_identity
@stubs.post '/api/track' do |env|
golden_body = {
'app_id' => 'test-app-id',
'identity' => '123456789',
'identity' => 123456789,
'event' => 'test_track',
}
assert_equal 'application/json', env[:request_headers]['Content-Type']
Expand Down Expand Up @@ -174,6 +174,43 @@ def test_track_with_properties
'test-identity','foo' => 'bar', :heap => :hurray)
end

def test_bulk_track
@stubs.post '/api/track' do |env|
golden_body = {
'app_id' => 'test-app-id',
'events' => [
{
'identity' => '123456789',
'event' => 'test_track'
},
{
'identity' => 'test-identity',
'event' => 'test_track_with_properties',
'properties' => { 'foo' => 'bar', 'heap' => 'hurray' }
}
]
}
assert_equal 'application/json', env[:request_headers]['Content-Type']
assert_equal @heap.user_agent, env[:request_headers]['User-Agent']
assert_equal golden_body, JSON.parse(env[:body])

[200, { 'Content-Type' => 'text/plain; encoding=utf8' }, '']
end

assert_equal @heap, @heap.bulk_track(
[
{
:event => 'test_track',
:identity => '123456789',
},
{
:event => 'test_track_with_properties',
:identity => 'test-identity',
:properties => { 'foo' => 'bar', :heap => :hurray }
}
])
end

def test_track_error
@stubs.post '/api/track' do |env|
[400, { 'Content-Type' => 'text/plain; encoding=utf8' }, 'Bad request']
Expand Down
2 changes: 1 addition & 1 deletion test/heap_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

class HeapTest < MiniTest::Test
def test_heap_app_id
assert_equal nil, Heap.app_id
assert_nil Heap.app_id
begin
Heap.app_id = 'global-app-id'
assert_equal 'global-app-id', Heap.app_id
Expand Down