MuranoCLI 3.2.0.beta.9 → 3.2.1.pre.beta.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/Rakefile +5 -0
  4. data/dockers/README.rst +7 -0
  5. data/dockers/RELEASE.rst +6 -3
  6. data/dockers/docker-test.sh +45 -17
  7. data/docs/completions/murano_completion-bash +211 -86
  8. data/lib/MrMurano/Account.rb +72 -4
  9. data/lib/MrMurano/Business.rb +163 -2
  10. data/lib/MrMurano/Commander-Entry.rb +1 -2
  11. data/lib/MrMurano/Config.rb +19 -18
  12. data/lib/MrMurano/Content.rb +26 -19
  13. data/lib/MrMurano/Gateway.rb +51 -10
  14. data/lib/MrMurano/ReCommander.rb +1 -1
  15. data/lib/MrMurano/Solution-Services.rb +80 -35
  16. data/lib/MrMurano/Solution-Users.rb +1 -0
  17. data/lib/MrMurano/SyncRoot.rb +10 -3
  18. data/lib/MrMurano/SyncUpDown-Core.rb +47 -36
  19. data/lib/MrMurano/SyncUpDown-Item.rb +46 -14
  20. data/lib/MrMurano/SyncUpDown.rb +22 -20
  21. data/lib/MrMurano/Webservice-Endpoint.rb +20 -18
  22. data/lib/MrMurano/Webservice-File.rb +63 -20
  23. data/lib/MrMurano/commands/business.rb +14 -1
  24. data/lib/MrMurano/commands/child.rb +148 -0
  25. data/lib/MrMurano/commands/devices.rb +298 -149
  26. data/lib/MrMurano/commands/element.rb +2 -1
  27. data/lib/MrMurano/commands/globals.rb +3 -0
  28. data/lib/MrMurano/commands/network.rb +152 -33
  29. data/lib/MrMurano/commands/sync.rb +2 -2
  30. data/lib/MrMurano/commands.rb +1 -0
  31. data/lib/MrMurano/verbosing.rb +13 -2
  32. data/lib/MrMurano/version.rb +1 -1
  33. data/spec/Account_spec.rb +43 -11
  34. data/spec/Content_spec.rb +5 -3
  35. data/spec/GatewayBase_spec.rb +1 -1
  36. data/spec/GatewayDevice_spec.rb +47 -8
  37. data/spec/GatewayResource_spec.rb +1 -1
  38. data/spec/GatewaySettings_spec.rb +1 -1
  39. data/spec/HttpAuthed_spec.rb +17 -3
  40. data/spec/ProjectFile_spec.rb +59 -23
  41. data/spec/Setting_spec.rb +2 -1
  42. data/spec/Solution-ServiceConfig_spec.rb +1 -1
  43. data/spec/Solution-ServiceEventHandler_spec.rb +27 -20
  44. data/spec/Solution-ServiceModules_spec.rb +7 -5
  45. data/spec/Solution-UsersRoles_spec.rb +7 -1
  46. data/spec/Solution_spec.rb +9 -1
  47. data/spec/SyncRoot_spec.rb +5 -5
  48. data/spec/SyncUpDown_spec.rb +262 -211
  49. data/spec/Verbosing_spec.rb +49 -8
  50. data/spec/Webservice-Cors_spec.rb +10 -1
  51. data/spec/Webservice-Endpoint_spec.rb +84 -65
  52. data/spec/Webservice-File_spec.rb +16 -11
  53. data/spec/Webservice-Setting_spec.rb +7 -1
  54. data/spec/_workspace.rb +9 -0
  55. data/spec/cmd_business_spec.rb +5 -10
  56. data/spec/cmd_common.rb +67 -32
  57. data/spec/cmd_config_spec.rb +9 -14
  58. data/spec/cmd_content_spec.rb +15 -26
  59. data/spec/cmd_cors_spec.rb +9 -12
  60. data/spec/cmd_device_spec.rb +31 -45
  61. data/spec/cmd_domain_spec.rb +12 -10
  62. data/spec/cmd_element_spec.rb +18 -17
  63. data/spec/cmd_exchange_spec.rb +1 -4
  64. data/spec/cmd_init_spec.rb +56 -72
  65. data/spec/cmd_keystore_spec.rb +17 -26
  66. data/spec/cmd_link_spec.rb +13 -17
  67. data/spec/cmd_password_spec.rb +9 -10
  68. data/spec/cmd_setting_application_spec.rb +95 -68
  69. data/spec/cmd_setting_product_spec.rb +59 -37
  70. data/spec/cmd_status_spec.rb +46 -84
  71. data/spec/cmd_syncdown_application_spec.rb +28 -50
  72. data/spec/cmd_syncdown_both_spec.rb +44 -93
  73. data/spec/cmd_syncdown_unit_spec.rb +858 -0
  74. data/spec/cmd_syncup_spec.rb +21 -56
  75. data/spec/cmd_token_spec.rb +0 -3
  76. data/spec/cmd_usage_spec.rb +15 -10
  77. data/spec/dry_run_formatter.rb +1 -0
  78. data/spec/fixtures/dumped_config +4 -4
  79. data/spec/spec_helper.rb +3 -0
  80. metadata +4 -2
@@ -18,22 +18,20 @@ RSpec.describe 'murano single sync', :cmd, :needs_password do
18
18
  murano_solutions_expunge_yes
19
19
 
20
20
  @applctn_name = rname('syncdownTestApp')
