garb 0.9.1 → 0.9.7

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 (175) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.travis.yml +7 -0
  4. data/CHANGELOG.md +95 -0
  5. data/Gemfile +15 -0
  6. data/README.md +47 -25
  7. data/Rakefile +8 -34
  8. data/garb.gemspec +22 -0
  9. data/lib/garb.rb +71 -48
  10. data/lib/garb/attributes.rb +35 -0
  11. data/lib/garb/core_ext/array.rb +13 -0
  12. data/lib/garb/core_ext/string.rb +48 -0
  13. data/lib/garb/core_ext/symbol.rb +59 -0
  14. data/lib/garb/destination.rb +5 -6
  15. data/lib/garb/errors.rb +20 -0
  16. data/lib/garb/filter_parameters.rb +20 -29
  17. data/lib/garb/management/account.rb +10 -16
  18. data/lib/garb/management/feed.rb +4 -5
  19. data/lib/garb/management/goal.rb +10 -15
  20. data/lib/garb/management/profile.rb +11 -20
  21. data/lib/garb/management/segment.rb +9 -15
  22. data/lib/garb/management/web_property.rb +11 -16
  23. data/lib/garb/model.rb +37 -13
  24. data/lib/garb/path_attribute.rb +7 -0
  25. data/lib/garb/report_parameter.rb +5 -5
  26. data/lib/garb/report_response.rb +29 -28
  27. data/lib/garb/reports/bounces.rb +1 -1
  28. data/lib/garb/reports/exits.rb +1 -1
  29. data/lib/garb/reports/pageviews.rb +1 -1
  30. data/lib/garb/reports/unique_pageviews.rb +1 -1
  31. data/lib/garb/reports/visits.rb +1 -1
  32. data/lib/garb/request/authentication.rb +54 -0
  33. data/lib/garb/request/data.rb +98 -0
  34. data/lib/garb/result_set.rb +23 -9
  35. data/lib/garb/session.rb +3 -3
  36. data/lib/garb/step.rb +4 -4
  37. data/lib/garb/support.rb +6 -0
  38. data/lib/garb/version.rb +3 -3
  39. data/test/fixtures/account_management.json +1 -0
  40. data/test/fixtures/ga_profile_management.json +1 -0
  41. data/test/fixtures/ga_segment_management.json +1 -0
  42. data/test/fixtures/ga_webproperty_management.json +1 -0
  43. data/test/fixtures/goal_management.json +1 -0
  44. data/test/fixtures/profile_feed.json +1 -0
  45. data/test/fixtures/report_feed.json +75 -0
  46. data/test/test_helper.rb +6 -10
  47. data/test/unit/garb/filter_parameters_test.rb +15 -46
  48. data/test/unit/garb/management/account_test.rb +8 -16
  49. data/test/unit/garb/management/feed_test.rb +5 -10
  50. data/test/unit/garb/management/goal_test.rb +7 -21
  51. data/test/unit/garb/management/profile_test.rb +11 -26
  52. data/test/unit/garb/management/segment_test.rb +7 -6
  53. data/test/unit/garb/management/web_property_test.rb +10 -12
  54. data/test/unit/garb/model_test.rb +70 -32
  55. data/test/unit/garb/report_parameter_test.rb +6 -6
  56. data/test/unit/garb/report_response_test.rb +23 -13
  57. data/test/unit/garb/request/authentication_test.rb +152 -0
  58. data/test/unit/garb/request/data_test.rb +157 -0
  59. data/test/unit/garb/session_test.rb +13 -13
  60. data/test/unit/garb_test.rb +4 -11
  61. data/test/unit/symbol_operator_test.rb +3 -3
  62. metadata +90 -292
  63. data/lib/garb/account.rb +0 -22
  64. data/lib/garb/account_feed_request.rb +0 -25
  65. data/lib/garb/authentication_request.rb +0 -53
  66. data/lib/garb/data_request.rb +0 -42
  67. data/lib/garb/goal.rb +0 -20
  68. data/lib/garb/profile.rb +0 -33
  69. data/lib/garb/report.rb +0 -28
  70. data/lib/garb/resource.rb +0 -115
  71. data/lib/support.rb +0 -40
  72. data/test/unit/garb/account_feed_request_test.rb +0 -42
  73. data/test/unit/garb/account_test.rb +0 -53
  74. data/test/unit/garb/authentication_request_test.rb +0 -121
  75. data/test/unit/garb/coverage/assets/0.3.9/app.js +0 -66
  76. data/test/unit/garb/coverage/assets/0.3.9/fancybox/blank.gif +0 -0
  77. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_close.png +0 -0
  78. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_loading.png +0 -0
  79. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_nav_left.png +0 -0
  80. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_nav_right.png +0 -0
  81. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_shadow_e.png +0 -0
  82. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_shadow_n.png +0 -0
  83. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_shadow_ne.png +0 -0
  84. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_shadow_nw.png +0 -0
  85. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_shadow_s.png +0 -0
  86. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_shadow_se.png +0 -0
  87. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_shadow_sw.png +0 -0
  88. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_shadow_w.png +0 -0
  89. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_title_left.png +0 -0
  90. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_title_main.png +0 -0
  91. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_title_over.png +0 -0
  92. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_title_right.png +0 -0
  93. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancybox-x.png +0 -0
  94. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancybox-y.png +0 -0
  95. data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancybox.png +0 -0
  96. data/test/unit/garb/coverage/assets/0.3.9/fancybox/jquery.fancybox-1.3.1.css +0 -363
  97. data/test/unit/garb/coverage/assets/0.3.9/fancybox/jquery.fancybox-1.3.1.pack.js +0 -44
  98. data/test/unit/garb/coverage/assets/0.3.9/favicon.png +0 -0
  99. data/test/unit/garb/coverage/assets/0.3.9/jquery-1.4.2.min.js +0 -155
  100. data/test/unit/garb/coverage/assets/0.3.9/jquery.dataTables.min.js +0 -152
  101. data/test/unit/garb/coverage/assets/0.3.9/jquery.timeago.js +0 -141
  102. data/test/unit/garb/coverage/assets/0.3.9/jquery.url.js +0 -174
  103. data/test/unit/garb/coverage/assets/0.3.9/loading.gif +0 -0
  104. data/test/unit/garb/coverage/assets/0.3.9/magnify.png +0 -0
  105. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  106. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  107. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  108. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  109. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  110. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  111. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  112. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  113. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-icons_222222_256x240.png +0 -0
  114. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  115. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-icons_454545_256x240.png +0 -0
  116. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-icons_888888_256x240.png +0 -0
  117. data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  118. data/test/unit/garb/coverage/assets/0.3.9/smoothness/jquery-ui-1.8.4.custom.css +0 -295
  119. data/test/unit/garb/coverage/assets/0.3.9/stylesheet.css +0 -341
  120. data/test/unit/garb/coverage/index.html +0 -100
  121. data/test/unit/garb/coverage/resultset.yml +0 -5
  122. data/test/unit/garb/data_request_test.rb +0 -107
  123. data/test/unit/garb/destination_test.rb +0 -28
  124. data/test/unit/garb/goal_test.rb +0 -24
  125. data/test/unit/garb/management/coverage/assets/0.3.9/app.js +0 -66
  126. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/blank.gif +0 -0
  127. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_close.png +0 -0
  128. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_loading.png +0 -0
  129. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_nav_left.png +0 -0
  130. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_nav_right.png +0 -0
  131. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_shadow_e.png +0 -0
  132. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_shadow_n.png +0 -0
  133. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_shadow_ne.png +0 -0
  134. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_shadow_nw.png +0 -0
  135. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_shadow_s.png +0 -0
  136. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_shadow_se.png +0 -0
  137. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_shadow_sw.png +0 -0
  138. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_shadow_w.png +0 -0
  139. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_title_left.png +0 -0
  140. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_title_main.png +0 -0
  141. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_title_over.png +0 -0
  142. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_title_right.png +0 -0
  143. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancybox-x.png +0 -0
  144. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancybox-y.png +0 -0
  145. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancybox.png +0 -0
  146. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/jquery.fancybox-1.3.1.css +0 -363
  147. data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/jquery.fancybox-1.3.1.pack.js +0 -44
  148. data/test/unit/garb/management/coverage/assets/0.3.9/favicon.png +0 -0
  149. data/test/unit/garb/management/coverage/assets/0.3.9/jquery-1.4.2.min.js +0 -155
  150. data/test/unit/garb/management/coverage/assets/0.3.9/jquery.dataTables.min.js +0 -152
  151. data/test/unit/garb/management/coverage/assets/0.3.9/jquery.timeago.js +0 -141
  152. data/test/unit/garb/management/coverage/assets/0.3.9/jquery.url.js +0 -174
  153. data/test/unit/garb/management/coverage/assets/0.3.9/loading.gif +0 -0
  154. data/test/unit/garb/management/coverage/assets/0.3.9/magnify.png +0 -0
  155. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  156. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  157. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  158. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  159. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  160. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  161. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  162. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  163. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-icons_222222_256x240.png +0 -0
  164. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  165. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-icons_454545_256x240.png +0 -0
  166. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-icons_888888_256x240.png +0 -0
  167. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  168. data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/jquery-ui-1.8.4.custom.css +0 -295
  169. data/test/unit/garb/management/coverage/assets/0.3.9/stylesheet.css +0 -341
  170. data/test/unit/garb/management/coverage/index.html +0 -100
  171. data/test/unit/garb/management/coverage/resultset.yml +0 -5
  172. data/test/unit/garb/profile_test.rb +0 -77
  173. data/test/unit/garb/report_test.rb +0 -99
  174. data/test/unit/garb/resource_test.rb +0 -50
  175. data/test/unit/garb/step_test.rb +0 -15
