MrMurano 1.11.3 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/Gemfile +2 -0
  4. data/README.markdown +12 -14
  5. data/Rakefile +2 -2
  6. data/TODO.taskpaper +8 -6
  7. data/docs/demo.md +109 -0
  8. data/lib/MrMurano/Account.rb +6 -3
  9. data/lib/MrMurano/Config.rb +13 -37
  10. data/lib/MrMurano/Product-1P-Device.rb +2 -0
  11. data/lib/MrMurano/Product-Resources.rb +5 -4
  12. data/lib/MrMurano/Product.rb +3 -3
  13. data/lib/MrMurano/Solution-File.rb +1 -2
  14. data/lib/MrMurano/Solution-ServiceConfig.rb +11 -1
  15. data/lib/MrMurano/Solution-Services.rb +24 -7
  16. data/lib/MrMurano/Solution-Users.rb +6 -4
  17. data/lib/MrMurano/SyncUpDown.rb +67 -28
  18. data/lib/MrMurano/commands/config.rb +4 -1
  19. data/lib/MrMurano/commands/exportImport.rb +3 -0
  20. data/lib/MrMurano/hash.rb +2 -0
  21. data/lib/MrMurano/http.rb +3 -3
  22. data/lib/MrMurano/verbosing.rb +9 -3
  23. data/lib/MrMurano/version.rb +1 -1
  24. data/spec/Account_spec.rb +104 -0
  25. data/spec/Config_spec.rb +202 -57
  26. data/spec/Http_spec.rb +204 -0
  27. data/spec/MakePretties_spec.rb +35 -0
  28. data/spec/Mock_spec.rb +13 -20
  29. data/spec/ProductBase_spec.rb +2 -0
  30. data/spec/ProductContent_spec.rb +77 -12
  31. data/spec/ProductResources_spec.rb +235 -0
  32. data/spec/Product_1P_Device_spec.rb +62 -0
  33. data/spec/Product_1P_RPC_spec.rb +2 -0
  34. data/spec/Product_spec.rb +18 -8
  35. data/spec/Solution-Cors_spec.rb +28 -1
  36. data/spec/Solution-Endpoint_spec.rb +250 -33
  37. data/spec/Solution-File_spec.rb +210 -0
  38. data/spec/Solution-ServiceConfig_spec.rb +2 -0
  39. data/spec/Solution-ServiceDevice_spec.rb +174 -0
  40. data/spec/Solution-ServiceEventHandler_spec.rb +134 -1
  41. data/spec/Solution-ServiceModules_spec.rb +317 -64
  42. data/spec/Solution-UsersRoles_spec.rb +207 -0
  43. data/spec/Solution_spec.rb +90 -0
  44. data/spec/SyncRoot_spec.rb +52 -46
  45. data/spec/SyncUpDown_spec.rb +364 -0
  46. data/spec/Verbosing_spec.rb +279 -0
  47. data/spec/_workspace.rb +27 -0
  48. data/spec/fixtures/dumped_config +47 -0
  49. data/spec/fixtures/product_spec_files/lightbulb-no-state.yaml +11 -0
  50. data/spec/fixtures/product_spec_files/lightbulb.yaml +2 -0
  51. data/spec/fixtures/roles-three.yaml +11 -0
  52. data/spec/spec_helper.rb +9 -0
  53. metadata +26 -2
