google_apps 0.5 → 0.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe "GoogleApps::DocumentHandler" do
4
+ let (:handler) { GoogleApps::DocumentHandler.new }
5
+ let (:documents) { to_meth GoogleApps::Atom::Document.types }
6
+
7
+ describe "#create_doc" do
8
+ it "Returns a XML document when given xml and @format is :atom" do
9
+ handler.create_doc(finished_export, :export).should be_a LibXML::XML::Document
10
+ end
11
+
12
+ it "Returns a XML document when given xml and @format is :xml" do
13
+ handler.create_doc(finished_export, :export).should be_a LibXML::XML::Document
14
+ end
15
+ end
16
+
17
+ describe "#unknown_type" do
18
+ it "Returns an XML Document when given a string and @format is :atom" do
19
+ handler.unknown_type(finished_export).should be_a LibXML::XML::Document
20
+ end
21
+
22
+ it "Returns an XML Document when given a string and @format is :xml" do
23
+ handler.unknown_type(finished_export).should be_a LibXML::XML::Document
24
+ end
25
+ end
26
+
27
+ describe "#doc_of_type" do
28
+ it "Returns an object of the specified type if the type is valid for the format" do
29
+ user = handler.doc_of_type File.read('spec/fixture_xml/user.xml'), :user
30
+
31
+ user.should be_a GoogleApps::Atom::User
32
+ end
33
+
34
+ it "Raises a RuntimeError if the type is not valid for the format" do
35
+ lambda { handler.doc_of_type :goat, File.read('spec/fixture_xml/user.xml') }.should raise_error
36
+ end
37
+ end
38
+
39
+ describe "#look_up_doc_types" do
40
+ it "Returns a list of all Atom documents when @format is :atom" do
41
+ handler.send(:look_up_doc_types).should == documents
42
+ end
43
+
44
+ it "Returns a list of all Atom documents when @format is :xml" do
45
+ handler.send(:look_up_doc_types).should == documents
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,235 @@
1
+ require 'spec_helper'
2
+
3
+ describe GoogleApps::Transport do
4
+ let (:mock_request) { mock(GoogleApps::AppsRequest) }
5
+ let (:mock_response) { mock(Net::HTTPResponse) }
6
+ let (:user_doc) { GoogleApps::Atom::User.new File.read('spec/fixture_xml/user.xml') }
7
+ let (:credentials) { get_credentials }
8
+ let (:user_name) { generate_username }
9
+ let (:document) { mock(GoogleApps::Atom::User).stub!(:to_s).and_return("stub xml") }
10
+
11
+ before(:each) do
12
+ @headers = {
13
+ auth: [['content-type', 'application/x-www-form-urlencoded']],
14
+ migration: [['content-type', "multipart/related; boundary=\"#{GoogleApps::Transport::BOUNDARY}\""], ['Authorization', "OAuth #{transporter.instance_eval { @token } }"]],
15
+ other: [['content-type', 'application/atom+xml'], ['Authorization', "OAuth #{transporter.instance_eval { @token } }"]]
16
+ }
17
+
18
+ GoogleApps::AppsRequest.stub(:new).and_return(mock_request)
19
+
20
+ mock_request.stub(:send_request).and_return(mock_response)
21
+ mock_request.stub(:add_body)
22
+ end
23
+
24
+ let(:transporter) do
25
+ GoogleApps::Transport.new(
26
+ domain: 'cnm.edu',
27
+ token: 'some-token',
28
+ refresh_token: 'refresh_token',
29
+ token_changed_callback: 'callback-proc'
30
+ )
31
+ end
32
+
33
+ describe '#new' do
34
+ it "assigns endpoints" do
35
+ transporter.user.should == "https://apps-apis.google.com/a/feeds/cnm.edu/user/2.0"
36
+ transporter.group.should == "https://apps-apis.google.com/a/feeds/group/2.0/cnm.edu"
37
+ transporter.nickname.should == "https://apps-apis.google.com/a/feeds/cnm.edu/nickname/2.0"
38
+ transporter.pubkey.should == "https://apps-apis.google.com/a/feeds/compliance/audit/publickey/cnm.edu"
39
+ transporter.export.should == "https://apps-apis.google.com/a/feeds/compliance/audit/mail/export/cnm.edu"
40
+ transporter.migration.should == "https://apps-apis.google.com/a/feeds/migration/2.0/cnm.edu"
41
+ end
42
+ end
43
+
44
+ describe "#add_member_to" do
45
+ it "creates an HTTP POST request to add a member to a group" do
46
+ GoogleApps::AppsRequest.should_receive(:new).with(:post, URI(transporter.group + '/Test/member'), @headers[:other])
47
+ transporter.should_receive(:success_response?).and_return(true)
48
+
49
+ mock_request.should_receive :add_body
50
+ mock_response.should_receive(:body).and_return("document")
51
+ transporter.stub(:create_doc)
52
+
53
+ transporter.add_member_to 'Test', 'Bob'
54
+ get_path("group")
55
+ end
56
+ end
57
+
58
+ describe "#add_owner_to" do
59
+ before(:each) do
60
+ @owner_doc = double(GoogleApps::Atom::GroupOwner)
61
+ end
62
+
63
+ it "adds the specified address as an owner of the specified group" do
64
+ GoogleApps::AppsRequest.should_receive(:new).with(:post, URI(transporter.group + '/test_group@cnm.edu/owner'), @headers[:other])
65
+ transporter.add_owner_to 'test_group@cnm.edu', @owner_doc
66
+ end
67
+ end
68
+
69
+ describe "#delete_owner_from" do
70
+ it "Deletes the owner from the group" do
71
+ GoogleApps::AppsRequest.should_receive(:new).with(:delete, URI(transporter.group + '/test_group@cnm.edu/owner/lholcomb2@cnm.edu'), @headers[:other])
72
+
73
+ transporter.delete_owner_from 'test_group@cnm.edu', 'lholcomb2@cnm.edu'
74
+ end
75
+ end
76
+
77
+ describe "#get_nicknames_for" do
78
+ it "Gets a feed of the nicknames for the requested user" do
79
+ GoogleApps::AppsRequest.should_receive(:new).with(:get, URI(transporter.nickname + '?username=lholcomb2'), @headers[:other])
80
+ transporter.should_receive(:success_response?).and_return(true)
81
+ mock_response.should_receive(:body).and_return(fake_nickname)
82
+
83
+ transporter.get_nicknames_for 'lholcomb2'
84
+ end
85
+ end
86
+
87
+ describe "#delete_member_from" do
88
+ it "crafts an HTTP DELETE request for a group member" do
89
+ GoogleApps::AppsRequest.should_receive(:new).with(:delete, URI(transporter.group + '/next_group/member/lholcomb2@cnm.edu'), @headers[:other])
90
+ transporter.delete_member_from 'next_group', 'lholcomb2@cnm.edu'
91
+ end
92
+ end
93
+
94
+ describe "#request_export" do
95
+ before(:each) do
96
+ GoogleApps::AppsRequest.should_receive(:new).with(:post, URI(transporter.export + '/lholcomb2'), @headers[:other])
97
+ end
98
+
99
+ it "crafts a HTTP POST request for a mailbox export" do
100
+ mock_response.should_receive(:body).and_return(pending_export)
101
+ transporter.should_receive(:success_response?).and_return(true)
102
+ transporter.request_export('lholcomb2', document).should == 75133001
103
+ end
104
+
105
+ it "Crafts a HTTP POST request and raises an error if Google returns an error" do
106
+ transporter.should_receive(:success_response?).and_return(false)
107
+ expect { transporter.request_export('lholcomb2', document) }.to raise_error
108
+ end
109
+ end
110
+
111
+ describe "#export_status" do
112
+ before(:each) do
113
+ GoogleApps::AppsRequest.should_receive(:new).with(:get, URI(transporter.export + '/lholcomb2/83838'), @headers[:other])
114
+ mock_response.stub(:body).and_return(pending_export)
115
+ transporter.stub(:success_response?).and_return(true)
116
+ end
117
+
118
+ it "crafts a HTTP GET request for a mailbox export status" do
119
+ transporter.export_status 'lholcomb2', 83838
120
+ end
121
+
122
+ it "Returns the response body from Google" do
123
+ transporter.export_status('lholcomb2', 83838).should be_a LibXML::XML::Document
124
+ end
125
+ end
126
+
127
+ describe "#build_id" do
128
+ it "Returns a query string unchanged" do
129
+ transporter.send(:build_id, '?bob').should == '?bob'
130
+ end
131
+
132
+ it "Prepends a slash to non-query strings" do
133
+ transporter.send(:build_id, 'tom').should == '/tom'
134
+ end
135
+ end
136
+
137
+ describe '#add_user' do
138
+ it "sends a POST request to the User endpoint" do
139
+ GoogleApps::AppsRequest.should_receive(:new).with(:post, URI(transporter.user), @headers[:other])
140
+ mock_request.should_receive(:add_body).with user_doc.to_s
141
+ transporter.should_receive(:success_response?).and_return(true)
142
+ mock_response.should_receive(:body).and_return(File.read('spec/fixture_xml/user.xml'))
143
+
144
+ transporter.add_user user_doc
145
+ end
146
+ end
147
+
148
+ describe "#get_users" do
149
+ before(:each) do
150
+ mock_response.stub(:body).and_return(File.read('spec/fixture_xml/users_feed.xml'))
151
+ transporter.stub(:success_response?).and_return(true)
152
+ end
153
+
154
+ it "Builds a GET request for the user endpoint" do
155
+ GoogleApps::AppsRequest.should_receive(:new).with(:get, URI(transporter.user + '?startUsername=znelson1'), @headers[:other])
156
+ transporter.get_users start: 'znelson1', limit: 2
157
+ end
158
+
159
+ it "Makes another request if the response has a <link rel=\"next\" node"
160
+ end
161
+
162
+ describe "#download" do
163
+ before(:all) do
164
+ @url = 'http://www.google.com'
165
+ @filename = 'spec/download_test'
166
+ end
167
+
168
+ before(:each) do
169
+ mock_response.stub(:body).and_return("Test body")
170
+ end
171
+
172
+ after(:all) do
173
+ File.delete('spec/download_test')
174
+ end
175
+
176
+ it "Makes a GET request for the specified url" do
177
+ GoogleApps::AppsRequest.should_receive(:new).with(:get, URI(@url), @headers[:other])
178
+ mock_response.should_receive(:body)
179
+
180
+ transporter.download @url, @filename
181
+ end
182
+
183
+ it "Saves the response body to the specified filename" do
184
+ GoogleApps::AppsRequest.should_receive(:new).with(:get, URI(@url), @headers[:other])
185
+ mock_response.should_receive(:body)
186
+ transporter.download @url, @filename
187
+
188
+ File.read('spec/download_test').should == "Test body\n"
189
+ end
190
+ end
191
+
192
+ describe "#migrate" do
193
+ it "Make a POST request to the migration endpoint" do
194
+ GoogleApps::AppsRequest.should_receive(:new).with(:post, URI(transporter.migration + "/#{user_name}/mail"), @headers[:migration])
195
+ mock_request.should_receive(:add_body).with(transporter.send(:multi_part, "bob", "cat"))
196
+
197
+ transporter.migrate(user_name, "bob", "cat")
198
+ end
199
+ end
200
+
201
+ describe "#export_ready?" do
202
+ before(:all) do
203
+ @id = 828456
204
+ end
205
+
206
+ it "Returns true if there is a fileUrl property in an export status doc" do
207
+ GoogleApps::AppsRequest.should_receive(:new).with(:get, URI(transporter.export + "/#{user_name}/#{@id}"), @headers[:other])
208
+ mock_response.should_receive(:body).and_return(finished_export)
209
+ transporter.should_receive(:success_response?).and_return(true)
210
+ export_status_doc = transporter.export_status(user_name, @id)
211
+ transporter.export_ready?(export_status_doc).should == true
212
+ end
213
+
214
+ it "Returns false if there is no fileUrl property in an export status doc" do
215
+ GoogleApps::AppsRequest.should_receive(:new).with(:get, URI(transporter.export + "/#{user_name}/#{@id}"), @headers[:other])
216
+ mock_response.should_receive(:body).and_return(pending_export)
217
+ transporter.should_receive(:success_response?).and_return(true)
218
+ export_status_doc = transporter.export_status(user_name, @id)
219
+
220
+ transporter.export_ready?(export_status_doc).should == false
221
+ end
222
+ end
223
+
224
+ describe "#process_response" do
225
+ before(:each) do
226
+ @mock_handler = double(GoogleApps::DocumentHandler)
227
+ transporter.instance_eval { @handler = @mock_handler }
228
+ end
229
+
230
+ it "Raises an error if Google Responds in kind" do
231
+ transporter.should_receive(:success_response?).and_return(false)
232
+ expect { transporter.get_user 'lholcomb2' }.to raise_error
233
+ end
234
+ end
235
+ end
@@ -0,0 +1,16 @@
1
+ require 'google_apps'
2
+ require 'webmock/rspec'
3
+ require 'yaml'
4
+
5
+ # Requires supporting ruby files with custom matchers and macros, etc,
6
+ # in spec/support/ and its subdirectories.
7
+ Dir[File.expand_path(File.dirname(__FILE__) + '/support/**/*.rb')].each { |f| require f }
8
+
9
+ #WebMock.allow_net_connect!
10
+ WebMock.disable_net_connect!
11
+
12
+ RSpec.configure do |config|
13
+ #config.include FactoryGirl::Syntax::Methods
14
+ #config.order = "random"
15
+ end
16
+
@@ -0,0 +1,66 @@
1
+ def get_credentials
2
+ YAML.load_file(cred_file_absolute).inject({}) do |hsh, part|
3
+ hsh[part.flatten[0]] = part.flatten[1]
4
+ hsh
5
+ end
6
+ end
7
+
8
+ def cred_file_absolute
9
+ Dir.getwd + '/spec/credentials.yaml'
10
+ end
11
+
12
+ def to_meth(klasses)
13
+ klasses.inject([]) do |list, klass|
14
+ list << klass.to_s.split('::').last.scan(/[A-Z][a-z0-9]+/).map(&:downcase).join('_')
15
+ list
16
+ end
17
+ end
18
+
19
+ def basic_header
20
+ '<atom:entry xmlns:atom="http://www.w3.org/2005/Atom" xmlns:apps="http://schemas.google.com/apps/2006" xmlns:gd="http://schemas.google.com/g/2005"/>'
21
+ end
22
+
23
+ def generate_username
24
+ characters = [('a'..'z'), ('A'..'Z'), (0..9)].map { |i| i.to_a }.flatten
25
+
26
+ (0..6).map { characters[rand(characters.length)] }.join
27
+ end
28
+
29
+ def get_path(category)
30
+ transporter.send(category.to_sym).split('/')[3..-1].join('/')
31
+ end
32
+
33
+ def build_request(verb)
34
+ GoogleApps::AppsRequest.new verb, 'http://www.google.com', test: 'bob'
35
+ end
36
+
37
+ def entry_node
38
+ entry = LibXML::XML::Node.new 'entry'
39
+
40
+ entry << LibXML::XML::Node.new('uncle')
41
+ entry << LibXML::XML::Node.new('aunt')
42
+
43
+ entry
44
+ end
45
+
46
+ def hash_password(password)
47
+ OpenSSL::Digest::SHA1.hexdigest password
48
+ end
49
+
50
+ def finished_export
51
+ <<-XML.strip!
52
+ <?xml version='1.0' encoding='UTF-8'?><entry xmlns='http://www.w3.org/2005/Atom' xmlns:apps='http://schemas.google.com/apps/2006'><id>https://apps-apis.google.com/a/feeds/compliance/audit/mail/export/cnm.edu/lholcomb2/74876701</id><updated>2012-07-26T13:32:08.438Z</updated><link rel='self' type='application/atom+xml' href='https://apps-apis.google.com/a/feeds/compliance/audit/mail/export/cnm.edu/lholcomb2/74876701'/><link rel='edit' type='application/atom+xml' href='https://apps-apis.google.com/a/feeds/compliance/audit/mail/export/cnm.edu/lholcomb2/74876701'/><apps:property name='numberOfFiles' value='1'/><apps:property name='packageContent' value='FULL_MESSAGE'/><apps:property name='completedDate' value='2012-07-25 19:13'/><apps:property name='status' value='COMPLETED'/><apps:property name='requestId' value='74876701'/><apps:property name='fileUrl0' value='https://apps-apis.google.com/a/data/compliance/audit/OgAAALqfKGjaeLMsuu54zP7CihO4G2eNZkXAvohVhYW4DjljfG4ltcYzUsjUY95GwfWMoS16ShFAcCr5XdxmC_skWnkAlbTyA8BJje3hRc5lIjExG-BfzzkhShNU'/><apps:property name='userEmailAddress' value='lholcomb2@cnm.edu'/><apps:property name='searchQuery' value='from: *'/><apps:property name='adminEmailAddress' value='lholcomb2@cnm.edu'/><apps:property name='requestDate' value='2012-07-25 15:56'/></entry>
53
+ XML
54
+ end
55
+
56
+ def pending_export
57
+ <<-XML.strip!
58
+ <?xml version='1.0' encoding='UTF-8'?><entry xmlns='http://www.w3.org/2005/Atom' xmlns:apps='http://schemas.google.com/apps/2006'><id>https://apps-apis.google.com/a/feeds/compliance/audit/mail/export/cnm.edu/lholcomb2/75133001</id><updated>2012-07-26T13:37:22.497Z</updated><link rel='self' type='application/atom+xml' href='https://apps-apis.google.com/a/feeds/compliance/audit/mail/export/cnm.edu/lholcomb2/75133001'/><link rel='edit' type='application/atom+xml' href='https://apps-apis.google.com/a/feeds/compliance/audit/mail/export/cnm.edu/lholcomb2/75133001'/><apps:property name='packageContent' value='HEADER_ONLY'/><apps:property name='status' value='PENDING'/><apps:property name='requestId' value='75133001'/><apps:property name='userEmailAddress' value='lholcomb2@cnm.edu'/><apps:property name='searchQuery' value='from: *'/><apps:property name='adminEmailAddress' value='lholcomb2@cnm.edu'/><apps:property name='requestDate' value='2012-07-26 13:37'/></entry>
59
+ XML
60
+ end
61
+
62
+ def fake_nickname
63
+ <<-XML.strip!
64
+ <?xml version="1.0" encoding="UTF-8"?><atom:entry xmlns:atom="http://www.w3.org/2005/Atom" xmlns:apps="http://schemas.google.com/apps/2006"> <apps:category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/apps/2006#nickname"/> <apps:nickname name="bobo"/></atom:entry>
65
+ XML
66
+ end
metadata CHANGED
@@ -1,15 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: google_apps
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.5'
4
+ version: '0.9'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Glen Holcomb
9
+ - Will Read
9
10
  autorequire:
