km 1.1.0

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.
Files changed (71) hide show
  1. data/.gitignore +4 -0
  2. data/CHANGELOG +4 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +33 -0
  5. data/README.rdoc +10 -0
  6. data/Rakefile +5 -0
  7. data/bin/km_send +26 -0
  8. data/doc/Accept.html +546 -0
  9. data/doc/Gemfile.html +110 -0
  10. data/doc/Hash.html +283 -0
  11. data/doc/Helper.html +318 -0
  12. data/doc/KM/IdentError.html +159 -0
  13. data/doc/KM/InitError.html +159 -0
  14. data/doc/KM/SaaS.html +451 -0
  15. data/doc/KM.html +493 -0
  16. data/doc/KMError.html +159 -0
  17. data/doc/Object.html +211 -0
  18. data/doc/README_rdoc.html +122 -0
  19. data/doc/Rakefile.html +111 -0
  20. data/doc/String.html +244 -0
  21. data/doc/bin/km_send.html +54 -0
  22. data/doc/created.rid +15 -0
  23. data/doc/images/brick.png +0 -0
  24. data/doc/images/brick_link.png +0 -0
  25. data/doc/images/bug.png +0 -0
  26. data/doc/images/bullet_black.png +0 -0
  27. data/doc/images/bullet_toggle_minus.png +0 -0
  28. data/doc/images/bullet_toggle_plus.png +0 -0
  29. data/doc/images/date.png +0 -0
  30. data/doc/images/find.png +0 -0
  31. data/doc/images/loadingAnimation.gif +0 -0
  32. data/doc/images/macFFBgHack.png +0 -0
  33. data/doc/images/package.png +0 -0
  34. data/doc/images/page_green.png +0 -0
  35. data/doc/images/page_white_text.png +0 -0
  36. data/doc/images/page_white_width.png +0 -0
  37. data/doc/images/plugin.png +0 -0
  38. data/doc/images/ruby.png +0 -0
  39. data/doc/images/tag_green.png +0 -0
  40. data/doc/images/wrench.png +0 -0
  41. data/doc/images/wrench_orange.png +0 -0
  42. data/doc/images/zoom.png +0 -0
  43. data/doc/index.html +142 -0
  44. data/doc/js/darkfish.js +116 -0
  45. data/doc/js/jquery.js +32 -0
  46. data/doc/js/quicksearch.js +114 -0
  47. data/doc/js/thickbox-compressed.js +10 -0
  48. data/doc/lib/km/saas_rb.html +54 -0
  49. data/doc/lib/km/version_rb.html +52 -0
  50. data/doc/lib/km_rb.html +60 -0
  51. data/doc/rdoc.css +730 -0
  52. data/doc/spec/accept_rb.html +62 -0
  53. data/doc/spec/km_old_rb.html +54 -0
  54. data/doc/spec/km_saas_spec_rb.html +56 -0
  55. data/doc/spec/km_send_spec_rb.html +54 -0
  56. data/doc/spec/km_spec_rb.html +54 -0
  57. data/doc/spec/setup_rb.html +60 -0
  58. data/doc/spec/watchr_rb.html +52 -0
  59. data/km.gemspec +28 -0
  60. data/lib/km/saas.rb +39 -0
  61. data/lib/km/version.rb +3 -0
  62. data/lib/km.rb +263 -0
  63. data/spec/accept.rb +90 -0
  64. data/spec/km_old.rb +105 -0
  65. data/spec/km_saas_spec.rb +121 -0
  66. data/spec/km_send_spec.rb +82 -0
  67. data/spec/km_spec.rb +186 -0
  68. data/spec/log/.hold +0 -0
  69. data/spec/setup.rb +78 -0
  70. data/spec/watchr.rb +3 -0
  71. metadata +224 -0