@@ -8,18 +8,18 @@ module Garb
8
8
  feed = stub(:entries => ["entry1"])
9
9
  Feed.stubs(:new).returns(feed)
10
10
 
11
- Profile.stubs(:new_from_entry)
11
+ Profile.stubs(:new)
12
12
  Profile.all
13
13
 
14
14
  assert_received(Feed, :new) {|e| e.with(Session, '/accounts/~all/webproperties/~all/profiles')}
15
15
  assert_received(feed, :entries)
16
- assert_received(Profile, :new_from_entry) {|e| e.with("entry1", Session)}
16
+ assert_received(Profile, :new) {|e| e.with("entry1", Session)}
17
17
  end
18
18
 
19
19
  should "find all profiles for a given account" do
20
20
  Profile.stubs(:all)
21
21
  Profile.for_account(stub(:session => 'session', :path => '/accounts/123'))
22
- assert_received(Profile, :all) {|e| e.with('session', '/accounts/123/webproperties/~all/profiles')}
22
+ assert_received(Profile, :all) {|e| e.with('session', '/accounts/123/webproperties/~all/profiles')}
23
23
  end
24
24
 
25
25
  should "find all profiles for a given web_property" do
@@ -31,43 +31,28 @@ module Garb
31
31
 
32
32
  context "A Profile" do
