diff --git a/lib/heap/client.rb b/lib/heap/client.rb index e1d16ba..6c1c4df 100644 --- a/lib/heap/client.rb +++ b/lib/heap/client.rb @@ -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, @@ -129,6 +128,32 @@ def track(event, identity, properties = nil) self end + # Sends a collection of custom events to the Heap API servers. + # + # @param [EnumerableString,: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 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 diff --git a/lib/heap/validations.rb b/lib/heap/validations.rb index e409641..423e627 100644 --- a/lib/heap/validations.rb +++ b/lib/heap/validations.rb @@ -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 @@ -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! @@ -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 diff --git a/test/client_test.rb b/test/client_test.rb index 3f3c75a..4d69009 100644 --- a/test/client_test.rb +++ b/test/client_test.rb @@ -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 diff --git a/test/client_track_test.rb b/test/client_track_test.rb index 79a6aae..01b67f2 100644 --- a/test/client_track_test.rb +++ b/test/client_track_test.rb @@ -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'] @@ -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'] diff --git a/test/heap_test.rb b/test/heap_test.rb index 6939da3..11f278a 100644 --- a/test/heap_test.rb +++ b/test/heap_test.rb @@ -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