@@ -0,0 +1,90 @@
1
+ require 'MrMurano/version'
2
+ require 'MrMurano/Solution-Cors'
3
+ require 'tempfile'
4
+ require 'yaml'
5
+ require '_workspace'
6
+
7
+ RSpec.describe MrMurano::Solution do
8
+ include_context "WORKSPACE"
9
+ before(:example) do
10
+ $cfg = MrMurano::Config.new
11
+ $cfg.load
12
+ $cfg['net.host'] = 'bizapi.hosted.exosite.io'
13
+ $cfg['solution.id'] = 'XYZ'
14
+
15
+ @srv = MrMurano::Solution.new
16
+ allow(@srv).to receive(:token).and_return("TTTTTTTTTT")
17
+ end
18
+
19
+ it "initializes" do
20
+ uri = @srv.endPoint('/')
21
+ expect(uri.to_s).to eq("https://bizapi.hosted.exosite.io/api:1/solution/XYZ/")
22
+ end
23
+
24
+ it "gets info" do
25
+ body = {
26
+ :id=>"XYZ",
27
+ :label=>nil,
28
+ :domain=>"ugdemo.apps.exosite.io",
29
+ :biz_id=>"ABCDEFG",
30
+ :cors=> "{\"origin\":true,\"methods\":[\"HEAD\",\"GET\",\"POST\",\"PUT\",\"DELETE\",\"OPTIONS\",\"PATCH\"],\"headers\":[\"Content-Type\",\"Cookie\",\"Authorization\"],\"credentials\":true}"
31
+ }
32
+
33
+ stub_request(:get, "https://bizapi.hosted.exosite.io/api:1/solution/XYZ").
34
+ with(:headers=>{'Authorization'=>'token TTTTTTTTTT',
35
+ 'Content-Type'=>'application/json'}).
36
+ to_return(body: body.to_json)
37
+
38
+ ret = @srv.info()
39
+ expect(ret).to eq(body)
40
+ end
41
+
42
+ it "lists" do
43
+ body = {
44
+ :id=>"XYZ",
45
+ :label=>nil,
46
+ :domain=>"ugdemo.apps.exosite.io",
47
+ :biz_id=>"ABCDEFG",
48
+ :cors=> "{\"origin\":true,\"methods\":[\"HEAD\",\"GET\",\"POST\",\"PUT\",\"DELETE\",\"OPTIONS\",\"PATCH\"],\"headers\":[\"Content-Type\",\"Cookie\",\"Authorization\"],\"credentials\":true}"
49
+ }
50
+
51
+ stub_request(:get, "https://bizapi.hosted.exosite.io/api:1/solution/XYZ/").
52
+ with(:headers=>{'Authorization'=>'token TTTTTTTTTT',
53
+ 'Content-Type'=>'application/json'}).
54
+ to_return(body: body.to_json)
55
+
56
+ ret = @srv.list()
57
+ expect(ret).to eq(body)
58
+ end
59
+
60
+ it "Gets version" do
61
+ body = {:min_cli_version=>"0.10"}
62
+ stub_request(:get, "https://bizapi.hosted.exosite.io/api:1/solution/XYZ/version").
63
+ with(:headers=>{'Authorization'=>'token TTTTTTTTTT',
64
+ 'Content-Type'=>'application/json'}).
65
+ to_return(body: body.to_json)
66
+
67
+ ret = @srv.version()
68
+ expect(ret).to eq(body)
69
+ end
70
+
71
+ it "Gets logs" do
72
+ body = {:p=>[
73
+ {:type=>"error",
74
+ :timestamp=>1481746755,
75
+ :subject=>"service call failed",
76
+ :data=>{:service_alias=>"user", :function_call=>"assignUser"}
77
+ }, ],
78
+ :total=>1}
79
+ stub_request(:get, "https://bizapi.hosted.exosite.io/api:1/solution/XYZ/logs").
80
+ with(:headers=>{'Authorization'=>'token TTTTTTTTTT',
81
+ 'Content-Type'=>'application/json'}).
82
+ to_return(body: body.to_json)
83
+
84
+ ret = @srv.log()
85
+ expect(ret).to eq(body)
86
+ end
87
+
88
+ end
89
+
90
+ # vim: set ai et sw=2 ts=2 :
@@ -1,74 +1,80 @@
1
1
  require 'MrMurano/version'
2
2
  require 'MrMurano/Config'
3
3
  require 'MrMurano/SyncUpDown'
4
+ require '_workspace'
4
5
 
5
6
  RSpec.describe MrMurano::SyncRoot do
7
+ include_context "WORKSPACE"
6
8
 
7
9
  after(:example) do
8
10
  MrMurano::SyncRoot.reset
9
11
  end
10
12
 
11
- it "Adds" do
13
+ before(:example) do
14
+ MrMurano::SyncRoot.reset # also creates @@syncset
12
15
  class User