33
33
  setup do
34
- entry = {
35
- "link" => [{"rel" => "self", "href" => Feed::BASE_URL+"/accounts/1189765/webproperties/UA-1189765-1/profiles/98765"}],
36
- "dxp:property" => [
37
- {"name" => "ga:profileId", "value" => "98765"},
38
- {"name" => "ga:accountId", "value" => "1189765"},
39
- {"name" => "ga:webPropertyId", "value" => 'UA-1189765-1'},
40
- {"name" => "ga:profileName", "value" => "example.com"},
41
- {"name"=>"dxp:tableId", "value"=>"ga:4506"},
42
- {"name"=>"ga:currency", "value"=>"USD"},
43
- {"name"=>"ga:timezone", "value"=>"America/New_York"}
44
- ]
45
- }
46
- @profile = Profile.new_from_entry(entry, Session)
34
+ entry = MultiJson.load(read_fixture("ga_profile_management.json"))["items"].first
35
+ @profile = Profile.new(entry, Session)
47
36
  end
48
37
 
49
- should "have a title" do
50
- assert_equal "example.com", @profile.title
38
+ should "have a name" do
39
+ assert_equal "the profile name", @profile.name
51
40
  end
52
41
 
53
42
  should "have an id" do
54
- assert_equal '98765', @profile.id
43
+ assert_equal '2', @profile.id
55
44
  end
56
45
 
57
46
  should "have an account_id" do
58
- assert_equal '1189765', @profile.account_id
47
+ assert_equal '1234', @profile.account_id
59
48
  end
60
49
 
61
50
  should "have a web_property_id" do
62
- assert_equal 'UA-1189765-1', @profile.web_property_id
63
- end
64
-
65
- should "have a table_id (for old Garb::Report)" do
66
- assert_equal 'ga:4506', @profile.table_id
51
+ assert_equal 'UA-5555-1', @profile.web_property_id
67
52
  end
68
53
 
69
54
  should "have a path" do
70
- assert_equal "/accounts/1189765/webproperties/UA-1189765-1/profiles/98765", @profile.path
55
+ assert_equal "/accounts/1234/webproperties/UA-5555-1/profiles/2", @profile.path
71
56
  end
72
57
 
73
58
  should "have goals" do
@@ -8,12 +8,12 @@ module Garb
8
8
  feed = stub(:entries => ["entry1"])
9
9
  Feed.stubs(:new).returns(feed)
10
10
 
11
- Segment.stubs(:new_from_entry)
11
+ Segment.stubs(:new)
12
12
  Segment.all
