MuranoCLI 2.2.4 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (159) hide show
  1. checksums.yaml +4 -4
  2. data/.agignore +3 -0
  3. data/.gitignore +18 -1
  4. data/.rubocop.yml +222 -0
  5. data/.trustme.sh +185 -0
  6. data/.trustme.vim +24 -0
  7. data/Gemfile +23 -4
  8. data/LICENSE.txt +1 -1
  9. data/MuranoCLI.gemspec +43 -8
  10. data/README.markdown +9 -11
  11. data/Rakefile +187 -143
  12. data/TODO.taskpaper +2 -2
  13. data/bin/murano +51 -52
  14. data/docs/basic_example.rst +436 -0
  15. data/docs/completions/murano_completion-bash +3484 -0
  16. data/docs/demo.md +32 -32
  17. data/docs/develop.rst +391 -0
  18. data/lib/MrMurano.rb +21 -7
  19. data/lib/MrMurano/Account.rb +159 -174
  20. data/lib/MrMurano/Business.rb +381 -0
  21. data/lib/MrMurano/Config-Migrate.rb +32 -26
  22. data/lib/MrMurano/Config.rb +407 -128
  23. data/lib/MrMurano/Content.rb +191 -0
  24. data/lib/MrMurano/Gateway.rb +489 -0
  25. data/lib/MrMurano/Keystore.rb +48 -0
  26. data/lib/MrMurano/Passwords.rb +103 -0
  27. data/lib/MrMurano/ProjectFile.rb +121 -79
  28. data/lib/MrMurano/ReCommander.rb +114 -10
  29. data/lib/MrMurano/Setting.rb +90 -0
  30. data/lib/MrMurano/Solution-ServiceConfig.rb +89 -45
  31. data/lib/MrMurano/Solution-Services.rb +461 -166
  32. data/lib/MrMurano/Solution-Users.rb +70 -31
  33. data/lib/MrMurano/Solution.rb +372 -13
  34. data/lib/MrMurano/SolutionId.rb +73 -0
  35. data/lib/MrMurano/SyncRoot.rb +137 -0
  36. data/lib/MrMurano/SyncUpDown.rb +594 -284
  37. data/lib/MrMurano/Webservice-Cors.rb +71 -0
  38. data/lib/MrMurano/Webservice-Endpoint.rb +234 -0
  39. data/lib/MrMurano/Webservice-File.rb +193 -0
  40. data/lib/MrMurano/Webservice.rb +51 -0
  41. data/lib/MrMurano/commands.rb +18 -15
  42. data/lib/MrMurano/commands/business.rb +300 -6
  43. data/lib/MrMurano/commands/completion-bash.erb +166 -0
  44. data/lib/MrMurano/commands/{zshcomplete.erb → completion-zsh.erb} +0 -0
  45. data/lib/MrMurano/commands/completion.rb +76 -39
  46. data/lib/MrMurano/commands/config.rb +108 -44
  47. data/lib/MrMurano/commands/content.rb +115 -72
  48. data/lib/MrMurano/commands/cors.rb +29 -14
  49. data/lib/MrMurano/commands/devices.rb +286 -0
  50. data/lib/MrMurano/commands/domain.rb +52 -12
  51. data/lib/MrMurano/commands/gb.rb +24 -9
  52. data/lib/MrMurano/commands/globals.rb +64 -0
  53. data/lib/MrMurano/commands/init.rb +377 -155
  54. data/lib/MrMurano/commands/keystore.rb +92 -82
  55. data/lib/MrMurano/commands/link.rb +300 -0
  56. data/lib/MrMurano/commands/login.rb +74 -11
  57. data/lib/MrMurano/commands/logs.rb +63 -32
  58. data/lib/MrMurano/commands/mock.rb +57 -29
  59. data/lib/MrMurano/commands/password.rb +57 -39
  60. data/lib/MrMurano/commands/postgresql.rb +127 -94
  61. data/lib/MrMurano/commands/settings.rb +203 -0
  62. data/lib/MrMurano/commands/show.rb +79 -38
  63. data/lib/MrMurano/commands/solution.rb +423 -5
  64. data/lib/MrMurano/commands/solution_picker.rb +547 -0
  65. data/lib/MrMurano/commands/status.rb +195 -61
  66. data/lib/MrMurano/commands/sync.rb +78 -39
  67. data/lib/MrMurano/commands/timeseries.rb +71 -55
  68. data/lib/MrMurano/commands/tsdb.rb +113 -87
  69. data/lib/MrMurano/commands/usage.rb +57 -15
  70. data/lib/MrMurano/hash.rb +100 -10
  71. data/lib/MrMurano/http.rb +187 -43
  72. data/lib/MrMurano/makePretty.rb +16 -14
  73. data/lib/MrMurano/optparse.rb +2178 -0
  74. data/lib/MrMurano/progress.rb +138 -0
  75. data/lib/MrMurano/schema/resource-v1.0.0.yaml +32 -0
  76. data/lib/MrMurano/template/projectFile.murano.erb +16 -13
  77. data/lib/MrMurano/verbosing.rb +166 -29
  78. data/lib/MrMurano/version.rb +30 -1
  79. data/spec/Account-Passwords_spec.rb +21 -4
  80. data/spec/Account_spec.rb +69 -146
  81. data/spec/Business_spec.rb +290 -0
  82. data/spec/ConfigFile_spec.rb +1 -0
  83. data/spec/ConfigMigrate_spec.rb +12 -8
  84. data/spec/Config_spec.rb +40 -34
  85. data/spec/Content_spec.rb +363 -0
  86. data/spec/GatewayBase_spec.rb +54 -0
  87. data/spec/GatewayDevice_spec.rb +321 -0
  88. data/spec/GatewayResource_spec.rb +266 -0
  89. data/spec/GatewaySettings_spec.rb +120 -0
  90. data/spec/Http_spec.rb +18 -8
  91. data/spec/Mock_spec.rb +2 -2
  92. data/spec/ProjectFile_spec.rb +25 -14
  93. data/spec/Setting_spec.rb +110 -0
  94. data/spec/Solution-ServiceConfig_spec.rb +44 -5
  95. data/spec/Solution-ServiceEventHandler_spec.rb +23 -14
  96. data/spec/Solution-ServiceModules_spec.rb +47 -37
  97. data/spec/Solution-UsersRoles_spec.rb +10 -8
  98. data/spec/Solution_spec.rb +17 -8
  99. data/spec/SyncRoot_spec.rb +46 -20
  100. data/spec/SyncUpDown_spec.rb +437 -201
  101. data/spec/Verbosing_spec.rb +12 -4
  102. data/spec/{Solution-Cors_spec.rb → Webservice-Cors_spec.rb} +23 -20
  103. data/spec/{Solution-Endpoint_spec.rb → Webservice-Endpoint_spec.rb} +43 -41
  104. data/spec/{Solution-File_spec.rb → Webservice-File_spec.rb} +44 -33
  105. data/spec/Webservice-Setting_spec.rb +89 -0
  106. data/spec/_workspace.rb +4 -4
  107. data/spec/cmd_business_spec.rb +9 -4
  108. data/spec/cmd_common.rb +44 -1
  109. data/spec/cmd_content_spec.rb +43 -17
  110. data/spec/cmd_cors_spec.rb +4 -4
  111. data/spec/cmd_device_spec.rb +61 -16
  112. data/spec/cmd_domain_spec.rb +29 -6
  113. data/spec/cmd_init_spec.rb +281 -126
  114. data/spec/cmd_keystore_spec.rb +3 -3
  115. data/spec/cmd_link_spec.rb +98 -0
  116. data/spec/cmd_password_spec.rb +1 -1
  117. data/spec/cmd_setting_application_spec.rb +260 -0
  118. data/spec/cmd_setting_product_spec.rb +220 -0
  119. data/spec/cmd_status_spec.rb +223 -114
  120. data/spec/cmd_syncdown_spec.rb +115 -35
  121. data/spec/cmd_syncup_spec.rb +68 -15
  122. data/spec/cmd_usage_spec.rb +35 -8
  123. data/spec/fixtures/dumped_config +6 -4
  124. data/spec/fixtures/gateway_resource_files/resources.notyaml +12 -0
  125. data/spec/fixtures/gateway_resource_files/resources.yaml +13 -0
  126. data/spec/fixtures/gateway_resource_files/resources_invalid.yaml +13 -0
  127. data/spec/fixtures/mrmuranorc_deleted_bob +0 -2
  128. data/spec/fixtures/product_spec_files/lightbulb.yaml +20 -13
  129. data/spec/fixtures/{syncable_content → syncable_conflict}/services/devdata.lua +1 -1
  130. data/spec/fixtures/{syncable_content → syncable_conflict}/services/timers.lua +0 -0
  131. data/spec/spec_helper.rb +5 -0
  132. metadata +262 -171
  133. data/bin/mr +0 -8
  134. data/lib/MrMurano/Product-1P-Device.rb +0 -145
  135. data/lib/MrMurano/Product-Resources.rb +0 -205
  136. data/lib/MrMurano/Product.rb +0 -358
  137. data/lib/MrMurano/Solution-Cors.rb +0 -47
  138. data/lib/MrMurano/Solution-Endpoint.rb +0 -191
  139. data/lib/MrMurano/Solution-File.rb +0 -166
  140. data/lib/MrMurano/commands/assign.rb +0 -57
  141. data/lib/MrMurano/commands/businessList.rb +0 -45
  142. data/lib/MrMurano/commands/product.rb +0 -14
  143. data/lib/MrMurano/commands/productCreate.rb +0 -39
  144. data/lib/MrMurano/commands/productDelete.rb +0 -33
  145. data/lib/MrMurano/commands/productDevice.rb +0 -87
  146. data/lib/MrMurano/commands/productDeviceIdCmds.rb +0 -89
  147. data/lib/MrMurano/commands/productList.rb +0 -45
  148. data/lib/MrMurano/commands/productWrite.rb +0 -27
  149. data/lib/MrMurano/commands/solutionCreate.rb +0 -41
  150. data/lib/MrMurano/commands/solutionDelete.rb +0 -34
  151. data/lib/MrMurano/commands/solutionList.rb +0 -45
  152. data/spec/ProductBase_spec.rb +0 -113
  153. data/spec/ProductContent_spec.rb +0 -162
  154. data/spec/ProductResources_spec.rb +0 -329
  155. data/spec/Product_1P_Device_spec.rb +0 -202
  156. data/spec/Product_1P_RPC_spec.rb +0 -175
  157. data/spec/Product_spec.rb +0 -153
  158. data/spec/Solution-ServiceDevice_spec.rb +0 -176
  159. data/spec/cmd_assign_spec.rb +0 -51
@@ -1,42 +1,154 @@
1
+ # Last Modified: 2017.08.17 /coding: utf-8
2
+ # frozen_string_literal: probably not yet
3
+
4
+ # Copyright © 2016-2017 Exosite LLC.
5
+ # License: MIT. See LICENSE.txt.
6
+ # vim:tw=0:ts=2:sw=2:et:ai
7
+
1
8
  require 'fileutils'
9
+ require 'json'
2
10
  require 'open3'
3
11
  require 'pathname'
4
- require 'json'
12
+ require 'rbconfig'
13
+
5
14
  require 'cmd_common'
6
15
 
7
16
  RSpec.describe 'murano status', :cmd, :needs_password do
8
17
  include_context "CI_CMD"
9
18
 
10
19
  before(:example) do
11
- @project_name = rname('statusTest')
12
- out, err, status = Open3.capture3(capcmd('murano', 'solution', 'create', @project_name, '--save'))
20
+ @product_name = rname('statusTest')
21
+ out, err, status = Open3.capture3(capcmd('murano', 'product', 'create', @product_name, '--save'))
13
22
  expect(err).to eq('')
14
23
  expect(out.chomp).to match(/^[a-zA-Z0-9]+$/)
15
24
  expect(status.exitstatus).to eq(0)
16
25
 
