nsync 0.0.2
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/LICENSE +21 -0
- data/README.md +204 -0
- data/Rakefile +47 -0
- data/VERSION +1 -0
- data/jeweler_monkey_patch.rb +59 -0
- data/lib/nsync/active_record/consumer/methods.rb +47 -0
- data/lib/nsync/active_record/methods.rb +23 -0
- data/lib/nsync/active_record/producer/methods.rb +21 -0
- data/lib/nsync/class_methods.rb +17 -0
- data/lib/nsync/config.rb +96 -0
- data/lib/nsync/consumer.rb +293 -0
- data/lib/nsync/git_version_manager.rb +29 -0
- data/lib/nsync/producer/methods.rb +23 -0
- data/lib/nsync/producer.rb +129 -0
- data/lib/nsync.rb +30 -0
- data/nsync.gemspec +80 -0
- data/test/active_record_test.rb +153 -0
- data/test/classes.rb +22 -0
- data/test/helper.rb +12 -0
- data/test/nsync_config_test.rb +142 -0
- data/test/nsync_consumer_test.rb +260 -0
- data/test/nsync_producer_test.rb +261 -0
- data/test/repo.rb +64 -0
- metadata +165 -0
@@ -0,0 +1,261 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "helper")
|
2
|
+
|
3
|
+
class NsyncProducerTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
#Grit.debug = true
|
6
|
+
Nsync.reset_config
|
7
|
+
@lock_file = "/private/tmp/nsync_test_#{Process.pid}.lock"
|
8
|
+
FileUtils.rm @lock_file, :force => true
|
9
|
+
Nsync.config.lock_file = @lock_file
|
10
|
+
end
|
11
|
+
|
12
|
+
context "Initializing Producer" do
|
13
|
+
context "when the repo already exists" do
|
14
|
+
setup do
|
15
|
+
@repo = TestRepo.new
|
16
|
+
|
17
|
+
Nsync.config.repo_path = @repo.repo_path
|
18
|
+
end
|
19
|
+
|
20
|
+
should "not try to reinitialize it" do
|
21
|
+
Grit::Git.any_instance.expects(:init).never
|
22
|
+
@producer = Nsync::Producer.new
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "when the repo does not exist" do
|
27
|
+
setup do
|
28
|
+
@repo_path = TestRepo.repo_path
|
29
|
+
Nsync.config.repo_path = @repo_path
|
30
|
+
FileUtils.rm_rf @repo_path
|
31
|
+
end
|
32
|
+
|
33
|
+
should "initialize it and make a base commit" do
|
34
|
+
Grit::Repo.expects(:init).with(@repo_path).once
|
35
|
+
Nsync::Producer.any_instance.expects(:write_file).with(".gitignore", "").once
|
36
|
+
Nsync::Producer.any_instance.expects(:commit).returns(true).once
|
37
|
+
Nsync::Producer.new
|
38
|
+
end
|
39
|
+
|
40
|
+
should "initialize the repo into a working state" do
|
41
|
+
@producer = Nsync::Producer.new
|
42
|
+
assert_equal "Initial Commit", @producer.repo.head.commit.message
|
43
|
+
assert File.exists?(File.join(@repo_path, ".gitignore"))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "Consumer methods that are probably not what you want" do
|
49
|
+
setup do
|
50
|
+
@repo = TestRepo.new
|
51
|
+
|
52
|
+
Nsync.config.repo_path = @repo.repo_path
|
53
|
+
@producer = Nsync::Producer.new
|
54
|
+
end
|
55
|
+
|
56
|
+
should "be protected" do
|
57
|
+
assert_equal [], @producer.public_methods & ["update", "apply_changes"]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
context "Writing a file" do
|
63
|
+
setup do
|
64
|
+
@repo = TestRepo.new
|
65
|
+
|
66
|
+
Nsync.config.repo_path = @repo.repo_path
|
67
|
+
@producer = Nsync::Producer.new
|
68
|
+
end
|
69
|
+
|
70
|
+
context "when creating a file" do
|
71
|
+
setup do
|
72
|
+
@file = "foo/1.json"
|
73
|
+
@hash = {"id" => 1, "val" => "Shazam"}
|
74
|
+
end
|
75
|
+
|
76
|
+
should "write the file to disk, add it to the index, but not commit" do
|
77
|
+
@producer.repo.expects(:add).with(File.join(@repo.repo_path, @file)).once
|
78
|
+
@producer.expects(:commit).never
|
79
|
+
@producer.repo.expects(:commit_all).never
|
80
|
+
@producer.write_file(@file, @hash)
|
81
|
+
|
82
|
+
assert_equal JSON.load(File.read(File.join(@repo.repo_path, @file))), @hash
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context "when modifying a file" do
|
87
|
+
setup do
|
88
|
+
@file = "foo/1.json"
|
89
|
+
@hash = {"id" => 1, "val" => "Shazam"}
|
90
|
+
@producer.write_file(@file, @hash)
|
91
|
+
end
|
92
|
+
|
93
|
+
should "behave just like a create" do
|
94
|
+
new_hash = {"id" => 1, "val" => "Kaboom"}
|
95
|
+
@producer.repo.expects(:add).with(File.join(@repo.repo_path, @file)).once
|
96
|
+
@producer.expects(:commit).never
|
97
|
+
@producer.write_file(@file, new_hash)
|
98
|
+
|
99
|
+
assert_equal JSON.load(File.read(File.join(@repo.repo_path, @file))), new_hash
|
100
|
+
end
|
101
|
+
|
102
|
+
context "but then removing it" do
|
103
|
+
setup do
|
104
|
+
@producer.remove_file(@file)
|
105
|
+
end
|
106
|
+
|
107
|
+
should "just be gone" do
|
108
|
+
assert !File.exists?(File.join(@repo.repo_path, @file))
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context "Committing changes" do
|
115
|
+
setup do
|
116
|
+
@repo = TestRepo.new
|
117
|
+
|
118
|
+
Nsync.config.repo_path = @repo.repo_path
|
119
|
+
@producer = Nsync::Producer.new
|
120
|
+
end
|
121
|
+
|
122
|
+
should "commit all changes as well as push" do
|
123
|
+
@msg = "Test Update"
|
124
|
+
@producer.repo.expects(:commit_all).with(@msg).once
|
125
|
+
@producer.expects(:push).once
|
126
|
+
@producer.commit(@msg)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context "Pushing changes" do
|
131
|
+
setup do
|
132
|
+
@repo = TestRepo.new
|
133
|
+
|
134
|
+
Nsync.config.repo_path = @repo.repo_path
|
135
|
+
@producer = Nsync::Producer.new
|
136
|
+
end
|
137
|
+
|
138
|
+
context "when there is a remote push url" do
|
139
|
+
setup do
|
140
|
+
@push_url = "/tmp/foo/bar"
|
141
|
+
Nsync.config.repo_push_url = @push_url
|
142
|
+
end
|
143
|
+
|
144
|
+
should "push changes to that" do
|
145
|
+
@producer.repo.git.expects(:push).with({}, @push_url, "+master").once
|
146
|
+
@producer.push
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
context "when there is no remote push url" do
|
151
|
+
should "not try to push" do
|
152
|
+
@producer.repo.git.expects(:push).never
|
153
|
+
@producer.push
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
context "Because a producer is a consumer that consumes itself" do
|
159
|
+
setup do
|
160
|
+
@repo = TestRepo.new
|
161
|
+
|
162
|
+
Nsync.config.repo_path = @repo.repo_path
|
163
|
+
@producer = Nsync::Producer.new
|
164
|
+
end
|
165
|
+
|
166
|
+
context "the class mapping" do
|
167
|
+
setup do
|
168
|
+
Nsync.config.map_class "NsyncTestBar", "NsyncTestFoo"
|
169
|
+
end
|
170
|
+
|
171
|
+
context "when unset for a class" do
|
172
|
+
should "return the producer class" do
|
173
|
+
assert_equal [NsyncTestFoo],
|
174
|
+
@producer.send(:consumer_classes_and_id_from_path, "nsync_test_foo/1.json")[0]
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
context "when set for a class" do
|
179
|
+
should "return a consumer class normally" do
|
180
|
+
assert_equal [NsyncTestFoo],
|
181
|
+
@producer.send(:consumer_classes_and_id_from_path, "nsync_test_bar/1.json")[0]
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
context "rollback behaves quite differently" do
|
187
|
+
setup do
|
188
|
+
Nsync.config.version_manager = stub(:version => "bad_rev",
|
189
|
+
:previous_version => "good_rev")
|
190
|
+
end
|
191
|
+
|
192
|
+
should "reset from bad to good, apply changes between bad and good, and push" do
|
193
|
+
@producer.repo.git.expects(:reset).never
|
194
|
+
@producer.repo.git.expects(:reset).with({:hard => true}, "good_rev").once
|
195
|
+
@producer.expects(:apply_changes).with("bad_rev", "good_rev").once
|
196
|
+
@producer.expects(:push).once
|
197
|
+
@producer.rollback
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
context "basic flow" do
|
203
|
+
setup do
|
204
|
+
@repo_path = TestRepo.repo_path
|
205
|
+
@repo_push_url = TestRepo.bare_consumer_repo_path
|
206
|
+
FileUtils.rm_rf @repo_path
|
207
|
+
FileUtils.rm_rf @repo_push_url
|
208
|
+
|
209
|
+
@remote_repo = Grit::Repo.init_bare(@repo_push_url)
|
210
|
+
Nsync.config.repo_path = @repo_path
|
211
|
+
Nsync.config.repo_push_url = @repo_push_url
|
212
|
+
Nsync.config.version_manager = Nsync::GitVersionManager.new
|
213
|
+
|
214
|
+
@producer = Nsync::Producer.new
|
215
|
+
@repo = @producer.repo
|
216
|
+
end
|
217
|
+
|
218
|
+
should "work" do
|
219
|
+
@producer.write_file("nsync_test_foo/1.json", {:id => 1, :val => "Party"})
|
220
|
+
@producer.write_file("nsync_test_bar/2.json", {:id => 2, :val => "Study"})
|
221
|
+
assert_equal 1, @repo.commits.size
|
222
|
+
assert_equal 1, @remote_repo.commits.size
|
223
|
+
assert File.exists?(File.join(@repo_path, "nsync_test_foo/1.json"))
|
224
|
+
assert File.exists?(File.join(@repo_path, "nsync_test_bar/2.json"))
|
225
|
+
@producer.commit("Added some files")
|
226
|
+
|
227
|
+
assert_equal 2, @repo.commits.size
|
228
|
+
assert_equal 2, @remote_repo.commits.size
|
229
|
+
|
230
|
+
@producer.write_file("nsync_test_foo/2.json", {:id => 2, :val => "Rock"})
|
231
|
+
assert File.exists?(File.join(@repo_path, "nsync_test_foo/2.json"))
|
232
|
+
@producer.commit("And another")
|
233
|
+
|
234
|
+
assert_equal 3, @repo.commits.size
|
235
|
+
assert_equal 3, @remote_repo.commits.size
|
236
|
+
|
237
|
+
@producer.remove_file("nsync_test_bar/2.json")
|
238
|
+
assert !File.exists?(File.join(@repo_path, "nsync_test_bar/2.json"))
|
239
|
+
@producer.commit("Remove the no-fun brigade")
|
240
|
+
|
241
|
+
assert_equal 4, @repo.commits.size
|
242
|
+
assert_equal 4, @remote_repo.commits.size
|
243
|
+
|
244
|
+
NsyncTestBar.expects(:nsync_find).with('2').returns([]).once
|
245
|
+
NsyncTestBar.expects(:nsync_add_data).once
|
246
|
+
|
247
|
+
@producer.rollback
|
248
|
+
|
249
|
+
assert File.exists?(File.join(@repo_path, "nsync_test_bar/2.json"))
|
250
|
+
assert_equal 3, @repo.commits.size
|
251
|
+
assert_equal 3, @remote_repo.commits.size
|
252
|
+
|
253
|
+
@producer.write_file("nsync_test_bar/5.json", {:id => 5, :val => "No Fun"})
|
254
|
+
assert File.exists?(File.join(@repo_path, "nsync_test_bar/5.json"))
|
255
|
+
@producer.commit("Life goes on")
|
256
|
+
|
257
|
+
assert_equal 4, @repo.commits.size
|
258
|
+
assert_equal 4, @remote_repo.commits.size
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
data/test/repo.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
class TestRepo
|
2
|
+
attr_accessor :repo
|
3
|
+
|
4
|
+
def initialize(opts={})
|
5
|
+
FileUtils.rm_rf(repo_path)
|
6
|
+
self.repo = Grit::Repo.init(repo_path)
|
7
|
+
add_file(".gitignore", "")
|
8
|
+
commit("Initial Commit")
|
9
|
+
end
|
10
|
+
|
11
|
+
def cd
|
12
|
+
old_pwd = FileUtils.pwd
|
13
|
+
begin
|
14
|
+
FileUtils.cd repo_path
|
15
|
+
yield
|
16
|
+
ensure
|
17
|
+
FileUtils.cd old_pwd
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def repo_path
|
22
|
+
self.class.repo_path
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.repo_path
|
26
|
+
"/private/tmp/nsync_test_repo_#{Process.pid}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def bare_consumer_repo_path
|
30
|
+
self.class.bare_consumer_repo_path
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.bare_consumer_repo_path
|
34
|
+
"#{repo_path}_consumer.git"
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.repo_push_path
|
38
|
+
"#{repo_path}_producer_push.git"
|
39
|
+
end
|
40
|
+
|
41
|
+
def add_file(filename, content)
|
42
|
+
cd do
|
43
|
+
dir = File.dirname(filename)
|
44
|
+
if ![".", "/"].include?(dir) && !File.exists?(dir)
|
45
|
+
FileUtils.mkdir_p(File.join(repo_path, dir))
|
46
|
+
end
|
47
|
+
File.open(File.join(repo_path, filename), "w") do |f|
|
48
|
+
f.write((content.is_a?(Hash))? content.to_json : content)
|
49
|
+
end
|
50
|
+
repo.add(File.join(repo_path, filename))
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def remove_file(filename)
|
55
|
+
FileUtils.rm File.join(repo_path, filename)
|
56
|
+
end
|
57
|
+
|
58
|
+
def commit(message)
|
59
|
+
cd do
|
60
|
+
repo.commit_all(message)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
metadata
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nsync
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
version: 0.0.2
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Ben Hughes
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-12-06 00:00:00 -05:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: json
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :runtime
|
31
|
+
version_requirements: *id001
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: activesupport
|
34
|
+
prerelease: false
|
35
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ~>
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
segments:
|
40
|
+
- 2
|
41
|
+
- 3
|
42
|
+
- 5
|
43
|
+
version: 2.3.5
|
44
|
+
type: :runtime
|
45
|
+
version_requirements: *id002
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: schleyfox-grit
|
48
|
+
prerelease: false
|
49
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
segments:
|
54
|
+
- 2
|
55
|
+
- 3
|
56
|
+
- 0
|
57
|
+
- 1
|
58
|
+
version: 2.3.0.1
|
59
|
+
type: :runtime
|
60
|
+
version_requirements: *id003
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: schleyfox-lockfile
|
63
|
+
prerelease: false
|
64
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
segments:
|
69
|
+
- 1
|
70
|
+
- 0
|
71
|
+
- 0
|
72
|
+
version: 1.0.0
|
73
|
+
type: :runtime
|
74
|
+
version_requirements: *id004
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: shoulda
|
77
|
+
prerelease: false
|
78
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
segments:
|
83
|
+
- 0
|
84
|
+
version: "0"
|
85
|
+
type: :development
|
86
|
+
version_requirements: *id005
|
87
|
+
- !ruby/object:Gem::Dependency
|
88
|
+
name: mocha
|
89
|
+
prerelease: false
|
90
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
segments:
|
95
|
+
- 0
|
96
|
+
version: "0"
|
97
|
+
type: :development
|
98
|
+
version_requirements: *id006
|
99
|
+
description: |-
|
100
|
+
Nsync is designed to allow you to have a separate data
|
101
|
+
processing app with its own data processing optimized database and a consumer
|
102
|
+
app with its own database, while keeping the data as in sync as you want it.
|
103
|
+
email: ben@pixelmachine.org
|
104
|
+
executables: []
|
105
|
+
|
106
|
+
extensions: []
|
107
|
+
|
108
|
+
extra_rdoc_files:
|
109
|
+
- LICENSE
|
110
|
+
- README.md
|
111
|
+
files:
|
112
|
+
- LICENSE
|
113
|
+
- README.md
|
114
|
+
- Rakefile
|
115
|
+
- VERSION
|
116
|
+
- jeweler_monkey_patch.rb
|
117
|
+
- lib/nsync.rb
|
118
|
+
- lib/nsync/active_record/consumer/methods.rb
|
119
|
+
- lib/nsync/active_record/methods.rb
|
120
|
+
- lib/nsync/active_record/producer/methods.rb
|
121
|
+
- lib/nsync/class_methods.rb
|
122
|
+
- lib/nsync/config.rb
|
123
|
+
- lib/nsync/consumer.rb
|
124
|
+
- lib/nsync/git_version_manager.rb
|
125
|
+
- lib/nsync/producer.rb
|
126
|
+
- lib/nsync/producer/methods.rb
|
127
|
+
- nsync.gemspec
|
128
|
+
has_rdoc: true
|
129
|
+
homepage: http://github.com/schleyfox/nsync
|
130
|
+
licenses: []
|
131
|
+
|
132
|
+
post_install_message:
|
133
|
+
rdoc_options: []
|
134
|
+
|
135
|
+
require_paths:
|
136
|
+
- lib
|
137
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
138
|
+
requirements:
|
139
|
+
- - ">="
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
segments:
|
142
|
+
- 0
|
143
|
+
version: "0"
|
144
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
145
|
+
requirements:
|
146
|
+
- - ">="
|
147
|
+
- !ruby/object:Gem::Version
|
148
|
+
segments:
|
149
|
+
- 0
|
150
|
+
version: "0"
|
151
|
+
requirements: []
|
152
|
+
|
153
|
+
rubyforge_project:
|
154
|
+
rubygems_version: 1.3.6
|
155
|
+
signing_key:
|
156
|
+
specification_version: 3
|
157
|
+
summary: Keep your data processors and apps in sync
|
158
|
+
test_files:
|
159
|
+
- test/active_record_test.rb
|
160
|
+
- test/classes.rb
|
161
|
+
- test/helper.rb
|
162
|
+
- test/nsync_config_test.rb
|
163
|
+
- test/nsync_consumer_test.rb
|
164
|
+
- test/nsync_producer_test.rb
|
165
|
+
- test/repo.rb
|