13
13
 
14
14
  assert_received(Feed, :new) {|e| e.with(Session, '/segments')}
15
15
  assert_received(feed, :entries)
16
- assert_received(Segment, :new_from_entry) {|e| e.with("entry1", Session)}
16
+ assert_received(Segment, :new) {|e| e.with("entry1", Session)}
17
17
  end
18
18
  end
19
19
 
@@ -27,19 +27,20 @@ module Garb
27
27
  "dxp:definition" => "ga:visitorType==Returning Visitor"
28
28
  }
29
29
  }
30
- @segment = Segment.new_from_entry(entry, Session)
30
+ entry = MultiJson.load(read_fixture("ga_segment_management.json"))["items"].first
31
+ @segment = Segment.new(entry, Session)
31
32
  end
32
33
 
33
34
  should "have an id" do
34
- assert_equal "gaid::-3", @segment.id
35
+ assert_equal "gaid::1", @segment.id
35
36
  end
36
37
 
37
38
  should "have a name" do
38
- assert_equal "Returning Visitor", @segment.name
39
+ assert_equal "derpy", @segment.name
39
40
  end
40
41
 
41
42
  should "have a definition" do
42
- assert_equal "ga:visitorType==Returning Visitor", @segment.definition
43
+ assert_equal "ga:pagePath=@derpy", @segment.definition
43
44
  end
44
45
  end
45
46
  end
@@ -8,12 +8,12 @@ module Garb
8
8
  feed = stub(:entries => ["entry1"])
9
9
  Feed.stubs(:new).returns(feed)
10
10
 
11
- WebProperty.stubs(:new_from_entry)
11
+ WebProperty.stubs(:new)
12
12
  WebProperty.all
13
13
 
14
14
  assert_received(Feed, :new) {|e| e.with(Session, '/accounts/~all/webproperties')}
15
15
  assert_received(feed, :entries)
16
- assert_received(WebProperty, :new_from_entry) {|e| e.with("entry1", Session)}
16
+ assert_received(WebProperty, :new) {|e| e.with("entry1", Session)}
17
17
  end
18
18
 
19
19
  should "find all web properties for a given account" do
@@ -28,23 +28,21 @@ module Garb
28
28
 
29
29
  context "a WebProperty" do
30
30
  setup do
31
- entry = {
32
- "link" => [{"rel" => "self", "href" => Feed::BASE_URL+"/accounts/1189765/webproperties/UA-1189765-1"}],
33
- "dxp:property" => [
34
- {"name" => "ga:accountId", "value" => "1189765"},
35
- {"name" => "ga:webPropertyId", "value" => 'UA-1189765-1'}
36
- ]
37
- }
31
+ entry = MultiJson.load(read_fixture("ga_webproperty_management.json"))["items"].first
38
32
 
39
- @web_property = WebProperty.new_from_entry(entry, Session)
33
+ @web_property = WebProperty.new(entry, Session)
40
34
  end
41
35
 
42
36
  should "have an id" do
43
- assert_equal "UA-1189765-1", @web_property.id
37
+ assert_equal "UA-7777-1", @web_property.id
44
38
  end
45
39
 
46
40
  should "have an account_id" do
47
- assert_equal "1189765", @web_property.account_id
41
+ assert_equal "1", @web_property.account_id
42
+ end
43
+
44
+ should "combine the WebProperty.path and the id into an new path" do
45
+ assert_equal "/accounts/1/webproperties/UA-7777-1", @web_property.path
48
46
  end
49
47
 
50
48
  should "have profiles" do
@@ -41,77 +41,96 @@ module Garb
41
41
 
42
42
  context "with a profile" do
43
43
  setup do
44
- entry = {
45
- "title" => "Google Analytics Profile example.com",
46
- "link" => [{"rel" => "self", "href" => Garb::Management::Feed::BASE_URL+"/accounts/1189765/webproperties/UA-1189765-1/profiles/98765"}],
47
- "dxp:property" => [
48
- {"name" => "ga:profileId", "value" => "98765"},
49
- {"name" => "ga:accountId", "value" => "1189765"},
50
- {"name" => "ga:webPropertyId", "value" => 'UA-1189765-1'}
51
- ]
52
- }
53
-
54
- @profile = Garb::Management::Profile.new_from_entry(entry, Session)
44
+ entry = MultiJson.load(read_fixture('ga_profile_management.json'))['items'].first
45
+
46
+ @profile = Garb::Management::Profile.new(entry, Session)
55
47
  end
56
48
 
57
49
  context "when getting results" do
58
50
  setup do
