MuranoCLI 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (151) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +28 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +21 -0
  5. data/Gemfile +27 -0
  6. data/LICENSE.txt +19 -0
  7. data/MuranoCLI.gemspec +50 -0
  8. data/MuranoCLI.iss +50 -0
  9. data/README.markdown +208 -0
  10. data/Rakefile +188 -0
  11. data/TODO.taskpaper +122 -0
  12. data/bin/mr +8 -0
  13. data/bin/murano +84 -0
  14. data/docs/demo.md +109 -0
  15. data/lib/MrMurano/Account.rb +211 -0
  16. data/lib/MrMurano/Config-Migrate.rb +47 -0
  17. data/lib/MrMurano/Config.rb +286 -0
  18. data/lib/MrMurano/Mock.rb +63 -0
  19. data/lib/MrMurano/Product-1P-Device.rb +145 -0
  20. data/lib/MrMurano/Product-Resources.rb +195 -0
  21. data/lib/MrMurano/Product.rb +358 -0
  22. data/lib/MrMurano/ProjectFile.rb +349 -0
  23. data/lib/MrMurano/Solution-Cors.rb +46 -0
  24. data/lib/MrMurano/Solution-Endpoint.rb +177 -0
  25. data/lib/MrMurano/Solution-File.rb +150 -0
  26. data/lib/MrMurano/Solution-ServiceConfig.rb +140 -0
  27. data/lib/MrMurano/Solution-Services.rb +326 -0
  28. data/lib/MrMurano/Solution-Users.rb +129 -0
  29. data/lib/MrMurano/Solution.rb +59 -0
  30. data/lib/MrMurano/SubCmdGroupContext.rb +49 -0
  31. data/lib/MrMurano/SyncUpDown.rb +565 -0
  32. data/lib/MrMurano/commands/assign.rb +57 -0
  33. data/lib/MrMurano/commands/businessList.rb +45 -0
  34. data/lib/MrMurano/commands/completion.rb +152 -0
  35. data/lib/MrMurano/commands/config.rb +67 -0
  36. data/lib/MrMurano/commands/content.rb +130 -0
  37. data/lib/MrMurano/commands/cors.rb +30 -0
  38. data/lib/MrMurano/commands/domain.rb +17 -0
  39. data/lib/MrMurano/commands/gb.rb +33 -0
  40. data/lib/MrMurano/commands/init.rb +138 -0
  41. data/lib/MrMurano/commands/keystore.rb +157 -0
  42. data/lib/MrMurano/commands/logs.rb +78 -0
  43. data/lib/MrMurano/commands/mock.rb +63 -0
  44. data/lib/MrMurano/commands/password.rb +88 -0
  45. data/lib/MrMurano/commands/postgresql.rb +41 -0
  46. data/lib/MrMurano/commands/product.rb +14 -0
  47. data/lib/MrMurano/commands/productCreate.rb +39 -0
  48. data/lib/MrMurano/commands/productDelete.rb +33 -0
  49. data/lib/MrMurano/commands/productDevice.rb +84 -0
  50. data/lib/MrMurano/commands/productDeviceIdCmds.rb +86 -0
  51. data/lib/MrMurano/commands/productList.rb +45 -0
  52. data/lib/MrMurano/commands/productWrite.rb +27 -0
  53. data/lib/MrMurano/commands/show.rb +80 -0
  54. data/lib/MrMurano/commands/solution.rb +14 -0
  55. data/lib/MrMurano/commands/solutionCreate.rb +39 -0
  56. data/lib/MrMurano/commands/solutionDelete.rb +34 -0
  57. data/lib/MrMurano/commands/solutionList.rb +45 -0
  58. data/lib/MrMurano/commands/status.rb +92 -0
  59. data/lib/MrMurano/commands/sync.rb +60 -0
  60. data/lib/MrMurano/commands/timeseries.rb +115 -0
  61. data/lib/MrMurano/commands/tsdb.rb +271 -0
  62. data/lib/MrMurano/commands/usage.rb +23 -0
  63. data/lib/MrMurano/commands/zshcomplete.erb +112 -0
  64. data/lib/MrMurano/commands.rb +32 -0
  65. data/lib/MrMurano/hash.rb +20 -0
  66. data/lib/MrMurano/http.rb +153 -0
  67. data/lib/MrMurano/makePretty.rb +75 -0
  68. data/lib/MrMurano/schema/pf-v1.0.0.yaml +114 -0
  69. data/lib/MrMurano/schema/sf-v0.2.0.yaml +77 -0
  70. data/lib/MrMurano/schema/sf-v0.3.0.yaml +78 -0
  71. data/lib/MrMurano/template/mock.erb +9 -0
  72. data/lib/MrMurano/template/projectFile.murano.erb +81 -0
  73. data/lib/MrMurano/verbosing.rb +99 -0
  74. data/lib/MrMurano/version.rb +4 -0
  75. data/lib/MrMurano.rb +20 -0
  76. data/spec/Account-Passwords_spec.rb +242 -0
  77. data/spec/Account_spec.rb +272 -0
  78. data/spec/ConfigFile_spec.rb +50 -0
  79. data/spec/ConfigMigrate_spec.rb +89 -0
  80. data/spec/Config_spec.rb +409 -0
  81. data/spec/Http_spec.rb +204 -0
  82. data/spec/MakePretties_spec.rb +118 -0
  83. data/spec/Mock_spec.rb +53 -0
  84. data/spec/ProductBase_spec.rb +113 -0
  85. data/spec/ProductContent_spec.rb +162 -0
  86. data/spec/ProductResources_spec.rb +329 -0
  87. data/spec/Product_1P_Device_spec.rb +202 -0
  88. data/spec/Product_1P_RPC_spec.rb +175 -0
  89. data/spec/Product_spec.rb +153 -0
  90. data/spec/ProjectFile_spec.rb +324 -0
  91. data/spec/Solution-Cors_spec.rb +164 -0
  92. data/spec/Solution-Endpoint_spec.rb +581 -0
  93. data/spec/Solution-File_spec.rb +212 -0
  94. data/spec/Solution-ServiceConfig_spec.rb +202 -0
  95. data/spec/Solution-ServiceDevice_spec.rb +176 -0
  96. data/spec/Solution-ServiceEventHandler_spec.rb +385 -0
  97. data/spec/Solution-ServiceModules_spec.rb +465 -0
  98. data/spec/Solution-UsersRoles_spec.rb +207 -0
  99. data/spec/Solution_spec.rb +92 -0
  100. data/spec/SyncRoot_spec.rb +83 -0
  101. data/spec/SyncUpDown_spec.rb +495 -0
  102. data/spec/Verbosing_spec.rb +279 -0
  103. data/spec/_workspace.rb +27 -0
  104. data/spec/cmd_assign_spec.rb +51 -0
  105. data/spec/cmd_business_spec.rb +59 -0
  106. data/spec/cmd_common.rb +72 -0
  107. data/spec/cmd_config_spec.rb +68 -0
  108. data/spec/cmd_content_spec.rb +71 -0
  109. data/spec/cmd_cors_spec.rb +50 -0
  110. data/spec/cmd_device_spec.rb +96 -0
  111. data/spec/cmd_domain_spec.rb +32 -0
  112. data/spec/cmd_init_spec.rb +30 -0
  113. data/spec/cmd_keystore_spec.rb +97 -0
  114. data/spec/cmd_password_spec.rb +62 -0
  115. data/spec/cmd_status_spec.rb +239 -0
  116. data/spec/cmd_syncdown_spec.rb +86 -0
  117. data/spec/cmd_syncup_spec.rb +62 -0
  118. data/spec/cmd_usage_spec.rb +36 -0
  119. data/spec/fixtures/.mrmuranorc +9 -0
  120. data/spec/fixtures/ProjectFiles/invalid.yaml +9 -0
  121. data/spec/fixtures/ProjectFiles/only_meta.yaml +24 -0
  122. data/spec/fixtures/ProjectFiles/with_routes.yaml +27 -0
  123. data/spec/fixtures/SolutionFiles/0.2.0.json +20 -0
  124. data/spec/fixtures/SolutionFiles/0.2.0_invalid.json +18 -0
  125. data/spec/fixtures/SolutionFiles/0.2.json +21 -0
  126. data/spec/fixtures/SolutionFiles/0.3.0.json +20 -0
  127. data/spec/fixtures/SolutionFiles/0.3.0_invalid.json +19 -0
  128. data/spec/fixtures/SolutionFiles/0.3.json +20 -0
  129. data/spec/fixtures/SolutionFiles/basic.json +20 -0
  130. data/spec/fixtures/SolutionFiles/secret.json +6 -0
  131. data/spec/fixtures/configfile +9 -0
  132. data/spec/fixtures/dumped_config +42 -0
  133. data/spec/fixtures/mrmuranorc_deleted_bob +8 -0
  134. data/spec/fixtures/mrmuranorc_tool_bob +3 -0
  135. data/spec/fixtures/product_spec_files/example.exoline.spec.yaml +116 -0
  136. data/spec/fixtures/product_spec_files/example.murano.spec.yaml +14 -0
  137. data/spec/fixtures/product_spec_files/gwe.exoline.spec.yaml +21 -0
  138. data/spec/fixtures/product_spec_files/gwe.murano.spec.yaml +16 -0
  139. data/spec/fixtures/product_spec_files/lightbulb-no-state.yaml +11 -0
  140. data/spec/fixtures/product_spec_files/lightbulb.yaml +14 -0
  141. data/spec/fixtures/roles-three.yaml +11 -0
  142. data/spec/fixtures/syncable_content/assets/icon.png +0 -0
  143. data/spec/fixtures/syncable_content/assets/index.html +0 -0
  144. data/spec/fixtures/syncable_content/assets/js/script.js +0 -0
  145. data/spec/fixtures/syncable_content/modules/table_util.lua +58 -0
  146. data/spec/fixtures/syncable_content/routes/manyRoutes.lua +11 -0
  147. data/spec/fixtures/syncable_content/routes/singleRoute.lua +5 -0
  148. data/spec/fixtures/syncable_content/services/devdata.lua +18 -0
  149. data/spec/fixtures/syncable_content/services/timers.lua +4 -0
  150. data/spec/spec_helper.rb +119 -0
  151. metadata +498 -0