13
16
  end
14
17
  class Role
15
18
  end
16
- MrMurano::SyncRoot.add('user', User, 'U', "describe user")
19
+ MrMurano::SyncRoot.add('user', User, 'U', "describe user", true)
17
20
  MrMurano::SyncRoot.add('role', Role, 'R', "describe role")
18
- end
19
21
 
20
- context "b" do
21
- before(:example) do
22
- class User
23
- end
24
- class Role
25
- end
26
- MrMurano::SyncRoot.add('user', User, 'U', "describe user", true)
27
- MrMurano::SyncRoot.add('role', Role, 'R', "describe role")
22
+ # This must happen after all syncables have been added.
23
+ $cfg = MrMurano::Config.new
24
+ $cfg.load
28
25
 
29
- @options = {}
30
- @options.define_singleton_method(:method_missing) do |mid,*args|
31
- if mid.to_s.match(/^(.+)=$/) then
32
- self[$1.to_sym] = args.first
33
- else
34
- self[mid]
35
- end
26
+ @options = {}
27
+ @options.define_singleton_method(:method_missing) do |mid,*args|
28
+ if mid.to_s.match(/^(.+)=$/) then
29
+ self[$1.to_sym] = args.first
30
+ else
31
+ self[mid]
36
32
  end
37
-
38
33
  end
34
+ end
39
35
 
40
- it "iterrates on each" do
41
- ret=[]
42
- MrMurano::SyncRoot.each{|a,b,c| ret << a}
43
- expect(ret).to eq(["user", "role"])
44
- end
36
+ it "has defaults" do
37
+ ret = MrMurano::SyncRoot.bydefault
38
+ expect(ret).to eq(['user'])
39
+ end
45
40
 
46
- it "iterrates only on selected" do
47
- @options.role = true
48
- ret=[]
49
- MrMurano::SyncRoot.each_filtered(@options) {|a,b,c| ret << a}
50
- expect(ret).to eq(["role"])
51
- end
41
+ it "iterates on each" do
42
+ ret=[]
43
+ MrMurano::SyncRoot.each{|a,b,c| ret << a}
44
+ expect(ret).to eq(["user", "role"])
45
+ end
52
46
 
53
- it "selects all" do
54
- @options.all = true
55
- MrMurano::SyncRoot.checkSAME(@options)
56
- expect(@options).to eq({:all=>true, :user=>true, :role=>true})
57
- end
47
+ it "iterates only on selected" do
48
+ @options.role = true
49
+ ret=[]
50
+ MrMurano::SyncRoot.each_filtered(@options) {|a,b,c| ret << a}
51
+ expect(ret).to eq(["role"])
52
+ end
58
53
 
59
- it "selects defaults when none" do
60
- MrMurano::SyncRoot.checkSAME(@options)
61
- expect(@options).to eq({:user=>true})
62
- end
54
+ it "selects all" do
55
+ @options.all = true
56
+ MrMurano::SyncRoot.checkSAME(@options)
57
+ expect(@options).to eq({:all=>true, :user=>true, :role=>true})
58
+ end
63
59
 
64
- it "builds option params" do
65
- ret=[]
66
- MrMurano::SyncRoot.each_option do |s,l,d|
67
- ret << [s,l,d]
68
- end
69
- expect(ret).to eq([["-u", "--[no-]user", "describe user"], ["-r", "--[no-]role", "describe role"]])
70
- end
60
+ it "selects defaults when none" do
61
+ MrMurano::SyncRoot.checkSAME(@options)
62
+ expect(@options).to eq({:user=>true})
63
+ end
71
64
 
65
+ it "selects custom defaults when none" do
66
+ $cfg['sync.bydefault'] = 'role'
67
+ MrMurano::SyncRoot.checkSAME(@options)
68
+ expect(@options).to eq({:role=>true})
72
69
  end
70
+
71
+ it "builds option params" do
72
+ ret=[]
73
+ MrMurano::SyncRoot.each_option do |s,l,d|
74
+ ret << [s,l,d]
75
+ end
76
+ expect(ret).to eq([["-u", "--[no-]user", "describe user"], ["-r", "--[no-]role", "describe role"]])
77
+ end
78
+
73
79
  end