59
51
  @response = stub(:body => "raw report data")
60
- DataRequest.stubs(:new).returns(stub(:send_request => @response))
61
- ReportResponse.stubs(:new).returns(stub(:results => ['result']))
52
+ Request::Data.stubs(:new).returns(stub(:send_request => @response))
53
+ @results = ResultSet.new(Array.new(10) { |i| 'result #%d' % i })
54
+ ReportResponse.stubs(:new).returns(stub(:results => @results))
62
55
 
63
56
  @test_model.stubs(:metrics).returns(stub(:to_params => {'metrics' => 'ga:visits'}))
64
57
  @test_model.stubs(:dimensions).returns(stub(:to_params => {'dimensions' => 'ga:pagePath'}))
65
58
 
66
59
  now = Time.now
67
60
  Time.stubs(:now).returns(now)
61
+ @params = {
62
+ 'ids' => Garb.to_ga(@profile.id),
63
+ 'start-date' => (now - Model::MONTH).strftime('%Y-%m-%d'),
64
+ 'end-date' => now.strftime('%Y-%m-%d'),
65
+ 'metrics' => 'ga:visits',
66
+ 'dimensions' => 'ga:pagePath'
67
+ }
68
+ end
68
69
 
69
- # p @profile.id
70
+ should "get results" do
71
+ assert_equal @results, @test_model.results(@profile)
72
+ assert_received(ReportResponse, :new) {|e| e.with('raw report data', OpenStruct)}
73
+ assert_data_params(@params)
74
+ end
70
75
 
71
- @params = {'ids' => Garb.to_ga(@profile.id),
72
- 'start-date' => (now - Model::MONTH).strftime('%Y-%m-%d'),
73
- 'end-date' => now.strftime('%Y-%m-%d'),
74
- 'metrics' => 'ga:visits',
75
- 'dimensions' => 'ga:pagePath'}
76
+ should "get subset of results using bracket notation" do
77
+ assert_equal @results[0..2], @test_model.results(@profile)[0..2]
78
+ assert_received(ReportResponse, :new) {|e| e.with('raw report data', OpenStruct)}
79
+ assert_data_params(@params)
76
80
  end
77
81
 
78
- should "get all results" do
79
- assert_equal ['result'], @test_model.results(@profile)
80
- assert_received(ReportResponse, :new) {|e| e.with("raw report data", OpenStruct)}
82
+ should "get one of the results using bracket notation" do
83
+ assert_equal @results[2], @test_model.results(@profile)[2]
84
+ assert_received(ReportResponse, :new) {|e| e.with('raw report data', OpenStruct)}
81
85
  assert_data_params(@params)
82
86
  end
83
87
 
84
88
  should "be able to filter" do
85
- filter_parameters = stub(:<<)
86
- FilterParameters.stubs(:new).returns(stub(:parameters => filter_parameters, :to_params => {'filters' => "params"}))
87
- assert_equal ['result'], @test_model.results(@profile, :filters => {:page_path => '/'})
89
+ FilterParameters.stubs(:new).returns(stub(:to_params => {'filters' => 'params'}))
90
+ assert_equal @results, @test_model.results(@profile, :filters => {:page_path => '/'})
88
91
 
89
92
  assert_data_params(@params.merge({'filters' => 'params'}))
90
- assert_received(filter_parameters, :<<) {|e| e.with({:page_path => '/'})}
93
+ assert_received(FilterParameters, :new) {|e| e.with({:page_path => '/'})}
91
94
  end
92
95
 
93
96
  should "be able to set the filter segment by id" do
94
- assert_equal ['result'], @test_model.results(@profile, :segment_id => 1)
97
+ assert_equal @results, @test_model.results(@profile, :segment_id => 1)
95
98
  assert_data_params(@params.merge({'segment' => 'gaid::1'}))
96
99
  end
97
100
 
101
+ should "be able to set the filter segment by alphanumeric id" do
102
+ assert_equal @results, @test_model.results(@profile, :segment_id => '1a')
103
+ assert_data_params(@params.merge({'segment' => 'gaid::1a'}))
104
+ end
105
+
106
+ should "be able to filter with a dynamic segment" do
107
+ # parse_filters called first...
108
+ filter_parameters = stub(:<<)
109
+ filters = stub(:parameters => filter_parameters, :to_params => {'filters' => nil})
110
+ segments = stub(:parameters => filter_parameters, :to_params => {'filters' => 'dynamic_segment_params'})
111
+ FilterParameters.stubs(:new).returns(filters).then.returns(segments)
112
+
113
+ assert_equal @results, @test_model.results(@profile, :dynamic_segment => 'dynamic_segment_params')
114
+ assert_data_params(@params.merge({'segment' => 'dynamic::dynamic_segment_params'}))
115
+ end
116
+
98
117
  should "be able to sort" do