10
11
  bindir: bin
11
12
  cert_chain: []
12
- date: 2012-09-20 00:00:00.000000000 Z
13
+ date: 2013-03-11 00:00:00.000000000 Z
13
14
  dependencies:
14
15
  - !ruby/object:Gem::Dependency
15
16
  name: libxml-ruby
@@ -27,12 +28,67 @@ dependencies:
27
28
  - - ! '>='
28
29
  - !ruby/object:Gem::Version
29
30
  version: 2.2.2
31
+ - !ruby/object:Gem::Dependency
32
+ name: httparty
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: rspec
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ - !ruby/object:Gem::Dependency
64
+ name: webmock
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ type: :development
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
30
79
  description: Library for interfacing with Google Apps' Domain and Application APIs
31
80
  email:
32
81
  executables: []
33
82
  extensions: []
34
83
  extra_rdoc_files: []
35
84
  files:
85
+ - .gitignore
86
+ - Gemfile
87
+ - Gemfile.lock
88
+ - LICENSE
89
+ - README.md
90
+ - google_apps.gemspec
91
+ - lib/google_apps.rb
36
92
  - lib/google_apps/apps_request.rb
37
93
  - lib/google_apps/atom/atom.rb
38
94
  - lib/google_apps/atom/document.rb
@@ -48,9 +104,30 @@ files:
48
104
  - lib/google_apps/atom/user.rb
49
105
  - lib/google_apps/document_handler.rb
50
106
  - lib/google_apps/transport.rb
51
- - lib/google_apps.rb
107
+ - spec/credentials.example.yaml
108
+ - spec/fixture_xml/mes_attr.xml
109
+ - spec/fixture_xml/test_doc.xml
110
+ - spec/fixture_xml/user.xml
111
+ - spec/fixture_xml/users_feed.xml
112
+ - spec/google_apps/apps_request_spec.rb
113
+ - spec/google_apps/atom/document_spec.rb
114
+ - spec/google_apps/atom/export_spec.rb
115
+ - spec/google_apps/atom/feed_spec.rb
116
+ - spec/google_apps/atom/group_member_spec.rb
117
+ - spec/google_apps/atom/group_owner_spec.rb
118
+ - spec/google_apps/atom/group_spec.rb
119
+ - spec/google_apps/atom/message_attributes_spec.rb
120
+ - spec/google_apps/atom/nickname_spec.rb
121
+ - spec/google_apps/atom/node_spec.rb
122
+ - spec/google_apps/atom/public_key_spec.rb
123
+ - spec/google_apps/atom/user_spec.rb
124
+ - spec/google_apps/document_handler_spec.rb
125
+ - spec/google_apps/transport_spec.rb
126
+ - spec/spec_helper.rb
127
+ - spec/support/helpers.rb
52
128
  homepage: https://github.com/LeakyBucket/google_apps