data/lib/km.rb ADDED
@@ -0,0 +1,263 @@
1
+ require 'cgi'
2
+ require 'socket'
3
+ require 'fileutils'
4
+ require 'km/saas'
5
+
6
+ class Hash
7
+ def reverse_merge(other_hash)
8
+ other_hash.merge(self)
9
+ end if !respond_to?(:reverse_merge)
10
+ def reverse_merge!(other_hash)
11
+ replace(reverse_merge(other_hash))
12
+ end if !respond_to?(:reverse_merge)
13
+ end
14
+
15
+ class KMError < StandardError; end
16
+
17
+ class KM
18
+ @id = nil
19
+ @key = nil
20
+ @logs = {}
21
+ @host = 'trk.kissmetrics.com:80'
22
+ @log_dir = '/tmp'
23
+ @to_stderr = true
24
+ @use_cron = false
25
+
26
+ class << self
27
+ class IdentError < StandardError; end
28
+ class InitError < StandardError; end
29
+
30
+ def init(key, options={})
31
+ default = {
32
+ :host => @host,
33
+ :log_dir => @log_dir,
34
+ :to_stderr => @to_stderr,
35
+ :use_cron => @use_cron,
36
+ :env => set_env,
37
+ }
38
+ options.reverse_merge!(default)
39
+ begin
40
+ @key = key
41
+ @host = options[:host]
42
+ @log_dir = options[:log_dir]
43
+ @use_cron = options[:use_cron]
44
+ @to_stderr = options[:to_stderr]
45
+ @env = options[:env]
46
+ log_dir_writable?
47
+ rescue Exception => e
48
+ log_error(e)
49
+ end
50
+ end
51
+
52
+ def set_env
53
+ @env = Rails.env if defined? Rails
54
+ @env ||= ENV['RACK_ENV']
55
+ @env ||= 'production'
56
+ end
57
+
58
+ def identify(id)
59
+ @id = id
60
+ end
61
+
62
+ def record(action,props={})
63
+ props = hash_keys_to_str(props)
64
+ begin
65
+ return unless is_initialized_and_identified?
66
+ return set(action) if action.class == Hash
67
+
68
+ props.update('_n' => action)
69
+ generate_query('e', props)
70
+ rescue Exception => e
71
+ log_error(e)
72
+ end
73
+ end
74
+
75
+ def alias(name, alias_to)
76
+ begin
77
+ return unless is_initialized?
78
+ generate_query('a', { '_n' => alias_to, '_p' => name }, false)
79
+ rescue Exception => e
80
+ log_error(e)
81
+ end
82
+ end
83
+
84
+ def set(data)
85
+ begin
86
+ return unless is_initialized_and_identified?
87
+ generate_query('s', data)
88
+ rescue Exception => e
89
+ log_error(e)
90
+ end
91
+ end
92
+
93
+ def send_logged_queries # :nodoc:
94
+ line = nil
95
+ begin
96
+ query_log = log_name(:query_old)
97
+ query_log = log_name(:query) unless File.exists?(query_log)
98
+ return unless File.exists?(query_log) # can't find logfile to send
99
+ FileUtils.move(query_log, log_name(:send))
100
+ File.open(log_name(:send)) do |fh|
101
+ while not fh.eof?
102
+ begin
103
+ line = fh.readline.chomp
104
+ send_query(line)
105
+ rescue Exception => e
106
+ log_query(line) if line
107
+ log_error(e)
108
+ end
109
+ end
110
+ end
111
+ FileUtils.rm(log_name(:send))
112
+ rescue Exception => e
113
+ log_error(e)
114
+ end
115
+ end
116
+
117
+ def log_dir
118
+ @log_dir
119
+ end
120
+ def host
121
+ @host
122
+ end
123
+
124
+ # :stopdoc:
125
+ protected
126
+ def hash_keys_to_str(hash)
127
+ Hash[*hash.map { |k,v| k.class == Symbol ? [k.to_s,v] : [k,v] }.flatten] # convert all keys to strings
128
+ end
129
+ def reset
130
+ @id = nil
131
+ @key = nil
132
+ @logs = {}
133
+ @host = 'trk.kissmetrics.com:80'
134
+ @log_dir = '/tmp'
135
+ @to_stderr = true
136
+ @use_cron = false
137
+ end
138
+
139
+ def log_name(type)
140
+ return @logs[type] if @logs[type]
141
+ fname = ''
142
+ env = @env ? "_#{@env}" : ''
143
+ case type
144
+ when :error
145
+ fname = "kissmetrics#{env}_error.log"
146
+ when :query
147
+ fname = "kissmetrics#{env}_query.log"
148
+ when :query_old # backwards compatibility
149
+ fname = "kissmetrics_query.log"
150
+ when :sent
151
+ fname = "kissmetrics#{env}_sent.log"
152
+ when :send
153
+ fname = Time.now.to_i.to_s + "kissmetrics_#{env}_sending.log"
154
+ end
155
+ @logs[type] = File.join(@log_dir,fname)
156
+ end
157
+
158
+ def log_query(msg)
159
+ log(:query,msg)
160
+ end
161
+
162
+ def log_sent(msg)
163
+ log(:sent,msg)
164
+ end
165
+
166
+ def log_send(msg)
167
+ log(:send,msg)
168
+ end
169
+
170
+ def log_error(error)
171
+ if defined?(HoptoadNotifier)
172
+ HoptoadNotifier.notify_or_ignore(KMError.new(error))
173
+ end
174
+ msg = Time.now.strftime("<%c> ") + error.message
175
+ $stderr.puts msg if @to_stderr
176
+ log(:error, msg)
177
+ rescue Exception # rescue incase hoptoad has issues
178
+ end
179
+
180
+ def log(type,msg)
181
+ begin
182
+ File.open(log_name(type), 'a') do |fh|
183
+ fh.puts(msg)
184
+ end
185
+ rescue Exception => e
186
+ raise KMError.new(e) if type.to_s == 'query'
187
+ # just discard at this point otherwise
188
+ end
189
+ end
190
+
191
+
192
+ def generate_query(type, data, update=true)
193
+ data = hash_keys_to_str(data)
194
+ query_arr = []
195
+ query = ''
196
+ data.update('_p' => @id) unless update == false
197
+ data.update('_k' => @key)
198
+ data.update '_d' => 1 if data['_t']
199
+ data.reverse_merge!('_t' => Time.now.to_i)
200
+ data.inject(query) do |query,key_val|
201
+ query_arr << key_val.collect { |i| CGI.escape i.to_s }.join('=')
202
+ end
203
+ query = '/' + type + '?' + query_arr.join('&')
204
+ if @use_cron
205
+ log_query(query)
206
+ else
207
+ begin
208
+ send_query(query)
209
+ rescue Exception => e
210
+ log_query(query)
211
+ log_error(e)
212
+ end
213
+ end
214
+ end
215
+
216
+ def send_query(line)
217
+ if @env != 'production'
218
+ log_sent(line)
219
+ return
220
+ end
221
+ host,port = @host.split(':')
222
+ begin
223
+ sock = TCPSocket.open(host,port)
224
+ request = 'GET ' + line + " HTTP/1.1\r\n"
225
+ request += "Host: " + Socket.gethostname + "\r\n"
226
+ request += "Connection: Close\r\n\r\n";
227
+ sock.print(request)
228
+ sock.close
229
+ rescue Exception => e
230
+ raise KMError.new("#{e} for host #{@host}")
231
+ end
232
+ log_sent(line)
233
+ end
234
+
235
+ def log_dir_writable?
236
+ if not FileTest.writable? @log_dir
237
+ $stderr.puts("Could't open #{log_name(:query)} for writing. Does #{@log_dir} exist? Permissions?") if @to_stderr
238
+ end
239
+ end
240
+
241
+ def is_identified?
242
+ if @id == nil
243
+ log_error IdentError.new("Need to identify first (KM::identify <user>)")
244
+ return false
245
+ end
246
+ return true
247
+ end
248
+
249
+ def is_initialized_and_identified?
250
+ return false unless is_initialized?
251
+ return is_identified?
252
+ end
253
+
254
+ def is_initialized?
255
+ if @key == nil
256
+ log_error InitError.new("Need to initialize first (KM::init <your_key>)")
257
+ return false
258
+ end
259
+ return true
260
+ end
261
+ # :startdoc:
262
+ end
263
+ end
data/spec/accept.rb ADDED
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env ruby
2
+ require 'socket'
3
+ require 'rubygems'
4
+ require 'json'
5
+ require 'uri'
6
+ require 'cgi'
7
+
8
+ # a library to accept connections as a server, and send back what it received on request.
9
+
10
+ class Accept
11
+ attr_accessor :server, :session
12
+ attr_reader :opts
13
+ URI_REXEGP = /^\s*(\w+)\s+([^ ]*)\s+(.*)$/
14
+ def initialize(args = {})
15
+ opts = { :port => 9292, :debug => false }
16
+ opts.update(args)
17
+
18
+ puts "Starting up server on port #{opts[:port]} ..."
19
+ @opts = opts
20
+ @server = TCPServer.new(opts[:port])
21
+ @@input_history = []
22
+ @handle = Thread.start do
23
+ while (@session = server.accept)
24
+ Thread.start do
25
+ # puts "log: Connection from #{session.peeraddr[2]} at #{session.peeraddr[3]}"
26
+ # session.puts "Server: Connection from #{session.peeraddr[2]}\n"
27
+ handle_input
28
+ session.close
29
+ end
30
+ end
31
+ end
32
+ end
33
+ def input_history
34
+ @@input_history
35
+ end
36
+ def wait
37
+ @handle.join
38
+ end
39
+
40
+ def handle_input
41
+ input = session.gets
42
+ if input
43
+ puts "received: #{input.inspect}" if opts[:debug]
44
+ case input
45
+ when /clear/
46
+ clear
47
+ when /history/
48
+ session.puts input_history.to_json
49
+ when /exit/
50
+ begin
51
+ close
52
+ rescue Exception
53
+ end
54
+ return
55
+ when /^\s*(GET|POST|PUT|DELETE)\s+([^ ]*)\s+(.*)$/
56
+ @@input_history << parse_input(input)
57
+ else
58
+ @@input_history << input.chomp
59
+ end
60
+ end
61
+ end
62
+ def parse_input(input)
63
+ data = {}
64
+ data[:raw] = input.chomp
65
+ (method,uri,http) = input.scan(/^\s*(\w+)\s+([^ ]*)\s+(.*)$/).flatten
66
+
67
+ data[:method] = method
68
+ data[:http] = http.chomp
69
+ data[:uri] = uri
70
+ u = URI(uri)
71
+ data[:path] = u.path
72
+ data[:query] = CGI.parse(u.query)
73
+ return data
74
+ end
75
+ def close
76
+ session = nil
77
+ server.close
78
+ end
79
+ # clear history
80
+ def clear
81
+ @@input_history.clear
82
+ end
83
+ end
84
+ __END__
85
+ % ruby -r './lib/ruby/accept.rb' -e 'Accept.new(:debug => true, :port => 9292).wait'
86
+ Starting up server on port 9292 ...
87
+
88
+ echo rain | nc localhost 9292
89
+ % echo history | nc localhost 9292
90
+ ["rain"]
data/spec/km_old.rb ADDED
@@ -0,0 +1,105 @@
1
+ require 'setup'
2
+
3
+ describe KM do
4
+ attr_accessor :send_query, :log
5
+ before do
6
+ @send_query = []
7
+ @log = []
8
+ KM.stub(:send_query).and_return { |*args| send_query << args }
9
+ KM.stub(:log).and_return { |*args| log << Hash[*args] }
10
+ time = Time.at 1234567890
11
+ Time.stub!(:now).and_return(time)
12
+ KM.reset
13
+ end
14
+ context "initialization" do
15
+ it "should not record without initialization" do
16
+ KM::record 'My Action'
17
+ log.first[:error].should =~ /Need to initialize first \(KM::init <your_key>\)/
18
+ end
19
+ it "should not set initialization" do
20
+ KM::set :day => 'friday'
21
+ log.first[:error].should =~ /Need to initialize first \(KM::init <your_key>\)/
22
+ end
23
+ end
24
+ context "identification" do
25
+ before do
26
+ KM::init 'KM_KEY'
27
+ end
28
+ it "should not record without identification" do
29
+ KM::record 'My Action'
30
+ log.first[:error].should include("Need to identify first (KM::identify <user>)")
31
+ end
32
+ it "should set without identification" do
33
+ KM::record 'My Action'
34
+ log.first[:error].should include("Need to identify first (KM::identify <user>)")
35
+ end
36
+
37
+ context "aliasing" do
38
+ it "shouldn't fail on alias without identifying" do
39
+ KM::alias 'peter','joe' # Alias "bob" to "robert"
40
+ send_query.first.first.should have_query_string("/a?_n=joe&_p=peter&_k=KM_KEY&_t=1234567890")
41
+ end
42
+ end
43
+ end
44
+
45
+ context "events" do
46
+ before do
47
+ KM::init 'KM_KEY'
48
+ KM::identify 'bob'
49
+ end
50
+ it "should record an action with no specific props" do
51
+ KM::record 'My Action'
52
+ send_query.first.first.should have_query_string("/e?_n=My+Action&_p=bob&_k=KM_KEY&_t=1234567890")
53
+ end
54
+ it "should record an action with properties" do
55
+ KM::record 'Signup', 'age' => 26
56
+ send_query.first.first.should have_query_string("/e?age=26&_n=Signup&_p=bob&_k=KM_KEY&_t=1234567890")
57
+ end
58
+ it "should reocrd properties with spaces in key and value" do
59
+ KM::record 'Signup', 'age' => 26, 'city of residence' => 'eug ene'
60
+ send_query.first.first.should have_query_string("/e?age=26&city+of+residence=eug+ene&_n=Signup&_p=bob&_k=KM_KEY&_t=1234567890")
61
+ end
62
+ it "should not over-write special keys" do
63
+ KM::record 'Signup', 'age' => 26, '_p' => 'billybob', '_k' => 'foo', '_n' => 'something else'
64
+ send_query.first.first.should have_query_string("/e?age=26&_p=bob&_k=KM_KEY&_n=Signup&_t=1234567890")
65
+ end
66
+ it "should not over-write special keys with symbols" do
67
+ KM::record 'Signup', 'age' => 26, '_p' => 'billybob', :'_k' => 'foo', :'_n' => 'something else'
68
+ send_query.first.first.should have_query_string("/e?age=26&_p=bob&_k=KM_KEY&_n=Signup&_t=1234567890")
69
+ end
70
+ it "should work with properties with @" do
71
+ KM::record 'Signup', 'email' => 'test@blah.com', '_p' => 'billybob', '_k' => 'foo', '_n' => 'something else'
72
+ send_query.first.first.should have_query_string("/e?email=test%40blah.com&_p=bob&_k=KM_KEY&_n=Signup&_t=1234567890")
73
+ end
74
+ it "should work with just set" do
75
+ KM::record 'age' => 26
76
+ send_query.first.first.should have_query_string("/s?age=26&_p=bob&_k=KM_KEY&_t=1234567890")
77
+ end
78
+ it "should record ok with multiple calls" do
79
+ KM::record 'Signup', 'age' => 26
80
+ KM::record 'Signup', 'age' => 36
81
+ send_query.first.first.should have_query_string("/e?age=26&_n=Signup&_p=bob&_k=KM_KEY&_t=1234567890")
82
+ send_query.last.first.should have_query_string("/e?age=36&_n=Signup&_p=bob&_k=KM_KEY&_t=1234567890")
83
+ end
84
+ it "shouldn't store the key anywhere" do
85
+ KM::init 'KM_OTHER'
86
+ KM::alias 'truman','harry' # Alias "bob" to "robert"
87
+ send_query.first.first.should have_query_string("/a?_n=harry&_p=truman&_k=KM_OTHER&_t=1234567890")
88
+ end
89
+ it "should override the time if defined" do
90
+ KM::record 'Signup', 'age' => 36, '_t' => 1234567891
91
+ send_query.last.first.should have_query_string("/e?age=36&_n=Signup&_p=bob&_k=KM_KEY&_t=1234567891&_d=1")
92
+ end
93
+ it "should work with either symbols or strings" do
94
+ KM::record :Signup, :age => 36, :_t => 1234567891
95
+ send_query.last.first.should have_query_string("/e?age=36&_n=Signup&_p=bob&_k=KM_KEY&_t=1234567891&_d=1")
96
+ end
97
+ end
98
+
99
+ it "should test cron" do
100
+ pending
101
+ end
102
+ it "should send logged queries" do
103
+ pending
104
+ end
105
+ end
@@ -0,0 +1,121 @@
1
+ require 'setup'
2
+ require 'km/saas'
3
+ describe KM do
4
+ before do
5
+ KM::reset
6
+ now = Time.now
7
+ Time.stub!(:now).and_return(now)
8
+ FileUtils.rm_f KM::log_name(:error)
9
+ FileUtils.rm_f KM::log_name(:query)
10
+ Helper.clear
11
+ end
12
+
13
+ describe "should record events" do
14
+ before do
15
+ KM::init 'KM_KEY', :log_dir => __('log'), :host => '127.0.0.1:9292'
16
+ KM::identify 'bob'
17
+ end
18
+ context "plain usage" do
19
+ it "records a signup event" do
20
+ KM.signed_up 'Premium'
21
+ sleep 0.1
22
+ res = Helper.accept(:history).first.indifferent
23
+ res[:path].should == '/e'
24
+ res[:query]['_n'].first.should == 'Signed Up'
25
+ res[:query]['Plan Name'].first.should == 'Premium'
26
+ end
27
+ it "records an upgraded event" do
28
+ KM.upgraded 'Unlimited'
29
+ sleep 0.1
30
+ res = Helper.accept(:history).first.indifferent
31
+ res[:path].should == '/e'
32
+ res[:query]['_n'].first.should == 'Upgraded'
33
+ res[:query]['Plan Name'].first.should == 'Unlimited'
34
+ end
35
+ it "records a downgraded event" do
36
+ KM.downgraded 'Free'
37
+ sleep 0.1
38
+ res = Helper.accept(:history).first.indifferent
39
+ res[:path].should == '/e'
40
+ res[:query]['_n'].first.should == 'Downgraded'
41
+ res[:query]['Plan Name'].first.should == 'Free'
42
+ end
43
+ it "records a billed event" do
44
+ KM.billed 32, 'Upgraded'
45
+ sleep 0.1
46
+ res = Helper.accept(:history).first.indifferent
47
+ res[:path].should == '/e'
48
+ res[:query]['_n'].first.should == 'Billed'
49
+ res[:query]['Billing Amount'].first.should == '32'
50
+ res[:query]['Billing Description'].first.should == 'Upgraded'
51
+ end
52
+ it "records a canceled event" do
53
+ KM.canceled
54
+ sleep 0.1
55
+ res = Helper.accept(:history).first.indifferent
56
+ res[:path].should == '/e'
57
+ res[:query]['_n'].first.should == 'Canceled'
58
+ end
59
+ it "records a cancelled event" do
60
+ KM.cancelled
61
+ sleep 0.1
62
+ res = Helper.accept(:history).first.indifferent
63
+ res[:path].should == '/e'
64
+ res[:query]['_n'].first.should == 'Canceled'
65
+ end
66
+ it "records a visited site event" do
67
+ KM.visited_site 'http://duckduckgo.com', 'http://kissmetrics.com'
68
+ sleep 0.1
69
+ res = Helper.accept(:history).first.indifferent
70
+ res[:path].should == '/e'
71
+ res[:query]['_n'].first.should == 'Visited Site'
72
+ res[:query]['URL'].first.should == 'http://duckduckgo.com'
73
+ res[:query]['Referrer'].first.should == 'http://kissmetrics.com'
74
+ end
75
+ end
76
+ context "usage with props" do
77
+ it "records a signup event" do
78
+ KM.signed_up 'Premium', :foo => 'bar'
79
+ sleep 0.1
80
+ res = Helper.accept(:history).first.indifferent
81
+ res[:query]['foo'].first.should == 'bar'
82
+ end
83
+ it "records an upgraded event" do
84
+ KM.upgraded 'Unlimited', :foo => 'bar'
85
+ sleep 0.1
86
+ res = Helper.accept(:history).first.indifferent
87
+ res[:query]['foo'].first.should == 'bar'
88
+ end
89
+ it "records a downgraded event" do
90
+ KM.downgraded 'Free', :foo => 'bar'
91
+ sleep 0.1
92
+ res = Helper.accept(:history).first.indifferent
93
+ res[:query]['foo'].first.should == 'bar'
94
+ end
95
+ it "records a billed event" do
96
+ KM.billed 32, 'Upgraded', :foo => 'bar'
97
+ sleep 0.1
98
+ res = Helper.accept(:history).first.indifferent
99
+ res[:query]['foo'].first.should == 'bar'
100
+ end
101
+ it "records a canceled event" do
102
+ KM.canceled :foo => 'bar'
103
+ sleep 0.1
104
+ res = Helper.accept(:history).first.indifferent
105
+ res[:query]['foo'].first.should == 'bar'
106
+ end
107
+ it "records a cancelled event" do
108
+ KM.cancelled :foo => 'bar'
109
+ sleep 0.1
110
+ res = Helper.accept(:history).first.indifferent
111
+ res[:query]['foo'].first.should == 'bar'
112
+ end
113
+ it "records a visited site event" do
114
+ KM.visited_site 'http://duckduckgo.com', 'http://kissmetrics.com', :foo => 'bar'
115
+ sleep 0.1
116
+ res = Helper.accept(:history).first.indifferent
117
+ res[:query]['foo'].first.should == 'bar'
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,82 @@
1
+ require 'setup'
2
+
3
+ describe 'km_send' do
4
+ context "using cron for sending logs" do
5
+ before do
6
+ now = Time.now
7
+ Time.stub!(:now).and_return(now)
8
+ Dir.glob(__('log','*')).each do |file|
9
+ FileUtils.rm file
10
+ end
11
+ KM.reset
12
+ Helper.clear
13
+ end
14
+ it "should test commandline version" do
15
+ KM::init 'KM_KEY', :log_dir => __('log'), :host => '127.0.0.1:9292', :use_cron => true
16
+ KM::identify 'bob'
17
+ KM::record 'Signup', 'age' => 26
18
+ `bundle exec km_send #{__('log/')} 127.0.0.1:9292`
19
+ sleep 0.1
20
+ res = Helper.accept(:history).first.indifferent
21
+ res[:path].should == '/e'
22
+ res[:query]['_k'].first.should == 'KM_KEY'
23
+ res[:query]['_p'].first.should == 'bob'
24
+ res[:query]['_n'].first.should == 'Signup'
25
+ res[:query]['_t'].first.should == Time.now.to_i.to_s
26
+ res[:query]['age'].first.should == '26'
27
+ end
28
+ it "should send from query_log" do
29
+ write_log :query, "/e?_t=1297105499&_n=Signup&_p=bob&_k=KM_KEY&age=26"
30
+ `bundle exec km_send #{__('log/')} 127.0.0.1:9292`
31
+ sleep 0.1
32
+ res = Helper.accept(:history).first.indifferent
33
+ res[:path].should == '/e'
34
+ res[:query]['_k'].first.should == 'KM_KEY'
35
+ res[:query]['_p'].first.should == 'bob'
36
+ res[:query]['_n'].first.should == 'Signup'
37
+ res[:query]['_t'].first.should == '1297105499'
38
+ res[:query]['age'].first.should == '26'
39
+ end
40
+ it "should send from query_log_old" do
41
+ write_log :query_old, "/e?_t=1297105499&_n=Signup&_p=bob&_k=KM_KEY&age=26"
42
+ `bundle exec km_send #{__('log/')} 127.0.0.1:9292`
43
+ sleep 0.1
44
+ res = Helper.accept(:history).first.indifferent
45
+ res[:path].should == '/e'
46
+ res[:query]['_k'].first.should == 'KM_KEY'
47
+ res[:query]['_p'].first.should == 'bob'
48
+ res[:query]['_n'].first.should == 'Signup'
49
+ res[:query]['_t'].first.should == '1297105499'
50
+ res[:query]['age'].first.should == '26'
51
+ end
52
+ it "should send from both query_log and query_log_old" do
53
+ File.open(__('log/kissmetrics_query.log'), 'w+') { |h| h.puts "/e?_t=1297105499&_n=Signup&_p=bob&_k=KM_KEY&age=27" }
54
+ File.open(__('log/kissmetrics_production_query.log'), 'w+') { |h| h.puts "/e?_t=1297105499&_n=Signup&_p=bob&_k=KM_KEY&age=26" }
55
+ `bundle exec km_send #{__('log/')} 127.0.0.1:9292`
56
+ sleep 0.1
57
+ res = Helper.accept(:history).first.indifferent
58
+ res[:path].should == '/e'
59
+ res[:query]['_k'].first.should == 'KM_KEY'
60
+ res[:query]['_p'].first.should == 'bob'
61
+ res[:query]['_n'].first.should == 'Signup'
62
+ res[:query]['_t'].first.should == '1297105499'
63
+ res[:query]['age'].first.should == '27'
64
+ Helper.clear
65
+ `bundle exec km_send #{__('log/')} 127.0.0.1:9292`
66
+ sleep 0.1
67
+ res = Helper.accept(:history).first.indifferent
68
+ res[:path].should == '/e'
69
+ res[:query]['_k'].first.should == 'KM_KEY'
70
+ res[:query]['_p'].first.should == 'bob'
71
+ res[:query]['_n'].first.should == 'Signup'
72
+ res[:query]['_t'].first.should == '1297105499'
73
+ res[:query]['age'].first.should == '26'
74
+ end
75
+ it "should not send from diff environment as we only send when env is production" do
76
+ File.open(__('log/kissmetrics_alpha_query.log'), 'w+') { |h| h.puts "/e?_t=1297105499&_n=Signup&_p=bob&_k=KM_KEY&age=26" }
77
+ `bundle exec km_send -e alpha #{__('log/')} 127.0.0.1:9292`
78
+ sleep 0.1
79
+ res = Helper.accept(:history).first.should == nil
80
+ end
81
+ end
82
+ end