99
118
  sort_parameter = stub(:<<)
100
119
  sort_parameter.stubs(:to_params => {'sort' => 'sort value'})
101
120
  ReportParameter.stubs(:new).returns(sort_parameter)
102
121
 
103
- assert_equal ['result'], @test_model.results(@profile, :sort => [:visits])
122
+ assert_equal @results, @test_model.results(@profile, :sort => [:visits])
104
123
  assert_received(sort_parameter, :<<) {|e| e.with([:visits])}
105
124
  assert_data_params(@params.merge({'sort' => 'sort value'}))
106
125
  end
107
126
 
108
127
  should "be able to limit" do
109
- assert_equal ['result'], @test_model.results(@profile, :limit => 20)
128
+ assert_equal @results, @test_model.results(@profile, :limit => 20)
110
129
  assert_data_params(@params.merge({'max-results' => 20}))
111
130
  end
112
131
 
113
132
  should "be able to offset" do
114
- assert_equal ['result'], @test_model.results(@profile, :offset => 10)
133
+ assert_equal @results, @test_model.results(@profile, :offset => 10)
115
134
  assert_data_params(@params.merge({'start-index' => 10}))
116
135
  end
117
136
 
@@ -119,16 +138,35 @@ module Garb
119
138
  start_date = (Time.now - 1296000)
120
139
  end_date = Time.now
121
140
 
122
- assert_equal ['result'], @test_model.results(@profile, :start_date => start_date, :end_date => end_date)
141
+ assert_equal @results, @test_model.results(@profile, :start_date => start_date, :end_date => end_date)
123
142
  assert_data_params(@params.merge({'start-date' => start_date.strftime('%Y-%m-%d'), 'end-date' => end_date.strftime('%Y-%m-%d')}))
124
143
  end
125
144
 
126
145
  should "return a set of results in the defined class" do
127
146
  @test_model.stubs(:instance_klass).returns(ResultKlass)
128
147
 
129
- assert_equal ['result'], @test_model.results(@profile)
148
+ assert_equal @results, @test_model.results(@profile)
130
149
  assert_received(ReportResponse, :new) {|e| e.with("raw report data", ResultKlass)}
131
150
  end
151
+
152
+ should "be able to fetch multiple pages of results" do
153
+ @results.total_results = 25
154
+ results = @test_model.all_results(@profile)
155
+ assert_equal results.size, 30
156
+ end
157
+
158
+ should "be able to pass :all symbol to fetch multiple pages of results" do
159
+ @results.results = ['result']
160
+ @results.total_results = 25
161
+ results = @test_model.results(@profile, :all => true)
162
+ assert_equal results.size, @results.total_results
163
+ end
164
+
165
+ should "be able to fetch multiple pages of results with a limit" do
166
+ @results.total_results = 25
167
+ results = @test_model.all_results(@profile, :limit => 1)
168
+ assert_equal results.size, 1
169
+ end
132
170
  end
133
171
 
134
172
  # should "return results as an array of the class it belongs to, if that class is an ActiveRecord descendant"
@@ -2,25 +2,25 @@ require 'test_helper'
2
2
 
3
3
  module Garb
4
4
  class ReportParameterTest < MiniTest::Unit::TestCase
5
-
5
+
6
6
  context "An instance of the ReportParameter class" do
7
7
  setup do
8
8
  @metrics = ReportParameter.new(:metrics)
9
9
  end
10
-
10
+
11
11
  should "have a name" do
12
12
  assert_equal "metrics", @metrics.name
13
13
  end
14
-
14
+
15
15
  should "have a list of elements" do
16
16
  assert_equal [], @metrics.elements
17
17
  end
18
-
18
+
19
19
  should "be able to add new elements" do
20
20
  assert_equal(@metrics, @metrics << :page_path)
21
21
  assert_equal [:page_path], @metrics.elements
22
22
  end
23
-
23
+
24
24
  should "merge an array of elements" do
25
25
  assert_equal(@metrics, @metrics << [:page_path])
26
26
  assert_equal [:page_path], @metrics.elements
@@ -38,6 +38,6 @@ module Garb
38
38
  end
39
39
  end
40
40
  end
41
-
41
+
42
42
  end
43
43
  end
@@ -7,38 +7,48 @@ module Garb
7
7
  context "A ReportResponse" do
8
8
  context "with a report feed" do
9
9
  setup do