21
- out, err, status = Open3.capture3(
22
- capcmd('murano', 'application', 'create', @applctn_name, '--save')
21
+ out, err = murano_command_run(
22
+ 'solution create', '--type', 'application', @applctn_name, '--save',
23
23
  )
24
24
  expect(err).to eq('')
25
25
  soln_id = out
26
26
  expect(soln_id.chomp).to match(/^[a-zA-Z0-9]+$/)
27
- expect(status.exitstatus).to eq(0)
28
27
  end
29
28
 
30
29
  after(:example) do
31
- out, err, status = Open3.capture3(
32
- capcmd('murano', 'solution', 'delete', '-y', @applctn_name)
30
+ out, err = murano_command_run(
31
+ 'solution delete', '-y', @applctn_name,
33
32
  )
34
33
  expect(out).to eq('')
35
34
  expect(err).to eq('')
36
- expect(status.exitstatus).to eq(0)
37
35
  end
38
36
 
39
37
  context 'without ProjectFile' do
@@ -44,16 +42,19 @@ RSpec.describe 'murano single sync', :cmd, :needs_password do
44
42
  end
45
43
 
46
44
  it 'syncdown', :club_30s, :club_20s, :club_10s do
47
- out, err, status = Open3.capture3(capcmd('murano', 'syncup'))
45
+ out, err = murano_command_run('syncup')
48
46
  out_lines = out.lines.map { |line| strip_fancy(line) }
49
47
  expect(out_lines).to match_array(
50
48
  [
51
49
  "Adding item table_util\n",
52
- # FIXME/MUR-XXX: Should config_service/config_status be whitelisted?
53
- "Removing item config_service\n",
54
- "Removing item config_status\n",
55
- "Removing item user_account\n",
56
- "Updating item timer_timer\n",
50
+ # WATCH/2018-07-19: user_account present on staging Solution by default,
51
+ # and has an example script comment as its script.
52
+ # Note also that config_service and config_status exist by default, but
53
+ # their scripts are the empty string, and they are undeletable, so they
54
+ # will not be synced.
55
+ "Clearing item user_account\n",
56
+ # WATCH/2018-07-19: timer_timer not added by default on staging, but is on dev.
57
+ "Adding item timer_timer\n",
57
58
  "Adding item POST_/api/fire\n",
58
59
  "Adding item PUT_/api/fire/{code}\n",
59
60
  "Adding item DELETE_/api/fire/{code}\n",
@@ -65,22 +66,17 @@ RSpec.describe 'murano single sync', :cmd, :needs_password do
65
66
  )
66
67
 
67
68
  expect(err).to eq('')
68
- expect(status.exitstatus).to eq(0)
69
69
 
70
70
  FileUtils.rm_r(%w[files modules routes services])
71
71
  expect(Dir['**/*']).to eq([])
72
72
 
73
- out, err, status = Open3.capture3(capcmd('murano', 'syncdown'))
73
+ out, err = murano_command_run('syncdown')
74
74
  out_lines = out.lines.map { |line| strip_fancy(line) }
75
75
  # MAYBE/2018-04-13: (lb): I see the order here change sometimes.
76
76
  # We might want to use expect().to include() instead of match_array().
77
77
  expect(out_lines).to match_array(
78
78
  [
79
79
  "Adding item table_util\n",
80
- # FIXME/MUR-XXX: Should config_service/config_status be whitelisted?
81
- # (lb): Hahaha, looks like you cannot delete these 2 services after all?
82
- "Adding item config_service\n",
83
- "Adding item config_status\n",
84
80
  "Adding item timer_timer\n",
85
81
  "Adding item POST_/api/fire\n",
86
82
  "Adding item DELETE_/api/fire/{code}\n",
@@ -92,56 +88,38 @@ RSpec.describe 'murano single sync', :cmd, :needs_password do
92
88
  ]
93
89
  )
94
90
  expect(err).to eq('')
95
- expect(status.exitstatus).to eq(0)
96
91
 
97
92
  after = Dir['**/*'].sort
98
93
  expect(after).to include(
99
- 'files',
100
- 'files/icon.png',
101
- 'files/index.html',
102
- 'files/js',
103
- 'files/js/script.js',
94
+ 'assets',
95
+ 'assets/icon.png',
96
+ 'assets/index.html',
97
+ 'assets/js',
98
+ 'assets/js/script.js',
104
99
  'modules',
105
100
  'modules/table_util.lua',
106
- 'routes',
107
- 'routes/api-fire-{code}.delete.lua',
108
- 'routes/api-fire-{code}.put.lua',
109
- 'routes/api-fire.post.lua',
110
- 'routes/api-onfire.get.lua',
101
+ 'endpoints',
102
+ 'endpoints/api-fire-{code}.delete.lua',
103
+ 'endpoints/api-fire-{code}.put.lua',
104
+ 'endpoints/api-fire.post.lua',
105
+ 'endpoints/api-onfire.get.lua',
111
106
  'services',
112
- 'services/config_service.lua',
113
- 'services/config_status.lua',
114
107
  'services/timer_timer.lua',
115
108
  )
116
109
 
117
110
  # A status should show no differences.
118
- out, err, status = Open3.capture3(capcmd('murano', 'status'))
111
+ out, err = murano_command_run('status')
119
112
  expect(err).to eq('')
120
113
  expect(out.lines).to match(
121
114
  [
122
115
  "Nothing new locally\n",
123
116
  "Nothing new remotely\n",
124
- # 2018-04-23 16:30: ???: Happening on Jenkins server:
125
- #"Nothing that differs\n",
126
- "Items that differ:\n",
127
- " M A files/index.html\n",
128
- " M A files/js/script.js\n",
129
- "Items without a solution:\n",
130
- " - R Resource\n",
131
- " - I Interface\n",
117
+ "Nothing that differs\n",
132
118
  ]
133
119
  )
134
- expect(status.exitstatus).to eq(0)
135
-
136
- out, err, status = Open3.capture3(capcmd('murano', 'diff'))
120
+ out, err = murano_command_run('status', '--diff', '--no-grouped')
137
121
  expect(err).to eq('')
138
- expect(out.lines).to match(
139
- [
140
- " - R Resource\n",
141
- " - I Interface\n",
142
- ]
143
- )
144
- expect(status.exitstatus).to eq(0)
122
+ expect(out.lines).to match([])
145
123
  end
146
124
  end
147
125
  end
@@ -16,24 +16,20 @@ RSpec.describe 'murano syncdown', :cmd, :needs_password do
16
16
  murano_solutions_expunge_yes
17
17
 
18
18
  @product_name = rname('syncdownTestPrd')
19
- out, err, status = Open3.capture3(
20
- capcmd('murano', 'product', 'create', @product_name, '--save')
19
+ out, err = murano_command_run(
20
+ 'solution create', '--type', 'product', @product_name, '--save',
21
21
  )
22
22
  expect(err).to eq('')
23
- soln_id = out
24
- expect(soln_id.chomp).to match(/^[a-zA-Z0-9]+$/)
25
- expect(status.exitstatus).to eq(0)
23
+ expect(out.chomp).to match(/^[a-zA-Z0-9]+$/)
26
24
 
27
25
  @applctn_name = rname('syncdownTestApp')
28
- out, err, status = Open3.capture3(
29
- capcmd('murano', 'application', 'create', @applctn_name, '--save')
26
+ out, err = murano_command_run(
27
+ 'solution create', '--type', 'application', @applctn_name, '--save',
30
28
  )
31
29
  expect(err).to eq('')
32
- soln_id = out
33
- expect(soln_id.chomp).to match(/^[a-zA-Z0-9]+$/)
34
- expect(status.exitstatus).to eq(0)
30
+ expect(out.chomp).to match(/^[a-zA-Z0-9]+$/)
35
31
 
36
- out, err, status = Open3.capture3(capcmd('murano', 'assign', 'set'))
32
+ out, err = murano_command_run('assign set')
37
33
  #expect(out).to a_string_starting_with("Linked product #{@product_name}")
38
34
  olines = out.lines
39
35
  expect(strip_fancy(olines[0])).to eq(
@@ -41,65 +37,58 @@ RSpec.describe 'murano syncdown', :cmd, :needs_password do
41
37
  )
42
38
  expect(olines[1]).to eq("Created default event handler\n")
43
39
  expect(err).to eq('')
44
- expect(status.exitstatus).to eq(0)
40
+
41
+ # (lb): The default project directory names for routes and assets were changed,
42
+ # from routes and files, to endpoints and assets, respectively, expect we did
43
+ # not change the text fixtures, so wire the config and project config accordingly.
44
+ $cfg = MrMurano::Config.new
45
+ $cfg.load
46
+ $cfg['tool.no-progress'] = true
47
+ $cfg['eventhandler.searchFor'] = '*.lua */*.lua ../routes/*.lua ../routes/*/*.lua'
48
+ $project = MrMurano::ProjectFile.new
49
+ $project.load
50
+ $project['routes.location'] = 'routes'
51
+ $project['assets.location'] = 'files'
45
52
  end
46
53
 
47
54
  after(:example) do
48
55
  # VERIFY/2017-07-03: Skipping assign unset. Murano will clean up, right?
49
56
 
50
- out, err, status = Open3.capture3(
51
- capcmd('murano', 'solution', 'delete', '-y', @applctn_name)
57
+ out, err = murano_command_run(
58
+ 'solution delete', '-y', @applctn_name,
52
59
  )
53
60
  expect(out).to eq('')
54
61
  expect(err).to eq('')
55
- expect(status.exitstatus).to eq(0)
56
62
 
57
- out, err, status = Open3.capture3(
58
- capcmd('murano', 'solution', 'delete', '--yes', @product_name)
63
+ out, err = murano_command_run(
64
+ 'solution delete', '--yes', @product_name,
59
65
  )
60
66
  expect(out).to eq('')
61
67
  expect(err).to eq('')
62
- expect(status.exitstatus).to eq(0)
63
68
  end
64
69
 
65
70
  context 'without ProjectFile' do
66
71
  before(:example) do
67
72
  FileUtils.cp_r(File.join(@testdir, 'spec/fixtures/syncable_content/.'), '.')
68
73
  FileUtils.move('assets', 'files')
69
- #FileUtils.mkpath('specs')
70
- #FileUtils.copy(
71
- # File.join(@testdir, 'spec/fixtures/product_spec_files/lightbulb.yaml'),
72
- # 'specs/resources.yaml'
73
- #)
74
- # 2017-07-03: So long as this command does not syncdown first, these
75
- # two files -- that conflict in name with what's on the platform --
76
- # won't be a problem (but would be if we synceddown first).
74
+ # Copy the services/ directory, which includes 2 LUA files.
75
+ # 2017-07-03: So long as this command does not syncdown first, the two
76
+ # files -- that conflict in name with what's on the platform -- won't be
77
+ # a problem (but would be if we synceddown first).
77
78
  FileUtils.cp_r(File.join(@testdir, 'spec/fixtures/syncable_conflict/.'), '.')
78
79
  end
79
80
 
80
81
  it 'syncdown', :club_20s, :club_10s do
81
- out, err, status = Open3.capture3(capcmd('murano', 'syncup'))
82
- #expect(out).to eq('')
83
- #out_lines = out.lines
82
+ out, err = murano_command_run_gentle('syncup')
84
83
  out_lines = out.lines.map { |line| strip_fancy(line) }
85
84
  expect(out_lines).to match_array(
86
85
  [
87
86
  "Adding item table_util\n",
88
- #a_string_starting_with('Adding item '),
89
- #"Removing item config_service\n",
90
- #"Removing item config_status\n",
91
- #"Removing item user_account\n",
92
- #"Removing item y4y6bjfslmio00000_event\n",
93
- a_string_starting_with('Removing item '),
94
- a_string_starting_with('Removing item '),
95
- a_string_starting_with('Removing item '),
96
- a_string_starting_with('Removing item '),
97
- "Updating item timer_timer\n",
98
- #a_string_starting_with('Updating item '),
99
- #"Removing item config_service\n",
100
- #"Removing item config_status\n",
101
- a_string_starting_with('Removing item '),
102
- a_string_starting_with('Removing item '),
87
+ #"Clearing item user_account\n",
88
+ #"Clearing item y4y6bjfslmio00000_event\n",
89
+ a_string_starting_with('Clearing item '),
90
+ a_string_starting_with('Clearing item '),
91
+ "Adding item timer_timer\n",
103
92
  #"Adding item device2_event\n",
104
93
  #"Adding item POST_/api/fire\n",
105
94
  #"Adding item PUT_/api/fire/{code}\n",
@@ -118,47 +107,36 @@ RSpec.describe 'murano syncdown', :cmd, :needs_password do
118
107
  a_string_starting_with('Adding item '),
119
108
  ]
120
109
  )
121
-
122
- #expect(err).to eq('')
123
- expect(strip_fancy(err)).to start_with("\e[33mSkipping missing location '")
124
- expect(status.exitstatus).to eq(0)
110
+ expect(strip_fancy(err)).to start_with("Skipping missing location '")
125
111
 
126
112
  FileUtils.rm_r(%w[files modules routes services])
127
113
  expect(Dir['**/*']).to eq([])
128
114
 
129
- out, err, status = Open3.capture3(capcmd('murano', 'syncdown'))
130
- #expect(out).to eq('')
115
+ out, err = murano_command_run_gentle('syncdown')
131
116
  out_lines = out.lines.map { |line| strip_fancy(line) }
132
117
  expect(out_lines).to match_array(
133
118
  [
134
119
  "Updating local product resources\n",
135
120
  "Adding item table_util\n",
136
- "Adding item config_service\n",
137
- "Adding item config_status\n",
138
121
  "Adding item timer_timer\n",
139
- "Adding item config_service\n",
140
- "Adding item config_status\n",
141
122
  "Adding item POST_/api/fire\n",
142
123
  "Adding item DELETE_/api/fire/{code}\n",
143
124
  "Adding item PUT_/api/fire/{code}\n",
144
125
  "Adding item GET_/api/onfire\n",
145
126
  "Adding item /icon.png\n",
146
- # MAYBE: (lb): I just reenabled these. Is it related to MUR-6477/MUR-6479?
147
127
  "Adding item /\n",
148
128
  "Adding item /js/script.js\n",
149
129
  ]
150
130
  )
151
- expect(strip_fancy(err)).to start_with("\e[33mSkipping missing location '")
152
- expect(status.exitstatus).to eq(0)
131
+ expect(strip_fancy(err)).to start_with("Skipping missing location '")
153
132
 
154
133
  after = Dir['**/*'].sort
155
134
  expect(after).to include(
156
135
  'files',
157
136
  'files/icon.png',
158
- # 2018-04-11: So, like, where'd these go? (lb)
159
- #'files/index.html',
160
- #'files/js',
161
- #'files/js/script.js',
137
+ 'files/index.html',
138
+ 'files/js',
139
+ 'files/js/script.js',
162
140
  'modules',
163
141
  'modules/table_util.lua',
164
142
  'routes',
@@ -166,53 +144,26 @@ RSpec.describe 'murano syncdown', :cmd, :needs_password do
166
144
  'routes/api-fire-{code}.put.lua',
167
145
  'routes/api-fire.post.lua',
168
146
  'routes/api-onfire.get.lua',
169
- # 2017-07-03: services/ would not exist if we did not include
170
- # fixtures/syncable_conflict/.
171
147
  'services',
172
- # MAYBE/2018-04-11: These 2 config_* services are new; whitelist them? (lb)
173
- 'services/config_service.lua',
174
- 'services/config_status.lua',
175
- # 2017-07-13: No longer syncing device2_event; is internal to platform.
176
- #'services/device2_event.lua',
177
148
  'services/timer_timer.lua',
178
- # 2018-04-11: Well, this specs/resources.yaml is new... (lb)
179
149
  'specs',
180
150
  'specs/resources.yaml',
181
151
  )
182
152
 
183
153
  # A status should show no differences.
184
- out, err, status = Open3.capture3(capcmd('murano', 'status'))
154
+ out, err = murano_command_run_gentle('status')
185
155
  expect(err).to eq('')
186
156
  expect(out.lines).to match(
187
157
  [
188
158
  "Nothing new locally\n",
189
- # 2018-04-11: So, this is all new. Do we need to whitelist/skiplist? (lb)
190
- # Was:
191
- # "Nothing new remotely\n",
192
- # "Nothing that differs\n",
193
- # now:
194
- "Only on remote server:\n",
195
- " - I config_service\n",
196
- " - I config_status\n",
197
- "Items that differ:\n",
198
- " M S services/config_service.lua\n",
199
- " M S services/config_status.lua\n",
200
- # 2018-04-23 16:30: ???: Happening on Jenkins server:
201
- " M A files/index.html\n",
202
- " M A files/js/script.js\n",
159
+ "Nothing new remotely\n",
160
+ "Nothing that differs\n",
203
161
  ]
204
162
  )
205
- expect(status.exitstatus).to eq(0)
206
163
 
207
- out, err, status = Open3.capture3(capcmd('murano', 'diff'))
164
+ out, err = murano_command_run_gentle('status', '--diff', '--no-grouped')
208
165
  expect(err).to eq('')
209
- expect(out.lines).to match(
210
- [
211
- " - I config_service\n",
212
- " - I config_status\n",
213
- ]
214
- )
215
- expect(status.exitstatus).to eq(0)
166
+ expect(out).to eq('')
216
167
  end
217
168
  end
218
169
 
@@ -0,0 +1,858 @@
1
+ # Copyright © 2016-2017 Exosite LLC. All Rights Reserved
2
+ # License: PROPRIETARY. See LICENSE.txt.
3
+ # frozen_string_literal: true
4
+
5
+ # vim:tw=0:ts=2:sw=2:et:ai
6
+ # Unauthorized copying of this file is strictly prohibited.
7
+
8
+ # NOTE: (lb): This test mimics the sync integration test,
9
+ # cmd_syncdown_both_spec.rb, implemented as a unit test
10
+ # (by stubbing all the HTTP calls).
11
+ #
12
+ # You'll see that this is really a Big Chore.
13
+ #
14
+ # So what are the tradeoffs?
15
+ #
16
+ # - The integration test is easier to write and to maintain,
17
+ # but it takes longer to run (over 1 minute).
18
+ #
19
+ # - The unit test, on the other hand, runs almost instantaneously,
20
+ # but it's much more work to maintain, and it'll break easily if
21
+ # we make changes to any of the API calls (whereas the integration
22
+ # test doesn't have to change if the API calls change, because
23
+ # the underlying code with just handle it, and the test won't see
24
+ # any difference).
25
+ #
26
+ # Ideally, we'd use unit tests, so that tests run expediently
27
+ # (and also to enable offline development and testing). But
28
+ # because of the cost, we might just want to stick with the
29
+ # using integration tests.
30
+ #
31
+ # Although, another option might be to avoid stubbing out the
32
+ # HTTP calls in a unit test by mocking the methods that make
33
+ # those HTTP calls. But that also seems like a chore, especially
34
+ # because we'd still have to mock the various items that the
35
+ # platform returns (and which can be quite complex).
36
+ #
37
+ # So really, I don't know what the best option is. Currently,
38
+ # it's to have integration tests, and to be super annoyed that
39
+ # it takes a half hour for all tests to run; but to not be
40
+ # frustrated with maintaining a large collection of HTTP stubs.
41
+ #
42
+ # There's also the possibility of using HTTP stubs more wisely,
43
+ # e.g., we could maybe use regex to simplify them (i.e., perhaps
44
+ # we could combine all the individual eventhandler/ stubs in this
45
+ # file into a single generic stub to handle all different item types).
46
+ #
47
+ # Unfortunately, it would take time and effort to figure that out,
48
+ # and because tests already run (albeit slowly), the easiest path
49
+ # forward is the path we're already on, which is to build integration
50
+ # tests, sometimes adding another minute to the total test time,
51
+ # and not to mess around with trying to turn everything into pure,
52
+ # fast-running unit tests. (<sigh> I wish I had a better answer!)
53
+
54
+ require 'fileutils'
55
+ require 'highline'
56
+ # Set HighLine's $terminal global.
57
+ require 'highline/import'
58
+ require 'open3'
59
+ require 'webmock'
60
+
61
+ require 'cmd_common'
62
+ require 'HttpAuthed_spec.rb'
63
+
64
+ require 'MrMurano/commands/sync'
65
+
66
+ # *** Syncup mocks.
67
+
68
+ unless defined? stub_request_syncup_get_service_device2
69
+ def stub_request_syncup_get_service_device2
70
+ stub_request(
71
+ :get,
72
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/service/#{$cfg['product.id']}/device2"
73
+ ).to_return(
74
+ status: 200,
75
+ body: {
76
+ "fqdn":"#{$cfg['product.id']}.m2.exosite-staging.io","protocol":{"name":"onep","devmode":false,"port":443},"provisioning":{"auth_type":"token","enabled":true,"generate_identity":false,"presenter_identity":true,"ip_whitelisting":{"enabled":false,"allowed":[]}},"identity_format":{"prefix":"","type":"opaque","options":{"casing":"mixed","length":0}},"resources":{}
77
+ }.to_json,
78
+ headers: {}
79
+ )
80
+ end
81
+ end
82
+
83
+ unless defined? stub_request_syncup_get_application_module
84
+ def stub_request_syncup_get_application_module
85
+ stub_request(
86
+ :get,
87
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/module"
88
+ ).to_return(
89
+ status: 200,
90
+ body: {
91
+ "items":[],"total":0,"next":"/api/v1/module?query={\"solution_id\":\"#{$cfg['application.id']}\"}&limit=100&offset=100"
92
+ }.to_json,
93
+ headers: {}
94
+ )
95
+ end
96
+ end
97
+
98
+ unless defined? stub_request_syncup_put_solution_module_table_util
99
+ def stub_request_syncup_put_solution_module_table_util
100
+ stub_request(
101
+ :put,
102
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/module/#{$cfg['application.id']}_table_util"
103
+ ).with(
104
+ body: {
105
+ "name":"table_util","solution_id":"#{$cfg['application.id']}","script":"-- luacheck: ignore 122/table (This is all about modifying the table)\n\n---\n-- Dump a table as a string; recursively\n-- \\returns string\nfunction table.dump(o)\n\tif type(o) == 'table' then\n\t\tlocal s = '{ '\n\t\tfor k,v in pairs(o) do\n\t\t\tif type(k) ~= 'number' then k = '\"'..k..'\"' end\n\t\t\ts = s .. '['..k..'] = ' .. table.dump(v) .. ','\n\t\tend\n\t\treturn s .. '} '\n\telse\n\t\treturn tostring(o)\n\tend\nend\n\n---\n-- Does table have item?\nfunction table.contains(table, element)\n\tfor _, value in pairs(table) do\n\t\tif value == element then\n\t\t\treturn true\n\t\tend\n\tend\n\treturn false\nend\n\n\n---\n-- Find a table in a list of tables.\n-- \\returns idx, table found; nil if not found\nfunction table.find(tbl, key, value)\n\tif type(key) == 'nil' then return nil, nil end\n\tfor i,v in ipairs(tbl) do\n\t\tif type(v) == 'table' then\n\t\t\tif v[key] == value then\n\t\t\t\treturn i, v\n\t\t\tend\n\t\tend\n\tend\n\treturn nil, nil\nend\n\n---\n-- Replace a table\nfunction table.replacingAdd(tbl, key, newitem)\n\tlocal idx, _ = table.find(tbl, key, newitem[key])\n\tif idx == nil then\n\t\ttable.insert(tbl, newitem)\n\telse\n\t\ttable.remove(tbl, idx)\n\t\ttable.insert(tbl, idx, newitem)\n\tend\nend\n\n-- vim: set ai sw=2 ts=2 :\n","alias":"#{$cfg['application.id']}_table_util"
106
+ }.to_json
107
+ ).to_return(
108
+ status: 200,
109
+ body: {
110
+ "id":"7324f4e0-8f69-11e8-8ed7-f51bce8b98d1","source_map":{},"name":"table_util","solution_id":"#{$cfg['application.id']}","script":"-- luacheck: ignore 122/table (This is all about modifying the table)\n\n---\n-- Dump a table as a string; recursively\n-- \\returns string\nfunction table.dump(o)\n\tif type(o) == 'table' then\n\t\tlocal s = '{ '\n\t\tfor k,v in pairs(o) do\n\t\t\tif type(k) ~= 'number' then k = '\"'..k..'\"' end\n\t\t\ts = s .. '['..k..'] = ' .. table.dump(v) .. ','\n\t\tend\n\t\treturn s .. '} '\n\telse\n\t\treturn tostring(o)\n\tend\nend\n\n---\n-- Does table have item?\nfunction table.contains(table, element)\n\tfor _, value in pairs(table) do\n\t\tif value == element then\n\t\t\treturn true\n\t\tend\n\tend\n\treturn false\nend\n\n\n---\n-- Find a table in a list of tables.\n-- \\returns idx, table found; nil if not found\nfunction table.find(tbl, key, value)\n\tif type(key) == 'nil' then return nil, nil end\n\tfor i,v in ipairs(tbl) do\n\t\tif type(v) == 'table' then\n\t\t\tif v[key] == value then\n\t\t\t\treturn i, v\n\t\t\tend\n\t\tend\n\tend\n\treturn nil, nil\nend\n\n---\n-- Replace a table\nfunction table.replacingAdd(tbl, key, newitem)\n\tlocal idx, _ = table.find(tbl, key, newitem[key])\n\tif idx == nil then\n\t\ttable.insert(tbl, newitem)\n\telse\n\t\ttable.remove(tbl, idx)\n\t\ttable.insert(tbl, idx, newitem)\n\tend\nend\n\n-- vim: set ai sw=2 ts=2 :\n","alias":"#{$cfg['application.id']}_table_util","updated_at":"2018-07-24T17:46:10.094Z","created_at":"2018-07-24T17:46:10.094Z"
111
+ }.to_json,
112
+ headers: {}
113
+ )
114
+ end
115
+ end
116
+
117
+ unless defined? stub_request_syncup_get_application_eventhandler_link_event
118
+ def stub_request_syncup_get_application_eventhandler_link_event
119
+ stub_request(
120
+ :get,
121
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/eventhandler/#{$cfg['application.id']}_#{$cfg['product.id']}_event"
122
+ ).to_return(
123
+ status: 200,
124
+ body: {
125
+ "id":"4abb3140-8f69-11e8-8ed7-f51bce8b98d1","name":"#{$cfg['product.id']}_event","alias":"#{$cfg['application.id']}_#{$cfg['product.id']}_event","service":"#{$cfg['product.id']}","event":"event","solution_id":"#{$cfg['application.id']}","script":"print(event)","source_map":{},"created_at":"2018-07-24T17:45:02.292Z","updated_at":"2018-07-24T17:45:02.292Z"
126
+ }.to_json,
127
+ headers: {}
128
+ )
129
+ end
130
+ end
131
+
132
+ unless defined? stub_request_syncup_get_application_eventhandler_apiId_user_account
133
+ def stub_request_syncup_get_application_eventhandler_apiId_user_account
134
+ stub_request(
135
+ :get,
136
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/eventhandler/#{$cfg['application.id']}_user_account"
137
+ ).to_return(
138
+ {
139
+ status: 200,
140
+ body: {
141
+ "id":"47680ea0-8f69-11e8-8ed7-f51bce8b98d1","name":"user_account","alias":"#{$cfg['application.id']}_user_account","service":"user","event":"account","solution_id":"#{$cfg['application.id']}","script":"-- event\n-- .type 'CREATE' | 'DELETE' | 'UPDATE'\n-- .id User ID\n-- .email User email address\n\nif (event.type == 'CREATE') then\n -- handle user create\nend\n\nif (event.type == 'DELETE') then\n -- handle user delete\nend\n\nif (event.type == 'UPDATE') then\n -- handle user update\nend","source_map":{},"created_at":"2018-07-24T17:44:56.716Z","updated_at":"2018-07-24T17:44:56.716Z"
142
+ }.to_json,
143
+ headers: {}
144
+ },
145
+ # FIXME/2018-07-25: (lb): I disabled the syncdown code temporarily, because
146
+ # this test broke, but I want to get a release out.
147
+ #
148
+ # # Second request: After PUT <app_id>_user_account [part of syncdown]
149
+ # {
150
+ # status: 200,
151
+ # body: {
152
+ ## #"id":"9fa89af0-86c0-11e8-af9f-b1462469a93d","name":"user_account","alias":"#{$cfg['application.id']}_user_account","service":"user","event":"account","solution_id":"#{$cfg['application.id']}","script":"","source_map":{},"created_at":"2018-07-13T17:17:30.530Z","updated_at":"2018-07-13T17:18:15.129Z"
153
+ # "id":"67705400-8f5f-11e8-8ed7-f51bce8b98d1","name":"user_account","alias":"i4leq8zdz3my00000_user_account","service":"user","event":"account","solution_id":"i4leq8zdz3my00000","script":"","source_map":{},"created_at":"2018-07-24T16:34:15.490Z","updated_at":"2018-07-24T16:34:54.905Z"
154
+ # }.to_json,
155
+ # headers: {}
156
+ # }
157
+ )
158
+ end
159
+ end
160
+
161
+ unless defined? stub_request_syncup_put_application_eventhandler_user_account
162
+ def stub_request_syncup_put_application_eventhandler_user_account
163
+ stub_request(
164
+ :put,
165
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/eventhandler/#{$cfg['application.id']}_user_account"
166
+ ).with(
167
+ body: {
168
+ "alias":"#{$cfg['application.id']}_user_account","event":"account","name":"user_account","script":"","service":"user","solution_id":"#{$cfg['application.id']}"
169
+ }.to_json
170
+ ).to_return(
171
+ status: 204,
172
+ )
173
+ end
174
+ end
175
+
176
+ unless defined? stub_request_syncup_get_application_eventhandler_base_user_account
177
+ def stub_request_syncup_get_application_eventhandler_base_user_account
178
+ stub_request(
179
+ :get,
180
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/eventhandler/user_account"
181
+ ).to_return(
182
+ status: 200,
183
+ body: {
184
+ "id":"47680ea0-8f69-11e8-8ed7-f51bce8b98d1","name":"user_account","alias":"#{$cfg['application.id']}_user_account","service":"user","event":"account","solution_id":"#{$cfg['application.id']}","script":"","source_map":{},"created_at":"2018-07-24T17:44:56.716Z","updated_at":"2018-07-24T17:46:11.015Z"
185
+ }.to_json,
186
+ headers: {}
187
+ )
188
+ end
189
+ end
190
+
191
+ unless defined? stub_request_syncup_put_application_eventhandler_link_event
192
+ def stub_request_syncup_put_application_eventhandler_link_event
193
+ stub_request(
194
+ :put,
195
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/eventhandler/#{$cfg['application.id']}_#{$cfg['product.id']}_event"
196
+ ).with(
197
+ body: {
198
+ "alias":"#{$cfg['application.id']}_#{$cfg['product.id']}_event","event":"event","name":"#{$cfg['product.id']}_event","script":"","service":"#{$cfg['product.id']}","solution_id":"#{$cfg['application.id']}"
199
+ }.to_json
200
+ ).to_return(
201
+ status: 204,
202
+ )
203
+ end
204
+ end
205
+
206
+ unless defined? stub_request_syncup_get_application_eventhandler_product_event
207
+ def stub_request_syncup_get_application_eventhandler_product_event
208
+ stub_request(
209
+ :get,
210
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/eventhandler/#{$cfg['product.id']}_event"
211
+ ).to_return(
212
+ status: 200,
213
+ body: {
214
+ "id":"4abb3140-8f69-11e8-8ed7-f51bce8b98d1","name":"#{$cfg['product.id']}_event","alias":"#{$cfg['application.id']}_#{$cfg['product.id']}_event","service":"#{$cfg['product.id']}","event":"event","solution_id":"#{$cfg['application.id']}","script":"","source_map":{},"created_at":"2018-07-24T17:45:02.292Z","updated_at":"2018-07-24T17:46:11.308Z"
215
+ }.to_json,
216
+ headers: {}
217
+ )
218
+ end
219
+ end
220
+
221
+ unless defined? stub_request_syncup_put_application_eventhandler_timer_timer
222
+ def stub_request_syncup_put_application_eventhandler_timer_timer
223
+ stub_request(
224
+ :put,
225
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/eventhandler/#{$cfg['application.id']}_timer_timer"
226
+ ).with(
227
+ body: {
228
+ "event":"timer","script":"--#EVENT timer timer\n-- Nothing here.\n\n-- vim: set ai sw=2 ts=2 :\n","service":"timer","solution_id":"#{$cfg['application.id']}","alias":"#{$cfg['application.id']}_timer_timer","name":"timer_timer"
229
+ }.to_json
230
+ ).to_return(
231
+ #? WAS?: status: 204,
232
+ status: 200,
233
+ body: {
234
+ "id":"73ff7660-8f69-11e8-9add-9b37ad51f7b7","source_map":{},"event":"timer","script":"--#EVENT timer timer\n-- Nothing here.\n\n-- vim: set ai sw=2 ts=2 :\n","service":"timer","solution_id":"#{$cfg['application.id']}","name":"timer_timer","alias":"#{$cfg['application.id']}_timer_timer","updated_at":"2018-07-24T17:46:11.526Z","created_at":"2018-07-24T17:46:11.526Z"
235
+ }.to_json,
236
+ headers: {}
237
+ )
238
+ end
239
+ end
240
+
241
+ unless defined? stub_request_syncup_get_product_eventhandler
242
+ def stub_request_syncup_get_product_eventhandler
243
+ stub_request(
244
+ :get,
245
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['product.id']}/eventhandler"
246
+ ).to_return(
247
+ status: 200,
248
+ body: {
249
+ "items":[
250
+ {"id":"456fc119-8f69-11e8-9add-9b37ad51f7b7","name":"interface_updateGatewaySettings","alias":"#{$cfg['product.id']}_interface_updateGatewaySettings","solution_id":"#{$cfg['product.id']}","service":"interface","event":"updateGatewaySettings","created_at":"2018-07-24T17:44:53.415Z","updated_at":"2018-07-24T17:44:53.415Z"},
251
+ {"id":"456fc117-8f69-11e8-9add-9b37ad51f7b7","name":"interface_setIdentityState","alias":"#{$cfg['product.id']}_interface_setIdentityState","solution_id":"#{$cfg['product.id']}","service":"interface","event":"setIdentityState","created_at":"2018-07-24T17:44:53.415Z","updated_at":"2018-07-24T17:44:53.415Z"},
252
+ {"id":"456fc11a-8f69-11e8-9add-9b37ad51f7b7","name":"interface_updateIdentity","alias":"#{$cfg['product.id']}_interface_updateIdentity","solution_id":"#{$cfg['product.id']}","service":"interface","event":"updateIdentity","created_at":"2018-07-24T17:44:53.415Z","updated_at":"2018-07-24T17:44:53.415Z"},
253
+ {"id":"456fc11b-8f69-11e8-9add-9b37ad51f7b7","name":"interface_uploadContent","alias":"#{$cfg['product.id']}_interface_uploadContent","solution_id":"#{$cfg['product.id']}","service":"interface","event":"uploadContent","created_at":"2018-07-24T17:44:53.415Z","updated_at":"2018-07-24T17:44:53.415Z"},
254
+ {"id":"456fc118-8f69-11e8-9add-9b37ad51f7b7","name":"interface_updateGatewayResource","alias":"#{$cfg['product.id']}_interface_updateGatewayResource","solution_id":"#{$cfg['product.id']}","service":"interface","event":"updateGatewayResource","created_at":"2018-07-24T17:44:53.415Z","updated_at":"2018-07-24T17:44:53.415Z"},
255
+ {"id":"456f72f2-8f69-11e8-9add-9b37ad51f7b7","name":"interface_addIdentity","alias":"#{$cfg['product.id']}_interface_addIdentity","solution_id":"#{$cfg['product.id']}","service":"interface","event":"addIdentity","created_at":"2018-07-24T17:44:53.414Z","updated_at":"2018-07-24T17:44:53.414Z"},
256
+ {"id":"456f72f0-8f69-11e8-9add-9b37ad51f7b7","name":"device2_event","alias":"#{$cfg['product.id']}_device2_event","solution_id":"#{$cfg['product.id']}","service":"device2","event":"event","created_at":"2018-07-24T17:44:53.414Z","updated_at":"2018-07-24T17:44:53.414Z"},
257
+ {"id":"456f9a00-8f69-11e8-9add-9b37ad51f7b7","name":"interface_downloadContent","alias":"#{$cfg['product.id']}_interface_downloadContent","solution_id":"#{$cfg['product.id']}","service":"interface","event":"downloadContent","created_at":"2018-07-24T17:44:53.414Z","updated_at":"2018-07-24T17:44:53.414Z"},
258
+ {"id":"456f72f1-8f69-11e8-9add-9b37ad51f7b7","name":"interface_addGatewayResource","alias":"#{$cfg['product.id']}_interface_addGatewayResource","solution_id":"#{$cfg['product.id']}","service":"interface","event":"addGatewayResource","created_at":"2018-07-24T17:44:53.414Z","updated_at":"2018-07-24T17:44:53.414Z"},
259
+ {"id":"456fc112-8f69-11e8-9add-9b37ad51f7b7","name":"interface_listContent","alias":"#{$cfg['product.id']}_interface_listContent","solution_id":"#{$cfg['product.id']}","service":"interface","event":"listContent","created_at":"2018-07-24T17:44:53.414Z","updated_at":"2018-07-24T17:44:53.414Z"},
260
+ {"id":"456fc115-8f69-11e8-9add-9b37ad51f7b7","name":"interface_removeGatewayResource","alias":"#{$cfg['product.id']}_interface_removeGatewayResource","solution_id":"#{$cfg['product.id']}","service":"interface","event":"removeGatewayResource","created_at":"2018-07-24T17:44:53.414Z","updated_at":"2018-07-24T17:44:53.414Z"},
261
+ {"id":"456f72f4-8f69-11e8-9add-9b37ad51f7b7","name":"interface_deleteContent","alias":"#{$cfg['product.id']}_interface_deleteContent","solution_id":"#{$cfg['product.id']}","service":"interface","event":"deleteContent","created_at":"2018-07-24T17:44:53.414Z","updated_at":"2018-07-24T17:44:53.414Z"},
262
+ {"id":"456f9a03-8f69-11e8-9add-9b37ad51f7b7","name":"interface_getIdentity","alias":"#{$cfg['product.id']}_interface_getIdentity","solution_id":"#{$cfg['product.id']}","service":"interface","event":"getIdentity","created_at":"2018-07-24T17:44:53.414Z","updated_at":"2018-07-24T17:44:53.414Z"},
263
+ {"id":"456fc111-8f69-11e8-9add-9b37ad51f7b7","name":"interface_infoContent","alias":"#{$cfg['product.id']}_interface_infoContent","solution_id":"#{$cfg['product.id']}","service":"interface","event":"infoContent","created_at":"2018-07-24T17:44:53.414Z","updated_at":"2018-07-24T17:44:53.414Z"},
264
+ {"id":"456fc116-8f69-11e8-9add-9b37ad51f7b7","name":"interface_removeIdentity","alias":"#{$cfg['product.id']}_interface_removeIdentity","solution_id":"#{$cfg['product.id']}","service":"interface","event":"removeIdentity","created_at":"2018-07-24T17:44:53.414Z","updated_at":"2018-07-24T17:44:53.414Z"},
265
+ {"id":"456fc114-8f69-11e8-9add-9b37ad51f7b7","name":"interface_makeIdentity","alias":"#{$cfg['product.id']}_interface_makeIdentity","solution_id":"#{$cfg['product.id']}","service":"interface","event":"makeIdentity","created_at":"2018-07-24T17:44:53.414Z","updated_at":"2018-07-24T17:44:53.414Z"},
266
+ {"id":"456f9a02-8f69-11e8-9add-9b37ad51f7b7","name":"interface_getGatewaySettings","alias":"#{$cfg['product.id']}_interface_getGatewaySettings","solution_id":"#{$cfg['product.id']}","service":"interface","event":"getGatewaySettings","created_at":"2018-07-24T17:44:53.414Z","updated_at":"2018-07-24T17:44:53.414Z"},
267
+ {"id":"456f72f3-8f69-11e8-9add-9b37ad51f7b7","name":"interface_clearContent","alias":"#{$cfg['product.id']}_interface_clearContent","solution_id":"#{$cfg['product.id']}","service":"interface","event":"clearContent","created_at":"2018-07-24T17:44:53.414Z","updated_at":"2018-07-24T17:44:53.414Z"},
268
+ {"id":"456f9a01-8f69-11e8-9add-9b37ad51f7b7","name":"interface_getGatewayResource","alias":"#{$cfg['product.id']}_interface_getGatewayResource","solution_id":"#{$cfg['product.id']}","service":"interface","event":"getGatewayResource","created_at":"2018-07-24T17:44:53.414Z","updated_at":"2018-07-24T17:44:53.414Z"},
269
+ {"id":"456fc110-8f69-11e8-9add-9b37ad51f7b7","name":"interface_getIdentityState","alias":"#{$cfg['product.id']}_interface_getIdentityState","solution_id":"#{$cfg['product.id']}","service":"interface","event":"getIdentityState","created_at":"2018-07-24T17:44:53.414Z","updated_at":"2018-07-24T17:44:53.414Z"},
270
+ {"id":"456fc113-8f69-11e8-9add-9b37ad51f7b7","name":"interface_listIdentities","alias":"#{$cfg['product.id']}_interface_listIdentities","solution_id":"#{$cfg['product.id']}","service":"interface","event":"listIdentities","created_at":"2018-07-24T17:44:53.414Z","updated_at":"2018-07-24T17:44:53.414Z"}],"total":21,"next":"/api/v1/eventhandler?query={\"solution_id\":\"#{$cfg['product.id']}\"}&limit=100&offset=100"
271
+ }.to_json,
272
+ headers: {}
273
+ )
274
+ end
275
+ end
276
+
277
+ unless defined? stub_request_syncup_put_product_eventhandler_apiId_device2_event
278
+ def stub_request_syncup_put_product_eventhandler_apiId_device2_event
279
+ stub_request(
280
+ :put,
281
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['product.id']}/eventhandler/#{$cfg['product.id']}_device2_event"
282
+ ).with(
283
+ body: {
284
+ "event":"event","script":"--#EVENT device2 data_in\n-- luacheck: globals data (magic variable from Murano)\n\n-- Get the timestamp for this data if a record action.\n-- Otherwise use default (now)\nlocal stamped = nil\nif data.api == \"record\" then\n stamped = tostring(data.value[1]) .. 's'\nend\n\n-- Save it to timeseries database.\nTsdb.write{\n\ttags = {sn=data.device_sn},\n\tmetrics = {[data.alias] = tonumber(data.value[2])},\n\tts = stamped\n}\n\n-- vim: set et ai sw=2 ts=2 :\n","service":"device2","type":"data_in","solution_id":"#{$cfg['product.id']}","alias":"#{$cfg['product.id']}_device2_event","name":"device2_event"
285
+ }.to_json
286
+ ).to_return(
287
+ status: 204,
288
+ )
289
+ end
290
+ end
291
+
292
+ unless defined? stub_request_syncup_get_product_eventhandler_apiId_device2_event
293
+ def stub_request_syncup_get_product_eventhandler_apiId_device2_event
294
+ stub_request(
295
+ :get,
296
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['product.id']}/eventhandler/device2_event"
297
+ ).to_return(
298
+ status: 200,
299
+ body: {
300
+ "id":"456f72f0-8f69-11e8-9add-9b37ad51f7b7","name":"device2_event","alias":"#{$cfg['product.id']}_device2_event","service":"device2","event":"event","solution_id":"#{$cfg['product.id']}","script":"--#EVENT device2 data_in\n-- luacheck: globals data (magic variable from Murano)\n\n-- Get the timestamp for this data if a record action.\n-- Otherwise use default (now)\nlocal stamped = nil\nif data.api == \"record\" then\n stamped = tostring(data.value[1]) .. 's'\nend\n\n-- Save it to timeseries database.\nTsdb.write{\n\ttags = {sn=data.device_sn},\n\tmetrics = {[data.alias] = tonumber(data.value[2])},\n\tts = stamped\n}\n\n-- vim: set et ai sw=2 ts=2 :\n","source_map":{},"created_at":"2018-07-24T17:44:53.414Z","updated_at":"2018-07-24T17:46:11.995Z"
301
+ }.to_json,
302
+ headers: {}
303
+ )
304
+ end
305
+ end
306
+
307
+ unless defined? stub_request_syncup_get_application_endpoint
308
+ def stub_request_syncup_get_application_endpoint
309
+ stub_request(
310
+ :get,
311
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/endpoint"
312
+ ).to_return(
313
+ status: 200,
314
+ body: [].to_json,
315
+ headers: {}
316
+ )
317
+ end
318
+ end
319
+
320
+ unless defined? stub_request_syncup_post_POST_application_endpoint__api_fire
321
+ def stub_request_syncup_post_POST_application_endpoint__api_fire
322
+ stub_request(
323
+ :post,
324
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/endpoint"
325
+ ).with(
326
+ body: {
327
+ "content_type":"application/json","method":"POST","path":"/api/fire","script":"-- luacheck: globals request response (magic variables from Murano)\nresponse.code = 403\n\n"
328
+ }.to_json
329
+ ).to_return(
330
+ status: 200,
331
+ body: {
332
+ "id":"aM1H7Wr3Np"
333
+ }.to_json,
334
+ headers: {}
335
+ )
336
+ end
337
+ end
338
+
339
+ unless defined? stub_request_syncup_post_PUT_application_endpoint__api_fire_code
340
+ def stub_request_syncup_post_PUT_application_endpoint__api_fire_code
341
+ stub_request(
342
+ :post,
343
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/endpoint"
344
+ ).with(
345
+ body: {
346
+ "content_type":"application/json","method":"PUT","path":"/api/fire/{code}","script":"response.code = 500\n\n"
347
+ }.to_json
348
+ ).to_return(
349
+ status: 200,
350
+ body: {
351
+ "id":"XSfnyTpMgu"
352
+ }.to_json,
353
+ headers: {}
354
+ )
355
+ end
356
+ end
357
+
358
+ unless defined? stub_request_syncup_post_DELETE_application_endpoint__api_fire_code
359
+ def stub_request_syncup_post_DELETE_application_endpoint__api_fire_code
360
+ stub_request(
361
+ :post,
362
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/endpoint"
363
+ ).with(
364
+ body: {
365
+ "content_type":"application/json","method":"DELETE","path":"/api/fire/{code}","script":"return 'ok'\n\n-- vim: set ai sw=2 ts=2 :\n"
366
+ }.to_json
367
+ ).to_return(
368
+ status: 200,
369
+ body: {
370
+ "id":"RqpwtvYOVM"
371
+ }.to_json,
372
+ headers: {}
373
+ )
374
+ end
375
+ end
376
+
377
+ unless defined? stub_request_syncup_post_GET_application_endpoint__api_fire
378
+ def stub_request_syncup_post_GET_application_endpoint__api_fire
379
+ stub_request(
380
+ :post,
381
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/endpoint"
382
+ ).with(
383
+ body: {
384
+ "content_type":"application/json","method":"GET","path":"/api/onfire","script":"-- luacheck: globals request response (magic variables from Murano)\n\nreturn 'no'\n-- vim: set ai sw=2 ts=2 :\n"
385
+ }.to_json
386
+ ).to_return(
387
+ status: 200,
388
+ body: {
389
+ "id":"WWblIzv3DN"
390
+ }.to_json,
391
+ headers: {}
392
+ )
393
+ end
394
+ end
395
+
396
+ unless defined? stub_request_syncup_get_application_file
397
+ def stub_request_syncup_get_application_file
398
+ stub_request(
399
+ :get,
400
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/file"
401
+ ).to_return(
402
+ status: 200,
403
+ body: [].to_json,
404
+ headers: {}
405
+ )
406
+ end
407
+ end
408
+
409
+ unless defined? stub_request_syncup_put_product_fileupload_icon_png
410
+ def stub_request_syncup_put_product_fileupload_icon_png
411
+ stub_request(
412
+ :put,
413
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/fileupload/icon.png"
414
+ ).to_return(
415
+ status: 204,
416
+ )
417
+ end
418
+ end
419
+
420
+ unless defined? stub_request_syncup_put_product_fileupload_index_html
421
+ def stub_request_syncup_put_product_fileupload_index_html
422
+ stub_request(
423
+ :put,
424
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/fileupload/"
425
+ ).to_return(
426
+ status: 204,
427
+ )
428
+ end
429
+ end
430
+
431
+ unless defined? stub_request_syncup_put_product_fileupload_js_script_js
432
+ def stub_request_syncup_put_product_fileupload_js_script_js
433
+ stub_request(
434
+ :put,
435
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/fileupload/js%2Fscript.js"
436
+ ).to_return(
437
+ status: 204,
438
+ )
439
+ end
440
+ end
441
+
442
+ unless defined? stub_request_syncup_get_application_eventhandler
443
+ def stub_request_syncup_get_application_eventhandler
444
+ stub_request(
445
+ :get,
446
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/eventhandler"
447
+ ).to_return(
448
+ status: 200,
449
+ # FIXME/2018-07-24 10:11: (lb): What happened to this very long response?
450
+ body: "",
451
+ headers: {}
452
+ )
453
+ end
454
+ end
455
+
456
+ # *** Syncdown mocks.
457
+
458
+ # ##########################################################
459
+ # # #
460
+ # # FIXME/2018-07-25: (lb): Fix the following, eventually. #
461
+ # # (What's above is syncup; What's below is syncdown.) #
462
+ # # #
463
+ # ##########################################################
464
+
465
+ unless defined? stub_request_syncup_get_application_eventhandler_base_user_account
466
+ def stub_request_syncup_get_application_eventhandler_base_user_account
467
+ stub_request(
468
+ :get,
469
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/eventhandler/#{$cfg['application.id']}_user_account"
470
+ ).with(
471
+ body: {
472
+ "id":"5ff5e1c0-8f52-11e8-8ed7-f51bce8b98d1","name":"user_account","alias":"h1q4sci7fk1xc0000_user_account","service":"user","event":"account","solution_id":"h1q4sci7fk1xc0000","script":"-- event\n-- .type 'CREATE' | 'DELETE' | 'UPDATE'\n-- .id User ID\n-- .email User email address\n\nif (event.type == 'CREATE') then\n -- handle user create\nend\n\nif (event.type == 'DELETE') then\n -- handle user delete\nend\n\nif (event.type == 'UPDATE') then\n -- handle user update\nend","source_map":{},"created_at":"2018-07-24T15:00:59.487Z","updated_at":"2018-07-24T15:00:59.487Z"
473
+ }.to_json
474
+ ).to_return(
475
+ status: 204,
476
+ )
477
+ end
478
+ end
479
+
480
+ unless defined? stub_request_syncup_get_application_eventhandler_timer_timer
481
+ def stub_request_syncup_get_application_eventhandler_timer_timer
482
+ stub_request(
483
+ :get,
484
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/eventhandler/#{$cfg['application.id']}_timer_timer"
485
+ ).to_return(
486
+ status: 200,
487
+ body: {
488
+ "id":"9fa89af3-86c0-11e8-af9f-b1462469a93d","name":"timer_timer","alias":"#{$cfg['application.id']}_timer_timer","service":"timer","event":"timer","solution_id":"#{$cfg['application.id']}","script":"","source_map":{},"created_at":"2018-07-13T17:17:30.530Z","updated_at":"2018-07-13T17:17:30.530Z"
489
+ }.to_json,
490
+ headers: {}
491
+ )
492
+ end
493
+ end
494
+
495
+ unless defined? stub_request_syncup_get_application_eventhandler_tsdb_exportJob
496
+ def stub_request_syncup_get_application_eventhandler_tsdb_exportJob
497
+ stub_request(
498
+ :get,
499
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/eventhandler/#{$cfg['application.id']}_tsdb_exportJob"
500
+ ).to_return(
501
+ status: 200,
502
+ body: {
503
+ "id":"9fa89af6-86c0-11e8-af9f-b1462469a93d","name":"tsdb_exportJob","alias":"#{$cfg['application.id']}_tsdb_exportJob","service":"tsdb","event":"exportJob","solution_id":"#{$cfg['application.id']}","script":"","source_map":{},"created_at":"2018-07-13T17:17:30.530Z","updated_at":"2018-07-13T17:17:30.530Z"
504
+ }.to_json,
505
+ headers: {}
506
+ )
507
+ end
508
+ end
509
+
510
+ unless defined? stub_request_syncup_put_application_eventhandler_apiId_config_service
511
+ def stub_request_syncup_put_application_eventhandler_apiId_config_service
512
+ stub_request(
513
+ :put,
514
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/eventhandler/#{$cfg['application.id']}_config_service"
515
+ ).with(
516
+ body: {
517
+ "alias": "#{$cfg['application.id']}_config_service",
518
+ "created_at": "2018-07-13T17:17:30.530Z",
519
+ "event": "service",
520
+ "id": "9fa89af5-86c0-11e8-af9f-b1462469a93d",
521
+ "name": "config_service",
522
+ "script": "",
523
+ "service": "config",
524
+ "solution_id": "#{$cfg['application.id']}",
525
+ "synckey": "config_service",
526
+ "synctype": "Service",
527
+ "updated_at": "2018-07-13T17:17:30.530Z"
528
+ }.to_json
529
+ ).to_return(
530
+ status: 204,
531
+ )
532
+ end
533
+ end
534
+
535
+ unless defined? stub_request_syncup_get_application_eventhandler_config_service
536
+ def stub_request_syncup_get_application_eventhandler_config_service
537
+ stub_request(
538
+ :get,
539
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/eventhandler/config_service"
540
+
541
+ ).to_return(
542
+ status: 200,
543
+ body: {
544
+ "id":"9fa89af5-86c0-11e8-af9f-b1462469a93d","name":"config_service","alias":"#{$cfg['application.id']}_config_service","service":"config","event":"service","solution_id":"#{$cfg['application.id']}","script":"","source_map":{},"created_at":"2018-07-13T17:17:30.530Z","updated_at":"2018-07-13T17:18:13.558Z"
545
+ }.to_json,
546
+ headers: {}
547
+ )
548
+ end
549
+ end
550
+
551
+ unless defined? stub_request_syncup_put_application_eventhandler_apiId_config_status
552
+ def stub_request_syncup_put_application_eventhandler_apiId_config_status
553
+ stub_request(
554
+ :put,
555
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/eventhandler/#{$cfg['application.id']}_config_status"
556
+ ).with(
557
+ body: {
558
+ "alias": "#{$cfg['application.id']}_config_status",
559
+ "created_at": "2018-07-13T17:17:30.530Z",
560
+ "event": "status",
561
+ "id": "9fa89af4-86c0-11e8-af9f-b1462469a93d",
562
+ "name": "config_status",
563
+ "script": "",
564
+ "service": "config",
565
+ "solution_id": "#{$cfg['application.id']}",
566
+ "synckey": "config_status",
567
+ "synctype": "Service",
568
+ "updated_at": "2018-07-13T17:17:30.530Z"
569
+ }.to_json
570
+ ).to_return(
571
+ status: 204,
572
+ )
573
+ end
574
+ end
575
+
576
+ unless defined? stub_request_syncup_get_application_eventhandler_config_status
577
+ def stub_request_syncup_get_application_eventhandler_config_status
578
+ stub_request(
579
+ :get,
580
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/eventhandler/config_status"
581
+ ).to_return(
582
+ status: 200,
583
+ body: {
584
+ "id":"9fa89af4-86c0-11e8-af9f-b1462469a93d","name":"config_status","alias":"#{$cfg['application.id']}_config_status","service":"config","event":"status","solution_id":"#{$cfg['application.id']}","script":"","source_map":{},"created_at":"2018-07-13T17:17:30.530Z","updated_at":"2018-07-13T17:18:14.218Z"
585
+ }.to_json,
586
+ headers: {}
587
+ )
588
+ end
589
+ end
590
+
591
+ unless defined? stub_request_syncup_get_application_eventhandler_base_timer_timer
592
+ def stub_request_syncup_get_application_eventhandler_base_timer_timer
593
+ stub_request(
594
+ :get,
595
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/eventhandler/timer_timer"
596
+ ).to_return(
597
+ status: 200,
598
+ body: {
599
+ "id":"9fa89af3-86c0-11e8-af9f-b1462469a93d","name":"timer_timer","alias":"#{$cfg['application.id']}_timer_timer","service":"timer","event":"timer","solution_id":"#{$cfg['application.id']}","script":"--#EVENT timer timer\n-- Nothing here.\n\n-- vim: set ai sw=2 ts=2 :\n","source_map":{},"created_at":"2018-07-13T17:17:30.530Z","updated_at":"2018-07-13T17:18:17.771Z"
600
+ }.to_json,
601
+ headers: {}
602
+ )
603
+ end
604
+ end
605
+
606
+ unless defined? stub_request_syncup_put_product_eventhandler_apiId_config_service
607
+ def stub_request_syncup_put_product_eventhandler_apiId_config_service
608
+ stub_request(
609
+ :put,
610
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['product.id']}/eventhandler/#{$cfg['product.id']}_config_service"
611
+ ).with(
612
+ body: {
613
+ "alias":"#{$cfg['product.id']}_config_service","created_at":"2018-07-13T17:17:25.570Z","event":"service","id":"9cb376d1-86c0-11e8-bdf5-0747b0df3eb6","name":"config_service","script":"","service":"config","solution_id":"#{$cfg['product.id']}","synckey":"config_service","synctype":"Interface","updated_at":"2018-07-13T17:17:25.570Z"
614
+ }.to_json
615
+ ).to_return(
616
+ status: 204,
617
+ )
618
+ end
619
+ end
620
+
621
+ unless defined? stub_request_syncup_put_product_eventhandler_apiId_config_status
622
+ def stub_request_syncup_put_product_eventhandler_apiId_config_status
623
+ stub_request(
624
+ :put,
625
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['product.id']}/eventhandler/#{$cfg['product.id']}_config_status"
626
+ ).with(
627
+ body: {
628
+ "alias":"#{$cfg['product.id']}_config_status","created_at":"2018-07-13T17:17:25.570Z","event":"status","id":"9cb376d0-86c0-11e8-bdf5-0747b0df3eb6","name":"config_status","script":"","service":"config","solution_id":"#{$cfg['product.id']}","synckey":"config_status","synctype":"Interface","updated_at":"2018-07-13T17:17:25.570Z"
629
+ }.to_json
630
+ ).to_return(
631
+ status: 204,
632
+ )
633
+ end
634
+ end
635
+
636
+ unless defined? stub_request_syncup_get_product_eventhandler_config_service
637
+ def stub_request_syncup_get_product_eventhandler_config_service
638
+ stub_request(
639
+ :get,
640
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['product.id']}/eventhandler/config_service"
641
+ ).to_return(
642
+ status: 200,
643
+ body: {
644
+ "id":"9cb376d1-86c0-11e8-bdf5-0747b0df3eb6","name":"config_service","alias":"#{$cfg['product.id']}_config_service","service":"config","event":"service","solution_id":"#{$cfg['product.id']}","script":"","source_map":{},"created_at":"2018-07-13T17:17:25.570Z","updated_at":"2018-07-13T17:18:19.109Z"
645
+ }.to_json,
646
+ headers: {}
647
+ )
648
+ end
649
+ end
650
+
651
+ unless defined? stub_request_syncup_get_product_eventhandler_config_status
652
+ def stub_request_syncup_get_product_eventhandler_config_status
653
+ stub_request(
654
+ :get,
655
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['product.id']}/eventhandler/config_status"
656
+ ).to_return(
657
+ status: 200,
658
+ body: {
659
+ "id":"9cb376d0-86c0-11e8-bdf5-0747b0df3eb6","name":"config_status","alias":"#{$cfg['product.id']}_config_status","service":"config","event":"status","solution_id":"#{$cfg['product.id']}","script":"","source_map":{},"created_at":"2018-07-13T17:17:25.570Z","updated_at":"2018-07-13T17:18:19.705Z"
660
+ }.to_json,
661
+ headers: {}
662
+ )
663
+ end
664
+ end
665
+
666
+ unless defined? stub_request_syncup_post_PUT_application_endpoint__api_fire
667
+ def stub_request_syncup_post_PUT_application_endpoint__api_fire
668
+ stub_request(
669
+ :post,
670
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/endpoint"
671
+ ).with(
672
+ body: {
673
+ "content_type":"application/json","method":"POST","path":"/api/fire","script":"-- luacheck: globals request response (magic variables from Murano)\nresponse.code = 403\n\n"
674
+ }.to_json
675
+ ).to_return(
676
+ status: 200,
677
+ body: {
678
+ "id":"iWy4ayrPFT"
679
+ }.to_json,
680
+ headers: {}
681
+ )
682
+ end
683
+ end
684
+
685
+ unless defined? stub_request_syncup_put_product_fileupload_root
686
+ def stub_request_syncup_put_product_fileupload_root
687
+ stub_request(
688
+ :put,
689
+ "#{$cfg['net.protocol']}://#{$cfg['net.host']}/api:1/solution/#{$cfg['application.id']}/fileupload/"
690
+ ).to_return(
691
+ status: 204,
692
+ )
693
+ end
694
+ end
695
+
696
+ # *** WebMock Setup
697
+
698
+ unless defined? stub_request_content_conflict_syncup
699
+ def stub_request_content_conflict_syncup
700
+ WebMock.disable_net_connect!
701
+
702
+ stub_request_syncup_get_service_device2
703
+ stub_request_syncup_get_application_module
704
+ stub_request_syncup_put_solution_module_table_util
705
+ stub_request_syncup_get_application_eventhandler_link_event
706
+ stub_request_syncup_get_application_eventhandler_apiId_user_account
707
+ stub_request_syncup_put_application_eventhandler_user_account
708
+ stub_request_syncup_get_application_eventhandler_base_user_account
709
+ stub_request_syncup_put_application_eventhandler_link_event
710
+ stub_request_syncup_get_application_eventhandler_product_event
711
+ stub_request_syncup_put_application_eventhandler_timer_timer
712
+ stub_request_syncup_get_product_eventhandler
713
+ stub_request_syncup_put_product_eventhandler_apiId_device2_event
714
+ stub_request_syncup_get_product_eventhandler_apiId_device2_event
715
+ stub_request_syncup_get_application_endpoint
716
+ stub_request_syncup_post_POST_application_endpoint__api_fire
717
+ stub_request_syncup_post_PUT_application_endpoint__api_fire_code
718
+ stub_request_syncup_post_DELETE_application_endpoint__api_fire_code
719
+ stub_request_syncup_post_GET_application_endpoint__api_fire
720
+ stub_request_syncup_get_application_file
721
+ stub_request_syncup_put_product_fileupload_icon_png
722
+ stub_request_syncup_put_product_fileupload_index_html
723
+ stub_request_syncup_put_product_fileupload_js_script_js
724
+
725
+ stub_request_syncup_get_application_eventhandler
726
+
727
+ # FIXME/2018-07-25: (lb): In the interest of time, I disabled the
728
+ # syncdown part of this test, so currently this tests just runs
729
+ # syncup. (See cmd_syncdown_both_spec.rb, which runs the sequence:
730
+ # syncup; remove local files; syncdown; status & diff.
731
+ if false
732
+ stub_request_syncup_get_application_eventhandler_timer_timer
733
+ stub_request_syncup_get_application_eventhandler_tsdb_exportJob
734
+ stub_request_syncup_put_application_eventhandler_apiId_config_service
735
+ stub_request_syncup_get_application_eventhandler_config_service
736
+ stub_request_syncup_put_application_eventhandler_apiId_config_status
737
+ stub_request_syncup_get_application_eventhandler_config_status
738
+ stub_request_syncup_get_application_eventhandler_base_timer_timer
739
+ stub_request_syncup_put_product_eventhandler_apiId_config_service
740
+ stub_request_syncup_put_product_eventhandler_apiId_config_status
741
+
742
+ stub_request_syncup_get_product_eventhandler_config_service
743
+ stub_request_syncup_get_product_eventhandler_config_status
744
+
745
+ stub_request_syncup_post_PUT_application_endpoint__api_fire
746
+
747
+ stub_request_syncup_put_product_fileupload_root
748
+ end
749
+ end
750
+ end
751
+
752
+ RSpec.describe 'murano syncdown stubbed', :cmd, :needs_password do
753
+ include_context 'CI_CMD'
754
+
755
+ before(:example) do
756
+ $cfg = MrMurano::Config.new
757
+ $cfg.load
758
+
759
+ $cfg['user.name'] = 'BoB@place.net'
760
+ # Skipping: net.protocol, net.host
761
+ $cfg['business.id'] = 'BBBBBBBB'
762
+ $cfg['product.id'] = 'PPPPPPPP'
763
+ $cfg['application.id'] = 'AAAAAAAA'
764
+
765
+ # So that progress gets reported as succinct strings on stdout.
766
+ $cfg['tool.no-progress'] = true
767
+
768
+ # (lb): The default project directory names for routes and assets were changed,
769
+ # from routes and files, to endpoints and assets, respectively, expect we did
770
+ # not change the text fixtures, so wire the config and project config accordingly.
771
+ $cfg['eventhandler.searchFor'] = "*.lua */*.lua ../routes/*.lua ../routes/*/*.lua"
772
+ $project = MrMurano::ProjectFile.new
773
+ $project.load
774
+ $project['routes.location'] = 'routes'
775
+ $project['assets.location'] = 'files'
776
+
777
+ # Stub the multitude of API calls that get made.
778
+ WebMock.reset!
779
+ stub_request_email_password
780
+ stub_request_content_conflict_syncup
781
+ end
782
+
783
+ after(:example) do
784
+ WebMock.reset!
785
+ end
786
+
787
+ context 'without ProjectFile' do
788
+ before(:example) do
789
+ FileUtils.cp_r(File.join(@testdir, 'spec/fixtures/syncable_content/.'), '.')
790
+ FileUtils.move('assets', 'files')
791
+ FileUtils.cp_r(File.join(@testdir, 'spec/fixtures/syncable_conflict/.'), '.')
792
+ end
793
+
794
+ def stdio_capture
795
+ tmpout = StringIO.new
796
+ tmperr = StringIO.new
797
+
798
+ # Commander's `say` calls HighLine's $terminal.say, so redirect that, too.
799
+ hline = HighLine.new($stdin, tmpout)
800
+ $terminal = hline
801
+
802
+ @murcli_wasout = $stdout
803
+ @murcli_waserr = $stderr
804
+ $stdout = tmpout
805
+ $stderr = tmperr
806
+ end
807
+
808
+ def stdio_release
809
+ out = $stdout.string
810
+ err = $stderr.string
811
+
812
+ $stdout = @murcli_wasout
813
+ $stderr = @murcli_waserr
814
+
815
+ return out, err
816
+ end
817
+
818
+ it 'syncdown', :club_20s, :club_10s do
819
+ stdio_capture
820
+
821
+ # (lb): Here's what cmd_syncdown_both_spec calls:
822
+ # out, err, status = Open3.capture3(capcmd('murano', 'syncup'))
823
+ # Here, we skip the wrapper, and just call syncup_files directly.
824
+ options = { delete: true, create: true, update: true }
825
+
826
+ syncup_files(options, [])
827
+
828
+ out, err = stdio_release
829
+
830
+ out_lines = out.lines.map { |line| strip_fancy(line) }
831
+ expect(out_lines).to match_array(
832
+ [
833
+ "Adding item table_util\n",
834
+ "Adding item timer_timer\n",
835
+ "Adding item device2_event\n",
836
+ "Adding item POST_/api/fire\n",
837
+ "Adding item PUT_/api/fire/{code}\n",
838
+ "Adding item DELETE_/api/fire/{code}\n",
839
+ "Adding item GET_/api/onfire\n",
840
+ "Adding item /icon.png\n",
841
+ "Adding item /\n",
842
+ "Adding item /js/script.js\n",
843
+ ]
844
+ )
845
+
846
+ expect(strip_fancy(err)).to start_with("\e[33mSkipping missing location '")
847
+
848
+ # (lb): The integration test on which this unit test is based [originally
849
+ # copied from], cmd_syncdown_both_spec.rb, does additional work, like
850
+ # removing all local files and running syncdown again, but I'm stopping
851
+ # here. Maintaining this file -- stubbing all the HTTP requests -- is
852
+ # really a pain, and does not seem like a worthwhile endeavour. (Unless
853
+ # we come up with a shortcut, such as making more generic stubs to replace
854
+ # all the specific stubs, e.g., using regex in the stub_request calls.)
855
+ end
856
+ end
857
+ end
858
+