74
80
  # vim: set ai et sw=2 ts=2 :
@@ -0,0 +1,364 @@
1
+ require 'MrMurano/version'
2
+ require 'MrMurano/verbosing'
3
+ require 'MrMurano/Config'
4
+ require 'MrMurano/SyncUpDown'
5
+ require '_workspace'
6
+
7
+ class TSUD
8
+ include MrMurano::Verbose
9
+ include MrMurano::SyncUpDown
10
+ def initialize
11
+ @itemkey = :name
12
+ @locationbase = $cfg['location.base']
13
+ @location = 'tsud'
14
+ end
15
+ def fetch(id)
16
+ end
17
+ end
18
+ RSpec.describe MrMurano::SyncUpDown do
19
+ include_context "WORKSPACE"
20
+ before(:example) do
21
+ $cfg = MrMurano::Config.new
22
+ $cfg.load
23
+ $cfg['net.host'] = 'bizapi.hosted.exosite.io'
24
+ $cfg['solution.id'] = 'XYZ'
25
+ end
26
+
27
+ context "status" do
28
+ it "warns with missing directory" do
29
+ t = TSUD.new
30
+ expect(t).to receive(:warning).once.with(/Skipping missing location.*/)
31
+ ret = t.status
32
+ expect(ret).to eq({:toadd=>[], :todel=>[], :tomod=>[], :unchg=>[]})
33
+ end
34
+
35
+ it "finds nothing in empty directory" do
36
+ FileUtils.mkpath(@projectDir + '/tsud')
37
+ t = TSUD.new
38
+ ret = t.status
39
+ expect(ret).to eq({:toadd=>[], :todel=>[], :tomod=>[], :unchg=>[]})
40
+ end
41
+
42
+ it "finds things there but not here" do
43
+ FileUtils.mkpath(@projectDir + '/tsud')
44
+ t = TSUD.new
45
+ expect(t).to receive(:list).once.and_return([
46
+ {:name=>1},{:name=>2},{:name=>3}
47
+ ])
48
+ ret = t.status
49
+ expect(ret).to eq({
50
+ :toadd=>[],
51
+ :todel=>[{:name=>1, :synckey=>1}, {:name=>2, :synckey=>2}, {:name=>3, :synckey=>3}],
52
+ :tomod=>[],
53
+ :unchg=>[]})
54
+ end
55
+
56
+ it "finds things there but not here; asdown" do
57
+ FileUtils.mkpath(@projectDir + '/tsud')
58
+ t = TSUD.new
59
+ expect(t).to receive(:list).once.and_return([
60
+ {:name=>1},{:name=>2},{:name=>3}
61
+ ])
62
+ ret = t.status({:asdown=>true})
63
+ expect(ret).to eq({
64
+ :todel=>[],
65
+ :toadd=>[{:name=>1, :synckey=>1}, {:name=>2, :synckey=>2}, {:name=>3, :synckey=>3}],
66
+ :tomod=>[],
67
+ :unchg=>[]})
68
+ end
69
+
70
+ it "finds things here but not there" do
71
+ FileUtils.mkpath(@projectDir + '/tsud')
72
+ FileUtils.touch(@projectDir + '/tsud/one.lua')
73
+ FileUtils.touch(@projectDir + '/tsud/two.lua')
74
+ t = TSUD.new
75
+ expect(t).to receive(:toRemoteItem).and_return(
76
+ {:name=>'one.lua'},{:name=>'two.lua'}
77
+ )
78
+ ret = t.status
79
+ expect(ret).to match({
80
+ :toadd=>[
81
+ {:name=>'one.lua', :synckey=>'one.lua',
82
+ :local_path=>an_instance_of(Pathname)},
83
+ {:name=>'two.lua', :synckey=>'two.lua',
84
+ :local_path=>an_instance_of(Pathname)},
85
+ ],
86
+ :todel=>[],
87
+ :tomod=>[],
88
+ :unchg=>[]})
89
+ end
90
+
91
+ it "finds things here and there" do
92
+ FileUtils.mkpath(@projectDir + '/tsud')
93
+ FileUtils.touch(@projectDir + '/tsud/one.lua')
94
+ FileUtils.touch(@projectDir + '/tsud/two.lua')
95
+ t = TSUD.new
96
+ expect(t).to receive(:list).once.and_return([
97
+ {:name=>'one.lua'},{:name=>'two.lua'}
98
+ ])
99
+ expect(t).to receive(:toRemoteItem).and_return(
100
+ {:name=>'one.lua'},{:name=>'two.lua'}
101
+ )
102
+ ret = t.status
103
+ expect(ret).to match({
104
+ :tomod=>[
105
+ {:name=>'one.lua', :synckey=>'one.lua',
106
+ :local_path=>an_instance_of(Pathname)},
107
+ {:name=>'two.lua', :synckey=>'two.lua',
108
+ :local_path=>an_instance_of(Pathname)},
109
+ ],
110
+ :todel=>[],
111
+ :toadd=>[],
112
+ :unchg=>[]})
113
+ end
114
+ it "finds things here and there; but they're the same" do
115
+ FileUtils.mkpath(@projectDir + '/tsud')
116
+ FileUtils.touch(@projectDir + '/tsud/one.lua')
117
+ FileUtils.touch(@projectDir + '/tsud/two.lua')
118
+ t = TSUD.new
119
+ expect(t).to receive(:list).once.and_return([
120
+ {:name=>'one.lua'},{:name=>'two.lua'}
121
+ ])
122
+ expect(t).to receive(:toRemoteItem).and_return(
123
+ {:name=>'one.lua'},{:name=>'two.lua'}
124
+ )
125
+ expect(t).to receive(:docmp).twice.and_return(false)
126
+ ret = t.status
127
+ expect(ret).to match({
128
+ :unchg=>[
129
+ {:name=>'one.lua', :synckey=>'one.lua',
130
+ :local_path=>an_instance_of(Pathname)},
131
+ {:name=>'two.lua', :synckey=>'two.lua',
132
+ :local_path=>an_instance_of(Pathname)},
133
+ ],
134
+ :todel=>[],
135
+ :toadd=>[],
136
+ :tomod=>[]})
137
+ end
138
+
139
+ it "calls diff" do
140
+ FileUtils.mkpath(@projectDir + '/tsud')
141
+ FileUtils.touch(@projectDir + '/tsud/one.lua')
142
+ t = TSUD.new
143
+ expect(t).to receive(:list).once.and_return([
144
+ {:name=>'one.lua'}
145
+ ])
146
+ expect(t).to receive(:toRemoteItem).and_return(
147
+ {:name=>'one.lua'}
148
+ )
149
+ expect(t).to receive(:dodiff).once.and_return("diffed output")
150
+ ret = t.status({:diff=>true})
151
+ expect(ret).to match({
152
+ :tomod=>[
153
+ {:name=>'one.lua', :synckey=>'one.lua',
154
+ :local_path=>an_instance_of(Pathname),
155
+ :diff=>"diffed output"},
156
+ ],
157
+ :todel=>[],
158
+ :toadd=>[],
159
+ :unchg=>[]})
160
+ end
161
+ end
162
+
163
+ context "localitems" do
164
+ before(:example) do
165
+ FileUtils.mkpath('tsud')
166
+ FileUtils.touch('tsud/one.lua')
167
+ FileUtils.touch('tsud/two.lua')
168
+ @t = TSUD.new
169
+ end
170
+ it "finds local items" do
171
+ expect(@t).to receive(:toRemoteItem).and_return(
172
+ {:name=>'one.lua'},{:name=>'two.lua'}
173
+ )
174
+ ret = @t.localitems(Pathname.new(@projectDir + '/tsud').realpath)
175
+ expect(ret).to match([
176
+ {:name=>'one.lua',
177
+ :local_path=>an_instance_of(Pathname)},
178
+ {:name=>'two.lua',
179
+ :local_path=>an_instance_of(Pathname)},
180
+ ])
181
+ end
182
+
183
+ it "takes an array from toRemoteItem" do
184
+ expect(@t).to receive(:toRemoteItem).and_return(
185
+ [{:name=>'one:1'},{:name=>'one:2'}],
186
+ [{:name=>'two:1'},{:name=>'two:2'}]
187
+ )
188
+ ret = @t.localitems(Pathname.new(@projectDir + '/tsud').realpath)
189
+ expect(ret).to match([
190
+ {:name=>'one:1',
191
+ :local_path=>an_instance_of(Pathname)},
192
+ {:name=>'one:2',
193
+ :local_path=>an_instance_of(Pathname)},
194
+ {:name=>'two:1',
195
+ :local_path=>an_instance_of(Pathname)},
196
+ {:name=>'two:2',
197
+ :local_path=>an_instance_of(Pathname)},
198
+ ])
199
+ end
200
+ end
201
+
202
+ context "download" do
203
+ it "defaults to :id if @itemkey missing" do
204
+ FileUtils.mkpath(@projectDir + '/tsud')
205
+ FileUtils.touch(@projectDir + '/tsud/one.lua')
206
+ lp = Pathname.new(@projectDir + '/tsud/one.lua').realpath
207
+ t = TSUD.new
208
+ expect(t).to receive(:fetch).once.with(1).and_yield("foo")
209
+ t.download(lp, {:id=>1})
210
+ end
211
+ end
212
+
213
+ context "doing diffs" do
214
+ before(:example) do
215
+ FileUtils.mkpath(@projectDir + '/tsud')
216
+ @t = TSUD.new
217
+ @scpt = Pathname.new(@projectDir + '/tsud/one.lua')
218
+ @scpt.open('w'){|io| io << %{-- fake lua\nreturn 0\n}}
219
+ @scpt = @scpt.realpath
220
+ end
221
+
222
+ it "nothing when same." do
223
+ expect(@t).to receive(:fetch).and_yield(%{-- fake lua\nreturn 0\n})
224
+ ret = @t.dodiff({:name=>'one.lua', :local_path=>@scpt})
225
+ if Gem.win_platform? then
226
+ expect(ret).to match(/FC: no differences encountered/)
227
+ else
228
+ expect(ret).to eq('')
229
+ end
230
+ end
231
+
232
+ it "something when different." do
233
+ expect(@t).to receive(:fetch).and_yield(%{-- fake lua\nreturn 2\n})
234
+ ret = @t.dodiff({:name=>'one.lua', :local_path=>@scpt})
235
+ expect(ret).not_to eq('')
236
+ end
237
+
238
+ it "uses script in item" do
239
+ script = %{-- fake lua\nreturn 2\n}
240
+ expect(@t).to receive(:fetch).and_yield(script)
241
+ ret = @t.dodiff({:name=>'one.lua', :local_path=>@scpt, :script=>script})
242
+ if Gem.win_platform? then
243
+ expect(ret).to match(/FC: no differences encountered/)
244
+ else
245
+ expect(ret).to eq('')
246
+ end
247
+ end
248
+ end
249
+
250
+ context "syncup" do
251
+ before(:example) do
252
+ FileUtils.mkpath(@projectDir + '/tsud')
253
+ @t = TSUD.new
254
+ end
255
+
256
+ it "removes" do
257
+ expect(@t).to receive(:list).once.and_return([
258
+ {:name=>1},{:name=>2},{:name=>3}
259
+ ])
260
+ expect(@t).to receive(:remove).exactly(3).times
261
+ @t.syncup({:delete=>true})
262
+ end
263
+
264
+ it "creates" do
265
+ FileUtils.touch(@projectDir + '/tsud/one.lua')
266
+ FileUtils.touch(@projectDir + '/tsud/two.lua')
267
+
268
+ expect(@t).to receive(:upload).twice.with(kind_of(Pathname), kind_of(Hash), false)
269
+ @t.syncup({:create=>true})
270
+ end
271
+
272
+ it "updates" do
273
+ FileUtils.touch(@projectDir + '/tsud/one.lua')
274
+ FileUtils.touch(@projectDir + '/tsud/two.lua')
275
+ expect(@t).to receive(:list).once.and_return([
276
+ {:name=>'one.lua'},{:name=>'two.lua'}
277
+ ])
278
+
279
+ expect(@t).to receive(:upload).twice.with(kind_of(Pathname), kind_of(Hash), true)
280
+ expect(@t).to receive(:toRemoteItem).and_return(
281
+ {:name=>'one.lua'},{:name=>'two.lua'}
282
+ )
283
+ @t.syncup({:update=>true})
284
+ end
285
+ end
286
+
287
+ context "syncdown" do
288
+ before(:example) do
289
+ FileUtils.mkpath(@projectDir + '/tsud')
290
+ @t = TSUD.new
291
+ end
292
+
293
+ it "removes" do
294
+ FileUtils.touch(@projectDir + '/tsud/one.lua')
295
+ FileUtils.touch(@projectDir + '/tsud/two.lua')
296
+
297
+ @t.syncdown({:delete=>true})
298
+ expect(FileTest.exist?(@projectDir + '/tsud/one.lua')).to be false
299
+ expect(FileTest.exist?(@projectDir + '/tsud/two.lua')).to be false
300
+ end
301
+
302
+ it "creates" do
303
+ expect(@t).to receive(:list).once.and_return([
304
+ {:name=>'one.lua'},{:name=>'two.lua'}
305
+ ])
306
+
307
+ expect(@t).to receive(:fetch).twice.and_yield("--foo\n")
308
+ @t.syncdown({:create=>true})
309
+ expect(FileTest.exist?(@projectDir + '/tsud/one.lua')).to be true
310
+ expect(FileTest.exist?(@projectDir + '/tsud/two.lua')).to be true
311
+ end
312
+
313
+ it "updates" do
314
+ FileUtils.touch(@projectDir + '/tsud/one.lua')
315
+ FileUtils.touch(@projectDir + '/tsud/two.lua')
316
+ expect(@t).to receive(:list).once.and_return([
317
+ {:name=>'one.lua'},{:name=>'two.lua'}
318
+ ])
319
+
320
+ expect(@t).to receive(:fetch).twice.and_yield("--foo\n")
321
+ expect(@t).to receive(:toRemoteItem).and_return(
322
+ {:name=>'one.lua'},{:name=>'two.lua'}
323
+ )
324
+ @t.syncdown({:update=>true})
325
+ expect(FileTest.exist?(@projectDir + '/tsud/one.lua')).to be true
326
+ expect(FileTest.exist?(@projectDir + '/tsud/two.lua')).to be true
327
+ end
328
+ end
329
+
330
+ context "bundles" do
331
+ before(:example) do
332
+ FileUtils.mkpath(@projectDir + '/tsud')
333
+ FileUtils.mkpath(@projectDir + '/bundles/mybun/tsud')
334
+ @t = TSUD.new
335
+ end
336
+
337
+ it "finds items in bundles." do
338
+ FileUtils.touch(@projectDir + '/tsud/one.lua')
339
+ FileUtils.touch(@projectDir + '/bundles/mybun/tsud/two.lua')
340
+
341
+ expect(@t).to receive(:toRemoteItem).and_return(
342
+ {:name=>'two.lua'},{:name=>'one.lua'}
343
+ )
344
+ ret = @t.locallist
345
+ expect(ret).to match([
346
+ {:name=>'two.lua',
347
+ :bundled=>true,
348
+ :local_path=>an_instance_of(Pathname)},
349
+ {:name=>'one.lua',
350
+ :local_path=>an_instance_of(Pathname)},
351
+ ])
352
+ end
353
+
354
+ it "Doesn't download a bundled item" do
355
+ FileUtils.touch(@projectDir + '/tsud/one.lua')
356
+ lp = Pathname.new(@projectDir + '/tsud/one.lua').realpath
357
+
358
+ expect(@t).to receive(:warning).once.with(/Not downloading into bundled item.*/)
359
+
360
+ @t.download(lp, {:bundled=>true, :name=>'one.lua'})
361
+ end
362
+ end
363
+ end
364
+ # vim: set ai et sw=2 ts=2 :