10
- @xml = File.read(File.join(File.dirname(__FILE__), '..', '..', "/fixtures/report_feed.xml"))
10
+ @json = File.read(File.join(File.dirname(__FILE__), '..', '..', "/fixtures/report_feed.json"))
11
11
  end
12
12
 
13
- should "parse results from atom xml" do
14
- response = ReportResponse.new(@xml)
15
- assert_equal ['33', '2', '1'], response.results.map(&:pageviews)
13
+ should "parse results from json" do
14
+ response = ReportResponse.new(@json)
15
+ assert_equal ['4', '4', '17', '1', '5'], response.results.map(&:pageviews)
16
16
  end
17
17
 
18
18
  should "default to returning an array of OpenStruct objects" do
19
- response = ReportResponse.new(@xml)
20
- assert_equal [OpenStruct, OpenStruct, OpenStruct], response.results.map(&:class)
19
+ response = ReportResponse.new(@json)
20
+ assert_equal [OpenStruct, OpenStruct, OpenStruct, OpenStruct, OpenStruct], response.results.map(&:class)
21
21
  end
22
22
 
23
23
  should "return an array of instances of a specified class" do
24
- response = ReportResponse.new(@xml, SpecialKlass)
25
- assert_equal [SpecialKlass, SpecialKlass, SpecialKlass], response.results.map(&:class)
24
+ response = ReportResponse.new(@json, SpecialKlass)
25
+ assert_equal [SpecialKlass, SpecialKlass, SpecialKlass, SpecialKlass, SpecialKlass], response.results.map(&:class)
26
26
  end
27
27
 
28
28
  should "know the total number of results" do
29
- response = ReportResponse.new(@xml)
30
- assert_equal 18, response.results.total_results
29
+ response = ReportResponse.new(@json)
30
+ assert_equal 1261, response.results.total_results
31
31
  end
32
32
 
33
33
  should "know if the data has been sampled" do
34
- response = ReportResponse.new(@xml)
34
+ response = ReportResponse.new(@json)
35
35
  assert_equal true, response.results.sampled?
36
36
  end
37
+
38
+ should "return results as ResultSet which acts as Array proxy" do
39
+ response = ReportResponse.new(@json, SpecialKlass)
40
+ results = response.results
41
+ results_subset = results[0..1]
42
+
43
+ assert_equal ResultSet, results.class
44
+ assert_equal ResultSet, results_subset.class
45
+ assert_equal results_subset.results, results.results[0..1]
46
+ end
37
47
  end
38
48
 
39
49
  should "return an empty array if there are no results" do
40
- response = ReportResponse.new("result xml")
41
- Crack::XML.stubs(:parse).with("result xml").returns({'feed' => {'entry' => nil}})
50
+ response = ReportResponse.new('result json')
51
+ MultiJson.stubs(:load).with('result json').returns({'rows' => []})
42
52
 
43
53
  assert_equal [], response.results.to_a
44
54
  end
@@ -0,0 +1,152 @@
1
+ require 'test_helper'
2
+
3
+ module Garb
4
+ module Request
5
+ class AuthenticationTest < MiniTest::Unit::TestCase
6
+
7
+ context "An instance of the Request::Authentication class" do
8
+
9
+ setup do
10
+ @request = Request::Authentication.new('email', 'password')
11
+ Garb.ca_cert_file = File.join(File.dirname(__FILE__), '..', '/cacert.pem')
12
+ end
13
+ teardown do
14
+ Garb.proxy_address = nil
15
+ Garb.proxy_port = nil
16
+ Garb.ca_cert_file = nil
17
+ end
18
+
19
+ should "have a collection of parameters that include the email and password" do
20
+ expected =
21
+ {
22
+ 'Email' => 'user@example.com',
23
+ 'Passwd' => 'fuzzybunnies',
24
+ 'accountType' => 'HOSTED_OR_GOOGLE',
25
+ 'service' => 'analytics',
26
+ 'source' => "sija-garb-v#{Garb::VERSION}"
27
+ }
28
+
29
+ request = Request::Authentication.new('user@example.com', 'fuzzybunnies')
30
+ assert_equal expected, request.parameters
31
+ end
32
+
33
+ should "have a URI" do
34
+ assert_equal URI.parse('https://www.google.com/accounts/ClientLogin'), @request.uri
35
+ end
36
+
37
+ should "be able to send a request to the GAAPI service with proper ssl" do
38
+ @request.expects(:build_request).returns('post')
39
+
40
+ response = mock {|m| m.expects(:is_a?).with(Net::HTTPOK).returns(true) }
41
+
42
+ http = mock do |m|
43
+ m.expects(:open_timeout=).with(Garb.open_timeout)
44
+ m.expects(:read_timeout=).with(Garb.read_timeout)
45
+ m.expects(:use_ssl=).with(true)
46
+ m.expects(:verify_mode=).with(OpenSSL::SSL::VERIFY_PEER)
47
+ m.expects(:ca_file=).with(Garb.ca_cert_file)
48
+ m.expects(:request).with('post').yields(response)
49
+ end
50
+
51
+ Net::HTTP.expects(:new).with('www.google.com', 443, nil, nil).returns(http)
52
+
53
+ @request.send_request(OpenSSL::SSL::VERIFY_PEER)
54
+ end
55
+
56
+ should "be able to send a request to the GAAPI service with ignoring ssl" do
57
+ @request.expects(:build_request).returns('post')
58
+
59
+ response = mock {|m| m.expects(:is_a?).with(Net::HTTPOK).returns(true) }
60
+
61
+ http = mock do |m|
62
+ m.expects(:open_timeout=).with(Garb.open_timeout)
63
+ m.expects(:read_timeout=).with(Garb.read_timeout)
64
+ m.expects(:use_ssl=).with(true)
65
+ m.expects(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
66
+ m.expects(:request).with('post').yields(response)
67
+ end
68
+
69
+ Net::HTTP.expects(:new).with('www.google.com', 443, nil, nil).returns(http)
70
+
71
+ @request.send_request(OpenSSL::SSL::VERIFY_NONE)
72
+ end
73
+
74
+ should "be able to build a request for the GAAPI service" do
75
+ params = 'param'
76
+ @request.expects(:parameters).with().returns(params)
77
+
78
+ post = mock
79
+ post.expects(:set_form_data).with(params)
80
+
81
+ Net::HTTP::Post.expects(:new).with('/accounts/ClientLogin').returns(post)
82
+
83
+ @request.build_request
84
+ end
85
+
86
+ should "be able to retrieve an auth_token from the body" do
87
+ response_data =
88
+ "SID=mysid\n" +
89
+ "LSID=mylsid\n" +
90
+ "Auth=auth_token\n"
91
+
92
+ @request.expects(:send_request).with(OpenSSL::SSL::VERIFY_NONE).returns(stub(:body => response_data))
93
+
94
+ assert_equal 'auth_token', @request.auth_token
95
+ end
96
+
97
+ should "use VERIFY_PEER if auth_token needs to be secure" do
98
+ response_data =
99
+ "SID=mysid\n" +
100
+ "LSID=mylsid\n" +
101
+ "Auth=auth_token\n"
102
+
103
+ @request.expects(:send_request).with(OpenSSL::SSL::VERIFY_PEER).returns(stub(:body => response_data))
104
+
105
+ assert_equal 'auth_token', @request.auth_token(:secure => true)
106
+ end
107
+
108
+ should "raise an exception when requesting an auth_token when the authorization fails" do
109
+ @request.stubs(:build_request)
110
+ response = mock do |m|
111
+ m.expects(:is_a?).with(Net::HTTPOK).returns(false)
112
+ end
113
+
114
+ http = stub do |s|
115
+ s.stubs(:use_ssl=)
116
+ s.expects(:open_timeout=).with(Garb.open_timeout)
117
+ s.expects(:read_timeout=).with(Garb.read_timeout)
118
+ s.stubs(:verify_mode=)
119
+ s.stubs(:request).yields(response)
120
+ end
121
+
122
+ Net::HTTP.stubs(:new).with('www.google.com', 443, nil, nil).returns(http)
123
+
124
+ assert_raises(Garb::AuthError) do
125
+ @request.send_request(OpenSSL::SSL::VERIFY_NONE)
126
+ end
127
+ end
128
+
129
+ should "make use of Garb proxy settings in Net::HTTP request" do
130
+ @request.expects(:build_request).returns('post')
131
+
132
+ response = stub {|s| s.stubs(:is_a?).returns(true) }
133
+
134
+ http = mock do |m|
135
+ m.stubs(:open_timeout=)
136
+ m.stubs(:read_timeout=)
137
+ m.stubs(:use_ssl=)
138
+ m.stubs(:verify_mode=)
139
+ m.stubs(:request).yields(response)
140
+ end
141
+
142
+ Garb.proxy_address = '127.0.0.1'
143
+ Garb.proxy_port = '1234'
144
+
145
+ Net::HTTP.expects(:new).with('www.google.com', 443, '127.0.0.1', '1234').returns(http)
146
+
147
+ @request.send_request(nil)
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end