readmedia-garb 0.9.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +198 -0
- data/Rakefile +57 -0
- data/lib/garb/account.rb +22 -0
- data/lib/garb/account_feed_request.rb +25 -0
- data/lib/garb/authentication_request.rb +53 -0
- data/lib/garb/data_request.rb +42 -0
- data/lib/garb/destination.rb +18 -0
- data/lib/garb/filter_parameters.rb +42 -0
- data/lib/garb/goal.rb +20 -0
- data/lib/garb/management/account.rb +39 -0
- data/lib/garb/management/feed.rb +26 -0
- data/lib/garb/management/goal.rb +44 -0
- data/lib/garb/management/profile.rb +44 -0
- data/lib/garb/management/segment.rb +27 -0
- data/lib/garb/management/web_property.rb +38 -0
- data/lib/garb/model.rb +91 -0
- data/lib/garb/profile.rb +33 -0
- data/lib/garb/profile_reports.rb +16 -0
- data/lib/garb/report.rb +28 -0
- data/lib/garb/report_parameter.rb +25 -0
- data/lib/garb/report_response.rb +56 -0
- data/lib/garb/reports/bounces.rb +5 -0
- data/lib/garb/reports/exits.rb +5 -0
- data/lib/garb/reports/pageviews.rb +5 -0
- data/lib/garb/reports/unique_pageviews.rb +5 -0
- data/lib/garb/reports/visits.rb +5 -0
- data/lib/garb/reports.rb +5 -0
- data/lib/garb/resource.rb +115 -0
- data/lib/garb/result_set.rb +21 -0
- data/lib/garb/session.rb +25 -0
- data/lib/garb/step.rb +13 -0
- data/lib/garb/version.rb +14 -0
- data/lib/garb.rb +69 -0
- data/lib/support.rb +40 -0
- data/test/fixtures/cacert.pem +67 -0
- data/test/fixtures/profile_feed.xml +72 -0
- data/test/fixtures/report_feed.xml +48 -0
- data/test/test_helper.rb +45 -0
- data/test/unit/garb/account_feed_request_test.rb +42 -0
- data/test/unit/garb/account_test.rb +53 -0
- data/test/unit/garb/authentication_request_test.rb +121 -0
- data/test/unit/garb/data_request_test.rb +107 -0
- data/test/unit/garb/destination_test.rb +28 -0
- data/test/unit/garb/filter_parameters_test.rb +68 -0
- data/test/unit/garb/goal_test.rb +24 -0
- data/test/unit/garb/management/account_test.rb +70 -0
- data/test/unit/garb/management/feed_test.rb +44 -0
- data/test/unit/garb/management/goal_test.rb +81 -0
- data/test/unit/garb/management/profile_test.rb +81 -0
- data/test/unit/garb/management/segment_test.rb +47 -0
- data/test/unit/garb/management/web_property_test.rb +64 -0
- data/test/unit/garb/model_test.rb +141 -0
- data/test/unit/garb/oauth_session_test.rb +11 -0
- data/test/unit/garb/profile_reports_test.rb +29 -0
- data/test/unit/garb/profile_test.rb +77 -0
- data/test/unit/garb/report_parameter_test.rb +43 -0
- data/test/unit/garb/report_response_test.rb +47 -0
- data/test/unit/garb/report_test.rb +99 -0
- data/test/unit/garb/resource_test.rb +50 -0
- data/test/unit/garb/session_test.rb +84 -0
- data/test/unit/garb/step_test.rb +15 -0
- data/test/unit/garb_test.rb +26 -0
- data/test/unit/symbol_operator_test.rb +37 -0
- metadata +189 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
##
|
2
|
+
## cacert.pem-foo -- Bundle of CA Root Certificates
|
3
|
+
##
|
4
|
+
## Converted at: Thu Mar 26 21:23:06 2009 UTC
|
5
|
+
##
|
6
|
+
## This is a bundle of X.509 certificates of public Certificate Authorities
|
7
|
+
## (CA). These were automatically extracted from Mozilla's root certificates
|
8
|
+
## file (certdata.txt). This file can be found in the mozilla source tree:
|
9
|
+
## '/mozilla/security/nss/lib/ckfw/builtins/certdata.txt'
|
10
|
+
##
|
11
|
+
## It contains the certificates in PEM format and therefore
|
12
|
+
## can be directly used with curl / libcurl / php_curl, or with
|
13
|
+
## an Apache+mod_ssl webserver for SSL client authentication.
|
14
|
+
## Just configure this file as the SSLCACertificateFile.
|
15
|
+
##
|
16
|
+
|
17
|
+
# ***** BEGIN LICENSE BLOCK *****
|
18
|
+
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
19
|
+
#
|
20
|
+
# The contents of this file are subject to the Mozilla Public License Version
|
21
|
+
# 1.1 (the "License"); you may not use this file except in compliance with
|
22
|
+
# the License. You may obtain a copy of the License at
|
23
|
+
# http://www.mozilla.org/MPL/
|
24
|
+
#
|
25
|
+
# Software distributed under the License is distributed on an "AS IS" basis,
|
26
|
+
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
27
|
+
# for the specific language governing rights and limitations under the
|
28
|
+
# License.
|
29
|
+
#
|
30
|
+
# The Original Code is the Netscape security libraries.
|
31
|
+
#
|
32
|
+
# The Initial Developer of the Original Code is
|
33
|
+
# Netscape Communications Corporation.
|
34
|
+
# Portions created by the Initial Developer are Copyright (C) 1994-2000
|
35
|
+
# the Initial Developer. All Rights Reserved.
|
36
|
+
#
|
37
|
+
# Contributor(s):
|
38
|
+
#
|
39
|
+
# Alternatively, the contents of this file may be used under the terms of
|
40
|
+
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
41
|
+
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
42
|
+
# in which case the provisions of the GPL or the LGPL are applicable instead
|
43
|
+
# of those above. If you wish to allow use of your version of this file only
|
44
|
+
# under the terms of either the GPL or the LGPL, and not to allow others to
|
45
|
+
# use your version of this file under the terms of the MPL, indicate your
|
46
|
+
# decision by deleting the provisions above and replace them with the notice
|
47
|
+
# and other provisions required by the GPL or the LGPL. If you do not delete
|
48
|
+
# the provisions above, a recipient may use your version of this file under
|
49
|
+
# the terms of any one of the MPL, the GPL or the LGPL.
|
50
|
+
#
|
51
|
+
# ***** END LICENSE BLOCK *****
|
52
|
+
# @(#) $RCSfile: certdata.txt,v $ $Revision: 1.51 $ $Date: 2009/01/15 22:35:15 $
|
53
|
+
|
54
|
+
Verisign/RSA Secure Server CA
|
55
|
+
=============================
|
56
|
+
-----BEGIN CERTIFICATE-----
|
57
|
+
MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMx
|
58
|
+
IDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVy
|
59
|
+
IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk0MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVow
|
60
|
+
XzELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQL
|
61
|
+
EyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGbMA0GCSqGSIb3DQEBAQUA
|
62
|
+
A4GJADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6OLDfO6zV4ZFQD5YRAUcm/jwjiioII0haGN1Xp
|
63
|
+
sSECrXZogZoFokvJSyVmIlZsiAeP94FZbYQHZXATcXY+m3dM41CJVphIuR2nKRoTLkoRWZweFdVJ
|
64
|
+
VCxzOmmCsZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZIhvcNAQECBQADfgBl3X7hsuyw4jrg7HFG
|
65
|
+
mhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3YQO2WxZpO8ZECAyIUwxrl0nHPjXcbLm7qt9cuzovk2C2
|
66
|
+
qUtN8iD3zV9/ZHuO3ABc1/p3yjkWWW8O6tO1g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA==
|
67
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,72 @@
|
|
1
|
+
<?xml version='1.0' encoding='UTF-8'?>
|
2
|
+
<feed xmlns='http://www.w3.org/2005/Atom' xmlns:dxp='http://schemas.google.com/analytics/2009' xmlns:ga='http://schemas.google.com/ga/2009' xmlns:openSearch='http://a9.com/-/spec/opensearch/1.1/' xmlns:gd='http://schemas.google.com/g/2005' gd:etag='W/"A0UASX45cCp7I2A9WxFQEUQ."' gd:kind='analytics#accounts'>
|
3
|
+
<id>http://www.google.com/analytics/feeds/accounts/tpitale@gmail.com</id>
|
4
|
+
<updated>2010-05-06T19:27:28.028-07:00</updated>
|
5
|
+
<title>Profile list for tpitale@gmail.com</title>
|
6
|
+
<link rel='self' type='application/atom+xml' href='https://www.google.com/analytics/feeds/accounts/default'/>
|
7
|
+
<author><name>Google Analytics</name></author>
|
8
|
+
<generator version='1.0'>Google Analytics</generator>
|
9
|
+
<openSearch:totalResults>2</openSearch:totalResults>
|
10
|
+
<openSearch:startIndex>1</openSearch:startIndex>
|
11
|
+
<openSearch:itemsPerPage>2</openSearch:itemsPerPage>
|
12
|
+
<dxp:segment id='gaid::-1' name='All Visits'>
|
13
|
+
<dxp:definition> </dxp:definition>
|
14
|
+
</dxp:segment>
|
15
|
+
<dxp:segment id='gaid::-2' name='New Visitors'>
|
16
|
+
<dxp:definition>ga:visitorType==New Visitor</dxp:definition>
|
17
|
+
</dxp:segment>
|
18
|
+
<dxp:segment id='gaid::-3' name='Paid Search Traffic'>
|
19
|
+
<dxp:definition>ga:medium==cpa,ga:medium==cpc,ga:medium==cpm,ga:medium==cpp,ga:medium==cpv,ga:medium==ppc</dxp:definition>
|
20
|
+
</dxp:segment>
|
21
|
+
<dxp:segment id='gaid::0' name='Not New York'>
|
22
|
+
<dxp:definition>ga:city!=New York</dxp:definition>
|
23
|
+
</dxp:segment>
|
24
|
+
<entry gd:etag='W/"CUcHSXs8fip7I2A9WxBUFUg."' gd:kind='analytics#account'>
|
25
|
+
<id>http://www.google.com/analytics/feeds/accounts/ga:12345</id>
|
26
|
+
<updated>2008-07-21T14:05:57.000-07:00</updated>
|
27
|
+
<title>Historical</title>
|
28
|
+
<link rel='alternate' type='text/html' href='http://www.google.com/analytics'/>
|
29
|
+
<ga:goal active='true' name='Read Blog' number='1' value='10.0'>
|
30
|
+
<ga:destination caseSensitive='false' expression='/blog.html' matchType='head' step1Required='false'/>
|
31
|
+
</ga:goal>
|
32
|
+
<ga:goal active='true' name='Go for Support' number='2' value='5.0'>
|
33
|
+
<ga:destination caseSensitive='false' expression='/support.html' matchType='head' step1Required='false'/>
|
34
|
+
</ga:goal>
|
35
|
+
<ga:goal active='true' name='Contact Form Submission' number='3' value='100.0'>
|
36
|
+
<ga:destination caseSensitive='false' expression='/contact-submit' matchType='exact' step1Required='true'>
|
37
|
+
<ga:step name='Contact Form Page' number='1' path='/contact.html'/>
|
38
|
+
</ga:destination>
|
39
|
+
</ga:goal>
|
40
|
+
<ga:goal active='true' name='Newsletter Form Submission' number='4' value='25.0'>
|
41
|
+
<ga:destination caseSensitive='false' expression='/newsletter-submit' matchType='exact' step1Required='false'/>
|
42
|
+
</ga:goal>
|
43
|
+
<dxp:property name="ga:accountId" value="1111"/>
|
44
|
+
<dxp:property name="ga:accountName" value="Blog Beta"/>
|
45
|
+
<dxp:property name="ga:profileId" value="1212"/>
|
46
|
+
<dxp:property name="ga:webPropertyId" value="UA-1111-1"/>
|
47
|
+
<dxp:property name="ga:currency" value="USD"/>
|
48
|
+
<dxp:property name="ga:timezone" value="America/New_York"/>
|
49
|
+
<dxp:tableId>ga:12345</dxp:tableId>
|
50
|
+
</entry>
|
51
|
+
<entry gd:etag='W/"A0UASX45cCp7I2A9WxFQEUQ."' gd:kind='analytics#account'>
|
52
|
+
<id>http://www.google.com/analytics/feeds/accounts/ga:12346</id>
|
53
|
+
<updated>2008-11-24T11:51:07.000-08:00</updated>
|
54
|
+
<title>Presently</title>
|
55
|
+
<link rel='alternate' type='text/html' href='http://www.google.com/analytics'/>
|
56
|
+
<ga:goal active='true' name='Contact Form Submission' number='1' value='100.0'>
|
57
|
+
<ga:destination caseSensitive='false' expression='/contact-submit' matchType='exact' step1Required='true'>
|
58
|
+
<ga:step name='Contact Form Page' number='1' path='/contact.html'/>
|
59
|
+
</ga:destination>
|
60
|
+
</ga:goal>
|
61
|
+
<ga:goal active='true' name='Newsletter Form Submission' number='2' value='25.0'>
|
62
|
+
<ga:destination caseSensitive='false' expression='/newsletter-submit' matchType='exact' step1Required='false'/>
|
63
|
+
</ga:goal>
|
64
|
+
<dxp:property name="ga:accountId" value="1111"/>
|
65
|
+
<dxp:property name="ga:accountName" value="Blog Beta"/>
|
66
|
+
<dxp:property name="ga:profileId" value="1213"/>
|
67
|
+
<dxp:property name="ga:webPropertyId" value="UA-1111-2"/>
|
68
|
+
<dxp:property name="ga:currency" value="USD"/>
|
69
|
+
<dxp:property name="ga:timezone" value="America/New_York"/>
|
70
|
+
<dxp:tableId>ga:12346</dxp:tableId>
|
71
|
+
</entry>
|
72
|
+
</feed>
|
@@ -0,0 +1,48 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<feed xmlns="http://www.w3.org/2005/Atom"
|
3
|
+
xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/"
|
4
|
+
xmlns:dxp="http://schemas.google.com/analytics/2009"
|
5
|
+
xmlns:ga="http://schemas.google.com/analytics/2008">
|
6
|
+
<id>http://www.google.com/analytics/feeds/data?ids=ga:983247&dimensions=ga:country,ga:city&metrics=ga:pageViews&start-date=2008-01-01&end-date=2008-01-02</id>
|
7
|
+
<updated>2008-01-02T15:59:59.999-08:00 </updated>
|
8
|
+
<title type="text">Google Analytics Data for Profile 983247</title>
|
9
|
+
<link href="http://www.google.com/analytics/feeds/data" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
|
10
|
+
<link href="http://www.google.com/analytics/feeds/data?end-date=2008-01-02&start-date=2008-01-01&metrics=ga%3ApageViews&ids=ga%3A983247&dimensions=ga%3Acountry%2Cga%3Acity" rel="self" type="application/atom+xml"/>
|
11
|
+
<link href="http://www.google.com/analytics/feeds/data?start-index=1001&max-results=1000&end-date=2008-01-02&start-date=2008-01-01&metrics=ga%3ApageViews&ids=ga%3A983247&dimensions=ga%3Acountry%2Cga%3Acity" rel="next" type="application/atom+xml"/>
|
12
|
+
<author>
|
13
|
+
<name>Google Analytics</name>
|
14
|
+
</author>
|
15
|
+
<openSearch:startIndex>3</openSearch:startIndex>
|
16
|
+
<openSearch:itemsPerPage>4</openSearch:itemsPerPage>
|
17
|
+
<openSearch:totalResults>18</openSearch:totalResults>
|
18
|
+
<dxp:containsSampledData>true</dxp:containsSampledData>
|
19
|
+
<ga:webPropertyID>UA-983247-67</ga:webPropertyID>
|
20
|
+
<ga:start-date>2008-01-01</ga:start-date>
|
21
|
+
<ga:end-date>2008-01-02</ga:end-date>
|
22
|
+
|
23
|
+
<entry>
|
24
|
+
<id> http://www.google.com/analytics/feeds/data?ids=ga:1174&ga:country=%28not%20set%29&ga:city=%28not%20set%29&start-date=2008-01-01&end-date=2008-01-02 </id>
|
25
|
+
<updated> 2008-01-01T16:00:00.001-08:00 </updated>
|
26
|
+
<title type="text"> ga:country=(not set) | ga:city=(not set) </title>
|
27
|
+
<link href="http://www.google.com/analytics/feeds/data" rel="self" type="application/atom+xml"/>
|
28
|
+
<dxp:dimension name="ga:country" value="(not set)" />
|
29
|
+
<dxp:dimension name="ga:city" value="(not set)" />
|
30
|
+
<dxp:metric name="ga:pageviews" value="33" />
|
31
|
+
</entry>
|
32
|
+
<entry>
|
33
|
+
<id> http://www.google.com/analytics/feeds/data?ids=ga:1174&ga:country=Afghanistan&ga:city=Kabul&start-date=2008-01-01&end-date=2008-01-02 </id>
|
34
|
+
<updated> 2008-01-01T16:00:00.001-08:00 </updated>
|
35
|
+
<title type="text"> ga:country=Afghanistan | ga:city=Kabul </title>
|
36
|
+
<dxp:dimension name="ga:country" value="Afghanistan" />
|
37
|
+
<dxp:dimension name="ga:city" value="Kabul" />
|
38
|
+
<dxp:metric name="ga:pageviews" value="2" />
|
39
|
+
</entry>
|
40
|
+
<entry>
|
41
|
+
<id> http://www.google.com/analytics/feeds/data?ids=ga:1174&ga:country=Albania&ga:city=Tirana&start-date=2008-01-01&end-date=2008-01-02 </id>
|
42
|
+
<updated> 2008-01-01T16:00:00.001-08:00 </updated>
|
43
|
+
<title type="text"> ga:country=Albania | ga:city=Tirana </title>
|
44
|
+
<dxp:dimension name="ga:country" value="Albania" />
|
45
|
+
<dxp:dimension name="ga:city" value="Tirana" />
|
46
|
+
<dxp:metric name="ga:pageviews" value="1" />
|
47
|
+
</entry>
|
48
|
+
</feed>
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
begin
|
2
|
+
require 'simplecov'
|
3
|
+
SimpleCov.adapters.define 'garb' do
|
4
|
+
add_filter '/test/'
|
5
|
+
add_filter '/config/'
|
6
|
+
add_filter 'version'
|
7
|
+
|
8
|
+
add_group 'Libraries', 'lib'
|
9
|
+
end
|
10
|
+
|
11
|
+
SimpleCov.start 'garb'
|
12
|
+
rescue LoadError
|
13
|
+
puts "Install simplecov if you use 1.9 and want coverage metrics"
|
14
|
+
end
|
15
|
+
|
16
|
+
$:.reject! { |e| e.include? 'TextMate' }
|
17
|
+
|
18
|
+
require 'rubygems'
|
19
|
+
require 'bundler'
|
20
|
+
Bundler.setup(:default, :test)
|
21
|
+
|
22
|
+
require 'shoulda'
|
23
|
+
require 'minitest/unit'
|
24
|
+
require 'mocha'
|
25
|
+
|
26
|
+
$:.unshift File.expand_path('../../lib', __FILE__)
|
27
|
+
require 'garb'
|
28
|
+
|
29
|
+
class MiniTest::Unit::TestCase
|
30
|
+
include Shoulda::InstanceMethods
|
31
|
+
extend Shoulda::ClassMethods
|
32
|
+
include Shoulda::Assertions
|
33
|
+
extend Shoulda::Macros
|
34
|
+
include Shoulda::Helpers
|
35
|
+
|
36
|
+
def read_fixture(filename)
|
37
|
+
File.read(File.dirname(__FILE__) + "/fixtures/#{filename}")
|
38
|
+
end
|
39
|
+
|
40
|
+
def assert_data_params(expected)
|
41
|
+
assert_received(Garb::DataRequest, :new) {|e| e.with(Garb::Session, Garb::Model::URL, expected)}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
MiniTest::Unit.autorun
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Garb
|
4
|
+
class AccountFeedRequestTest < MiniTest::Unit::TestCase
|
5
|
+
context "An AccountFeedRequest" do
|
6
|
+
setup do
|
7
|
+
@request = stub
|
8
|
+
DataRequest.stubs(:new).returns(@request)
|
9
|
+
@feed = AccountFeedRequest.new
|
10
|
+
end
|
11
|
+
|
12
|
+
should "have a parsed response" do
|
13
|
+
Crack::XML.stubs(:parse)
|
14
|
+
@feed.stubs(:response).returns(stub(:body => 'response body'))
|
15
|
+
@feed.parsed_response
|
16
|
+
|
17
|
+
assert_received(Crack::XML, :parse) {|e| e.with('response body')}
|
18
|
+
end
|
19
|
+
|
20
|
+
should "have entries from the parsed response" do
|
21
|
+
@feed.stubs(:parsed_response).returns({'feed' => {'entry' => ['entry1', 'entry2']}})
|
22
|
+
assert_equal ['entry1', 'entry2'], @feed.entries
|
23
|
+
end
|
24
|
+
|
25
|
+
should "have segements from the parsed response" do
|
26
|
+
@feed.stubs(:parsed_response).returns({'feed' => {'dxp:segment' => ['segment1', 'segment2']}})
|
27
|
+
assert_equal ['segment1', 'segment2'], @feed.segments
|
28
|
+
end
|
29
|
+
|
30
|
+
should "have an empty array for entries without a response" do
|
31
|
+
@feed.stubs(:parsed_response).returns(nil)
|
32
|
+
assert_equal [], @feed.entries
|
33
|
+
end
|
34
|
+
|
35
|
+
should "have a response from the request" do
|
36
|
+
@request.stubs(:send_request)
|
37
|
+
@feed.response
|
38
|
+
assert_received(@request, :send_request)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Garb
|
4
|
+
class AccountTest < MiniTest::Unit::TestCase
|
5
|
+
context "The Account class" do
|
6
|
+
should "have an array of accounts with all profiles" do
|
7
|
+
p1 = stub(:account_id => '1111', :account_name => 'Blog 1')
|
8
|
+
p2 = stub(:account_id => '1112', :account_name => 'Blog 2')
|
9
|
+
|
10
|
+
Profile.stubs(:all).returns([p1,p2,p1,p2])
|
11
|
+
Account.stubs(:new).returns('account1', 'account2')
|
12
|
+
|
13
|
+
assert_equal ['account1','account2'], Account.all
|
14
|
+
assert_received(Profile, :all)
|
15
|
+
assert_received(Account, :new) {|e| e.with([p1,p1])}
|
16
|
+
assert_received(Account, :new) {|e| e.with([p2,p2])}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "An instance of the Account class" do
|
21
|
+
setup do
|
22
|
+
profile = stub(:account_id => '1111', :account_name => 'Blog 1')
|
23
|
+
@profiles = [profile,profile]
|
24
|
+
@account = Account.new(@profiles)
|
25
|
+
end
|
26
|
+
|
27
|
+
context "all" do
|
28
|
+
should "use an optional user session" do
|
29
|
+
session = Session.new
|
30
|
+
Garb::Profile.expects(:all).with(session).returns(@profiles)
|
31
|
+
|
32
|
+
accounts = Account.all(session)
|
33
|
+
assert_equal 1, accounts.size
|
34
|
+
assert_equal @profiles, accounts.first.profiles
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "when creating a new account from an array of profiles" do
|
39
|
+
should "take the account id from the first profile" do
|
40
|
+
assert_equal @profiles.first.account_id, @account.id
|
41
|
+
end
|
42
|
+
|
43
|
+
should "take the account name from the first profile" do
|
44
|
+
assert_equal @profiles.first.account_name, @account.name
|
45
|
+
end
|
46
|
+
|
47
|
+
should "store the array of profiles" do
|
48
|
+
assert_equal @profiles, @account.profiles
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
CA_CERT_FILE = File.join(File.dirname(__FILE__), '..', '/cacert.pem')
|
4
|
+
|
5
|
+
module Garb
|
6
|
+
class AuthenticationRequestTest < MiniTest::Unit::TestCase
|
7
|
+
|
8
|
+
context "An instance of the AuthenticationRequest class" do
|
9
|
+
|
10
|
+
setup { @request = AuthenticationRequest.new('email', 'password') }
|
11
|
+
|
12
|
+
should "have a collection of parameters that include the email and password" do
|
13
|
+
expected =
|
14
|
+
{
|
15
|
+
'Email' => 'user@example.com',
|
16
|
+
'Passwd' => 'fuzzybunnies',
|
17
|
+
'accountType' => 'HOSTED_OR_GOOGLE',
|
18
|
+
'service' => 'analytics',
|
19
|
+
'source' => 'vigetLabs-garb-001'
|
20
|
+
}
|
21
|
+
|
22
|
+
request = AuthenticationRequest.new('user@example.com', 'fuzzybunnies')
|
23
|
+
assert_equal expected, request.parameters
|
24
|
+
end
|
25
|
+
|
26
|
+
should "have a URI" do
|
27
|
+
assert_equal URI.parse('https://www.google.com/accounts/ClientLogin'), @request.uri
|
28
|
+
end
|
29
|
+
|
30
|
+
should "be able to send a request to the GAAPI service with proper ssl" do
|
31
|
+
@request.expects(:build_request).returns('post')
|
32
|
+
|
33
|
+
response = mock {|m| m.expects(:is_a?).with(Net::HTTPOK).returns(true) }
|
34
|
+
|
35
|
+
http = mock do |m|
|
36
|
+
m.expects(:use_ssl=).with(true)
|
37
|
+
m.expects(:verify_mode=).with(OpenSSL::SSL::VERIFY_PEER)
|
38
|
+
m.expects(:ca_file=).with(CA_CERT_FILE)
|
39
|
+
m.expects(:request).with('post').yields(response)
|
40
|
+
end
|
41
|
+
|
42
|
+
Net::HTTP.expects(:new).with('www.google.com', 443).returns(http)
|
43
|
+
|
44
|
+
@request.send_request(OpenSSL::SSL::VERIFY_PEER)
|
45
|
+
end
|
46
|
+
|
47
|
+
should "be able to send a request to the GAAPI service with ignoring ssl" do
|
48
|
+
@request.expects(:build_request).returns('post')
|
49
|
+
|
50
|
+
response = mock {|m| m.expects(:is_a?).with(Net::HTTPOK).returns(true) }
|
51
|
+
|
52
|
+
http = mock do |m|
|
53
|
+
m.expects(:use_ssl=).with(true)
|
54
|
+
m.expects(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
|
55
|
+
m.expects(:request).with('post').yields(response)
|
56
|
+
end
|
57
|
+
|
58
|
+
Net::HTTP.expects(:new).with('www.google.com', 443).returns(http)
|
59
|
+
|
60
|
+
@request.send_request(OpenSSL::SSL::VERIFY_NONE)
|
61
|
+
end
|
62
|
+
|
63
|
+
should "be able to build a request for the GAAPI service" do
|
64
|
+
params = "param"
|
65
|
+
@request.expects(:parameters).with().returns(params)
|
66
|
+
|
67
|
+
post = mock
|
68
|
+
post.expects(:set_form_data).with(params)
|
69
|
+
|
70
|
+
Net::HTTP::Post.expects(:new).with('/accounts/ClientLogin').returns(post)
|
71
|
+
|
72
|
+
@request.build_request
|
73
|
+
end
|
74
|
+
|
75
|
+
should "be able to retrieve an auth_token from the body" do
|
76
|
+
response_data =
|
77
|
+
"SID=mysid\n" +
|
78
|
+
"LSID=mylsid\n" +
|
79
|
+
"Auth=auth_token\n"
|
80
|
+
|
81
|
+
@request.expects(:send_request).with(OpenSSL::SSL::VERIFY_NONE).returns(stub(:body => response_data))
|
82
|
+
|
83
|
+
assert_equal 'auth_token', @request.auth_token
|
84
|
+
end
|
85
|
+
|
86
|
+
should "use VERIFY_PEER if auth_token needs to be secure" 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_PEER).returns(stub(:body => response_data))
|
93
|
+
|
94
|
+
assert_equal 'auth_token', @request.auth_token(:secure => true)
|
95
|
+
end
|
96
|
+
|
97
|
+
should "raise an exception when requesting an auth_token when the authorization fails" do
|
98
|
+
@request.stubs(:build_request)
|
99
|
+
response = mock do |m|
|
100
|
+
m.expects(:is_a?).with(Net::HTTPOK).returns(false)
|
101
|
+
end
|
102
|
+
|
103
|
+
http = stub do |s|
|
104
|
+
s.stubs(:use_ssl=)
|
105
|
+
s.stubs(:verify_mode=)
|
106
|
+
s.stubs(:request).yields(response)
|
107
|
+
end
|
108
|
+
|
109
|
+
Net::HTTP.stubs(:new).with('www.google.com', 443).returns(http)
|
110
|
+
|
111
|
+
assert_raises(Garb::AuthenticationRequest::AuthError) do
|
112
|
+
@request.send_request(OpenSSL::SSL::VERIFY_NONE)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Garb
|
4
|
+
class DataRequestTest < MiniTest::Unit::TestCase
|
5
|
+
|
6
|
+
context "An instance of the DataRequest class" do
|
7
|
+
setup do
|
8
|
+
@session = Session.new
|
9
|
+
@session.auth_token = 'abcdefg123456'
|
10
|
+
end
|
11
|
+
|
12
|
+
should "be able to build the query string from parameters" do
|
13
|
+
parameters = {'ids' => '12345', 'metrics' => 'country'}
|
14
|
+
data_request = DataRequest.new(@session, "", parameters)
|
15
|
+
|
16
|
+
query_string = data_request.query_string
|
17
|
+
|
18
|
+
assert_match(/^\?/, query_string)
|
19
|
+
|
20
|
+
query_string.sub!(/^\?/, '')
|
21
|
+
|
22
|
+
assert_equal ["ids=12345", "metrics=country"], query_string.split('&').sort
|
23
|
+
end
|
24
|
+
|
25
|
+
should "return an empty query string if parameters are empty" do
|
26
|
+
data_request = DataRequest.new(@session, "")
|
27
|
+
assert_equal "", data_request.query_string
|
28
|
+
end
|
29
|
+
|
30
|
+
should "be able to build a uri" do
|
31
|
+
url = 'http://example.com'
|
32
|
+
assert_equal URI.parse(url), DataRequest.new(@session, url).uri
|
33
|
+
end
|
34
|
+
|
35
|
+
should "be able to send a request for a single user" do
|
36
|
+
@session.stubs(:single_user?).returns(true)
|
37
|
+
response = mock('Net::HTTPOK') do |m|
|
38
|
+
m.expects(:kind_of?).with(Net::HTTPSuccess).returns(true)
|
39
|
+
end
|
40
|
+
|
41
|
+
data_request = DataRequest.new(@session, 'https://example.com/data', 'key' => 'value')
|
42
|
+
data_request.stubs(:single_user_request).returns(response)
|
43
|
+
data_request.send_request
|
44
|
+
|
45
|
+
assert_received(data_request, :single_user_request)
|
46
|
+
end
|
47
|
+
|
48
|
+
should "be able to send a request for an oauth user" do
|
49
|
+
@session.stubs(:single_user?).returns(false)
|
50
|
+
@session.stubs(:oauth_user?).returns(true)
|
51
|
+
response = mock('Net::HTTPOK') do |m|
|
52
|
+
m.expects(:kind_of?).with(Net::HTTPSuccess).returns(true)
|
53
|
+
end
|
54
|
+
|
55
|
+
data_request = DataRequest.new(@session, 'https://example.com/data', 'key' => 'value')
|
56
|
+
data_request.stubs(:oauth_user_request).returns(response)
|
57
|
+
data_request.send_request
|
58
|
+
|
59
|
+
assert_received(data_request, :oauth_user_request)
|
60
|
+
end
|
61
|
+
|
62
|
+
should "raise if the request is unauthorized" do
|
63
|
+
@session.stubs(:single_user?).returns(false)
|
64
|
+
@session.stubs(:oauth_user?).returns(true)
|
65
|
+
response = mock('Net::HTTPUnauthorized', :body => 'Error')
|
66
|
+
|
67
|
+
data_request = DataRequest.new(@session, 'https://example.com/data', 'key' => 'value')
|
68
|
+
data_request.stubs(:oauth_user_request).returns(response)
|
69
|
+
|
70
|
+
assert_raises(Garb::DataRequest::ClientError) do
|
71
|
+
data_request.send_request
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
should "be able to request via the ouath access token" do
|
76
|
+
access_token = stub(:get => "responseobject")
|
77
|
+
@session.stubs(:access_token).returns(access_token)
|
78
|
+
|
79
|
+
data_request = DataRequest.new(@session, 'https://example.com/data', 'key' => 'value')
|
80
|
+
assert_equal 'responseobject', data_request.oauth_user_request
|
81
|
+
|
82
|
+
assert_received(@session, :access_token)
|
83
|
+
assert_received(access_token, :get) {|e| e.with('https://example.com/data?key=value', {'GData-Version' => '2'})}
|
84
|
+
end
|
85
|
+
|
86
|
+
should "be able to request via http with an auth token" do
|
87
|
+
@session.expects(:auth_token).with().returns('toke')
|
88
|
+
response = mock
|
89
|
+
|
90
|
+
http = mock do |m|
|
91
|
+
m.expects(:use_ssl=).with(true)
|
92
|
+
m.expects(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
|
93
|
+
m.expects(:get).with('/data?key=value', {
|
94
|
+
'Authorization' => 'GoogleLogin auth=toke',
|
95
|
+
'GData-Version' => '2'
|
96
|
+
}).returns(response)
|
97
|
+
end
|
98
|
+
|
99
|
+
Net::HTTP.expects(:new).with('example.com', 443).returns(http)
|
100
|
+
|
101
|
+
data_request = DataRequest.new(@session, 'https://example.com/data', 'key' => 'value')
|
102
|
+
assert_equal response, data_request.single_user_request
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Garb
|
4
|
+
class DestinationTest < MiniTest::Unit::TestCase
|
5
|
+
context 'A Destination' do
|
6
|
+
should "have a match_type and an expression" do
|
7
|
+
destination = Destination.new({'matchType' => 'exact', 'expression' => '/contact.html', 'caseSensitive' => 'false'})
|
8
|
+
assert_equal 'exact', destination.match_type
|
9
|
+
assert_equal '/contact.html', destination.expression
|
10
|
+
end
|
11
|
+
|
12
|
+
should "know if it's case sensitive" do
|
13
|
+
destination = Destination.new({'matchType' => 'exact', 'expression' => '/contact.html', 'caseSensitive' => 'true'})
|
14
|
+
assert_equal true, destination.case_sensitive?
|
15
|
+
end
|
16
|
+
|
17
|
+
should "know if it's not case sensitive" do
|
18
|
+
destination = Destination.new({'matchType' => 'exact', 'expression' => '/contact.html', 'caseSensitive' => 'false'})
|
19
|
+
assert_equal false, destination.case_sensitive?
|
20
|
+
end
|
21
|
+
|
22
|
+
should "have steps" do
|
23
|
+
destination = Destination.new({'ga:step' => {'name' => 'Contact', 'number' => '1', 'path' => '/'}})
|
24
|
+
assert_equal ['Contact'], destination.steps.map(&:name)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Garb
|
4
|
+
class FilterParametersTest < MiniTest::Unit::TestCase
|
5
|
+
def self.should_define_operators(*operators)
|
6
|
+
operators.each do |operator|
|
7
|
+
should "create an operator and add to parameters for the #{operator} method" do
|
8
|
+
new_operator = stub
|
9
|
+
symbol = :foo
|
10
|
+
|
11
|
+
SymbolOperator.expects(:new).with(:bar, operator).returns(new_operator)
|
12
|
+
@filter_parameters.filters do
|
13
|
+
send(operator.to_sym, :bar, 100)
|
14
|
+
end
|
15
|
+
|
16
|
+
parameter = {new_operator => 100}
|
17
|
+
assert_equal parameter, @filter_parameters.parameters.last
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "A FilterParameters" do
|
23
|
+
setup do
|
24
|
+
@filter_parameters = FilterParameters.new
|
25
|
+
end
|
26
|
+
|
27
|
+
should_define_operators :eql, :not_eql, :gt, :gte, :lt, :lte,
|
28
|
+
:matches, :does_not_match, :contains, :does_not_contain, :substring, :not_substring
|
29
|
+
|
30
|
+
should "instance eval for filters" do
|
31
|
+
blk = lambda {"in a block"}
|
32
|
+
|
33
|
+
@filter_parameters.expects(:instance_eval)
|
34
|
+
@filter_parameters.filters(&blk)
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when converting parameters hash into query string parameters" do
|
38
|
+
should "parameterize hash operators and join elements with AND" do
|
39
|
+
@filter_parameters.filters do
|
40
|
+
eql(:city, 'New York City')
|
41
|
+
eql(:state, 'New York')
|
42
|
+
end
|
43
|
+
|
44
|
+
params = ['ga:city%3D%3DNew+York+City', 'ga:state%3D%3DNew+York']
|
45
|
+
assert_equal params, @filter_parameters.to_params['filters'].split('%3B').sort
|
46
|
+
end
|
47
|
+
|
48
|
+
should "properly encode operators" do
|
49
|
+
@filter_parameters.filters do
|
50
|
+
contains(:page_path, 'New York')
|
51
|
+
end
|
52
|
+
|
53
|
+
params = {'filters' => 'ga:pagePath%3D~New+York'}
|
54
|
+
assert_equal params, @filter_parameters.to_params
|
55
|
+
end
|
56
|
+
|
57
|
+
should "escape comma, semicolon, and backslash in values" do
|
58
|
+
@filter_parameters.filters do
|
59
|
+
eql(:url, 'this;that,thing\other')
|
60
|
+
end
|
61
|
+
|
62
|
+
params = {'filters' => 'ga:url%3D%3Dthis%5C%3Bthat%5C%2Cthing%5C%5Cother'}
|
63
|
+
assert_equal params, @filter_parameters.to_params
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|