bitsa 0.10
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.
- data/.gitignore +4 -0
- data/.rspec +3 -0
- data/COPYING +674 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +35 -0
- data/History.txt +4 -0
- data/README.md +117 -0
- data/Rakefile +10 -0
- data/bin/bitsa +35 -0
- data/bitsa.gemspec +28 -0
- data/lib/bitsa.rb +50 -0
- data/lib/bitsa/args_processor.rb +80 -0
- data/lib/bitsa/config_file.rb +39 -0
- data/lib/bitsa/contacts_cache.rb +100 -0
- data/lib/bitsa/gmail_contacts_loader.rb +80 -0
- data/lib/bitsa/settings.rb +50 -0
- data/lib/bitsa/version.rb +22 -0
- data/spec/args_processor_spec.rb +66 -0
- data/spec/confg_file_spec.rb +32 -0
- data/spec/contacts_cache_spec.rb +294 -0
- data/spec/data/bitsa_cache.yml +16 -0
- data/spec/data/config.yml +3 -0
- data/spec/gmail_contacts_loader_spec.rb +89 -0
- data/spec/helper.rb +11 -0
- data/spec/settings_spec.rb +34 -0
- data/tasks/create_tags.rake +7 -0
- data/tasks/retrieve_one_page.rake +24 -0
- data/tasks/spec.rake +3 -0
- metadata +177 -0
@@ -0,0 +1,80 @@
|
|
1
|
+
# Loads Contacts from Gmail into a <tt>ContactsCache</tt> object.
|
2
|
+
#
|
3
|
+
# Copyright (C) 2011 Colin Noel Bell.
|
4
|
+
#
|
5
|
+
# This file is part of Bitsa.
|
6
|
+
#
|
7
|
+
# Bitsa is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
require "gdata"
|
21
|
+
|
22
|
+
module Bitsa #:nodoc:
|
23
|
+
|
24
|
+
# Loads Contacts from Gmail into a <tt>ContactsCache</tt> object.
|
25
|
+
class GmailContactsLoader
|
26
|
+
|
27
|
+
# Number of contacts to retrieve as a single chunk.
|
28
|
+
@@FETCH_SIZE = 25
|
29
|
+
|
30
|
+
# Ctor specifying the Gmail (or Google Apps) user name and password.
|
31
|
+
def initialize(user, pw) #, lifespan_days)
|
32
|
+
@user = user
|
33
|
+
@pw = pw
|
34
|
+
end
|
35
|
+
|
36
|
+
# Refresh the passsed <tt>ContactsCache</tt> with the latest contact
|
37
|
+
# changes/deletions from Gmail.
|
38
|
+
def update_cache(cache)
|
39
|
+
client = GData::Client::Contacts.new
|
40
|
+
client.clientlogin(@user, @pw)
|
41
|
+
|
42
|
+
idx = 1
|
43
|
+
until load_chunk(client, idx, cache) < @@FETCH_SIZE
|
44
|
+
idx += @@FETCH_SIZE
|
45
|
+
end
|
46
|
+
cache.source_last_modified = DateTime.now.to_s
|
47
|
+
cache.save
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def load_chunk(client, idx, cache)
|
53
|
+
last_modified = nil
|
54
|
+
url = "http://www.google.com/m8/feeds/contacts/#{@user}/thin"
|
55
|
+
url += "?orderby=lastmodified"
|
56
|
+
url += "&showdeleted=true"
|
57
|
+
url += "&max-results=#{@@FETCH_SIZE}"
|
58
|
+
url += "&start-index=#{idx}"
|
59
|
+
url += "&updated-min=#{CGI.escape(cache.source_last_modified)}" if cache.source_last_modified
|
60
|
+
feed = client.get(url).to_xml
|
61
|
+
feed.elements.each('entry') do |entry|
|
62
|
+
name = entry.elements['title'].text
|
63
|
+
name ||= ""
|
64
|
+
gmail_id = entry.elements['id'].text
|
65
|
+
deleted = entry.elements['gd:deleted'] ? true : false
|
66
|
+
if deleted
|
67
|
+
cache.delete(gmail_id)
|
68
|
+
else
|
69
|
+
addresses = []
|
70
|
+
entry.each_element('gd:email') do | addr |
|
71
|
+
addresses << addr.attributes['address']
|
72
|
+
end
|
73
|
+
cache.update(gmail_id, name, addresses)
|
74
|
+
end
|
75
|
+
last_modified = entry.elements['updated'].text
|
76
|
+
end
|
77
|
+
feed.elements.count
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Application settings.
|
2
|
+
#
|
3
|
+
# Copyright (C) 2011 Colin Noel Bell.
|
4
|
+
#
|
5
|
+
# This file is part of Bitsa.
|
6
|
+
#
|
7
|
+
# Bitsa is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
module Bitsa #:nodoc:
|
21
|
+
|
22
|
+
# Application settings.
|
23
|
+
class Settings
|
24
|
+
|
25
|
+
# Login to use to connect to GMail.
|
26
|
+
attr_reader :login
|
27
|
+
|
28
|
+
# Password to use to connect to GMail.
|
29
|
+
attr_reader :password
|
30
|
+
|
31
|
+
# Path to file to store cached contact information in.
|
32
|
+
attr_reader :cache_file_path
|
33
|
+
|
34
|
+
# Load settings from a hash of data from the configuration file and
|
35
|
+
# options passed on the command line.
|
36
|
+
#
|
37
|
+
# Options passed on the command line override those in the
|
38
|
+
# configuration file.
|
39
|
+
def load(config_file_hash, options)
|
40
|
+
@login = config_file_hash.data[:login]
|
41
|
+
@password = config_file_hash.data[:password]
|
42
|
+
@cache_file_path = config_file_hash.data[:cache_file_path]
|
43
|
+
|
44
|
+
@login = options[:login] if options[:login]
|
45
|
+
@password = options[:password] if options[:password]
|
46
|
+
@cache_file_path = options[:cache_file_path] if options[:cache_file_path]
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Application Version information.
|
2
|
+
#
|
3
|
+
# Copyright (C) 2011 Colin Noel Bell.
|
4
|
+
#
|
5
|
+
# This file is part of Bitsa.
|
6
|
+
#
|
7
|
+
# Bitsa is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
module Bitsa #:nodoc:
|
21
|
+
VERSION = "0.10"
|
22
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require "helper"
|
2
|
+
require "bitsa/args_processor"
|
3
|
+
|
4
|
+
describe Bitsa::ArgsProcessor do
|
5
|
+
context "when created" do
|
6
|
+
before(:all) { @ap = Bitsa::ArgsProcessor.new }
|
7
|
+
|
8
|
+
it "should recognise the 'update' command" do
|
9
|
+
@ap.parse(["update"])
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should throw raise SystemExit if an invalid command passed" do
|
13
|
+
lambda {@ap.parse(['unknown'])}.should raise_error(SystemExit)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should throw raise SystemExit if nothing passed" do
|
17
|
+
lambda {@ap.parse([])}.should raise_error(SystemExit)
|
18
|
+
end
|
19
|
+
|
20
|
+
context "and being passed valid commands" do
|
21
|
+
[["reload"], ["search", "data"], ["update"]].each do |ar|
|
22
|
+
cmd = ar[0]
|
23
|
+
it "should recognise the #{cmd} command" do
|
24
|
+
@ap.parse(ar)
|
25
|
+
@ap.cmd.should == cmd
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should recognise valid long arguments" do
|
31
|
+
args = []
|
32
|
+
args << "--config-file"
|
33
|
+
args << "somefile"
|
34
|
+
args << "--login"
|
35
|
+
args << "someone"
|
36
|
+
args << "--password"
|
37
|
+
args << "mypassword"
|
38
|
+
args << "update"
|
39
|
+
|
40
|
+
@ap.parse(args)
|
41
|
+
|
42
|
+
@ap.global_opts[:config_file].should == "somefile"
|
43
|
+
@ap.global_opts[:login].should == "someone"
|
44
|
+
@ap.global_opts[:password].should == "mypassword"
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should recognise valid short arguments" do
|
48
|
+
args = []
|
49
|
+
args << "-c"
|
50
|
+
args << "somefile"
|
51
|
+
args << "-l"
|
52
|
+
args << "someone"
|
53
|
+
args << "-p"
|
54
|
+
args << "mypassword"
|
55
|
+
args << "update"
|
56
|
+
|
57
|
+
@ap.parse(args)
|
58
|
+
|
59
|
+
@ap.global_opts[:config_file].should == "somefile"
|
60
|
+
@ap.global_opts[:login].should == "someone"
|
61
|
+
@ap.global_opts[:password].should == "mypassword"
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "helper"
|
2
|
+
require "bitsa/config_file"
|
3
|
+
|
4
|
+
describe Bitsa::ConfigFile do
|
5
|
+
context "An existing configuration file" do
|
6
|
+
before(:all) { @config = Bitsa::ConfigFile.new("spec/data/config.yml") }
|
7
|
+
it "should read values from config file" do
|
8
|
+
@config.data[:login].should == "test@gmail.com"
|
9
|
+
@config.data[:password].should == "myPassword"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context "An non-existent configuration file" do
|
14
|
+
before(:all) { @config = Bitsa::ConfigFile.new("/tmp/i-dont-exist") }
|
15
|
+
it "should have no values" do
|
16
|
+
@config.data.should == {}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "An existing configuration file that I have no read rights to" do
|
21
|
+
before(:all) do
|
22
|
+
@tmp_file = Tempfile.open("cache")
|
23
|
+
FileUtils.cp("spec/data/config.yml", @tmp_file.path)
|
24
|
+
FileUtils.chmod(0222, @tmp_file.path)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should throw an exception when I try to read from it" do
|
28
|
+
lambda { Bitsa::ConfigFile.new(@tmp_file.path) }.should raise_error(Errno::EACCES)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,294 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "tempfile"
|
3
|
+
|
4
|
+
require "helper"
|
5
|
+
|
6
|
+
require "bitsa/contacts_cache"
|
7
|
+
|
8
|
+
describe Bitsa::ContactsCache do
|
9
|
+
context "cache" do
|
10
|
+
it "should build successfully if cache file empty" do
|
11
|
+
tmp_file = create_empty_temp_file
|
12
|
+
cache = Bitsa::ContactsCache.new(tmp_file.path, 1)
|
13
|
+
should_be_an_empty_cache cache
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should build successfully if cache file does not exist" do
|
17
|
+
cache = Bitsa::ContactsCache.new("/tmp/idonotexististhatoky", 1)
|
18
|
+
should_be_an_empty_cache cache
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should fail with exception if user not authorised to read cache file" do
|
22
|
+
tmp_file = create_empty_temp_file
|
23
|
+
FileUtils.chmod(0222, tmp_file.path)
|
24
|
+
lambda { Bitsa::ContactsCache.new(tmp_file.path, 1).should raise_error(Errno::EACCES) }
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should not be stale if last updated today" do
|
28
|
+
create_cache(DateTime.now, 1)
|
29
|
+
@cache.stale?.should_not be_true
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should be stale if last updated yesterday and lifespan is 1 day" do
|
33
|
+
create_cache(DateTime.now-1, 1)
|
34
|
+
@cache.stale?.should be_true
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should not be stale if last updated yesterday and lifespan is 2 days" do
|
38
|
+
create_cache(DateTime.now-1, 2)
|
39
|
+
@cache.stale?.should_not be_true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "clearing the cache" do
|
44
|
+
before(:each) do
|
45
|
+
create_cache
|
46
|
+
@cache.should have_at_least(1).entries
|
47
|
+
@cache.empty?.should be_false
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should leave the cache empty" do
|
51
|
+
@cache.clear!
|
52
|
+
@cache.size.should == 0
|
53
|
+
@cache.empty?.should be_true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "searching the test data" do
|
58
|
+
# 4 contacts with 5 email addresses
|
59
|
+
before(:all) { create_cache }
|
60
|
+
|
61
|
+
it "should have read the correct number of contacts" do
|
62
|
+
@cache.size.should == 4
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should return all entries if blank searched for" do
|
66
|
+
results = @cache.search('')
|
67
|
+
results.size.should == 5
|
68
|
+
results.flatten(0).sort.should == read_test_data
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should return all entries if a nill string searched for" do
|
72
|
+
results = @cache.search(nil)
|
73
|
+
results.size.should == 5
|
74
|
+
results.flatten(0).sort.should == read_test_data
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should find correctly when searching by start of email address" do
|
78
|
+
results = @cache.search('test1')
|
79
|
+
results.should =~ [["test1@example.com", "My Tester"]]
|
80
|
+
|
81
|
+
results = @cache.search('jo')
|
82
|
+
expected = [["john_smith@here.org", ""], ["Joan.bloggs@somewhere.com.au", "Joan Bloggshere"]]
|
83
|
+
results.should =~ expected
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should find correctly when searching by end of email address" do
|
87
|
+
results = @cache.search('org')
|
88
|
+
expected = [["john_smith@here.org", ""]]
|
89
|
+
results.should =~ expected
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should find correctly when searching by middle of email address" do
|
93
|
+
results = @cache.search('n_s')
|
94
|
+
expected = [["john_smith@here.org", ""]]
|
95
|
+
results.should =~ expected
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should find correctly when searching by email address irrespective of case" do
|
99
|
+
results = @cache.search('N_sMI')
|
100
|
+
expected = [["john_smith@here.org", ""]]
|
101
|
+
results.should =~ expected
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should find correctly when searching by start of name" do
|
105
|
+
results = @cache.search('Joan Blo')
|
106
|
+
expected = [["Joan.bloggs@somewhere.com.au", "Joan Bloggshere"]]
|
107
|
+
results.should =~ expected
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should find correctly when searching by end of name" do
|
111
|
+
results = @cache.search('ggshere')
|
112
|
+
expected = [["Joan.bloggs@somewhere.com.au", "Joan Bloggshere"]]
|
113
|
+
results.should =~ expected
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should find correctly when searching by middle of name" do
|
117
|
+
results = @cache.search('n Bl')
|
118
|
+
expected = [["Joan.bloggs@somewhere.com.au", "Joan Bloggshere"]]
|
119
|
+
results.should =~ expected
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should find correctly when searching by name irrespective of case" do
|
123
|
+
results = @cache.search('N BL')
|
124
|
+
expected = [["Joan.bloggs@somewhere.com.au", "Joan Bloggshere"]]
|
125
|
+
results.should =~ expected
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should find no results if nothing to find" do
|
129
|
+
results = @cache.search('nothing is here')
|
130
|
+
results.size.should == 0
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should return all email addresses on a contact with multiple email addresses when matching on name" do
|
134
|
+
results = @cache.search('multip')
|
135
|
+
expected = [["email2@somewhere.com", "Mr Multiple"], ["email1@somewhere.com", "Mr Multiple"]]
|
136
|
+
results.should =~ expected
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should return only the matched email address on a contact with multiple email addresses" do
|
140
|
+
results = @cache.search('email1')
|
141
|
+
expected = [["email1@somewhere.com", "Mr Multiple"]]
|
142
|
+
results.should =~ expected
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should find by ID correctly" do
|
146
|
+
id = "http://www.google.com/m8/feeds/contacts/person%40example.org/base/685e301a549c176e"
|
147
|
+
results = @cache.get(id)
|
148
|
+
expected = [["email1@somewhere.com", "Mr Multiple"],
|
149
|
+
["email2@somewhere.com", "Mr Multiple"]]
|
150
|
+
results.should =~ expected
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should return nil if finding by a non-existent ID" do
|
154
|
+
id = "http://www.google.com/m8/feeds/contacts/person%40example.org/base/4783783783"
|
155
|
+
@cache.get(id).should be_nil
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context "updating the test data" do
|
160
|
+
# 4 contacts with 5 email addresses
|
161
|
+
before(:each) { create_cache }
|
162
|
+
|
163
|
+
it "should handle update with a single email address correctly" do
|
164
|
+
id = "http://www.google.com/m8/feeds/contacts/person%40example.org/base/637e301a549c176e"
|
165
|
+
results = @cache.get(id)
|
166
|
+
expected = [["Joan.bloggs@somewhere.com.au", "Joan Bloggshere"]]
|
167
|
+
results.should =~ expected
|
168
|
+
|
169
|
+
@cache.update(id, "Tammy Smith", ["tammy5@example.com"])
|
170
|
+
results = @cache.get(id)
|
171
|
+
expected = [["tammy5@example.com", "Tammy Smith"]]
|
172
|
+
results.should =~ expected
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should handle update with two email addresses correctly" do
|
176
|
+
id = "http://www.google.com/m8/feeds/contacts/person%40example.org/base/637e301a549c176e"
|
177
|
+
results = @cache.get(id)
|
178
|
+
expected = [["Joan.bloggs@somewhere.com.au", "Joan Bloggshere"]]
|
179
|
+
results.should =~ expected
|
180
|
+
|
181
|
+
@cache.update(id, "Tammy Smith", ["tammy5@example.com", "smithtammy@exampel.org"])
|
182
|
+
results = @cache.get(id)
|
183
|
+
expected = [["smithtammy@exampel.org", "Tammy Smith"], ["tammy5@example.com", "Tammy Smith"]]
|
184
|
+
results.should =~ expected
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
context "deleting a non-existent entry" do
|
189
|
+
before(:each) { create_cache }
|
190
|
+
|
191
|
+
it "should no longer contain the deleted entry" do
|
192
|
+
@cache.delete("NONEXISTENT")
|
193
|
+
@cache.get("NONEXISTENT").should be_nil
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should not change the number of entries in the cache" do
|
197
|
+
lambda {
|
198
|
+
@cache.delete("NONEXISTENT")
|
199
|
+
}.should_not change(@cache, :size)
|
200
|
+
end
|
201
|
+
|
202
|
+
it "should return nil" do
|
203
|
+
@cache.delete("NONEXISTENT").should be_nil
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
context "deleting an existing entry" do
|
208
|
+
before(:each) do
|
209
|
+
create_cache
|
210
|
+
@id = "http://www.google.com/m8/feeds/contacts/person%40example.org/base/637e301a549c176e"
|
211
|
+
end
|
212
|
+
|
213
|
+
it "should_change the number of entries by -1" do
|
214
|
+
lambda {
|
215
|
+
@cache.delete(@id)
|
216
|
+
}.should change(@cache, :size).by(-1)
|
217
|
+
end
|
218
|
+
|
219
|
+
it "should return the deleted entry" do
|
220
|
+
results = @cache.delete(@id)
|
221
|
+
expected = [["Joan.bloggs@somewhere.com.au", "Joan Bloggshere"]]
|
222
|
+
results.should =~ expected
|
223
|
+
end
|
224
|
+
|
225
|
+
it "should no longer contain the deleted entry" do
|
226
|
+
@cache.delete(@id)
|
227
|
+
@cache.get(@id).should be_nil
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
context "saving the test data" do
|
232
|
+
before(:each) { create_cache }
|
233
|
+
it "should save changes to existing contacts" do
|
234
|
+
id = "http://www.google.com/m8/feeds/contacts/person%40example.org/base/637e301a549c176e"
|
235
|
+
@cache.update(id, "The Changed Name", ["change1@somewhere.org"])
|
236
|
+
@cache.save
|
237
|
+
new_cache = Bitsa::ContactsCache.new(@tmp_file.path, 1)
|
238
|
+
expected = [["change1@somewhere.org", "The Changed Name"]]
|
239
|
+
new_cache.get(id).should =~ expected
|
240
|
+
end
|
241
|
+
|
242
|
+
it "should save newly added entries" do
|
243
|
+
id = "NONEXISTENT"
|
244
|
+
@cache.update(id, "The Changed Name", ["change1@somewhere.org"])
|
245
|
+
@cache.save
|
246
|
+
new_cache = Bitsa::ContactsCache.new(@tmp_file.path, 1)
|
247
|
+
expected = [["change1@somewhere.org", "The Changed Name"]]
|
248
|
+
new_cache.get(id).should =~ expected
|
249
|
+
end
|
250
|
+
|
251
|
+
context "to a file that I have no write rights to" do
|
252
|
+
before(:each) { FileUtils.chmod(0444, @tmp_file.path) }
|
253
|
+
|
254
|
+
it "should throw an exception when I try to write to it" do
|
255
|
+
lambda {@cache.save}.should raise_error(Errno::EACCES)
|
256
|
+
end
|
257
|
+
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
private
|
262
|
+
|
263
|
+
def create_cache(last_modified = nil, lifespan_days = 1)
|
264
|
+
source_last_modified, addresses = YAML::load_file("spec/data/bitsa_cache.yml")
|
265
|
+
source_last_modified = last_modified.to_s if last_modified
|
266
|
+
|
267
|
+
@tmp_file = Tempfile.open("cache")
|
268
|
+
File.open(@tmp_file.path, "w") do |f|
|
269
|
+
f.write(YAML::dump([source_last_modified, addresses]))
|
270
|
+
end
|
271
|
+
@cache = Bitsa::ContactsCache.new(@tmp_file.path, lifespan_days)
|
272
|
+
end
|
273
|
+
|
274
|
+
def create_empty_temp_file
|
275
|
+
tmp_file = Tempfile.open("cache")
|
276
|
+
File.open(tmp_file.path, "w") do |f|
|
277
|
+
f.write('')
|
278
|
+
end
|
279
|
+
tmp_file
|
280
|
+
end
|
281
|
+
|
282
|
+
def should_be_an_empty_cache cache
|
283
|
+
cache.should_not be_nil
|
284
|
+
cache.size.should == 0
|
285
|
+
cache.source_last_modified.should be_nil
|
286
|
+
cache.stale?.should be_true
|
287
|
+
end
|
288
|
+
|
289
|
+
def read_test_data
|
290
|
+
source_last_modified, addresses = YAML::load_file(@tmp_file.path)
|
291
|
+
addresses.values.flatten(1).sort
|
292
|
+
end
|
293
|
+
|
294
|
+
end
|