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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+