17
- out, err, status = Open3.capture3(capcmd('murano', 'product', 'create', @project_name, '--save'))
26
+ @applctn_name = rname('statusTest')
27
+ out, err, status = Open3.capture3(capcmd('murano', 'application', 'create', @applctn_name, '--save'))
18
28
  expect(err).to eq('')
19
29
  expect(out.chomp).to match(/^[a-zA-Z0-9]+$/)
20
30
  expect(status.exitstatus).to eq(0)
31
+
32
+ #out, err, status = Open3.capture3(capcmd('murano', 'assign', 'set'))
33
+ #olines = out.lines
34
+ #expect(olines[0]).to eq("Linked ‘#{@product_name}’ to ‘#{@applctn_name}’\n")
35
+ #expect(olines[1]).to eq("Created default event handler\n")
36
+ #expect(err).to eq('')
37
+ #expect(status.exitstatus).to eq(0)
38
+
39
+ out, err, status = Open3.capture3(
40
+ #capcmd('murano', 'syncdown', '--eventhandlers', '--no-delete', '--no-update')
41
+ capcmd('murano', 'syncdown', '--eventhandlers', '--no-delete', '--no-create')
42
+ )
43
+ # E.g.,
44
+ # "Adding item timer_timer\nAdding item tsdb_exportJob\nAdding item user_account\n"
45
+ olines = out.lines
46
+ # 2017-08-08: Because of eventhandler.undeletable, the boilerplate items
47
+ # pre-exist, in a sense, and are therefore described as being updated,
48
+ # not added.
49
+ (0..2).each do |ln|
50
+ #expect(olines[ln].to_s).to a_string_starting_with("Adding item ")
51
+ expect(olines[ln].to_s).to a_string_starting_with("Updating item ")
52
+ end
53
+
54
+ expect(err).to eq('')
55
+ expect(status.exitstatus).to eq(0)
21
56
  end
57
+
22
58
  after(:example) do
23
- out, err, status = Open3.capture3(capcmd('murano', 'solution', 'delete', @project_name))
59
+ out, err, status = Open3.capture3(capcmd('murano', 'solution', 'delete', @applctn_name, '-y'))
24
60
  expect(out).to eq('')
25
61
  expect(err).to eq('')
26
62
  expect(status.exitstatus).to eq(0)
27
63
 
28
- out, err, status = Open3.capture3(capcmd('murano', 'product', 'delete', @project_name))
64
+ out, err, status = Open3.capture3(capcmd('murano', 'solution', 'delete', @product_name, '-y'))
29
65
  expect(out).to eq('')
30
66
  expect(err).to eq('')
31
67
  expect(status.exitstatus).to eq(0)
32
68
  end
33
69
 
70
+ def match_syncable_contents(slice)
71
+ expect(slice).to include(
72
+ a_string_matching(/ \+ \w .*modules\/table_util\.lua/),
73
+ a_string_matching(/ \+ \w .*routes\/manyRoutes\.lua/),
74
+ a_string_matching(/ \+ \w .*routes\/manyRoutes\.lua:4/),
75
+ a_string_matching(/ \+ \w .*routes\/manyRoutes\.lua:7/),
76
+ # singleRoute only appears in some of the tests.
77
+ a_string_matching(/ \+ \w .*routes\/singleRoute\.lua/),
78
+ a_string_matching(/ \+ \w .*files\/js\/script\.js/),
79
+ a_string_matching(/ \+ \w .*files\/icon\.png/),
80
+ a_string_matching(/ \+ \w .*files\/index\.html/),
81
+ )
82
+ end
83
+
84
+ def match_syncable_contents_resources(slice)
85
+ expect(slice).to include(
86
+ a_string_matching(/ \+ \w state/),
87
+ a_string_matching(/ \+ \w temperature/),
88
+ a_string_matching(/ \+ \w uptime/),
89
+ a_string_matching(/ \+ \w humidity/),
90
+ )
91
+ end
92
+
93
+ def match_syncable_contents_except_singleRoute(slice)
94
+ expect(slice).to include(
95
+ a_string_matching(/ \+ \w .*modules\/table_util\.lua/),
96
+ a_string_matching(/ \+ \w .*routes\/manyRoutes\.lua/),
97
+ a_string_matching(/ \+ \w .*routes\/manyRoutes\.lua:4/),
98
+ a_string_matching(/ \+ \w .*routes\/manyRoutes\.lua:7/),
99
+ # singleRoute does not appear in old Solutionfile tests
100
+ # that don't specify it.
101
+ #a_string_matching(/ \+ \w .*routes\/singleRoute\.lua/),
102
+ a_string_matching(/ \+ \w .*files\/js\/script\.js/),
103
+ a_string_matching(/ \+ \w .*files\/icon\.png/),
104
+ a_string_matching(/ \+ \w .*files\/index\.html/),
105
+ )
106
+ end
107
+
108
+ def match_remote_boilerplate_v1_0_0_service(slice)
109
+ expect(slice).to include(
110
+ #a_string_matching(/ - \w device2_event/),
111
+ #a_string_matching(/ - \w interface_addGatewayResource/),
112
+ #a_string_matching(/ - \w interface_addIdentity/),
113
+ #a_string_matching(/ - \w interface_clearContent/),
114
+ #a_string_matching(/ - \w interface_deleteContent/),
115
+ #a_string_matching(/ - \w interface_downloadContent/),
116
+ #a_string_matching(/ - \w interface_getGatewayResource/),
117
+ #a_string_matching(/ - \w interface_getGatewaySettings/),
118
+ #a_string_matching(/ - \w interface_getIdentity/),
119
+ #a_string_matching(/ - \w interface_getIdentityState/),
120
+ #a_string_matching(/ - \w interface_infoContent/),
121
+ #a_string_matching(/ - \w interface_listContent/),
122
+ #a_string_matching(/ - \w interface_listIdentities/),
123
+ #a_string_matching(/ - \w interface_makeIdentity/),
124
+ #a_string_matching(/ - \w interface_removeGatewayResource/),
125
+ #a_string_matching(/ - \w interface_removeIdentity/),
126
+ #a_string_matching(/ - \w interface_setIdentityState/),
127
+ #a_string_matching(/ - \w interface_updateGatewayResource/),
128
+ #a_string_matching(/ - \w interface_updateGatewaySettings/),
129
+ #a_string_matching(/ - \w interface_updateIdentity/),
130
+ #a_string_matching(/ - \w interface_uploadContent/),
131
+ #a_string_matching(/ - \w timer_timer (Application Event Handlers)/),
132
+ #a_string_matching(/ - \w tsdb_exportJob (Application Event Handlers)/),
133
+ #a_string_matching(/ - \w user_account (Application Event Handlers)/),
134
+ #a_string_matching(/ - \w timer_timer/),
135
+ #a_string_matching(/ - \w tsdb_exportJob/),
136
+ #a_string_matching(/ - \w user_account/),
137
+ a_string_matching(/ M \w timer_timer\.lua/),
138
+ a_string_matching(/ M \w tsdb_exportJob\.lua/),
139
+ a_string_matching(/ M \w user_account\.lua/),
140
+ )
141
+ end
142
+
34
143
  context "without ProjectFile" do
35
144
  before(:example) do
36
145
  FileUtils.cp_r(File.join(@testdir, 'spec/fixtures/syncable_content/.'), '.')
37
- FileUtils.move('assets','files')
146
+ FileUtils.move('assets', 'files')
38
147
  FileUtils.mkpath('specs')
39
- FileUtils.copy(File.join(@testdir, 'spec/fixtures/product_spec_files/lightbulb.yaml'), 'specs/resources.yaml')
148
+ FileUtils.copy(
149
+ File.join(@testdir, 'spec/fixtures/product_spec_files/lightbulb.yaml'),
150
+ 'specs/resources.yaml',
151
+ )
40
152
  end
41
153
 
42
154
  it "status" do
@@ -46,27 +158,32 @@ RSpec.describe 'murano status', :cmd, :needs_password do
46
158
  # 1: Order of files is not set
47
159
  # 2: Path prefixes could be different.
48
160
  olines = out.lines
49
- expect(olines[0]).to eq("Adding:\n")
50
- expect(olines[1..8]).to include(
51
- a_string_matching(/ \+ A .*routes\/manyRoutes\.lua/),
52
- a_string_matching(/ \+ A .*routes\/manyRoutes\.lua:4/),
53
- a_string_matching(/ \+ A .*routes\/manyRoutes\.lua:7/),
54
- a_string_matching(/ \+ A .*routes\/singleRoute\.lua/),
55
- a_string_matching(/ \+ S .*files\/icon\.png/),
56
- a_string_matching(/ \+ S .*files\/index\.html/),
57
- a_string_matching(/ \+ S .*files\/js\/script\.js/),
58
- a_string_matching(/ \+ M .*modules\/table_util\.lua/),
59
- )
60
- expect(olines[9]).to eq("Deleteing:\n")
61
- expect(olines[10..11]).to include(
62
- " - M my_library\n",
63
- " - E user_account\n",
64
- )
65
- expect(olines[12]).to eq("Changing:\n")
66
- expect(olines[13..14]).to include(
67
- a_string_matching(/ M E .*services\/devdata\.lua/),
68
- a_string_matching(/ M E .*services\/timers\.lua/),
69
- )
161
+ expect(olines[0]).to eq("Only on local machine:\n")
162
+ match_syncable_contents_resources(olines[1..4])
163
+ match_syncable_contents(olines[5..12])
164
+ #expect(olines[13]).to eq("Only on remote server:\n")
165
+ expect(olines[13]).to eq("Nothing new remotely\n")
166
+ # FIMXE/2017-06-23: We should DRY this long list which is same in each test.
167
+ # FIXME/2017-06-23: The interfaces the server creates for a new project
168
+ # will problem vary depending on what modules are loaded, and are likely
169
+ # to change over time...
170
+ #match_remote_boilerplate_v1_0_0_service(olines[14..35])
171
+
172
+ # NOTE: On Windows, touch doesn't work, so items differ.
173
+ # Check the platform, e.g., "linux-gnu", or other.
174
+ # 2017-07-14 08:51: Is there a race condition here? [lb] saw
175
+ # differences earlier, but then not after adding this...
176
+ #is_windows = (RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/)
177
+ #if is_windows
178
+ # expect(olines[14]).to eq("Items that differ:\n")
179
+ # expect(olines[15..16]).to contain_exactly(
180
+ # a_string_matching(/ M \w .*services\/timer_timer\.lua/),
181
+ # a_string_matching(/ M \w .*services\/tsdb_exportJob\.lua/),
182
+ # )
183
+ #else
184
+ expect(olines[14]).to eq("Nothing that differs\n")
185
+ #end
186
+
70
187
  expect(status.exitstatus).to eq(0)