53
- licenses: []
129
+ licenses:
130
+ - MIT
54
131
  post_install_message:
55
132
  rdoc_options: []
56
133
  require_paths:
@@ -69,9 +146,30 @@ required_rubygems_version: !ruby/object:Gem::Requirement
69
146
  version: '0'
70
147
  requirements: []
71
148
  rubyforge_project:
72
- rubygems_version: 1.8.23
149
+ rubygems_version: 1.8.25
73
150
  signing_key:
74
151
  specification_version: 3
75
152
  summary: Google Apps APIs
76
- test_files: []
153
+ test_files:
154
+ - spec/credentials.example.yaml
155
+ - spec/fixture_xml/mes_attr.xml
156
+ - spec/fixture_xml/test_doc.xml
157
+ - spec/fixture_xml/user.xml
158
+ - spec/fixture_xml/users_feed.xml
159
+ - spec/google_apps/apps_request_spec.rb
160
+ - spec/google_apps/atom/document_spec.rb
161
+ - spec/google_apps/atom/export_spec.rb
162
+ - spec/google_apps/atom/feed_spec.rb
163
+ - spec/google_apps/atom/group_member_spec.rb
164
+ - spec/google_apps/atom/group_owner_spec.rb
165
+ - spec/google_apps/atom/group_spec.rb
166
+ - spec/google_apps/atom/message_attributes_spec.rb
167
+ - spec/google_apps/atom/nickname_spec.rb
168
+ - spec/google_apps/atom/node_spec.rb
169
+ - spec/google_apps/atom/public_key_spec.rb
170
+ - spec/google_apps/atom/user_spec.rb
171
+ - spec/google_apps/document_handler_spec.rb
172
+ - spec/google_apps/transport_spec.rb
173
+ - spec/spec_helper.rb
174
+ - spec/support/helpers.rb
77
175
  has_rdoc: