turnstile-rb 2.0.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.
@@ -0,0 +1 @@
1
+ require_relative '../turnstile'
@@ -0,0 +1,20 @@
1
+ module Turnstile
2
+ class Sampler
3
+ def extrapolate(n)
4
+ (n * 100.0 / sampling_rate).to_i
5
+ end
6
+
7
+ # this method uses a unique string to integer hashing (object->hash)
8
+ # sampling shifts depending on the day of the month so that sampling
9
+ # does not stick to the same people all the time
10
+ def sample(uid)
11
+ ((uid.hash + Time.now.day) % 100) < sampling_rate
12
+ end
13
+
14
+ private
15
+
16
+ def sampling_rate
17
+ Turnstile.config.sampling_rate
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ module Turnstile
2
+ class Tracker
3
+ def track(uid, platform = 'unknown', ip = nil)
4
+ adapter.add(uid, platform, ip) if sampler.sample(uid)
5
+ end
6
+
7
+ private
8
+
9
+ def adapter
10
+ @adapter ||= Adapter.new
11
+ end
12
+
13
+ def sampler
14
+ @sampler ||= Sampler.new
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,3 @@
1
+ module Turnstile
2
+ VERSION = '2.0.0'
3
+ end
@@ -0,0 +1,4 @@
1
+ stuff hello x-turnstile|desktop|124.5.4.3|AF39945f8f87F more stuff
2
+ stuff hello x-turnstile|iphone|124.3.1.2|AF39945f8f87F more stuff
3
+ stuff hello x-turnstile|desktop|124.5.4.3|AF39945f8f87F more stuff
4
+ stuff hello x-turnstile|desktop|124.5.4.3|AF39945f8f87F more stuff
@@ -0,0 +1,37 @@
1
+ {"method":"GET","path":"/api/v1/users/5462583","format":"json","controller":"Api::V1::UsersController","action":"show","status":200,"duration":17.69,"view":11.92,"db":3.15,"time":"2017-03-22 10:46:17.592 -0700","pid":42045,"user_id":5462583,"platform":"ipad","session_id":"U6Dx4zoASN5KYfh6qLyU","params":{"last_view":"WMagicFeedViewController","client_id":"101","time":"1490204776","auth_token":"U6Dx4zoASN5KYfh6qLyU","format":"json","controller":"api/v1/users","action":"show","id":"5462583","user":{}},"ip_address":"69.61.173.104","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
2
+ called users_with_profile_by_product with per=10
3
+ {"method":"GET","path":"/api/v1/search/suggestions","format":"json","controller":"Api::V1::SearchController","action":"autocomplete","status":200,"duration":33.92,"view":17.07,"db":7.85,"time":"2017-03-22 10:46:17.622 -0700","pid":42021,"user_id":20860276,"platform":"iphone","session_id":"SRj6ePyUU9ey3y7DrFZw","params":{"query":"crop","type":"","last_view":"WProductSearchResultsViewController","client_id":"101","time":"1490204776","auth_token":"SRj6ePyUU9ey3y7DrFZw","format":"json","controller":"api/v1/search","action":"autocomplete","search":{}},"ip_address":"107.152.104.81","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
4
+ {"method":"GET","path":"/api/v1/products/39862579/details","format":"json","controller":"Api::V1::ProductsController","action":"details","status":200,"duration":70.26,"view":50.62,"db":15.4,"time":"2017-03-22 10:46:17.606 -0700","pid":42025,"user_id":null,"platform":"android","session_id":null,"params":{"format":"json","controller":"api/v1/products","action":"details","id":"39862579"},"ip_address":"23.235.47.28","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
5
+ {"method":"GET","path":"/api/v1/themes/products/5","format":"json","controller":"Api::V1::ThemesController","action":"products","status":200,"duration":944.52,"view":489.56,"db":195.77,"time":"2017-03-22 10:46:16.746 -0700","pid":42042,"user_id":5445274,"platform":"iphone","session_id":"qRQCRidfy88bHs1MzfYP","params":{"theme_path":"women,dresses,casual","last_view":"theme_Casual","client_id":"101","time":"1490204775","auth_token":"qRQCRidfy88bHs1MzfYP","format":"json","controller":"api/v1/themes","action":"products","page":"5","theme":{}},"ip_address":"68.134.103.85","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
6
+ {"method":"GET","path":"/api/v1/search/products/4","format":"json","controller":"Api::V1::ProductSearchController","action":"products","status":200,"duration":4.21,"view":0.0,"db":0.0,"time":"2017-03-22 10:46:17.693 -0700","pid":42021,"user_id":21086925,"platform":"iphone","session_id":"JKiDpyhSB5jaxwV9tECh","params":{"last_view":"theme_On Sale Now","on_sale":"true","per_page":"60","query":"","preprocess_query":"true","user":"brittnaydickinson","client_id":"101","time":"1490204776","auth_token":"JKiDpyhSB5jaxwV9tECh","format":"json","controller":"api/v1/product_search","action":"products","page":"4","product_search":{}},"ip_address":"168.17.61.221","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
7
+ searching solr for products (grand AND theft AND auto).. (elapsed: 1202.27ms)
8
+ {"method":"GET","path":"/api/v1/users/20447675","format":"json","controller":"Api::V1::UsersController","action":"show","status":200,"duration":23.39,"view":17.63,"db":3.29,"time":"2017-03-22 10:46:17.783 -0700","pid":42042,"user_id":20447675,"platform":"android","session_id":"vZQ5pJiPTLTsg7honwV5","params":{"time":"1490204777","client_id":"android","auth_token":"vZQ5pJiPTLTsg7honwV5","format":"json","controller":"api/v1/users","action":"show","id":"20447675"},"ip_address":"174.218.137.85","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
9
+ {"method":"GET","path":"/api/v1/users/19981112","format":"json","controller":"Api::V1::UsersController","action":"show","status":200,"duration":20.27,"view":14.9,"db":2.53,"time":"2017-03-22 10:46:17.793 -0700","pid":42030,"user_id":19981112,"platform":"iphone","session_id":"yyKeorp4QD98sxN4zLBu","params":{"last_view":"WReviewPhotosViewController","client_id":"101","time":"1490204777","auth_token":"yyKeorp4QD98sxN4zLBu","format":"json","controller":"api/v1/users","action":"show","id":"19981112","user":{}},"ip_address":"73.194.214.138","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
10
+ {"method":"GET","path":"/api/v1/users/4970486/order_surveys/current","format":"json","controller":"Api::V1::OrderSurveysController","action":"current","status":200,"duration":24.9,"view":10.6,"db":6.78,"time":"2017-03-22 10:46:17.841 -0700","pid":42030,"user_id":4970486,"platform":"iphone","session_id":"5z68kWXoCmWrwLidCut1","params":{"survey_version":"2","last_view":"WGuestLandingViewController","client_id":"101","time":"1490204777","auth_token":"5z68kWXoCmWrwLidCut1","format":"json","controller":"api/v1/order_surveys","action":"current","id":"4970486","order_survey":{}},"ip_address":"66.87.112.30","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
11
+ {"method":"GET","path":"/api/v1/saves/4SB8U-1Am9u-4ixC5","format":"json","controller":"Api::V1::SavesController","action":"show","status":200,"duration":49.01,"view":0.3,"db":9.31,"time":"2017-03-22 10:46:17.873 -0700","pid":42042,"user_id":17344742,"platform":"iphone","session_id":"4eKMZJ4nggzvkix29zpS","params":{"last_view":"product","client_id":"101","time":"1490204776","auth_token":"4eKMZJ4nggzvkix29zpS","format":"json","controller":"api/v1/saves","action":"show","id":"4SB8U-1Am9u-4ixC5","save":{}},"ip_address":"70.210.128.241","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
12
+ {"method":"GET","path":"/api/v1/products/trending","format":"json","controller":"Api::V1::TrendingController","action":"show","status":200,"duration":45.76,"view":17.29,"db":2.34,"time":"2017-03-22 10:46:17.878 -0700","pid":42021,"user_id":4970486,"platform":"iphone","session_id":"5z68kWXoCmWrwLidCut1","params":{"last_view":"trending","ignore_price_filters":"true","type":"","product_categories_from_settings":"true","client_id":"101","time":"1490204777","auth_token":"5z68kWXoCmWrwLidCut1","format":"json","controller":"api/v1/trending","action":"show","trending":{}},"ip_address":"66.87.112.30","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
13
+ {"method":"GET","path":"/api/v1/products/26548478/reviews","format":"json","controller":"Api::V1::ReviewsController","action":"product_index","status":200,"duration":21.28,"view":5.36,"db":6.0,"time":"2017-03-22 10:46:17.950 -0700","pid":42021,"user_id":10768109,"platform":"iphone","session_id":"RcT9ekNbhPsqydG4Pv7V","params":{"last_view":"WProductReviewsTableViewController","client_id":"101","time":"1490204776","auth_token":"RcT9ekNbhPsqydG4Pv7V","format":"json","controller":"api/v1/reviews","action":"product_index","product_id":"26548478","review":{}},"ip_address":"12.7.40.147","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
14
+ {"method":"GET","path":"/api/v1/products/40701853/variants/with_availability","format":"json","controller":"Api::V1::ProductsController","action":"variants_with_availability","status":200,"duration":312.66,"view":3.71,"db":26.85,"time":"2017-03-22 10:46:17.700 -0700","pid":42045,"user_id":8554487,"platform":"iphone","session_id":"qVwqQKpoBEtpE5H7TFpd","params":{"last_view":"product","f_type":"sf_195_cents_markup","p_type":"default","client_id":"101","time":"1490204777","auth_token":"qVwqQKpoBEtpE5H7TFpd","format":"json","controller":"api/v1/products","action":"variants_with_availability","id":"40701853","product":{}},"ip_address":"199.79.169.163","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
15
+ called users_with_profile_by_product with per=10
16
+ {"method":"GET","path":"/api/v1/products/50891048/details","format":"json","controller":"Api::V1::ProductsController","action":"details","status":200,"duration":76.89,"view":58.04,"db":15.28,"time":"2017-03-22 10:46:18.020 -0700","pid":42021,"user_id":null,"platform":"iphone","session_id":null,"params":{"f_type":"sf_180_cents_markup","p_type":"","format":"json","controller":"api/v1/products","action":"details","id":"50891048","product":{}},"ip_address":"23.235.47.40","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
17
+ {"method":"GET","path":"/search","format":"html","controller":"SearchController","action":"products","status":200,"duration":1595.73,"view":346.95,"db":50.27,"time":"2017-03-22 10:46:16.513 -0700","pid":42077,"user_id":null,"platform":"desktop","session_id":"90bba1d374001aedfe5b31525a528513","params":{"ref":"gsl","query":"Grand Theft Auto","page":"2","controller":"search","action":"products"},"ip_address":"162.223.13.23","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":"6LZrqw6xsO3nEiyheu340L7ObsGeCFmM11BILUFqljQ=","verified_request":true}
18
+ {"method":"HEAD","path":"/shop/custom-timberland-boots-etsy","format":"html","controller":"SeoPhrasesController","action":"show","status":200,"duration":1167.48,"view":391.63,"db":389.24,"time":"2017-03-22 10:46:16.966 -0700","pid":42079,"user_id":null,"platform":"desktop","session_id":"c00000b340017143f8502d0a2520274e","params":{"wnl_page_type":"Shop Page","wnl_page_version":"1.0","controller":"seo_phrases","action":"show","slug":"custom-timberland-boots-etsy"},"ip_address":"52.90.73.229","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":"4x1n4QllLThOYpXmR8bJgb8k+akwy1tBznIJWAttsLs=","verified_request":true}
19
+ {"method":"GET","path":"/api/v1/users/me/activity_feed/unified/2","format":"json","controller":"Api::V1::MagicFeedController","action":"unified","status":200,"duration":168.39,"view":70.15,"db":41.48,"time":"2017-03-22 10:46:17.973 -0700","pid":42042,"user_id":19719275,"platform":"iphone","session_id":"ywEoKieAZSvU7yoEbeyV","params":{"type":"no_affiliate_in_mf","last_view":"WMagicFeedViewController","client_id":"101","time":"1490204777","auth_token":"ywEoKieAZSvU7yoEbeyV","format":"json","controller":"api/v1/magic_feed","action":"unified","page":"2","magic_feed":{}},"ip_address":"69.80.178.31","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
20
+ Can't verify CSRF token authenticity
21
+ called users_with_profile_by_product with per=10
22
+ {"method":"GET","path":"/api/v1/saves/48WAQ-FpJA-4hvZ5/comments","format":"json","controller":"Api::V1::CommentsController","action":"index","status":200,"duration":7.9,"view":0.12,"db":2.36,"time":"2017-03-22 10:46:18.272 -0700","pid":42042,"user_id":null,"platform":"iphone","session_id":null,"params":{"order":"least_recent_first","format":"json","type":"save","controller":"api/v1/comments","action":"index","save_id":"48WAQ-FpJA-4hvZ5","comment":{}},"ip_address":"23.235.47.22","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
23
+ {"method":"GET","path":"/api/v1/saves/aTqO-8IVC-ew1O","format":"json","controller":"Api::V1::SavesController","action":"show","status":200,"duration":78.78,"view":0.38,"db":11.27,"time":"2017-03-22 10:46:18.229 -0700","pid":42079,"user_id":1977750,"platform":"iphone","session_id":"kHg6giEpAAQykW8uM6nf","params":{"last_view":"product","client_id":"101","time":"1490204777","auth_token":"kHg6giEpAAQykW8uM6nf","format":"json","controller":"api/v1/saves","action":"show","id":"aTqO-8IVC-ew1O","save":{}},"ip_address":"70.209.144.195","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
24
+ {"method":"GET","path":"/api/v1/products/40479095/comments","format":"json","controller":"Api::V1::CommentsController","action":"index","status":200,"duration":87.47,"view":0.16,"db":20.6,"time":"2017-03-22 10:46:18.298 -0700","pid":42088,"user_id":null,"platform":"iphone","session_id":null,"params":{"paged":"1","order":"least_recent_first","format":"json","type":"product","controller":"api/v1/comments","action":"index","product_id":"40479095","comment":{}},"ip_address":"23.235.47.40","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
25
+ {"method":"GET","path":"/api/v1/products/18531328/details","format":"json","controller":"Api::V1::ProductsController","action":"details","status":200,"duration":177.23,"view":153.44,"db":20.25,"time":"2017-03-22 10:46:18.223 -0700","pid":42045,"user_id":null,"platform":"iphone","session_id":null,"params":{"f_type":"sf_195_cents_markup","p_type":"default","format":"json","controller":"api/v1/products","action":"details","id":"18531328","product":{}},"ip_address":"23.235.47.51","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
26
+ {"method":"GET","path":"/api/v1/suggestions/products/8694532","format":"json","controller":"Api::V1::SuggestionsController","action":"products","status":200,"duration":451.62,"view":0.18,"db":153.67,"time":"2017-03-22 10:46:17.975 -0700","pid":42026,"user_id":null,"platform":"iphone","session_id":null,"params":{"type":"","format":"json","controller":"api/v1/suggestions","action":"products","product_id":"8694532","suggestion":{}},"ip_address":"23.235.47.44","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
27
+ {"method":"GET","path":"/api/v1/search/suggestions","format":"json","controller":"Api::V1::SearchController","action":"autocomplete","status":200,"duration":34.19,"view":17.4,"db":5.94,"time":"2017-03-22 10:46:18.400 -0700","pid":42079,"user_id":20860276,"platform":"iphone","session_id":"SRj6ePyUU9ey3y7DrFZw","params":{"query":"crop ","type":"","last_view":"WProductSearchResultsViewController","client_id":"101","time":"1490204777","auth_token":"SRj6ePyUU9ey3y7DrFZw","format":"json","controller":"api/v1/search","action":"autocomplete","search":{}},"ip_address":"107.152.104.81","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
28
+ called users_with_profile_by_product with per=10
29
+ {"method":"POST","path":"/api/v1/orders","format":"json","controller":"Api::V1::OrdersController","action":"new","status":200,"duration":343.03,"view":66.05,"db":142.68,"time":"2017-03-22 10:46:18.170 -0700","pid":42077,"user_id":9675208,"platform":"iphone","session_id":"9m5w4vTrfj7FVie9EMyN","params":{"product_id":"53487642","f_type":"sf_195_cents_markup","merge_tax_and_service_fee":"true","p_type":"default","last_view":"product","client_id":"101","time":"1490204776","auth_token":"9m5w4vTrfj7FVie9EMyN","format":"json","controller":"api/v1/orders","action":"new","order":{}},"ip_address":"172.56.29.65","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
30
+ {"method":"GET","path":"/api/v1/products/42913240/details","format":"json","controller":"Api::V1::ProductsController","action":"details","status":200,"duration":70.92,"view":48.06,"db":19.16,"time":"2017-03-22 10:46:18.457 -0700","pid":42026,"user_id":null,"platform":"iphone","session_id":null,"params":{"f_type":"sf_195_cents_markup","p_type":"fbw115","format":"json","controller":"api/v1/products","action":"details","id":"42913240","product":{}},"ip_address":"23.235.47.43","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
31
+ {"method":"GET","path":"/api/v1/suggestions/products/39862579","format":"json","controller":"Api::V1::SuggestionsController","action":"products","status":200,"duration":430.93,"view":0.36,"db":75.16,"time":"2017-03-22 10:46:18.100 -0700","pid":42009,"user_id":null,"platform":"android","session_id":null,"params":{"type":"buyable_and_affiliate","format":"json","controller":"api/v1/suggestions","action":"products","product_id":"39862579"},"ip_address":"23.235.47.49","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
32
+ {"method":"GET","path":"/api/v1/users/678238/collections","format":"json","controller":"Api::V1::UsersController","action":"collections","status":200,"duration":12.89,"view":0.14,"db":4.59,"time":"2017-03-22 10:46:18.608 -0700","pid":42026,"user_id":678238,"platform":"iphone","session_id":"L4dgADorpsmQUWFv5vJ7","params":{"last_view":"WMagicFeedViewController","client_id":"101","time":"1490204777","auth_token":"L4dgADorpsmQUWFv5vJ7","format":"json","controller":"api/v1/users","action":"collections","id":"678238","user":{}},"ip_address":"132.189.82.11","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
33
+ {"method":"GET","path":"/api/v1/products/34552155/variants/with_availability","format":"json","controller":"Api::V1::ProductsController","action":"variants_with_availability","status":200,"duration":77.38,"view":0.67,"db":17.95,"time":"2017-03-22 10:46:18.595 -0700","pid":42009,"user_id":10151188,"platform":"android","session_id":"uK8wwYNZjqXnoZz1bpGm","params":{"time":"1490204777","client_id":"android","auth_token":"uK8wwYNZjqXnoZz1bpGm","format":"json","controller":"api/v1/products","action":"variants_with_availability","id":"34552155"},"ip_address":"172.58.67.103","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
34
+ {"method":"GET","path":"/api/v1/users/5754901/collections","format":"json","controller":"Api::V1::UsersController","action":"collections","status":200,"duration":7.72,"view":0.12,"db":1.02,"time":"2017-03-22 10:46:18.668 -0700","pid":42088,"user_id":5754901,"platform":"iphone","session_id":"zqsActyuTd8zXpBo92ct","params":{"last_view":"trending","client_id":"101","time":"1490204777","auth_token":"zqsActyuTd8zXpBo92ct","format":"json","controller":"api/v1/users","action":"collections","id":"5754901","user":{}},"ip_address":"70.210.64.69","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
35
+ {"method":"POST","path":"/int/admin/stores/591600","format":"html","controller":"Admin::StoresController","action":"update","status":302,"duration":44.47,"view":0.0,"db":11.61,"location":"https://wanelo.co/int/admin/stores/591600","time":"2017-03-22 10:46:06.609 -0700","pid":75556,"user_id":14092896,"platform":"desktop","session_id":"2730608f1d862d6250f541b19ce8ffd3","params":{"_method":"put","authenticity_token":"t3A2nHFu5hyKmM66NPdEBUKBU4ePPlFGr0ufr64Qpzc=","store":{"category_id_with_event":"5"},"action":"update","controller":"admin/stores","id":"591600"},"ip_address":"182.255.42.49","hostname":null,"xhr":false,"authenticity_token":"t3A2nHFu5hyKmM66NPdEBUKBU4ePPlFGr0ufr64Qpzc=","authenticity_token_header":null,"expected_auth_token":"t3A2nHFu5hyKmM66NPdEBUKBU4ePPlFGr0ufr64Qpzc=","verified_request":true}
36
+ {"method":"GET","path":"/int/admin/stores/536402","format":"html","controller":"Admin::StoresController","action":"show","status":200,"duration":696.01,"view":267.24,"db":229.64,"time":"2017-03-22 10:46:05.977 -0700","pid":75568,"user_id":14092901,"platform":"desktop","session_id":"777dbb41f8d29008b1555630f1fb31a3","params":{"action":"show","controller":"admin/stores","id":"536402"},"ip_address":"103.196.139.175","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":"IV7BLkptllMtK+FAerenwT4bjFGaLymGD4jei9znUGw=","verified_request":true}
37
+ {"method":"GET","path":"/store/joyworkshoppe","format":"html","controller":"Legacy::StoresController","action":"show","status":200,"duration":469.7,"view":434.78,"db":16.0,"time":"2017-03-22 10:46:17.090 -0700","pid":42025,"user_id":null,"platform":"mobile_web","session_id":"5058494231f66532c08371587ed4eeb7","params":{"wnl_page_type":"Wanelo.com Store Page","wnl_page_version":"1.0","controller":"legacy/stores","action":"show","id":"joyworkshoppe"},"ip_address":"75.155.232.189","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":"Nf9dMhJlWzFHkzUouHnSLm1Cd+1EaSesoa75HhkJRkw=","verified_request":true}
@@ -0,0 +1,24 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+
8
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
9
+
10
+ require 'rubygems'
11
+ require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
12
+ require 'simplecov'
13
+
14
+ SimpleCov.start
15
+
16
+ require 'turnstile'
17
+ require 'rspec/its'
18
+
19
+ RSpec.configure do |config|
20
+ config.order = 'random'
21
+ config.before :each do
22
+ Turnstile::Adapter.new.redis.flushdb
23
+ end
24
+ end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+
3
+ describe Turnstile::Adapter do
4
+
5
+ subject { Turnstile::Adapter.new }
6
+
7
+ let(:redis) { subject.send(:redis) }
8
+
9
+ let(:uid) { 1238438 }
10
+ let(:other_uid) { 1238439 }
11
+ let(:another_uid) { 1238440 }
12
+
13
+ let(:ip) { '1.2.3.4' }
14
+ let(:another_ip) { '4.3.2.1' }
15
+
16
+ let(:platform) { :ios }
17
+ let(:another_platform) { :android }
18
+
19
+ describe '#add' do
20
+ it 'calls redis with the correct params' do
21
+ key = "t:#{uid}:#{platform}:#{ip}"
22
+ expect(redis).to receive(:setex).once.with(key, Turnstile.config.activity_interval, 1)
23
+ subject.add(uid, platform, ip)
24
+ end
25
+ end
26
+
27
+ describe '#fetch' do
28
+ let(:sort_lambda) { ->(a, b) { a[:uid] <=> b[:uid] } }
29
+ let(:expected_hash) do
30
+ [
31
+ { uid: uid.to_s, platform: platform.to_s, ip: ip },
32
+ { uid: other_uid.to_s, platform: platform.to_s, ip: ip },
33
+ { uid: another_uid.to_s, platform: another_platform.to_s, ip: another_ip },
34
+ ]
35
+ end
36
+
37
+ before do
38
+ subject.add(uid, platform, ip)
39
+ subject.add(other_uid, platform, ip)
40
+ subject.add(another_uid, another_platform, another_ip)
41
+ end
42
+
43
+ it 'pulls the platform specific stats from redis' do
44
+ expect(subject.fetch.sort(&sort_lambda)).to eq(expected_hash.sort(&sort_lambda))
45
+ end
46
+ end
47
+
48
+ describe '#aggregate' do
49
+ let(:expected_hash) do
50
+ {
51
+ 'android' => 3,
52
+ 'ios' => 2,
53
+ 'total' => 5
54
+ }
55
+ end
56
+
57
+ before do
58
+ subject.add(123, :android, ip)
59
+ subject.add(124, :android, ip)
60
+ subject.add(125, :android, ip)
61
+
62
+ subject.add(200, :ios, ip)
63
+ subject.add(201, :ios, ip)
64
+ end
65
+
66
+ it 'should calculated proper aggregation' do
67
+ expect(subject.aggregate).to eql expected_hash
68
+ end
69
+ end
70
+
71
+ end
@@ -0,0 +1,114 @@
1
+ require 'spec_helper'
2
+ require 'file/tail'
3
+ require 'timeout'
4
+ require 'thread'
5
+ require 'tempfile'
6
+
7
+ require 'turnstile/collector/log_reader'
8
+
9
+ describe Turnstile::Collector::LogReader do
10
+ include Timeout
11
+
12
+ def consume_file(reader, read_timeout)
13
+ hash = {}
14
+ counter = 0
15
+
16
+ run_reader(read_timeout) do
17
+ reader.read do |token|
18
+ counter += 1
19
+ hash[token] = 1
20
+ end
21
+ end
22
+ return counter, hash
23
+ end
24
+
25
+ def run_reader(read_timeout, &block)
26
+ t_reader = Thread.new do
27
+ begin
28
+ timeout(read_timeout) do
29
+ block.call
30
+ end
31
+ rescue Timeout::Error
32
+ end
33
+ end
34
+ t_reader.join
35
+ end
36
+
37
+ let(:queue) { Queue.new }
38
+ let(:read_timeout) { 0.1 }
39
+ let(:consume_file_result) { consume_file(reader, read_timeout) }
40
+ let(:counter) { consume_file_result.first }
41
+ let(:hash) { consume_file_result.last }
42
+
43
+ before { reader.file.backward(1000) }
44
+
45
+ context 'json log file' do
46
+ let(:file) { 'spec/fixtures/sample-production.log.json' }
47
+ let(:reader) { Turnstile::Collector::LogReader.json_formatted(file, queue) }
48
+
49
+ let(:expected_uniques) { 28 }
50
+ let(:expected_total) { 31 }
51
+ let(:expected_key) { 'ipad:69.61.173.104:5462583' }
52
+
53
+ context '#read' do
54
+ it 'should be able to read and parse IPs from a static file' do
55
+ expect(counter).to eql(expected_total)
56
+ expect(hash.keys.size).to eql(expected_uniques)
57
+ expect(hash.keys).to include(expected_key)
58
+ end
59
+ end
60
+
61
+ context '#process!' do
62
+ it 'should read values into the queue' do
63
+ run_reader(read_timeout) { reader.process! }
64
+ expect(queue.size).to eql(31)
65
+ end
66
+ end
67
+ end
68
+
69
+ context 'pipe delimited file' do
70
+ let(:file) { 'spec/fixtures/sample-production.log' }
71
+ let(:reader) { Turnstile::Collector::LogReader.pipe_delimited(file, queue) }
72
+
73
+ let(:log_reader) { Turnstile::Collector::LogReader }
74
+
75
+ let(:expected_uniques) { 2 }
76
+ let(:expected_total) { 4 }
77
+ let(:expected_key) { 'desktop:124.5.4.3:AF39945f8f87F' }
78
+
79
+ context 'matcher' do
80
+ subject(:matcher) { log_reader.delimited_matcher }
81
+
82
+ its(:regexp) { should_not be_nil }
83
+
84
+ its(:extractor) { should_not be_nil }
85
+ its(:extractor) { should be_kind_of(Proc) }
86
+
87
+ it 'should match lines in the file' do
88
+ File.open(file).each do |line|
89
+ expect(line).to match(matcher.regexp)
90
+ end
91
+ end
92
+ it 'should extract the token from file' do
93
+ File.open(file).each do |line|
94
+ expect(matcher.token_from(line)).to_not be_nil
95
+ end
96
+ end
97
+ end
98
+
99
+ context '#read' do
100
+ it 'should be load all matching rows' do
101
+ expect(counter).to eql(expected_total)
102
+ expect(hash.keys.size).to eql(expected_uniques)
103
+ expect(hash.keys).to include(expected_key)
104
+ end
105
+ end
106
+
107
+ context '#process!' do
108
+ it 'should read values into the queue' do
109
+ run_reader(read_timeout) { reader.process! }
110
+ expect(queue.size).to eql(expected_total)
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+
3
+ describe Turnstile::Configuration do
4
+
5
+ subject(:config) { Turnstile::Configuration.new }
6
+
7
+ let(:spec_ip) { '128.23.12.8' }
8
+ let(:spec_port) { '2134' }
9
+ let(:spec_db) { '13' }
10
+ let(:spec_timeout) { 0.087 }
11
+ let(:spec_activity_interval) { 30 }
12
+ let(:spec_sampling_rate) { 10 }
13
+
14
+ context 'using redis sub-config method missing' do
15
+ before do
16
+ config.configure do |c|
17
+ c.redis.configure do |r|
18
+ r.host = spec_ip
19
+ r.port = spec_port
20
+ r.db = spec_db
21
+ r.timeout = spec_timeout
22
+ end
23
+ c.activity_interval = spec_activity_interval
24
+ c.sampling_rate = spec_sampling_rate
25
+ end
26
+ end
27
+
28
+ context 'main config' do
29
+ its(:activity_interval) { should eq spec_activity_interval }
30
+ its(:sampling_rate) { should eq spec_sampling_rate }
31
+ end
32
+
33
+ context 'redis sub-config' do
34
+ subject(:redis_config) { config.redis }
35
+ its(:host) { should eq spec_ip }
36
+ its(:port) { should eq spec_port.to_i }
37
+ its(:db) { should eq spec_db.to_i }
38
+ its(:timeout) { should eq spec_timeout.to_f }
39
+ end
40
+ end
41
+
42
+ context 'using redis_<property> method missing' do
43
+ before do
44
+ config.configure do |c|
45
+ c.redis_host = spec_ip
46
+ c.redis_port = spec_port
47
+ c.redis_db = spec_db
48
+ c.redis_timeout = spec_timeout
49
+ c.activity_interval = spec_activity_interval
50
+ c.sampling_rate = spec_sampling_rate
51
+ end
52
+ end
53
+
54
+ its(:redis_host) { should eq spec_ip }
55
+ its(:redis_port) { should eq spec_port.to_i }
56
+ its(:redis_db) { should eq spec_db.to_i }
57
+ its(:redis_timeout) { should eq spec_timeout.to_f }
58
+ its(:activity_interval) { should eq spec_activity_interval }
59
+ its(:sampling_rate) { should eq spec_sampling_rate }
60
+ end
61
+
62
+ context 'without explicit assignment' do
63
+ let(:spec_ip) { '127.0.0.1' }
64
+ let(:spec_port) { 6379 }
65
+ let(:spec_db) { 1 }
66
+ let(:spec_timeout) { 0.05 }
67
+ let(:spec_activity_interval) { 60 }
68
+ let(:spec_sampling_rate) { 100 }
69
+
70
+ its(:redis_host) { should eq spec_ip }
71
+ its(:redis_port) { should eq spec_port }
72
+ its(:redis_db) { should eq spec_db }
73
+ its(:redis_timeout) { should eq spec_timeout }
74
+ its(:activity_interval) { should eq spec_activity_interval }
75
+ its(:sampling_rate) { should eq spec_sampling_rate }
76
+ end
77
+
78
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Turnstile::Nad' do
4
+
5
+ subject { Turnstile::Nad.new }
6
+
7
+ describe '#data' do
8
+ context 'have some data' do
9
+ let(:aggregate) { {
10
+ 'android' => 3,
11
+ 'ios' => 2,
12
+ 'total' => 5
13
+ }
14
+ }
15
+
16
+ let(:expected_string) {
17
+ <<-EOF
18
+ turnstile:android#{"\t"}n#{"\t"}3
19
+ turnstile:ios#{"\t"}n#{"\t"}2
20
+ turnstile:total#{"\t"}n#{"\t"}5
21
+ EOF
22
+ }
23
+
24
+ it "return data in NAD tab dilimited format" do
25
+ expect(subject).to receive(:aggregate).once.and_return(aggregate)
26
+ expect(subject.data).to eql(expected_string)
27
+ end
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ describe Turnstile::Observer do
4
+
5
+ subject { Turnstile::Observer.new }
6
+
7
+ let(:adapter) { subject.send(:adapter) }
8
+
9
+ let(:uid) { 1238438 }
10
+ let(:platform) { :ios }
11
+ let(:ip) { '1.2.3.4' }
12
+
13
+ let(:sample_data) { [{uid: uid, platform: platform, ip: ip}] }
14
+
15
+ let(:expected_stats) do
16
+ {
17
+ stats: {
18
+ total: 1,
19
+ platforms: {
20
+ ios: 1
21
+ }
22
+ },
23
+ users: sample_data
24
+ }
25
+ end
26
+
27
+ let(:extrapolated_stats) do
28
+ {
29
+ stats: {
30
+ total: 20,
31
+ platforms: {
32
+ ios: 20
33
+ }
34
+ },
35
+ users: sample_data
36
+ }
37
+ end
38
+
39
+ describe '#stats' do
40
+ context 'when there are users' do
41
+ before do
42
+ expect(adapter).to receive(:fetch).once.and_return(sample_data)
43
+ end
44
+
45
+ it 'fetches data from adapter and aggregates it' do
46
+ expect(subject.stats).to eql(expected_stats)
47
+ end
48
+
49
+ it 'extrapolates numbers correctly' do
50
+ allow(Turnstile.config).to receive(:sampling_rate).and_return(5)
51
+ expect(subject.stats).to eql(extrapolated_stats)
52
+ end
53
+ end
54
+
55
+ context 'when there are no users' do
56
+ before do
57
+ expect(adapter).to receive(:fetch).once.and_return([])
58
+ end
59
+
60
+ it 'returns 0 for total' do
61
+ expect(subject.stats[:stats][:total]).to eql 0
62
+ end
63
+ end
64
+ end
65
+ end