@@ -0,0 +1,207 @@
1
+ require 'MrMurano/version'
2
+ require 'MrMurano/Solution-Users'
3
+ require 'MrMurano/hash'
4
+ require 'tempfile'
5
+ require '_workspace'
6
+
7
+ RSpec.describe MrMurano::Role 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::Role.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/role/")
22
+ end
23
+
24
+ it "lists" do
25
+ body = [{:role_id=>"guest", :parameter=>[{:name=>"did"}]},
26
+ {:role_id=>"admin", :parameter=>[{:name=>"enabled"}]},
27
+ {:role_id=>"owns", :parameter=>[{:name=>"did"}]}]
28
+ stub_request(:get, "https://bizapi.hosted.exosite.io/api:1/solution/XYZ/role").
29
+ with(:headers=>{'Authorization'=>'token TTTTTTTTTT',
30
+ 'Content-Type'=>'application/json'}).
31
+ to_return(body: body.to_json)
32
+ ret = @srv.list
33
+ expect(ret).to eq(body)
34
+ end
35
+
36
+ it "fetches" do
37
+ body = {:role_id=>"guest", :parameter=>[{:name=>"did"}]}
38
+ stub_request(:get, "https://bizapi.hosted.exosite.io/api:1/solution/XYZ/role/guest").
39
+ with(:headers=>{'Authorization'=>'token TTTTTTTTTT',
40
+ 'Content-Type'=>'application/json'}).
41
+ to_return(body: body.to_json)
42
+ ret = @srv.fetch('guest')
43
+ expect(ret).to eq(body)
44
+ end
45
+
46
+ it "removes" do
47
+ stub_request(:delete, "https://bizapi.hosted.exosite.io/api:1/solution/XYZ/role/guest").
48
+ with(:headers=>{'Authorization'=>'token TTTTTTTTTT',
49
+ 'Content-Type'=>'application/json'}).
50
+ to_return(status: 200, body: "")
51
+ ret = @srv.remove('guest')
52
+ expect(ret).to eq({})
53
+ end
54
+
55
+ context "uploads" do
56
+ it "updating" do
57
+ body = {:role_id=>"guest", :parameter=>[{:name=>"did"}]}
58
+ stub_request(:delete, "https://bizapi.hosted.exosite.io/api:1/solution/XYZ/role/guest").
59
+ with(:headers=>{'Authorization'=>'token TTTTTTTTTT',
60
+ 'Content-Type'=>'application/json'}).
61
+ to_return(status: 200, body: "")
62
+ stub_request(:post, "https://bizapi.hosted.exosite.io/api:1/solution/XYZ/role/").
63
+ with(:headers=>{'Authorization'=>'token TTTTTTTTTT',
64
+ 'Content-Type'=>'application/json'},
65
+ :body=>body.to_json
66
+ ).
67
+ to_return(status: 205, body: "")
68
+
69
+
70
+ @srv.upload(nil, body, true)
71
+ end
72
+
73
+ it "creating" do
74
+ body = {:role_id=>"guest", :parameter=>[{:name=>"did"}]}
75
+ stub_request(:delete, "https://bizapi.hosted.exosite.io/api:1/solution/XYZ/role/guest").
76
+ with(:headers=>{'Authorization'=>'token TTTTTTTTTT',
77
+ 'Content-Type'=>'application/json'}).
78
+ to_return(status: 404, body: "")
79
+ stub_request(:post, "https://bizapi.hosted.exosite.io/api:1/solution/XYZ/role/").
80
+ with(:headers=>{'Authorization'=>'token TTTTTTTTTT',
81
+ 'Content-Type'=>'application/json'},
82
+ :body=>body.to_json
83
+ ).
84
+ to_return(status: 205, body: "")
85
+
86
+
87
+ @srv.upload(nil, body, false)
88
+ end
89
+
90
+ it "with delete error" do
91
+ body = {:role_id=>"guest", :parameter=>[{:name=>"did"}]}
92
+ stub_request(:delete, "https://bizapi.hosted.exosite.io/api:1/solution/XYZ/role/guest").
93
+ with(:headers=>{'Authorization'=>'token TTTTTTTTTT',
94
+ 'Content-Type'=>'application/json'}).
95
+ to_return(status: 418, body: "I'm a teapot!")
96
+ stub_request(:post, "https://bizapi.hosted.exosite.io/api:1/solution/XYZ/role/").
97
+ with(:headers=>{'Authorization'=>'token TTTTTTTTTT',
98
+ 'Content-Type'=>'application/json'},
99
+ :body=>body.to_json
100
+ ).
101
+ to_return(status: 205, body: "")
102
+
103
+ saved = $stderr
104
+ $stderr = StringIO.new
105
+ @srv.upload(nil, body, false)
106
+ expect($stderr.string).to match(/Request Failed: 418: I'm a teapot/)
107
+ $stderr = saved
108
+ end
109
+ end
110
+
111
+ context "downloads" do
112
+ before(:example) do
113
+ @lry = Pathname.new(@projectDir) + 'roles.yaml'
114
+ @grl = {:role_id=>"guest", :parameter=>[{:name=>"could"}]}
115
+ end
116
+
117
+ it "creates" do
118
+ @srv.download(@lry, @grl)
119
+
120
+ expect(@lry.exist?).to be true
121
+ got = YAML.load(@lry.read)
122
+ expect(got).to include(Hash.transform_keys_to_strings(@grl))
123
+ end
124
+
125
+ it "updates" do
126
+ FileUtils.copy(File.join(@testdir, 'spec/fixtures/roles-three.yaml'), @lry.to_path)
127
+
128
+ @srv.download(@lry, @grl)
129
+ got = YAML.load(@lry.read)
130
+ expect(got).to include(Hash.transform_keys_to_strings(@grl))
131
+ end
132
+ end
133
+
134
+ context "removing local roles" do
135
+ before(:example) do
136
+ @lry = Pathname.new(@projectDir) + 'roles.yaml'
137
+ @grl = {:role_id=>"guest", :parameter=>[{:name=>"could"}]}
138
+ end
139
+
140
+ it "when file missing" do
141
+ @srv.removelocal(@lry, @grl)
142
+ expect(@lry.exist?).to be true
143
+ got = YAML.load(@lry.read)
144
+ expect(got).to eq([])
145
+ end
146
+
147
+ it "when not there" do
148
+ FileUtils.copy(File.join(@testdir, 'spec/fixtures/roles-three.yaml'), @lry.to_path)
149
+ @srv.removelocal(@lry, {:role_id=>"undertow"})
150
+ got = YAML.load(@lry.read)
151
+ rty = Pathname.new(@testdir) + 'spec/fixtures/roles-three.yaml'
152
+ want = YAML.load(rty.read)
153
+ expect(got).to eq(want)
154
+ end
155
+
156
+ it "with matching role" do
157
+ FileUtils.copy(File.join(@testdir, 'spec/fixtures/roles-three.yaml'), @lry.to_path)
158
+ @srv.removelocal(@lry, @grl)
159
+ got = YAML.load(@lry.read)
160
+ expect(got.count).to eq(2)
161
+ expect(got).to contain_exactly(
162
+ a_hash_including('role_id' => 'admin'),
163
+ a_hash_including('role_id' => 'owns')
164
+ )
165
+ end
166
+ end
167
+
168
+ it "tolocalpath is into" do
169
+ lry = Pathname.new(@projectDir) + 'roles.yaml'
170
+ ret = @srv.tolocalpath(lry, {:role_id=>"guest", :parameter=>[{:name=>"could"}]})
171
+ expect(ret).to eq(lry)
172
+ end
173
+
174
+ context "list local items" do
175
+ before(:example) do
176
+ @lry = Pathname.new(@projectDir) + 'roles.yaml'
177
+ end
178
+
179
+ it "when missing" do
180
+ expect(@srv).to receive(:warning).with(/^Skipping missing/)
181
+ ret = @srv.localitems(@lry)
182
+ expect(ret).to eq([])
183
+ end
184
+
185
+ it "when not a file" do
186
+ FileUtils.mkpath(@lry.to_path)
187
+ expect(@srv).to receive(:warning).with(/^Cannot read from/)
188
+ ret = @srv.localitems(@lry)
189
+ expect(ret).to eq([])
190
+ end
191
+
192
+ it "when empty" do
193
+ FileUtils.touch(@lry.to_path)
194
+ ret = @srv.localitems(@lry)
195
+ expect(ret).to eq([])
196
+ end
197
+
198
+ it "with roles" do
199
+ FileUtils.copy(File.join(@testdir, 'spec/fixtures/roles-three.yaml'), @lry.to_path)
200
+ ret = @srv.localitems(@lry)
201
+ expect(ret).to eq([{:role_id=>"guest", :parameter=>[{:name=>"did"}]},
202
+ {:role_id=>"admin", :parameter=>[{:name=>"enabled"}]},
203
+ {:role_id=>"owns", :parameter=>[{:name=>"did"}]}])
204
+ end
205
+ end
206
+ end
207
+ # vim: set ai et sw=2 ts=2 :
@@ -0,0 +1,92 @@
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
+ $project = MrMurano::ProjectFile.new
13
+ $project.load
14
+ $cfg['net.host'] = 'bizapi.hosted.exosite.io'
15
+ $cfg['solution.id'] = 'XYZ'
16
+
17
+ @srv = MrMurano::Solution.new
18
+ allow(@srv).to receive(:token).and_return("TTTTTTTTTT")
19
+ end
20
+
21
+ it "initializes" do
22
+ uri = @srv.endPoint('/')
23
+ expect(uri.to_s).to eq("https://bizapi.hosted.exosite.io/api:1/solution/XYZ/")
24
+ end
25
+
26
+ it "gets info" do
27
+ body = {
28
+ :id=>"XYZ",
29
+ :label=>nil,
30
+ :domain=>"ugdemo.apps.exosite.io",
31
+ :biz_id=>"ABCDEFG",
32
+ :cors=> "{\"origin\":true,\"methods\":[\"HEAD\",\"GET\",\"POST\",\"PUT\",\"DELETE\",\"OPTIONS\",\"PATCH\"],\"headers\":[\"Content-Type\",\"Cookie\",\"Authorization\"],\"credentials\":true}"
33
+ }
34
+
35
+ stub_request(:get, "https://bizapi.hosted.exosite.io/api:1/solution/XYZ").
36
+ with(:headers=>{'Authorization'=>'token TTTTTTTTTT',
37
+ 'Content-Type'=>'application/json'}).
38
+ to_return(body: body.to_json)
39
+
40
+ ret = @srv.info()
41
+ expect(ret).to eq(body)
42
+ end
43
+
44
+ it "lists" do
45
+ body = {
46
+ :id=>"XYZ",
47
+ :label=>nil,
48
+ :domain=>"ugdemo.apps.exosite.io",
49
+ :biz_id=>"ABCDEFG",
50
+ :cors=> "{\"origin\":true,\"methods\":[\"HEAD\",\"GET\",\"POST\",\"PUT\",\"DELETE\",\"OPTIONS\",\"PATCH\"],\"headers\":[\"Content-Type\",\"Cookie\",\"Authorization\"],\"credentials\":true}"
51
+ }
52
+
53
+ stub_request(:get, "https://bizapi.hosted.exosite.io/api:1/solution/XYZ/").
54
+ with(:headers=>{'Authorization'=>'token TTTTTTTTTT',
55
+ 'Content-Type'=>'application/json'}).
56
+ to_return(body: body.to_json)
57
+
58
+ ret = @srv.list()
59
+ expect(ret).to eq(body)
60
+ end
61
+
62
+ it "Gets version" do
63
+ body = {:min_cli_version=>"0.10"}
64
+ stub_request(:get, "https://bizapi.hosted.exosite.io/api:1/solution/XYZ/version").
65
+ with(:headers=>{'Authorization'=>'token TTTTTTTTTT',
66
+ 'Content-Type'=>'application/json'}).
67
+ to_return(body: body.to_json)
68
+
69
+ ret = @srv.version()
70
+ expect(ret).to eq(body)
71
+ end
72
+
73
+ it "Gets logs" do
74
+ body = {:p=>[
75
+ {:type=>"error",
76
+ :timestamp=>1481746755,
77
+ :subject=>"service call failed",
78
+ :data=>{:service_alias=>"user", :function_call=>"assignUser"}
79
+ }, ],
80
+ :total=>1}
81
+ stub_request(:get, "https://bizapi.hosted.exosite.io/api:1/solution/XYZ/logs").
82
+ with(:headers=>{'Authorization'=>'token TTTTTTTTTT',
83
+ 'Content-Type'=>'application/json'}).
84
+ to_return(body: body.to_json)
85
+
86
+ ret = @srv.log()
87
+ expect(ret).to eq(body)
88
+ end
89
+
90
+ end
91
+
92
+ # vim: set ai et sw=2 ts=2 :
@@ -0,0 +1,83 @@
1
+ require 'MrMurano/version'
2
+ require 'MrMurano/Config'
3
+ require 'MrMurano/ProjectFile'
4
+ require 'MrMurano/SyncUpDown'
5
+ require '_workspace'
6
+
7
+ RSpec.describe MrMurano::SyncRoot do
8
+ include_context "WORKSPACE"
9
+
10
+ after(:example) do
11
+ MrMurano::SyncRoot.reset
12
+ end
13
+
14
+ before(:example) do
15
+ MrMurano::SyncRoot.reset # also creates @@syncset
16
+ class User
17
+ end
18
+ class Role
19
+ end
20
+ MrMurano::SyncRoot.add('user', User, 'U', "describe user", true)
21
+ MrMurano::SyncRoot.add('role', Role, 'R', "describe role")
22
+
23
+ # This must happen after all syncables have been added.
24
+ $cfg = MrMurano::Config.new
25
+ $cfg.load
26
+ $project = MrMurano::ProjectFile.new
27
+ $project.load
28
+
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
36
+ end
37
+ end
38
+
39
+ it "has defaults" do
40
+ ret = MrMurano::SyncRoot.bydefault
41
+ expect(ret).to eq(['user'])
42
+ end
43
+
44
+ it "iterates on each" do
45
+ ret=[]
46
+ MrMurano::SyncRoot.each{|a,b,c| ret << a}
47
+ expect(ret).to eq(["user", "role"])
48
+ end
49
+
50
+ it "iterates only on selected" do
51
+ @options.role = true
52
+ ret=[]
53
+ MrMurano::SyncRoot.each_filtered(@options) {|a,b,c| ret << a}
54
+ expect(ret).to eq(["role"])
55
+ end
56
+
57
+ it "selects all" do
58
+ @options.all = true
59
+ MrMurano::SyncRoot.checkSAME(@options)
60
+ expect(@options).to eq({:all=>true, :user=>true, :role=>true})
61
+ end
62
+
63
+ it "selects defaults when none" do
64
+ MrMurano::SyncRoot.checkSAME(@options)
65
+ expect(@options).to eq({:user=>true})
66
+ end
67
+
68
+ it "selects custom defaults when none" do
69
+ $cfg['sync.bydefault'] = 'role'
70
+ MrMurano::SyncRoot.checkSAME(@options)
71
+ expect(@options).to eq({:role=>true})
72
+ end
73
+
74
+ it "builds option params" do
75
+ ret=[]
76
+ MrMurano::SyncRoot.each_option do |s,l,d|
77
+ ret << [s,l,d]
78
+ end
79
+ expect(ret).to eq([["-u", "--[no-]user", "describe user"], ["-r", "--[no-]role", "describe role"]])
80
+ end
81
+
82
+ end
83
+ # vim: set ai et sw=2 ts=2 :
@@ -0,0 +1,495 @@
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
+ @project_section = :routes
13
+ end
14
+ def fetch(id)
15
+ end
16
+ end
17
+
18
+ RSpec::Matchers.define :pathname_globs do |glob|
19
+ match do |pthnm|
20
+ pthnm.fnmatch(glob)
21
+ end
22
+ end
23
+
24
+ RSpec.describe MrMurano::SyncUpDown do
25
+ include_context "WORKSPACE"
26
+ before(:example) do
27
+ MrMurano::SyncRoot.reset
28
+ $cfg = MrMurano::Config.new
29
+ $cfg.load
30
+ $project = MrMurano::ProjectFile.new
31
+ $project.load
32
+ $project['routes.location'] = 'tsud'
33
+ $project['routes.include'] = ['*.lua', '*/*.lua']
34
+ $cfg['net.host'] = 'bizapi.hosted.exosite.io'
35
+ $cfg['solution.id'] = 'XYZ'
36
+ end
37
+
38
+ context "status" do
39
+ it "warns with missing directory" do
40
+ t = TSUD.new
41
+ expect(t).to receive(:warning).once.with(/Skipping missing location.*/)
42
+ ret = t.status
43
+ expect(ret).to eq({:toadd=>[], :todel=>[], :tomod=>[], :unchg=>[]})
44
+ end
45
+
46
+ it "finds nothing in empty directory" do
47
+ FileUtils.mkpath(@projectDir + '/tsud')
48
+ t = TSUD.new
49
+ ret = t.status
50
+ expect(ret).to eq({:toadd=>[], :todel=>[], :tomod=>[], :unchg=>[]})
51
+ end
52
+
53
+ it "finds things there but not here" do
54
+ FileUtils.mkpath(@projectDir + '/tsud')
55
+ t = TSUD.new
56
+ expect(t).to receive(:list).once.and_return([
57
+ {:name=>1},{:name=>2},{:name=>3}
58
+ ])
59
+ ret = t.status
60
+ expect(ret).to eq({
61
+ :toadd=>[],
62
+ :todel=>[{:name=>1, :synckey=>1}, {:name=>2, :synckey=>2}, {:name=>3, :synckey=>3}],
63
+ :tomod=>[],
64
+ :unchg=>[]})
65
+ end
66
+
67
+ it "finds things there but not here; asdown" do
68
+ FileUtils.mkpath(@projectDir + '/tsud')
69
+ t = TSUD.new
70
+ expect(t).to receive(:list).once.and_return([
71
+ {:name=>1},{:name=>2},{:name=>3}
72
+ ])
73
+ ret = t.status({:asdown=>true})
74
+ expect(ret).to eq({
75
+ :todel=>[],
76
+ :toadd=>[{:name=>1, :synckey=>1}, {:name=>2, :synckey=>2}, {:name=>3, :synckey=>3}],
77
+ :tomod=>[],
78
+ :unchg=>[]})
79
+ end
80
+
81
+ it "finds things here but not there" do
82
+ FileUtils.mkpath(@projectDir + '/tsud')
83
+ FileUtils.touch(@projectDir + '/tsud/one.lua')
84
+ FileUtils.touch(@projectDir + '/tsud/two.lua')
85
+ t = TSUD.new
86
+ expect(t).to receive(:toRemoteItem).and_return(
87
+ {:name=>'one.lua'},{:name=>'two.lua'}
88
+ )
89
+ ret = t.status
90
+ expect(ret).to match({
91
+ :toadd=>[
92
+ {:name=>'one.lua', :synckey=>'one.lua',
93
+ :local_path=>an_instance_of(Pathname)},
94
+ {:name=>'two.lua', :synckey=>'two.lua',
95
+ :local_path=>an_instance_of(Pathname)},
96
+ ],
97
+ :todel=>[],
98
+ :tomod=>[],
99
+ :unchg=>[]})
100
+ end
101
+
102
+ it "finds things here and there" do
103
+ FileUtils.mkpath(@projectDir + '/tsud')
104
+ FileUtils.touch(@projectDir + '/tsud/one.lua')
105
+ FileUtils.touch(@projectDir + '/tsud/two.lua')
106
+ t = TSUD.new
107
+ expect(t).to receive(:list).once.and_return([
108
+ {:name=>'one.lua'},{:name=>'two.lua'}
109
+ ])
110
+ expect(t).to receive(:toRemoteItem).and_return(
111
+ {:name=>'one.lua'},{:name=>'two.lua'}
112
+ )
113
+ ret = t.status
114
+ expect(ret).to match({
115
+ :tomod=>[
116
+ {:name=>'one.lua', :synckey=>'one.lua',
117
+ :local_path=>an_instance_of(Pathname)},
118
+ {:name=>'two.lua', :synckey=>'two.lua',
119
+ :local_path=>an_instance_of(Pathname)},
120
+ ],
121
+ :todel=>[],
122
+ :toadd=>[],
123
+ :unchg=>[]})
124
+ end
125
+ it "finds things here and there; but they're the same" do
126
+ FileUtils.mkpath(@projectDir + '/tsud')
127
+ FileUtils.touch(@projectDir + '/tsud/one.lua')
128
+ FileUtils.touch(@projectDir + '/tsud/two.lua')
129
+ t = TSUD.new
130
+ expect(t).to receive(:list).once.and_return([
131
+ {:name=>'one.lua'},{:name=>'two.lua'}
132
+ ])
133
+ expect(t).to receive(:toRemoteItem).and_return(
134
+ {:name=>'one.lua'},{:name=>'two.lua'}
135
+ )
136
+ expect(t).to receive(:docmp).twice.and_return(false)
137
+ ret = t.status
138
+ expect(ret).to match({
139
+ :unchg=>[
140
+ {:name=>'one.lua', :synckey=>'one.lua',
141
+ :local_path=>an_instance_of(Pathname)},
142
+ {:name=>'two.lua', :synckey=>'two.lua',
143
+ :local_path=>an_instance_of(Pathname)},
144
+ ],
145
+ :todel=>[],
146
+ :toadd=>[],
147
+ :tomod=>[]})
148
+ end
149
+
150
+ it "calls diff" do
151
+ FileUtils.mkpath(@projectDir + '/tsud')
152
+ FileUtils.touch(@projectDir + '/tsud/one.lua')
153
+ t = TSUD.new
154
+ expect(t).to receive(:list).once.and_return([
155
+ {:name=>'one.lua'}
156
+ ])
157
+ expect(t).to receive(:toRemoteItem).and_return(
158
+ {:name=>'one.lua'}
159
+ )
160
+ expect(t).to receive(:dodiff).once.and_return("diffed output")
161
+ ret = t.status({:diff=>true})
162
+ expect(ret).to match({
163
+ :tomod=>[
164
+ {:name=>'one.lua', :synckey=>'one.lua',
165
+ :local_path=>an_instance_of(Pathname),
166
+ :diff=>"diffed output"},
167
+ ],
168
+ :todel=>[],
169
+ :toadd=>[],
170
+ :unchg=>[]})
171
+ end
172
+
173
+ context "Filtering" do
174
+ before(:example) do
175
+ FileUtils.mkpath(@projectDir + '/tsud/ga')
176
+ FileUtils.mkpath(@projectDir + '/tsud/gb')
177
+ FileUtils.touch(@projectDir + '/tsud/one.lua') # tomod
178
+ FileUtils.touch(@projectDir + '/tsud/ga/two.lua') # tomod
179
+ FileUtils.touch(@projectDir + '/tsud/three.lua') # unchg
180
+ FileUtils.touch(@projectDir + '/tsud/gb/four.lua') # unchg
181
+ FileUtils.touch(@projectDir + '/tsud/five.lua') # toadd
182
+ FileUtils.touch(@projectDir + '/tsud/ga/six.lua') # toadd
183
+ @t = TSUD.new
184
+ expect(@t).to receive(:list).once.and_return([
185
+ {:name=>'one.lua'},{:name=>'two.lua'}, # tomod
186
+ {:name=>'three.lua'},{:name=>'four.lua'}, # unchg
187
+ {:name=>'seven.lua'},{:name=>'eight.lua'}, # todel
188
+ ])
189
+ expect(@t).to receive(:toRemoteItem).
190
+ with(anything(), pathname_globs('**/one.lua')).
191
+ and_return({:name=>'one.lua'})
192
+ expect(@t).to receive(:toRemoteItem).
193
+ with(anything(), pathname_globs('**/two.lua')).
194
+ and_return({:name=>'two.lua'})
195
+ expect(@t).to receive(:toRemoteItem).
196
+ with(anything(), pathname_globs('**/three.lua')).
197
+ and_return({:name=>'three.lua'})
198
+ expect(@t).to receive(:toRemoteItem).
199
+ with(anything(), pathname_globs('**/four.lua')).
200
+ and_return({:name=>'four.lua'})
201
+ expect(@t).to receive(:toRemoteItem).
202
+ with(anything(), pathname_globs('**/five.lua')).
203
+ and_return({:name=>'five.lua'})
204
+ expect(@t).to receive(:toRemoteItem).
205
+ with(anything(), pathname_globs('**/six.lua')).
206
+ and_return({:name=>'six.lua'})
207
+
208
+ expect(@t).to receive(:docmp).with(include({:name=>'one.lua'}),anything()).and_return(true)
209
+ expect(@t).to receive(:docmp).with(include({:name=>'two.lua'}),anything()).and_return(true)
210
+ expect(@t).to receive(:docmp).with(include({:name=>'three.lua'}),anything()).and_return(false)
211
+ expect(@t).to receive(:docmp).with(include({:name=>'four.lua'}),anything()).and_return(false)
212
+ end
213
+
214
+ it "Returns all with no filter" do
215
+ ret = @t.status
216
+ expect(ret).to match({
217
+ :unchg=>[
218
+ {:name=>'three.lua', :synckey=>'three.lua',
219
+ :local_path=> pathname_globs('**/three.lua')},
220
+ {:name=>'four.lua', :synckey=>'four.lua',
221
+ :local_path=>pathname_globs('**/four.lua')},
222
+ ],
223
+ :toadd=>[
224
+ {:name=>'five.lua', :synckey=>'five.lua',
225
+ :local_path=>pathname_globs('**/five.lua')},
226
+ {:name=>'six.lua', :synckey=>'six.lua',
227
+ :local_path=>pathname_globs('**/six.lua')},
228
+ ],
229
+ :todel=>[
230
+ {:name=>'seven.lua', :synckey=>'seven.lua'},
231
+ {:name=>'eight.lua', :synckey=>'eight.lua'},
232
+ ],
233
+ :tomod=>[
234
+ {:name=>'one.lua', :synckey=>'one.lua',
235
+ :local_path=>pathname_globs('**/one.lua')},
236
+ {:name=>'two.lua', :synckey=>'two.lua',
237
+ :local_path=>pathname_globs('**/two.lua')},
238
+ ]})
239
+ end
240
+
241
+ it "Finds local path globs" do
242
+ ret = @t.status({}, ['**/ga/*.lua'])
243
+ expect(ret).to match({
244
+ :unchg=>[ ],
245
+ :toadd=>[
246
+ {:name=>'six.lua', :synckey=>'six.lua',
247
+ :local_path=>an_instance_of(Pathname)},
248
+ ],
249
+ :todel=>[ ],
250
+ :tomod=>[
251
+ {:name=>'two.lua', :synckey=>'two.lua',
252
+ :local_path=>an_instance_of(Pathname)},
253
+ ]})
254
+ end
255
+
256
+ it "Finds nothing with specific matcher" do
257
+ ret = @t.status({}, ['#foo'])
258
+ expect(ret).to match({
259
+ :unchg=>[ ],
260
+ :toadd=>[ ],
261
+ :todel=>[ ],
262
+ :tomod=>[ ]})
263
+ end
264
+
265
+ it "gets all the details" do
266
+ ret = @t.status({:unselected=>true})
267
+ expect(ret).to match({
268
+ :unchg=>[
269
+ {:name=>'three.lua', :synckey=>'three.lua', :selected=>true,
270
+ :local_path=> pathname_globs('**/three.lua')},
271
+ {:name=>'four.lua', :synckey=>'four.lua', :selected=>true,
272
+ :local_path=>pathname_globs('**/four.lua')},
273
+ ],
274
+ :toadd=>[
275
+ {:name=>'five.lua', :synckey=>'five.lua', :selected=>true,
276
+ :local_path=>pathname_globs('**/five.lua')},
277
+ {:name=>'six.lua', :synckey=>'six.lua', :selected=>true,
278
+ :local_path=>pathname_globs('**/six.lua')},
279
+ ],
280
+ :todel=>[
281
+ {:name=>'seven.lua', :selected=>true, :synckey=>'seven.lua'},
282
+ {:name=>'eight.lua', :selected=>true, :synckey=>'eight.lua'},
283
+ ],
284
+ :tomod=>[
285
+ {:name=>'one.lua', :synckey=>'one.lua', :selected=>true,
286
+ :local_path=>pathname_globs('**/one.lua')},
287
+ {:name=>'two.lua', :synckey=>'two.lua', :selected=>true,
288
+ :local_path=>pathname_globs('**/two.lua')},
289
+ ]})
290
+ end
291
+ end
292
+ end
293
+
294
+ context "localitems" do
295
+ before(:example) do
296
+ FileUtils.mkpath('tsud')
297
+ FileUtils.touch('tsud/one.lua')
298
+ FileUtils.touch('tsud/two.lua')
299
+ @t = TSUD.new
300
+ end
301
+ it "finds local items" do
302
+ expect(@t).to receive(:toRemoteItem).and_return(
303
+ {:name=>'one.lua'},{:name=>'two.lua'}
304
+ )
305
+ ret = @t.localitems(Pathname.new(@projectDir + '/tsud').realpath)
306
+ expect(ret).to match([
307
+ {:name=>'one.lua',
308
+ :local_path=>an_instance_of(Pathname)},
309
+ {:name=>'two.lua',
310
+ :local_path=>an_instance_of(Pathname)},
311
+ ])
312
+ end
313
+
314
+ it "takes an array from toRemoteItem" do
315
+ expect(@t).to receive(:toRemoteItem).and_return(
316
+ [{:name=>'one:1'},{:name=>'one:2'}],
317
+ [{:name=>'two:1'},{:name=>'two:2'}]
318
+ )
319
+ ret = @t.localitems(Pathname.new(@projectDir + '/tsud').realpath)
320
+ expect(ret).to match([
321
+ {:name=>'one:1',
322
+ :local_path=>an_instance_of(Pathname)},
323
+ {:name=>'one:2',
324
+ :local_path=>an_instance_of(Pathname)},
325
+ {:name=>'two:1',
326
+ :local_path=>an_instance_of(Pathname)},
327
+ {:name=>'two:2',
328
+ :local_path=>an_instance_of(Pathname)},
329
+ ])
330
+ end
331
+ end
332
+
333
+ context "download" do
334
+ it "defaults to :id if @itemkey missing" do
335
+ FileUtils.mkpath(@projectDir + '/tsud')
336
+ FileUtils.touch(@projectDir + '/tsud/one.lua')
337
+ lp = Pathname.new(@projectDir + '/tsud/one.lua').realpath
338
+ t = TSUD.new
339
+ expect(t).to receive(:fetch).once.with(1).and_yield("foo")
340
+ t.download(lp, {:id=>1})
341
+ end
342
+ end
343
+
344
+ context "doing diffs" do
345
+ before(:example) do
346
+ FileUtils.mkpath(@projectDir + '/tsud')
347
+ @t = TSUD.new
348
+ @scpt = Pathname.new(@projectDir + '/tsud/one.lua')
349
+ @scpt.open('w'){|io| io << %{-- fake lua\nreturn 0\n}}
350
+ @scpt = @scpt.realpath
351
+ end
352
+
353
+ it "nothing when same." do
354
+ expect(@t).to receive(:fetch).and_yield(%{-- fake lua\nreturn 0\n})
355
+ ret = @t.dodiff({:name=>'one.lua', :local_path=>@scpt})
356
+ if Gem.win_platform? then
357
+ expect(ret).to match(/FC: no differences encountered/)
358
+ else
359
+ expect(ret).to eq('')
360
+ end
361
+ end
362
+
363
+ it "something when different." do
364
+ expect(@t).to receive(:fetch).and_yield(%{-- fake lua\nreturn 2\n})
365
+ ret = @t.dodiff({:name=>'one.lua', :local_path=>@scpt})
366
+ expect(ret).not_to eq('')
367
+ end
368
+
369
+ it "uses script in item" do
370
+ script = %{-- fake lua\nreturn 2\n}
371
+ expect(@t).to receive(:fetch).and_yield(script)
372
+ ret = @t.dodiff({:name=>'one.lua', :local_path=>@scpt, :script=>script})
373
+ if Gem.win_platform? then
374
+ expect(ret).to match(/FC: no differences encountered/)
375
+ else
376
+ expect(ret).to eq('')
377
+ end
378
+ end
379
+ end
380
+
381
+ context "syncup" do
382
+ before(:example) do
383
+ FileUtils.mkpath(@projectDir + '/tsud')
384
+ @t = TSUD.new
385
+ end
386
+
387
+ it "removes" do
388
+ expect(@t).to receive(:list).once.and_return([
389
+ {:name=>1},{:name=>2},{:name=>3}
390
+ ])
391
+ expect(@t).to receive(:remove).exactly(3).times
392
+ @t.syncup({:delete=>true})
393
+ end
394
+
395
+ it "creates" do
396
+ FileUtils.touch(@projectDir + '/tsud/one.lua')
397
+ FileUtils.touch(@projectDir + '/tsud/two.lua')
398
+
399
+ expect(@t).to receive(:upload).twice.with(kind_of(Pathname), kind_of(Hash), false)
400
+ @t.syncup({:create=>true})
401
+ end
402
+
403
+ it "updates" do
404
+ FileUtils.touch(@projectDir + '/tsud/one.lua')
405
+ FileUtils.touch(@projectDir + '/tsud/two.lua')
406
+ expect(@t).to receive(:list).once.and_return([
407
+ {:name=>'one.lua'},{:name=>'two.lua'}
408
+ ])
409
+
410
+ expect(@t).to receive(:upload).twice.with(kind_of(Pathname), kind_of(Hash), true)
411
+ expect(@t).to receive(:toRemoteItem).and_return(
412
+ {:name=>'one.lua'},{:name=>'two.lua'}
413
+ )
414
+ @t.syncup({:update=>true})
415
+ end
416
+ end
417
+
418
+ context "syncdown" do
419
+ before(:example) do
420
+ FileUtils.mkpath(@projectDir + '/tsud')
421
+ @t = TSUD.new
422
+ end
423
+
424
+ it "removes" do
425
+ FileUtils.touch(@projectDir + '/tsud/one.lua')
426
+ FileUtils.touch(@projectDir + '/tsud/two.lua')
427
+
428
+ @t.syncdown({:delete=>true})
429
+ expect(FileTest.exist?(@projectDir + '/tsud/one.lua')).to be false
430
+ expect(FileTest.exist?(@projectDir + '/tsud/two.lua')).to be false
431
+ end
432
+
433
+ it "creates" do
434
+ expect(@t).to receive(:list).once.and_return([
435
+ {:name=>'one.lua'},{:name=>'two.lua'}
436
+ ])
437
+
438
+ expect(@t).to receive(:fetch).twice.and_yield("--foo\n")
439
+ @t.syncdown({:create=>true})
440
+ expect(FileTest.exist?(@projectDir + '/tsud/one.lua')).to be true
441
+ expect(FileTest.exist?(@projectDir + '/tsud/two.lua')).to be true
442
+ end
443
+
444
+ it "updates" do
445
+ FileUtils.touch(@projectDir + '/tsud/one.lua')
446
+ FileUtils.touch(@projectDir + '/tsud/two.lua')
447
+ expect(@t).to receive(:list).once.and_return([
448
+ {:name=>'one.lua'},{:name=>'two.lua'}
449
+ ])
450
+
451
+ expect(@t).to receive(:fetch).twice.and_yield("--foo\n")
452
+ expect(@t).to receive(:toRemoteItem).and_return(
453
+ {:name=>'one.lua'},{:name=>'two.lua'}
454
+ )
455
+ @t.syncdown({:update=>true})
456
+ expect(FileTest.exist?(@projectDir + '/tsud/one.lua')).to be true
457
+ expect(FileTest.exist?(@projectDir + '/tsud/two.lua')).to be true
458
+ end
459
+ end
460
+
461
+ context "bundles" do
462
+ before(:example) do
463
+ FileUtils.mkpath(@projectDir + '/tsud')
464
+ FileUtils.mkpath(@projectDir + '/bundles/mybun/tsud')
465
+ @t = TSUD.new
466
+ end
467
+
468
+ # it "finds items in bundles." do
469
+ # FileUtils.touch(@projectDir + '/tsud/one.lua')
470
+ # FileUtils.touch(@projectDir + '/bundles/mybun/tsud/two.lua')
471
+ #
472
+ # expect(@t).to receive(:toRemoteItem).and_return(
473
+ # {:name=>'two.lua'},{:name=>'one.lua'}
474
+ # )
475
+ # ret = @t.locallist
476
+ # expect(ret).to match([
477
+ # {:name=>'two.lua',
478
+ # :bundled=>true,
479
+ # :local_path=>an_instance_of(Pathname)},
480
+ # {:name=>'one.lua',
481
+ # :local_path=>an_instance_of(Pathname)},
482
+ # ])
483
+ # end
484
+
485
+ it "Doesn't download a bundled item" do
486
+ FileUtils.touch(@projectDir + '/tsud/one.lua')
487
+ lp = Pathname.new(@projectDir + '/tsud/one.lua').realpath
488
+
489
+ expect(@t).to receive(:warning).once.with(/Not downloading into bundled item.*/)
490
+
491
+ @t.download(lp, {:bundled=>true, :name=>'one.lua'})
492
+ end
493
+ end
494
+ end
495
+ # vim: set ai et sw=2 ts=2 :