71
188
  end
72
189
 
@@ -74,10 +191,10 @@ RSpec.describe 'murano status', :cmd, :needs_password do
74
191
  out, err, status = Open3.capture3(capcmd('murano', 'status', '**/icon.png'))
75
192
  expect(err).to eq('')
76
193
  expect(out.lines).to match([
77
- "Adding:\n",
78
- a_string_matching(/ \+ S .*files\/icon\.png/),
79
- "Deleteing:\n",
80
- "Changing:\n",
194
+ "Only on local machine:\n",
195
+ a_string_matching(/ \+ \w .*files\/icon\.png/),
196
+ "Nothing new remotely\n",
197
+ "Nothing that differs\n",
81
198
  ])
82
199
  expect(status.exitstatus).to eq(0)
83
200
  end
@@ -86,10 +203,10 @@ RSpec.describe 'murano status', :cmd, :needs_password do
86
203
  out, err, status = Open3.capture3(capcmd('murano', 'status', '#put#'))
87
204
  expect(err).to eq('')
88
205
  expect(out.lines).to match([
89
- "Adding:\n",
90
- a_string_matching(/ \+ A .*routes\/manyRoutes\.lua:4/),
91
- "Deleteing:\n",
92
- "Changing:\n",
206
+ "Only on local machine:\n",
207
+ a_string_matching(/ \+ \w .*routes\/manyRoutes\.lua:4/),
208
+ "Nothing new remotely\n",
209
+ "Nothing that differs\n",
93
210
  ])
94
211
  expect(status.exitstatus).to eq(0)
95
212
  end
@@ -97,10 +214,16 @@ RSpec.describe 'murano status', :cmd, :needs_password do
97
214
 
98
215
  context "with ProjectFile" do
99
216
  before(:example) do
217
+ # We previously called syncdown, which created the project/services/
218
+ # directory, but don't fret, this copy command will overlay files and
219
+ # it will not overwrite directories (or do nothing to them, either).
100
220
  FileUtils.cp_r(File.join(@testdir, 'spec/fixtures/syncable_content/.'), '.')
101
- FileUtils.move('assets','files')
221
+ FileUtils.move('assets', 'files')
102
222
  FileUtils.mkpath('specs')
103
- FileUtils.copy(File.join(@testdir, 'spec/fixtures/product_spec_files/lightbulb.yaml'), 'specs/resources.yaml')
223
+ FileUtils.copy(
224
+ File.join(@testdir, 'spec/fixtures/product_spec_files/lightbulb.yaml'),
225
+ 'specs/resources.yaml',
226
+ )
104
227
  FileUtils.copy(File.join(@testdir, 'spec/fixtures/ProjectFiles/only_meta.yaml'), 'test.murano')
105
228
  end
106
229
 
@@ -108,37 +231,36 @@ RSpec.describe 'murano status', :cmd, :needs_password do
108
231
  out, err, status = Open3.capture3(capcmd('murano', 'status'))
109
232
  expect(err).to eq('')
110
233
  olines = out.lines
111
- expect(olines[0]).to eq("Adding:\n")
112
- expect(olines[1..8]).to include(
113
- a_string_matching(/ \+ A .*routes\/manyRoutes\.lua/),
114
- a_string_matching(/ \+ A .*routes\/manyRoutes\.lua:4/),
115
- a_string_matching(/ \+ A .*routes\/manyRoutes\.lua:7/),
116
- a_string_matching(/ \+ A .*routes\/singleRoute\.lua/),
117
- a_string_matching(/ \+ S .*files\/icon\.png/),
118
- a_string_matching(/ \+ S .*files\/index\.html/),
119
- a_string_matching(/ \+ S .*files\/js\/script\.js/),
120
- a_string_matching(/ \+ M .*modules\/table_util\.lua/),
121
- )
122
- expect(olines[9]).to eq("Deleteing:\n")
123
- expect(olines[10..11]).to include(
124
- " - M my_library\n",
125
- " - E user_account\n",
126
- )
127
- expect(olines[12]).to eq("Changing:\n")
128
- expect(olines[13..14]).to include(
129
- a_string_matching(/ M E .*services\/devdata\.lua/),
130
- a_string_matching(/ M E .*services\/timers\.lua/),
131
- )
234
+ expect(olines[0]).to eq("Only on local machine:\n")
235
+ match_syncable_contents_resources(olines[1..4])
236
+ match_syncable_contents(olines[5..12])
237
+ expect(olines[13]).to eq("Nothing new remotely\n")
238
+
239
+ # NOTE: On Windows, touch doesn't work, so items differ.
240
+ # Check the platform, e.g., "linux-gnu", or other.
241
+ is_windows = (RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/)
242
+ if is_windows
243
+ expect(olines[14]).to eq("Items that differ:\n")
244
+ expect(olines[15..16]).to include(
245
+ a_string_matching(/ M \w .*services\/timer_timer\.lua/),
246
+ a_string_matching(/ M \w .*services\/tsdb_exportJob\.lua/),
247
+ )
248
+ else
249
+ expect(olines[14]).to eq("Nothing that differs\n")
250
+ end
251
+
132
252
  expect(status.exitstatus).to eq(0)
133
253
  end
134
254
  end
135
255
 
256
+ # XXX wait, should a Solutionfile even work with Okami?
136
257
  context "with Solutionfile 0.2.0" do
137
258
  before(:example) do
138
259
  FileUtils.cp_r(File.join(@testdir, 'spec/fixtures/syncable_content/.'), '.')
139
260
  FileUtils.move('assets','files')
140
261
  FileUtils.mkpath('specs')
141
- FileUtils.copy(File.join(@testdir, 'spec/fixtures/product_spec_files/lightbulb.yaml'), 'specs/resources.yaml')
262
+ FileUtils.copy(File.join(@testdir, 'spec/fixtures/product_spec_files/lightbulb.yaml'),
263
+ 'specs/resources.yaml')
142
264
  File.open('Solutionfile.json', 'wb') do |io|
143
265
  io << {
144
266
  :default_page => 'index.html',
@@ -159,83 +281,70 @@ RSpec.describe 'murano status', :cmd, :needs_password do
159
281
  it "status" do
160
282
  out, err, status = Open3.capture3(capcmd('murano', 'status'))
161
283
  expect(err).to eq('')
284
+ # Not a single match, because the order of items within groups can shift
162
285
  olines = out.lines
163
- expect(olines[0]).to eq("Adding:\n")
164
- expect(olines[1..7]).to include(
165
- a_string_matching(/ \+ A .*routes\/manyRoutes\.lua/),
166
- a_string_matching(/ \+ A .*routes\/manyRoutes\.lua:4/),
167
- a_string_matching(/ \+ A .*routes\/manyRoutes\.lua:7/),
168
- a_string_matching(/ \+ S .*files\/icon\.png/),
169
- a_string_matching(/ \+ S .*files\/index\.html/),
170
- a_string_matching(/ \+ S .*files\/js\/script\.js/),
171
- a_string_matching(/ \+ M .*modules\/table_util\.lua/),
172
- )
173
- expect(olines[8]).to eq("Deleteing:\n")
174
- expect(olines[9..11]).to include(
175
- " - M my_library\n",
176
- " - E user_account\n",
177
- " - E timer_timer\n",
178
- )
179
- expect(olines[12]).to eq("Changing:\n")
180
- expect(olines[13..14]).to include(
181
- a_string_matching(/ M E .*services\/devdata\.lua/),
182
- )
286
+ expect(olines[0]).to eq("Only on local machine:\n")
287
+ match_syncable_contents_resources(olines[1..4])
288
+ match_syncable_contents_except_singleRoute(olines[5..11])
289
+ #expect(olines[12]).to eq("Only on remote server:\n")
290
+ #match_remote_boilerplate_v1_0_0_service(olines[13..15])
291
+ expect(olines[12]).to eq("Nothing new remotely\n")
292
+ #expect(olines[16]).to eq("Nothing that differs\n")
293
+ ##expect(olines[11]).to eq("Items that differ:\n")
294
+ ##expect(olines[12..12]).to contain_exactly(
295
+ ## a_string_matching(/ M \w .*services\/devdata\.lua/),
296
+ ##)
297
+ expect(olines[13]).to eq("Items that differ:\n")
298
+ match_remote_boilerplate_v1_0_0_service(olines[14..16])
183
299
  expect(status.exitstatus).to eq(0)
184
300
  end
185
301
  end
186
302
 
303
+ # XXX wait, should a Solutionfile even work with Okami?
187
304
  context "with Solutionfile 0.3.0" do
188
305
  before(:example) do
189
306
  FileUtils.cp_r(File.join(@testdir, 'spec/fixtures/syncable_content/.'), '.')
190
- FileUtils.move('assets','files')
307
+ FileUtils.move('assets', 'files')
191
308
  FileUtils.mkpath('specs')
192
- FileUtils.copy(File.join(@testdir, 'spec/fixtures/product_spec_files/lightbulb.yaml'), 'specs/resources.yaml')
309
+ FileUtils.copy(
310
+ File.join(@testdir, 'spec/fixtures/product_spec_files/lightbulb.yaml'),
311
+ 'specs/resources.yaml',
312
+ )
193
313
  File.open('Solutionfile.json', 'wb') do |io|
194
314
  io << {
195
- :default_page => 'index.html',
196
- :assets => 'files',
197
- :routes => 'routes/manyRoutes.lua',
198
- :modules => {
199
- :table_util => 'modules/table_util.lua'
315
+ default_page: 'index.html',
316
+ assets: 'files',
317
+ routes: 'routes/manyRoutes.lua',
318
+ # Note that singleRoute.lua is not included, so it won't be seen by status command.
319
+ modules: {
320
+ table_util: 'modules/table_util.lua'
200
321
  },
201
- :services => {
202
- :device => {
203
- :datapoint => 'services/devdata.lua'
322
+ services: {
323
+ device: {
324
+ datapoint: 'services/devdata.lua'
204
325
  }
205
326
  },
206
- :version => '0.3.0',
327
+ version: '0.3.0',
207
328
  }.to_json
208
329
  end
209
330
  end
210
331
 
211
332
  it "status" do
212
333
  out, err, status = Open3.capture3(capcmd('murano', 'status'))
334
+ # pp out.split "\n"
213
335
  expect(err).to eq('')
214
336
  olines = out.lines
215
- expect(olines[0]).to eq("Adding:\n")
216
- expect(olines[1..7]).to include(
217
- a_string_matching(/ \+ A .*routes\/manyRoutes\.lua/),
218
- a_string_matching(/ \+ A .*routes\/manyRoutes\.lua:4/),
219
- a_string_matching(/ \+ A .*routes\/manyRoutes\.lua:7/),
220
- a_string_matching(/ \+ S .*files\/icon\.png/),
221
- a_string_matching(/ \+ S .*files\/index\.html/),
222
- a_string_matching(/ \+ S .*files\/js\/script\.js/),
223
- a_string_matching(/ \+ M .*modules\/table_util\.lua/),
224
- )
225
- expect(olines[8]).to eq("Deleteing:\n")
226
- expect(olines[9..11]).to include(
227
- " - M my_library\n",
228
- " - E user_account\n",
229
- " - E timer_timer\n",
230
- )
231
- expect(olines[12]).to eq("Changing:\n")
232
- expect(olines[13..14]).to include(
233
- a_string_matching(/ M E .*services\/devdata\.lua/),
234
- )
337
+ expect(olines[0]).to eq("Only on local machine:\n")
338
+ match_syncable_contents_resources(olines[1..4])
339
+ match_syncable_contents_except_singleRoute(olines[5..11])
340
+ #expect(olines[12]).to eq("Only on remote server:\n")
341
+ #match_remote_boilerplate_v1_0_0_service(olines[13..15])
342
+ expect(olines[12]).to eq("Nothing new remotely\n")
343
+ #expect(olines[16]).to eq("Nothing that differs\n")
344
+ expect(olines[13]).to eq("Items that differ:\n")
345
+ match_remote_boilerplate_v1_0_0_service(olines[14..16])
235
346
  expect(status.exitstatus).to eq(0)
236
347
  end
237
348
  end
238
-
239
349
  end
240
350
 
241
- # vim: set ai et sw=2 ts=2 :
@@ -1,3 +1,10 @@
1
+ # Last Modified: 2017.08.16 /coding: utf-8
2
+ # frozen_string_literal: probably not yet
3
+
4
+ # Copyright © 2016-2017 Exosite LLC.
5
+ # License: MIT. See LICENSE.txt.
6
+ # vim:tw=0:ts=2:sw=2:et:ai
7
+
1
8
  require 'fileutils'
2
9
  require 'open3'
3
10
  require 'pathname'
@@ -7,24 +14,38 @@ RSpec.describe 'murano syncdown', :cmd, :needs_password do
7
14
  include_context "CI_CMD"
8
15
 
9
16
  before(:example) do
10
- @project_name = rname('syncdownTest')
11
- out, err, status = Open3.capture3(capcmd('murano', 'solution', 'create', @project_name, '--save'))
17
+ @product_name = rname('syncdownTestPrd')
18
+ out, err, status = Open3.capture3(capcmd('murano', 'product', 'create', @product_name, '--save'))
19
+ expect(err).to eq('')
20
+ soln_id = out
21
+ expect(soln_id.chomp).to match(/^[a-zA-Z0-9]+$/)
22
+ expect(status.exitstatus).to eq(0)
23
+
24
+ @applctn_name = rname('syncdownTestApp')
25
+ out, err, status = Open3.capture3(capcmd('murano', 'application', 'create', @applctn_name, '--save'))
12
26
  expect(err).to eq('')
13
- expect(out.chomp).to match(/^[a-zA-Z0-9]+$/)
27
+ soln_id = out
28
+ expect(soln_id.chomp).to match(/^[a-zA-Z0-9]+$/)
14
29
  expect(status.exitstatus).to eq(0)
15
30
 
16
- out, err, status = Open3.capture3(capcmd('murano', 'product', 'create', @project_name, '--save'))
31
+ out, err, status = Open3.capture3(capcmd('murano', 'assign', 'set'))
32
+ #expect(out).to a_string_starting_with("Linked product #{@product_name}")
33
+ olines = out.lines
34
+ expect(olines[0].encode!('UTF-8', 'UTF-8')).to eq("Linked ‘#{@product_name}’ to ‘#{@applctn_name}’\n")
35
+ expect(olines[1]).to eq("Created default event handler\n")
17
36
  expect(err).to eq('')
18
- expect(out.chomp).to match(/^[a-zA-Z0-9]+$/)
19
37
  expect(status.exitstatus).to eq(0)
20
38
  end
39
+
21
40
  after(:example) do
22
- out, err, status = Open3.capture3(capcmd('murano', 'solution', 'delete', @project_name))
41
+ # VERIFY/2017-07-03: Skipping assign unset. Murano will clean up, right?
42
+
43
+ out, err, status = Open3.capture3(capcmd('murano', 'solution', 'delete', '-y', @applctn_name))
23
44
  expect(out).to eq('')
24
45
  expect(err).to eq('')
25
46
  expect(status.exitstatus).to eq(0)
26
47
 
27
- out, err, status = Open3.capture3(capcmd('murano', 'product', 'delete', @project_name))
48
+ out, err, status = Open3.capture3(capcmd('murano', 'solution', 'delete', '--yes', @product_name))
28
49
  expect(out).to eq('')
29
50
  expect(err).to eq('')
30
51
  expect(status.exitstatus).to eq(0)
@@ -35,52 +56,111 @@ RSpec.describe 'murano syncdown', :cmd, :needs_password do
35
56
  FileUtils.cp_r(File.join(@testdir, 'spec/fixtures/syncable_content/.'), '.')
36
57
  FileUtils.move('assets','files')
37
58
  #FileUtils.mkpath('specs')
38
- #FileUtils.copy(File.join(@testdir, 'spec/fixtures/product_spec_files/lightbulb.yaml'), 'specs/resources.yaml')
59
+ #FileUtils.copy(File.join(@testdir, 'spec/fixtures/product_spec_files/lightbulb.yaml'),
60
+ # 'specs/resources.yaml')
61
+ # 2017-07-03: So long as this command does not syncdown first, these
62
+ # two files -- that conflict in name with what's on the platform --
63
+ # won't be a problem (but would be if we synceddown first).
64
+ FileUtils.cp_r(File.join(@testdir, 'spec/fixtures/syncable_conflict/.'), '.')
39
65
  end
40
66
 
41
67
  it "syncdown" do
42
68
  out, err, status = Open3.capture3(capcmd('murano', 'syncup'))
43
- expect(out).to eq('')
44
- expect(err).to eq('')
69
+ #expect(out).to eq('')
70
+ #out_lines = out.lines
71
+ out_lines = out.lines.map { |line| line.encode!('UTF-8', 'UTF-8') }
72
+ expect(out_lines).to match_array([
73
+ "Adding item table_util\n",
74
+ "Updating item timer_timer\n",
75
+ # E.g., "Updating item i4kl64nn86xk00000_event\n":
76
+ a_string_starting_with('Updating item '),
77
+ "Updating item tsdb_exportJob\n",
78
+ "Updating item user_account\n",
79
+ # FIXME/2017-08-09: This test includes a fixture with "device2 data_in",
80
+ # which is deprecated, AFAIK [lb]. We convert it to "device2.event",
81
+ # but I think what we really want is to edit "<solution_id>.event".
82
+ "Adding item device2_event\n",
83
+ "Adding item POST_/api/fire\n",
84
+ "Adding item PUT_/api/fire/{code}\n",
85
+ "Adding item DELETE_/api/fire/{code}\n",
86
+ "Adding item GET_/api/onfire\n",
87
+ "Adding item /icon.png\n",
88
+ "Adding item /\n",
89
+ "Adding item /js/script.js\n",
90
+ ])
91
+
92
+ #expect(err).to eq('')
93
+ expect(err).to start_with("\e[33mSkipping missing location ‘")
45
94
  expect(status.exitstatus).to eq(0)
46
95
 
47
96
  FileUtils.rm_r(['files', 'modules', 'routes', 'services'])
48
97
  expect(Dir['**/*']).to eq([])
49
98
 
50
99
  out, err, status = Open3.capture3(capcmd('murano', 'syncdown'))
51
- expect(out).to eq('')
52
- expect(err.lines).to include(
53
- a_string_ending_with("routes\e[0m\n"),
54
- a_string_ending_with("files\e[0m\n"),
55
- a_string_ending_with("modules\e[0m\n"),
56
- a_string_ending_with("services\e[0m\n"),
57
- )
100
+ #expect(out).to eq('')
101
+ out_lines = out.lines.map { |line| line.encode!('UTF-8', 'UTF-8') }
102
+ expect(out_lines).to match_array([
103
+ "Adding item table_util\n",
104
+ # 2017-08-08: This says updating now because timer.timer is undeletable.
105
+ #"Adding item timer_timer\n",
106
+ "Updating item timer_timer\n",
107
+ "Adding item POST_/api/fire\n",
108
+ "Adding item DELETE_/api/fire/{code}\n",
109
+ "Adding item PUT_/api/fire/{code}\n",
110
+ "Adding item GET_/api/onfire\n",
111
+ "Adding item /js/script.js\n",
112
+ "Adding item /icon.png\n",
113
+ "Adding item /\n",
114
+ ])
115
+ # Look for skipping missing location lines, e.g.,
116
+ # "\e[33mSkipping missing location /tmp/d20170623-20035-17496y/project/modules\e[0m\n"
117
+ # 2017-07-03: Did I [lb] change syncdown not to complain about missing locations?
118
+ #expect(err.lines).to include(
119
+ # a_string_ending_with("routes\e[0m\n"),
120
+ # a_string_ending_with("files\e[0m\n"),
121
+ # a_string_ending_with("modules\e[0m\n"),
122
+ # a_string_ending_with("services\e[0m\n"),
123
+ #)
124
+ #expect(err).to eq('')
125
+ expect(err).to start_with("\e[33mSkipping missing location ‘")
58
126
  expect(status.exitstatus).to eq(0)
59
127
 
60
128
  after = Dir['**/*'].sort
61
- expect(after).to include("files",
62
- "files/icon.png",
63
- "files/index.html",
64
- "files/js",
65
- "files/js/script.js",
66
- "modules",
67
- "modules/table_util.lua",
68
- "routes",
69
- "routes/api-fire-{code}.delete.lua",
70
- "routes/api-fire-{code}.put.lua",
71
- "routes/api-fire.post.lua",
72
- "routes/api-onfire.get.lua",
73
- "services",
74
- "services/device_datapoint.lua",
75
- "services/timer_timer.lua")
76
- end
77
- end
129
+ expect(after).to include(
130
+ "files",
131
+ "files/icon.png",
132
+ "files/index.html",
133
+ "files/js",
134
+ "files/js/script.js",
135
+ "modules",
136
+ "modules/table_util.lua",
137
+ "routes",
138
+ "routes/api-fire-{code}.delete.lua",
139
+ "routes/api-fire-{code}.put.lua",
140
+ "routes/api-fire.post.lua",
141
+ "routes/api-onfire.get.lua",
142
+ # 2017-07-03: services/ would not exist if we did not include fixtures/syncable_conflict/.
143
+ "services",
144
+ # 2017-07-13: No longer syncing device2_event; is internal to platform.
145
+ #"services/device2_event.lua",
146
+ "services/timer_timer.lua",
147
+ )
78
148
 
149
+ # A status should show no differences.
150
+ out, err, status = Open3.capture3(capcmd('murano', 'status'))
151
+ expect(err).to eq('')
152
+ expect(out.lines).to match([
153
+ "Nothing new locally\n",
154
+ "Nothing new remotely\n",
155
+ "Nothing that differs\n",
156
+ ])
157
+ expect(status.exitstatus).to eq(0)
79
158
 
159
+ end
160
+ end
80
161
 
81
162
  # TODO: With ProjectFile
82
163
  # TODO: With Solutionfile 0.2.0
83
164
  # TODO: With Solutionfile 0.3.0
84
165
  end
85
166
 
86
- # vim: set ai et sw=2 ts=2 :