google_apps 0.5 → 0.9

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,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: