appium 2.0.0-beta.20 → 2.0.0-beta.24

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 (90) hide show
  1. package/README.md +1 -2
  2. package/build/check-npm-pack-files.js +23 -0
  3. package/build/commands-yml/parse.js +319 -0
  4. package/build/commands-yml/validator.js +130 -0
  5. package/build/index.js +19 -0
  6. package/build/lib/appium.js +22 -7
  7. package/build/lib/cli/args.js +13 -15
  8. package/build/lib/cli/npm.js +27 -16
  9. package/build/lib/cli/parser.js +7 -3
  10. package/build/lib/config.js +27 -47
  11. package/build/lib/extension-config.js +1 -1
  12. package/build/lib/main.js +29 -28
  13. package/build/lib/plugin-config.js +2 -2
  14. package/build/lib/plugins.js +4 -2
  15. package/build/lib/schema/appium-config-schema.js +3 -2
  16. package/build/lib/schema/arg-spec.js +5 -3
  17. package/build/lib/schema/cli-args.js +25 -16
  18. package/build/lib/schema/keywords.js +14 -4
  19. package/build/lib/schema/schema.js +80 -9
  20. package/build/lib/utils.js +16 -36
  21. package/build/postinstall.js +90 -0
  22. package/build/test/cli/cli-e2e-specs.js +221 -0
  23. package/build/test/cli/cli-helpers.js +86 -0
  24. package/build/test/cli/cli-specs.js +71 -0
  25. package/build/test/cli/fixtures/test-driver/package.json +27 -0
  26. package/build/test/cli/schema-args-specs.js +48 -0
  27. package/build/test/cli/schema-e2e-specs.js +47 -0
  28. package/build/test/config-e2e-specs.js +112 -0
  29. package/build/test/config-file-e2e-specs.js +209 -0
  30. package/build/test/config-file-specs.js +281 -0
  31. package/build/test/config-specs.js +246 -0
  32. package/build/test/driver-e2e-specs.js +435 -0
  33. package/build/test/driver-specs.js +386 -0
  34. package/build/test/ext-config-io-specs.js +181 -0
  35. package/build/test/extension-config-specs.js +365 -0
  36. package/build/test/fixtures/allow-feat.txt +5 -0
  37. package/build/test/fixtures/caps.json +3 -0
  38. package/build/test/fixtures/config/allow-insecure.txt +3 -0
  39. package/build/test/fixtures/config/appium.config.bad-nodeconfig.json +5 -0
  40. package/build/test/fixtures/config/appium.config.bad.json +32 -0
  41. package/build/test/fixtures/config/appium.config.ext-good.json +9 -0
  42. package/build/test/fixtures/config/appium.config.ext-unknown-props.json +10 -0
  43. package/build/test/fixtures/config/appium.config.good.js +40 -0
  44. package/build/test/fixtures/config/appium.config.good.json +33 -0
  45. package/build/test/fixtures/config/appium.config.good.yaml +30 -0
  46. package/build/test/fixtures/config/appium.config.invalid.json +31 -0
  47. package/build/test/fixtures/config/appium.config.security-array.json +5 -0
  48. package/build/test/fixtures/config/appium.config.security-delimited.json +5 -0
  49. package/build/test/fixtures/config/appium.config.security-path.json +5 -0
  50. package/build/test/fixtures/config/driver-fake.config.json +8 -0
  51. package/build/test/fixtures/config/nodeconfig.json +3 -0
  52. package/build/test/fixtures/config/plugin-fake.config.json +0 -0
  53. package/build/test/fixtures/default-args.js +35 -0
  54. package/build/test/fixtures/deny-feat.txt +5 -0
  55. package/build/test/fixtures/driver.schema.js +20 -0
  56. package/build/test/fixtures/extensions.yaml +27 -0
  57. package/build/test/fixtures/flattened-schema.js +532 -0
  58. package/build/test/fixtures/plugin.schema.js +20 -0
  59. package/build/test/fixtures/schema-with-extensions.js +28 -0
  60. package/build/test/grid-register-specs.js +74 -0
  61. package/build/test/helpers.js +75 -0
  62. package/build/test/logger-specs.js +76 -0
  63. package/build/test/npm-specs.js +20 -0
  64. package/build/test/parser-specs.js +319 -0
  65. package/build/test/plugin-e2e-specs.js +316 -0
  66. package/build/test/schema/arg-spec-specs.js +70 -0
  67. package/build/test/schema/cli-args-specs.js +408 -0
  68. package/build/test/schema/schema-specs.js +407 -0
  69. package/build/test/utils-specs.js +288 -0
  70. package/index.js +11 -0
  71. package/lib/appium-config.schema.json +2 -1
  72. package/lib/appium.js +51 -8
  73. package/lib/cli/args.js +17 -14
  74. package/lib/cli/npm.js +68 -6
  75. package/lib/cli/parser.js +5 -2
  76. package/lib/config.js +72 -54
  77. package/lib/extension-config.js +1 -1
  78. package/lib/main.js +93 -40
  79. package/lib/plugin-config.js +1 -1
  80. package/lib/plugins.js +2 -0
  81. package/lib/schema/appium-config-schema.js +1 -0
  82. package/lib/schema/arg-spec.js +12 -2
  83. package/lib/schema/cli-args.js +22 -34
  84. package/lib/schema/keywords.js +20 -4
  85. package/lib/schema/schema.js +142 -22
  86. package/lib/utils.js +28 -29
  87. package/package.json +10 -14
  88. package/types/types.d.ts +5 -0
  89. package/build/lib/cli/argparse-actions.js +0 -104
  90. package/lib/cli/argparse-actions.js +0 -77
@@ -0,0 +1,288 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ require("source-map-support/register");
6
+
7
+ var _utils = require("../lib/utils");
8
+
9
+ var _helpers = require("./helpers");
10
+
11
+ var _lodash = _interopRequireDefault(require("lodash"));
12
+
13
+ var _colors = require("@dabh/colors");
14
+
15
+ var _sinon = _interopRequireDefault(require("sinon"));
16
+
17
+ var _logger = _interopRequireDefault(require("../lib/logger"));
18
+
19
+ describe('utils', function () {
20
+ describe('parseCapsForInnerDriver()', function () {
21
+ it('should return an error if only JSONWP provided', function () {
22
+ let {
23
+ error,
24
+ protocol
25
+ } = (0, _utils.parseCapsForInnerDriver)(_helpers.BASE_CAPS);
26
+ protocol.should.equal('W3C');
27
+ error.message.should.match(/W3C/);
28
+ });
29
+ it('should return W3C caps unchanged if only W3C caps were provided', function () {
30
+ let {
31
+ desiredCaps,
32
+ processedJsonwpCapabilities,
33
+ processedW3CCapabilities,
34
+ protocol
35
+ } = (0, _utils.parseCapsForInnerDriver)(undefined, _helpers.W3C_CAPS);
36
+ desiredCaps.should.deep.equal(_helpers.BASE_CAPS);
37
+ should.not.exist(processedJsonwpCapabilities);
38
+ processedW3CCapabilities.should.deep.equal(_helpers.W3C_CAPS);
39
+ protocol.should.equal('W3C');
40
+ });
41
+ it('should return JSONWP and W3C caps if both were provided', function () {
42
+ let {
43
+ desiredCaps,
44
+ processedJsonwpCapabilities,
45
+ processedW3CCapabilities,
46
+ protocol
47
+ } = (0, _utils.parseCapsForInnerDriver)(_helpers.BASE_CAPS, _helpers.W3C_CAPS);
48
+ desiredCaps.should.deep.equal(_helpers.BASE_CAPS);
49
+ processedJsonwpCapabilities.should.deep.equal(_helpers.BASE_CAPS);
50
+ processedW3CCapabilities.should.deep.equal(_helpers.W3C_CAPS);
51
+ protocol.should.equal('W3C');
52
+ });
53
+ it('should include default capabilities in results', function () {
54
+ const defaultW3CCaps = {
55
+ 'appium:foo': 'bar',
56
+ 'appium:baz': 'bla'
57
+ };
58
+ const expectedDefaultCaps = {
59
+ foo: 'bar',
60
+ baz: 'bla'
61
+ };
62
+ const {
63
+ desiredCaps,
64
+ processedJsonwpCapabilities,
65
+ processedW3CCapabilities
66
+ } = (0, _utils.parseCapsForInnerDriver)(_helpers.BASE_CAPS, _helpers.W3C_CAPS, {}, defaultW3CCaps);
67
+ desiredCaps.should.deep.equal({ ...expectedDefaultCaps,
68
+ ..._helpers.BASE_CAPS
69
+ });
70
+ processedJsonwpCapabilities.should.deep.equal({ ...expectedDefaultCaps,
71
+ ..._helpers.BASE_CAPS
72
+ });
73
+ processedW3CCapabilities.alwaysMatch.should.deep.equal({ ...(0, _utils.insertAppiumPrefixes)(expectedDefaultCaps),
74
+ ...(0, _utils.insertAppiumPrefixes)(_helpers.BASE_CAPS)
75
+ });
76
+ });
77
+ it('should allow valid default capabilities', function () {
78
+ const res = (0, _utils.parseCapsForInnerDriver)(null, _helpers.W3C_CAPS, {}, {
79
+ 'appium:foo': 'bar2'
80
+ });
81
+ res.processedW3CCapabilities.alwaysMatch['appium:foo'].should.eql('bar2');
82
+ });
83
+ it('should not allow invalid default capabilities', function () {
84
+ const res = (0, _utils.parseCapsForInnerDriver)(null, _helpers.W3C_CAPS, {}, {
85
+ foo: 'bar',
86
+ 'appium:foo2': 'bar2'
87
+ });
88
+ res.error.should.eql({
89
+ jsonwpCode: 61,
90
+ error: 'invalid argument',
91
+ w3cStatus: 400,
92
+ _stacktrace: null
93
+ });
94
+ });
95
+ it('should reject if W3C caps are not passing constraints', function () {
96
+ const err = (0, _utils.parseCapsForInnerDriver)(undefined, _helpers.W3C_CAPS, {
97
+ hello: {
98
+ presence: true
99
+ }
100
+ }).error;
101
+ err.message.should.match(/'hello' can't be blank/);
102
+ _lodash.default.isError(err).should.be.true;
103
+ });
104
+ it('should only accept W3C caps that have passing constraints', function () {
105
+ let w3cCaps = { ..._helpers.W3C_CAPS,
106
+ firstMatch: [{
107
+ foo: 'bar'
108
+ }, {
109
+ 'appium:hello': 'world'
110
+ }]
111
+ };
112
+ (0, _utils.parseCapsForInnerDriver)(_helpers.BASE_CAPS, w3cCaps, {
113
+ hello: {
114
+ presence: true
115
+ }
116
+ }).error.should.eql({
117
+ jsonwpCode: 61,
118
+ error: 'invalid argument',
119
+ w3cStatus: 400,
120
+ _stacktrace: null
121
+ });
122
+ });
123
+ it('should add appium prefixes to W3C caps that are not standard in W3C', function () {
124
+ (0, _utils.parseCapsForInnerDriver)(undefined, {
125
+ alwaysMatch: {
126
+ platformName: 'Fake',
127
+ propertyName: 'PROP_NAME'
128
+ }
129
+ }).error.error.should.includes('invalid argument');
130
+ });
131
+ });
132
+ describe('removeAppiumPrefixes()', function () {
133
+ it('should remove appium prefixes from cap names', function () {
134
+ (0, _utils.removeAppiumPrefixes)({
135
+ 'appium:cap1': 'value1',
136
+ 'ms:cap2': 'value2',
137
+ someCap: 'someCap'
138
+ }).should.eql({
139
+ 'cap1': 'value1',
140
+ 'ms:cap2': 'value2',
141
+ someCap: 'someCap'
142
+ });
143
+ });
144
+ });
145
+ describe('insertAppiumPrefixes()', function () {
146
+ it('should apply prefixes to non-standard capabilities', function () {
147
+ (0, _utils.insertAppiumPrefixes)({
148
+ someCap: 'someCap'
149
+ }).should.deep.equal({
150
+ 'appium:someCap': 'someCap'
151
+ });
152
+ });
153
+ it('should not apply prefixes to standard capabilities', function () {
154
+ (0, _utils.insertAppiumPrefixes)({
155
+ browserName: 'BrowserName',
156
+ platformName: 'PlatformName'
157
+ }).should.deep.equal({
158
+ browserName: 'BrowserName',
159
+ platformName: 'PlatformName'
160
+ });
161
+ });
162
+ it('should not apply prefixes to capabilities that already have a prefix', function () {
163
+ (0, _utils.insertAppiumPrefixes)({
164
+ 'appium:someCap': 'someCap',
165
+ 'moz:someOtherCap': 'someOtherCap'
166
+ }).should.deep.equal({
167
+ 'appium:someCap': 'someCap',
168
+ 'moz:someOtherCap': 'someOtherCap'
169
+ });
170
+ });
171
+ it('should apply prefixes to non-prefixed, non-standard capabilities; should not apply prefixes to any other capabilities', function () {
172
+ (0, _utils.insertAppiumPrefixes)({
173
+ 'appium:someCap': 'someCap',
174
+ 'moz:someOtherCap': 'someOtherCap',
175
+ browserName: 'BrowserName',
176
+ platformName: 'PlatformName',
177
+ someOtherCap: 'someOtherCap',
178
+ yetAnotherCap: 'yetAnotherCap'
179
+ }).should.deep.equal({
180
+ 'appium:someCap': 'someCap',
181
+ 'moz:someOtherCap': 'someOtherCap',
182
+ browserName: 'BrowserName',
183
+ platformName: 'PlatformName',
184
+ 'appium:someOtherCap': 'someOtherCap',
185
+ 'appium:yetAnotherCap': 'yetAnotherCap'
186
+ });
187
+ });
188
+ });
189
+ describe('pullSettings()', function () {
190
+ it('should pull settings from caps', function () {
191
+ const caps = {
192
+ platformName: 'foo',
193
+ browserName: 'bar',
194
+ 'settings[settingName]': 'baz',
195
+ 'settings[settingName2]': 'baz2'
196
+ };
197
+ const settings = (0, _utils.pullSettings)(caps);
198
+ settings.should.eql({
199
+ settingName: 'baz',
200
+ settingName2: 'baz2'
201
+ });
202
+ caps.should.eql({
203
+ platformName: 'foo',
204
+ browserName: 'bar'
205
+ });
206
+ });
207
+ it('should pull settings dict if object values are present in caps', function () {
208
+ const caps = {
209
+ platformName: 'foo',
210
+ browserName: 'bar',
211
+ 'settings[settingName]': {
212
+ key: 'baz'
213
+ }
214
+ };
215
+ const settings = (0, _utils.pullSettings)(caps);
216
+ settings.should.eql({
217
+ settingName: {
218
+ key: 'baz'
219
+ }
220
+ });
221
+ caps.should.eql({
222
+ platformName: 'foo',
223
+ browserName: 'bar'
224
+ });
225
+ });
226
+ it('should pull empty dict if no settings are present in caps', function () {
227
+ const caps = {
228
+ platformName: 'foo',
229
+ browserName: 'bar',
230
+ 'setting[settingName]': 'baz'
231
+ };
232
+ const settings = (0, _utils.pullSettings)(caps);
233
+ settings.should.eql({});
234
+ caps.should.eql({
235
+ platformName: 'foo',
236
+ browserName: 'bar',
237
+ 'setting[settingName]': 'baz'
238
+ });
239
+ });
240
+ it('should pull empty dict if caps are empty', function () {
241
+ const caps = {};
242
+ const settings = (0, _utils.pullSettings)(caps);
243
+ settings.should.eql({});
244
+ caps.should.eql({});
245
+ });
246
+ });
247
+ describe('ReadonlyMap', function () {
248
+ it('should allow writing', function () {
249
+ const map = new _utils.ReadonlyMap();
250
+ (() => map.set('foo', 'bar')).should.not.throw();
251
+ });
252
+ it('should allow reading', function () {
253
+ const map = new _utils.ReadonlyMap([['foo', 'bar']]);
254
+ (() => map.get('foo')).should.not.throw();
255
+ });
256
+ it('should not allow deletion', function () {
257
+ const map = new _utils.ReadonlyMap([['foo', 'bar']]);
258
+ map.delete('foo').should.be.false;
259
+ });
260
+ it('should not allow clearing', function () {
261
+ const map = new _utils.ReadonlyMap([['foo', 'bar']]);
262
+ (() => map.clear()).should.throw();
263
+ });
264
+ it('should not allow updating', function () {
265
+ const map = new _utils.ReadonlyMap([['foo', 'bar']]);
266
+ (() => map.set('foo', 'baz')).should.throw();
267
+ });
268
+ });
269
+ describe('inspect()', function () {
270
+ let sandbox;
271
+ beforeEach(function () {
272
+ sandbox = _sinon.default.createSandbox();
273
+ sandbox.spy(_logger.default, 'info');
274
+ });
275
+ afterEach(function () {
276
+ sandbox.restore();
277
+ });
278
+ it('should log the result of inspecting a value', function () {
279
+ (0, _utils.inspect)({
280
+ foo: 'bar'
281
+ });
282
+ (0, _colors.stripColors)(_logger.default.info.firstCall.firstArg).should.equal('{ foo: \'bar\' }');
283
+ });
284
+ });
285
+ });require('source-map-support').install();
286
+
287
+
288
+ //# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvdXRpbHMtc3BlY3MuanMiXSwibmFtZXMiOlsiZGVzY3JpYmUiLCJpdCIsImVycm9yIiwicHJvdG9jb2wiLCJCQVNFX0NBUFMiLCJzaG91bGQiLCJlcXVhbCIsIm1lc3NhZ2UiLCJtYXRjaCIsImRlc2lyZWRDYXBzIiwicHJvY2Vzc2VkSnNvbndwQ2FwYWJpbGl0aWVzIiwicHJvY2Vzc2VkVzNDQ2FwYWJpbGl0aWVzIiwidW5kZWZpbmVkIiwiVzNDX0NBUFMiLCJkZWVwIiwibm90IiwiZXhpc3QiLCJkZWZhdWx0VzNDQ2FwcyIsImV4cGVjdGVkRGVmYXVsdENhcHMiLCJmb28iLCJiYXoiLCJhbHdheXNNYXRjaCIsInJlcyIsImVxbCIsImpzb253cENvZGUiLCJ3M2NTdGF0dXMiLCJfc3RhY2t0cmFjZSIsImVyciIsImhlbGxvIiwicHJlc2VuY2UiLCJfIiwiaXNFcnJvciIsImJlIiwidHJ1ZSIsInczY0NhcHMiLCJmaXJzdE1hdGNoIiwicGxhdGZvcm1OYW1lIiwicHJvcGVydHlOYW1lIiwiaW5jbHVkZXMiLCJzb21lQ2FwIiwiYnJvd3Nlck5hbWUiLCJzb21lT3RoZXJDYXAiLCJ5ZXRBbm90aGVyQ2FwIiwiY2FwcyIsInNldHRpbmdzIiwic2V0dGluZ05hbWUiLCJzZXR0aW5nTmFtZTIiLCJrZXkiLCJtYXAiLCJSZWFkb25seU1hcCIsInNldCIsInRocm93IiwiZ2V0IiwiZGVsZXRlIiwiZmFsc2UiLCJjbGVhciIsInNhbmRib3giLCJiZWZvcmVFYWNoIiwic2lub24iLCJjcmVhdGVTYW5kYm94Iiwic3B5IiwibG9nZ2VyIiwiYWZ0ZXJFYWNoIiwicmVzdG9yZSIsImluZm8iLCJmaXJzdENhbGwiLCJmaXJzdEFyZyJdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUE7O0FBSUE7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBRUFBLFFBQVEsQ0FBQyxPQUFELEVBQVUsWUFBWTtBQUM1QkEsRUFBQUEsUUFBUSxDQUFDLDJCQUFELEVBQThCLFlBQVk7QUFD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QywyQkFBRCxFQUE4QixZQUFZO0FBQzFDLFlBQU0rQyxHQUFHLEdBQUcsSUFBSUMsa0JBQUosQ0FBZ0IsQ0FBQyxDQUFDLEtBQUQsRUFBUSxLQUFSLENBQUQsQ0FBaEIsQ0FBWjtBQUNBLE9BQUMsTUFBTUQsR0FBRyxDQUFDRSxHQUFKLENBQVEsS0FBUixFQUFlLEtBQWYsQ0FBUCxFQUE4QjdDLE1BQTlCLENBQXFDOEMsS0FBckM7QUFDRCxLQUhDLENBQUY7QUFJRCxHQTFCTyxDQUFSO0FBNEJBbkQsRUFBQUEsUUFBUSxDQUFDLFdBQUQsRUFBYyxZQUFZO0FBS2hDLFFBQUl3RCxPQUFKO0FBQ0FDLElBQUFBLFVBQVUsQ0FBQyxZQUFZO0FBQ3JCRCxNQUFBQSxPQUFPLEdBQUdFLGVBQU1DLGFBQU4sRUFBVjtBQUNBSCxNQUFBQSxPQUFPLENBQUNJLEdBQVIsQ0FBWUMsZUFBWixFQUFvQixNQUFwQjtBQUNELEtBSFMsQ0FBVjtBQUtBQyxJQUFBQSxTQUFTLENBQUMsWUFBWTtBQUNwQk4sTUFBQUEsT0FBTyxDQUFDTyxPQUFSO0FBQ0QsS0FGUSxDQUFUO0FBSUE5RCxJQUFBQSxFQUFFLENBQUMsNkNBQUQsRUFBZ0QsWUFBWTtBQUM1RCwwQkFBUTtBQUFDa0IsUUFBQUEsR0FBRyxFQUFFO0FBQU4sT0FBUjtBQUNBLCtCQUFxRDBDLGdCQUFPRyxJQUFSLENBQWNDLFNBQWQsQ0FBd0JDLFFBQTVFLEVBQ0c3RCxNQURILENBQ1VDLEtBRFYsQ0FDZ0Isa0JBRGhCO0FBRUQsS0FKQyxDQUFGO0FBS0QsR0FwQk8sQ0FBUjtBQXFCRCxDQTdQTyxDQUFSIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgcGFyc2VDYXBzRm9ySW5uZXJEcml2ZXIsIGluc2VydEFwcGl1bVByZWZpeGVzLCBwdWxsU2V0dGluZ3MsXG4gIHJlbW92ZUFwcGl1bVByZWZpeGVzLCBSZWFkb25seU1hcCwgaW5zcGVjdFxufSBmcm9tICcuLi9saWIvdXRpbHMnO1xuaW1wb3J0IHsgQkFTRV9DQVBTLCBXM0NfQ0FQUyB9IGZyb20gJy4vaGVscGVycyc7XG5pbXBvcnQgXyBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IHsgc3RyaXBDb2xvcnMgfSBmcm9tICdAZGFiaC9jb2xvcnMnO1xuaW1wb3J0IHNpbm9uIGZyb20gJ3Npbm9uJztcbmltcG9ydCBsb2dnZXIgZnJvbSAnLi4vbGliL2xvZ2dlcic7XG5cbmRlc2NyaWJlKCd1dGlscycsIGZ1bmN0aW9uICgpIHtcbiAgZGVzY3JpYmUoJ3BhcnNlQ2Fwc0ZvcklubmVyRHJpdmVyKCknLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3Nob3VsZCByZXR1cm4gYW4gZXJyb3IgaWYgb25seSBKU09OV1AgcHJvdmlkZWQnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBsZXQge2Vycm9yLCBwcm90b2NvbH0gPSBwYXJzZUNhcHNGb3JJbm5lckRyaXZlcihCQVNFX0NBUFMpO1xuICAgICAgcHJvdG9jb2wuc2hvdWxkLmVxdWFsKCdXM0MnKTtcbiAgICAgIGVycm9yLm1lc3NhZ2Uuc2hvdWxkLm1hdGNoKC9XM0MvKTtcbiAgICB9KTtcbiAgICBpdCgnc2hvdWxkIHJldHVybiBXM0MgY2FwcyB1bmNoYW5nZWQgaWYgb25seSBXM0MgY2FwcyB3ZXJlIHByb3ZpZGVkJywgZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IHtkZXNpcmVkQ2FwcywgcHJvY2Vzc2VkSnNvbndwQ2FwYWJpbGl0aWVzLCBwcm9jZXNzZWRXM0NDYXBhYmlsaXRpZXMsIHByb3RvY29sfSA9IHBhcnNlQ2Fwc0ZvcklubmVyRHJpdmVyKHVuZGVmaW5lZCwgVzNDX0NBUFMpO1xuICAgICAgZGVzaXJlZENhcHMuc2hvdWxkLmRlZXAuZXF1YWwoQkFTRV9DQVBTKTtcbiAgICAgIHNob3VsZC5ub3QuZXhpc3QocHJvY2Vzc2VkSnNvbndwQ2FwYWJpbGl0aWVzKTtcbiAgICAgIHByb2Nlc3NlZFczQ0NhcGFiaWxpdGllcy5zaG91bGQuZGVlcC5lcXVhbChXM0NfQ0FQUyk7XG4gICAgICBwcm90b2NvbC5zaG91bGQuZXF1YWwoJ1czQycpO1xuICAgIH0pO1xuICAgIGl0KCdzaG91bGQgcmV0dXJuIEpTT05XUCBhbmQgVzNDIGNhcHMgaWYgYm90aCB3ZXJlIHByb3ZpZGVkJywgZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IHtkZXNpcmVkQ2FwcywgcHJvY2Vzc2VkSnNvbndwQ2FwYWJpbGl0aWVzLCBwcm9jZXNzZWRXM0NDYXBhYmlsaXRpZXMsIHByb3RvY29sfSA9IHBhcnNlQ2Fwc0ZvcklubmVyRHJpdmVyKEJBU0VfQ0FQUywgVzNDX0NBUFMpO1xuICAgICAgZGVzaXJlZENhcHMuc2hvdWxkLmRlZXAuZXF1YWwoQkFTRV9DQVBTKTtcbiAgICAgIHByb2Nlc3NlZEpzb253cENhcGFiaWxpdGllcy5zaG91bGQuZGVlcC5lcXVhbChCQVNFX0NBUFMpO1xuICAgICAgcHJvY2Vzc2VkVzNDQ2FwYWJpbGl0aWVzLnNob3VsZC5kZWVwLmVxdWFsKFczQ19DQVBTKTtcbiAgICAgIHByb3RvY29sLnNob3VsZC5lcXVhbCgnVzNDJyk7XG4gICAgfSk7XG4gICAgaXQoJ3Nob3VsZCBpbmNsdWRlIGRlZmF1bHQgY2FwYWJpbGl0aWVzIGluIHJlc3VsdHMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBkZWZhdWx0VzNDQ2FwcyA9IHtcbiAgICAgICAgJ2FwcGl1bTpmb28nOiAnYmFyJyxcbiAgICAgICAgJ2FwcGl1bTpiYXonOiAnYmxhJyxcbiAgICAgIH07XG4gICAgICBjb25zdCBleHBlY3RlZERlZmF1bHRDYXBzID0ge1xuICAgICAgICBmb286ICdiYXInLFxuICAgICAgICBiYXo6ICdibGEnLFxuICAgICAgfTtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgZGVzaXJlZENhcHMsXG4gICAgICAgIHByb2Nlc3NlZEpzb253cENhcGFiaWxpdGllcyxcbiAgICAgICAgcHJvY2Vzc2VkVzNDQ2FwYWJpbGl0aWVzXG4gICAgICB9ID0gcGFyc2VDYXBzRm9ySW5uZXJEcml2ZXIoQkFTRV9DQVBTLCBXM0NfQ0FQUywge30sIGRlZmF1bHRXM0NDYXBzKTtcbiAgICAgIGRlc2lyZWRDYXBzLnNob3VsZC5kZWVwLmVxdWFsKHtcbiAgICAgICAgLi4uZXhwZWN0ZWREZWZhdWx0Q2FwcyxcbiAgICAgICAgLi4uQkFTRV9DQVBTLFxuICAgICAgfSk7XG4gICAgICBwcm9jZXNzZWRKc29ud3BDYXBhYmlsaXRpZXMuc2hvdWxkLmRlZXAuZXF1YWwoe1xuICAgICAgICAuLi5leHBlY3RlZERlZmF1bHRDYXBzLFxuICAgICAgICAuLi5CQVNFX0NBUFNcbiAgICAgIH0pO1xuICAgICAgcHJvY2Vzc2VkVzNDQ2FwYWJpbGl0aWVzLmFsd2F5c01hdGNoLnNob3VsZC5kZWVwLmVxdWFsKHtcbiAgICAgICAgLi4uaW5zZXJ0QXBwaXVtUHJlZml4ZXMoZXhwZWN0ZWREZWZhdWx0Q2FwcyksXG4gICAgICAgIC4uLmluc2VydEFwcGl1bVByZWZpeGVzKEJBU0VfQ0FQUylcbiAgICAgIH0pO1xuICAgIH0pO1xuICAgIGl0KCdzaG91bGQgYWxsb3cgdmFsaWQgZGVmYXVsdCBjYXBhYmlsaXRpZXMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCByZXMgPSBwYXJzZUNhcHNGb3JJbm5lckRyaXZlcihudWxsLCBXM0NfQ0FQUywge30sIHtcbiAgICAgICAgJ2FwcGl1bTpmb28nOiAnYmFyMicsXG4gICAgICB9KTtcbiAgICAgIHJlcy5wcm9jZXNzZWRXM0NDYXBhYmlsaXRpZXMuYWx3YXlzTWF0Y2hbJ2FwcGl1bTpmb28nXS5zaG91bGQuZXFsKCdiYXIyJyk7XG4gICAgfSk7XG4gICAgaXQoJ3Nob3VsZCBub3QgYWxsb3cgaW52YWxpZCBkZWZhdWx0IGNhcGFiaWxpdGllcycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHJlcyA9IHBhcnNlQ2Fwc0ZvcklubmVyRHJpdmVyKG51bGwsIFczQ19DQVBTLCB7fSwge1xuICAgICAgICBmb286ICdiYXInLCAnYXBwaXVtOmZvbzInOiAnYmFyMicsXG4gICAgICB9KTtcbiAgICAgIHJlcy5lcnJvci5zaG91bGQuZXFsKHtcbiAgICAgICAganNvbndwQ29kZTogNjEsIGVycm9yOiAnaW52YWxpZCBhcmd1bWVudCcsIHczY1N0YXR1czogNDAwLCBfc3RhY2t0cmFjZTogbnVsbFxuICAgICAgfSk7XG4gICAgfSk7XG4gICAgaXQoJ3Nob3VsZCByZWplY3QgaWYgVzNDIGNhcHMgYXJlIG5vdCBwYXNzaW5nIGNvbnN0cmFpbnRzJywgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgZXJyID0gcGFyc2VDYXBzRm9ySW5uZXJEcml2ZXIodW5kZWZpbmVkLCBXM0NfQ0FQUywge2hlbGxvOiB7cHJlc2VuY2U6IHRydWV9fSkuZXJyb3I7XG4gICAgICBlcnIubWVzc2FnZS5zaG91bGQubWF0Y2goLydoZWxsbycgY2FuJ3QgYmUgYmxhbmsvKTtcbiAgICAgIF8uaXNFcnJvcihlcnIpLnNob3VsZC5iZS50cnVlO1xuXG4gICAgfSk7XG4gICAgaXQoJ3Nob3VsZCBvbmx5IGFjY2VwdCBXM0MgY2FwcyB0aGF0IGhhdmUgcGFzc2luZyBjb25zdHJhaW50cycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGxldCB3M2NDYXBzID0ge1xuICAgICAgICAuLi5XM0NfQ0FQUyxcbiAgICAgICAgZmlyc3RNYXRjaDogW1xuICAgICAgICAgIHtmb286ICdiYXInfSxcbiAgICAgICAgICB7J2FwcGl1bTpoZWxsbyc6ICd3b3JsZCd9LFxuICAgICAgICBdLFxuICAgICAgfTtcbiAgICAgIHBhcnNlQ2Fwc0ZvcklubmVyRHJpdmVyKEJBU0VfQ0FQUywgdzNjQ2Fwcywge2hlbGxvOiB7cHJlc2VuY2U6IHRydWV9fSkuZXJyb3Iuc2hvdWxkLmVxbCh7XG4gICAgICAgIGpzb253cENvZGU6IDYxLCBlcnJvcjogJ2ludmFsaWQgYXJndW1lbnQnLCB3M2NTdGF0dXM6IDQwMCwgX3N0YWNrdHJhY2U6IG51bGxcbiAgICAgIH0pO1xuICAgIH0pO1xuICAgIGl0KCdzaG91bGQgYWRkIGFwcGl1bSBwcmVmaXhlcyB0byBXM0MgY2FwcyB0aGF0IGFyZSBub3Qgc3RhbmRhcmQgaW4gVzNDJywgZnVuY3Rpb24gKCkge1xuICAgICAgcGFyc2VDYXBzRm9ySW5uZXJEcml2ZXIodW5kZWZpbmVkLCB7XG4gICAgICAgIGFsd2F5c01hdGNoOiB7XG4gICAgICAgICAgcGxhdGZvcm1OYW1lOiAnRmFrZScsXG4gICAgICAgICAgcHJvcGVydHlOYW1lOiAnUFJPUF9OQU1FJyxcbiAgICAgICAgfSxcbiAgICAgIH0pLmVycm9yLmVycm9yLnNob3VsZC5pbmNsdWRlcygnaW52YWxpZCBhcmd1bWVudCcpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgncmVtb3ZlQXBwaXVtUHJlZml4ZXMoKScsIGZ1bmN0aW9uICgpIHtcbiAgICBpdCgnc2hvdWxkIHJlbW92ZSBhcHBpdW0gcHJlZml4ZXMgZnJvbSBjYXAgbmFtZXMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICByZW1vdmVBcHBpdW1QcmVmaXhlcyh7XG4gICAgICAgICdhcHBpdW06Y2FwMSc6ICd2YWx1ZTEnLFxuICAgICAgICAnbXM6Y2FwMic6ICd2YWx1ZTInLFxuICAgICAgICBzb21lQ2FwOiAnc29tZUNhcCcsXG4gICAgICB9KS5zaG91bGQuZXFsKHtcbiAgICAgICAgJ2NhcDEnOiAndmFsdWUxJyxcbiAgICAgICAgJ21zOmNhcDInOiAndmFsdWUyJyxcbiAgICAgICAgc29tZUNhcDogJ3NvbWVDYXAnLFxuICAgICAgfSk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdpbnNlcnRBcHBpdW1QcmVmaXhlcygpJywgZnVuY3Rpb24gKCkge1xuICAgIGl0KCdzaG91bGQgYXBwbHkgcHJlZml4ZXMgdG8gbm9uLXN0YW5kYXJkIGNhcGFiaWxpdGllcycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGluc2VydEFwcGl1bVByZWZpeGVzKHtcbiAgICAgICAgc29tZUNhcDogJ3NvbWVDYXAnLFxuICAgICAgfSkuc2hvdWxkLmRlZXAuZXF1YWwoe1xuICAgICAgICAnYXBwaXVtOnNvbWVDYXAnOiAnc29tZUNhcCcsXG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBpdCgnc2hvdWxkIG5vdCBhcHBseSBwcmVmaXhlcyB0byBzdGFuZGFyZCBjYXBhYmlsaXRpZXMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBpbnNlcnRBcHBpdW1QcmVmaXhlcyh7XG4gICAgICAgIGJyb3dzZXJOYW1lOiAnQnJvd3Nlck5hbWUnLFxuICAgICAgICBwbGF0Zm9ybU5hbWU6ICdQbGF0Zm9ybU5hbWUnLFxuICAgICAgfSkuc2hvdWxkLmRlZXAuZXF1YWwoe1xuICAgICAgICBicm93c2VyTmFtZTogJ0Jyb3dzZXJOYW1lJyxcbiAgICAgICAgcGxhdGZvcm1OYW1lOiAnUGxhdGZvcm1OYW1lJyxcbiAgICAgIH0pO1xuICAgIH0pO1xuICAgIGl0KCdzaG91bGQgbm90IGFwcGx5IHByZWZpeGVzIHRvIGNhcGFiaWxpdGllcyB0aGF0IGFscmVhZHkgaGF2ZSBhIHByZWZpeCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGluc2VydEFwcGl1bVByZWZpeGVzKHtcbiAgICAgICAgJ2FwcGl1bTpzb21lQ2FwJzogJ3NvbWVDYXAnLFxuICAgICAgICAnbW96OnNvbWVPdGhlckNhcCc6ICdzb21lT3RoZXJDYXAnLFxuICAgICAgfSkuc2hvdWxkLmRlZXAuZXF1YWwoe1xuICAgICAgICAnYXBwaXVtOnNvbWVDYXAnOiAnc29tZUNhcCcsXG4gICAgICAgICdtb3o6c29tZU90aGVyQ2FwJzogJ3NvbWVPdGhlckNhcCcsXG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBpdCgnc2hvdWxkIGFwcGx5IHByZWZpeGVzIHRvIG5vbi1wcmVmaXhlZCwgbm9uLXN0YW5kYXJkIGNhcGFiaWxpdGllczsgc2hvdWxkIG5vdCBhcHBseSBwcmVmaXhlcyB0byBhbnkgb3RoZXIgY2FwYWJpbGl0aWVzJywgZnVuY3Rpb24gKCkge1xuICAgICAgaW5zZXJ0QXBwaXVtUHJlZml4ZXMoe1xuICAgICAgICAnYXBwaXVtOnNvbWVDYXAnOiAnc29tZUNhcCcsXG4gICAgICAgICdtb3o6c29tZU90aGVyQ2FwJzogJ3NvbWVPdGhlckNhcCcsXG4gICAgICAgIGJyb3dzZXJOYW1lOiAnQnJvd3Nlck5hbWUnLFxuICAgICAgICBwbGF0Zm9ybU5hbWU6ICdQbGF0Zm9ybU5hbWUnLFxuICAgICAgICBzb21lT3RoZXJDYXA6ICdzb21lT3RoZXJDYXAnLFxuICAgICAgICB5ZXRBbm90aGVyQ2FwOiAneWV0QW5vdGhlckNhcCcsXG4gICAgICB9KS5zaG91bGQuZGVlcC5lcXVhbCh7XG4gICAgICAgICdhcHBpdW06c29tZUNhcCc6ICdzb21lQ2FwJyxcbiAgICAgICAgJ21vejpzb21lT3RoZXJDYXAnOiAnc29tZU90aGVyQ2FwJyxcbiAgICAgICAgYnJvd3Nlck5hbWU6ICdCcm93c2VyTmFtZScsXG4gICAgICAgIHBsYXRmb3JtTmFtZTogJ1BsYXRmb3JtTmFtZScsXG4gICAgICAgICdhcHBpdW06c29tZU90aGVyQ2FwJzogJ3NvbWVPdGhlckNhcCcsXG4gICAgICAgICdhcHBpdW06eWV0QW5vdGhlckNhcCc6ICd5ZXRBbm90aGVyQ2FwJyxcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgncHVsbFNldHRpbmdzKCknLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3Nob3VsZCBwdWxsIHNldHRpbmdzIGZyb20gY2FwcycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGNhcHMgPSB7XG4gICAgICAgIHBsYXRmb3JtTmFtZTogJ2ZvbycsXG4gICAgICAgIGJyb3dzZXJOYW1lOiAnYmFyJyxcbiAgICAgICAgJ3NldHRpbmdzW3NldHRpbmdOYW1lXSc6ICdiYXonLFxuICAgICAgICAnc2V0dGluZ3Nbc2V0dGluZ05hbWUyXSc6ICdiYXoyJyxcbiAgICAgIH07XG4gICAgICBjb25zdCBzZXR0aW5ncyA9IHB1bGxTZXR0aW5ncyhjYXBzKTtcbiAgICAgIHNldHRpbmdzLnNob3VsZC5lcWwoe1xuICAgICAgICBzZXR0aW5nTmFtZTogJ2JheicsXG4gICAgICAgIHNldHRpbmdOYW1lMjogJ2JhejInLFxuICAgICAgfSk7XG4gICAgICBjYXBzLnNob3VsZC5lcWwoe1xuICAgICAgICBwbGF0Zm9ybU5hbWU6ICdmb28nLFxuICAgICAgICBicm93c2VyTmFtZTogJ2JhcicsXG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBpdCgnc2hvdWxkIHB1bGwgc2V0dGluZ3MgZGljdCBpZiBvYmplY3QgdmFsdWVzIGFyZSBwcmVzZW50IGluIGNhcHMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBjYXBzID0ge1xuICAgICAgICBwbGF0Zm9ybU5hbWU6ICdmb28nLFxuICAgICAgICBicm93c2VyTmFtZTogJ2JhcicsXG4gICAgICAgICdzZXR0aW5nc1tzZXR0aW5nTmFtZV0nOiB7a2V5OiAnYmF6J30sXG4gICAgICB9O1xuICAgICAgY29uc3Qgc2V0dGluZ3MgPSBwdWxsU2V0dGluZ3MoY2Fwcyk7XG4gICAgICBzZXR0aW5ncy5zaG91bGQuZXFsKHtcbiAgICAgICAgc2V0dGluZ05hbWU6IHtrZXk6ICdiYXonfSxcbiAgICAgIH0pO1xuICAgICAgY2Fwcy5zaG91bGQuZXFsKHtcbiAgICAgICAgcGxhdGZvcm1OYW1lOiAnZm9vJyxcbiAgICAgICAgYnJvd3Nlck5hbWU6ICdiYXInLFxuICAgICAgfSk7XG4gICAgfSk7XG4gICAgaXQoJ3Nob3VsZCBwdWxsIGVtcHR5IGRpY3QgaWYgbm8gc2V0dGluZ3MgYXJlIHByZXNlbnQgaW4gY2FwcycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGNhcHMgPSB7XG4gICAgICAgIHBsYXRmb3JtTmFtZTogJ2ZvbycsXG4gICAgICAgIGJyb3dzZXJOYW1lOiAnYmFyJyxcbiAgICAgICAgJ3NldHRpbmdbc2V0dGluZ05hbWVdJzogJ2JheicsXG4gICAgICB9O1xuICAgICAgY29uc3Qgc2V0dGluZ3MgPSBwdWxsU2V0dGluZ3MoY2Fwcyk7XG4gICAgICBzZXR0aW5ncy5zaG91bGQuZXFsKHt9KTtcbiAgICAgIGNhcHMuc2hvdWxkLmVxbCh7XG4gICAgICAgIHBsYXRmb3JtTmFtZTogJ2ZvbycsXG4gICAgICAgIGJyb3dzZXJOYW1lOiAnYmFyJyxcbiAgICAgICAgJ3NldHRpbmdbc2V0dGluZ05hbWVdJzogJ2JheicsXG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBpdCgnc2hvdWxkIHB1bGwgZW1wdHkgZGljdCBpZiBjYXBzIGFyZSBlbXB0eScsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGNhcHMgPSB7fTtcbiAgICAgIGNvbnN0IHNldHRpbmdzID0gcHVsbFNldHRpbmdzKGNhcHMpO1xuICAgICAgc2V0dGluZ3Muc2hvdWxkLmVxbCh7fSk7XG4gICAgICBjYXBzLnNob3VsZC5lcWwoe30pO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnUmVhZG9ubHlNYXAnLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3Nob3VsZCBhbGxvdyB3cml0aW5nJywgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgbWFwID0gbmV3IFJlYWRvbmx5TWFwKCk7XG4gICAgICAoKCkgPT4gbWFwLnNldCgnZm9vJywgJ2JhcicpKS5zaG91bGQubm90LnRocm93KCk7XG5cbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgYWxsb3cgcmVhZGluZycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IG1hcCA9IG5ldyBSZWFkb25seU1hcChbWydmb28nLCAnYmFyJ11dKTtcbiAgICAgICgoKSA9PiBtYXAuZ2V0KCdmb28nKSkuc2hvdWxkLm5vdC50aHJvdygpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBub3QgYWxsb3cgZGVsZXRpb24nLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBtYXAgPSBuZXcgUmVhZG9ubHlNYXAoW1snZm9vJywgJ2JhciddXSk7XG4gICAgICBtYXAuZGVsZXRlKCdmb28nKS5zaG91bGQuYmUuZmFsc2U7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIG5vdCBhbGxvdyBjbGVhcmluZycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IG1hcCA9IG5ldyBSZWFkb25seU1hcChbWydmb28nLCAnYmFyJ11dKTtcbiAgICAgICgoKSA9PiBtYXAuY2xlYXIoKSkuc2hvdWxkLnRocm93KCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIG5vdCBhbGxvdyB1cGRhdGluZycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IG1hcCA9IG5ldyBSZWFkb25seU1hcChbWydmb28nLCAnYmFyJ11dKTtcbiAgICAgICgoKSA9PiBtYXAuc2V0KCdmb28nLCAnYmF6JykpLnNob3VsZC50aHJvdygpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnaW5zcGVjdCgpJywgZnVuY3Rpb24gKCkge1xuXG4gICAgLyoqXG4gICAgICogQHR5cGUge2ltcG9ydCgnc2lub24nKS5TaW5vblNhbmRib3h9XG4gICAgICovXG4gICAgbGV0IHNhbmRib3g7XG4gICAgYmVmb3JlRWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICBzYW5kYm94ID0gc2lub24uY3JlYXRlU2FuZGJveCgpO1xuICAgICAgc2FuZGJveC5zcHkobG9nZ2VyLCAnaW5mbycpO1xuICAgIH0pO1xuXG4gICAgYWZ0ZXJFYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgIHNhbmRib3gucmVzdG9yZSgpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBsb2cgdGhlIHJlc3VsdCBvZiBpbnNwZWN0aW5nIGEgdmFsdWUnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBpbnNwZWN0KHtmb286ICdiYXInfSk7XG4gICAgICBzdHJpcENvbG9ycygvKiogQHR5cGUge2ltcG9ydCgnc2lub24nKS5TaW5vblN0dWJ9ICovKGxvZ2dlci5pbmZvKS5maXJzdENhbGwuZmlyc3RBcmcpXG4gICAgICAgIC5zaG91bGQuZXF1YWwoJ3sgZm9vOiBcXCdiYXJcXCcgfScpO1xuICAgIH0pO1xuICB9KTtcbn0pO1xuIl0sImZpbGUiOiJ0ZXN0L3V0aWxzLXNwZWNzLmpzIiwic291cmNlUm9vdCI6Ii4uLy4uIn0=
package/index.js ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+
3
+ const {asyncify} = require('asyncbox');
4
+
5
+ const appium = require('./build/lib/main.js');
6
+
7
+ if (require.main === module) {
8
+ asyncify(appium.main);
9
+ }
10
+
11
+ module.exports = appium;
@@ -210,7 +210,8 @@
210
210
  "default": false,
211
211
  "description": "Disable additional security checks, so it is possible to use some advanced features, provided by drivers supporting this option. Only enable it if all the clients are in the trusted network and it's not the case if a client could potentially break out of the session sandbox. Specific features can be overridden by using \"deny-insecure\"",
212
212
  "title": "relaxed-security config",
213
- "type": "boolean"
213
+ "type": "boolean",
214
+ "appiumCliDest": "relaxedSecurityEnabled"
214
215
  },
215
216
  "session-override": {
216
217
  "default": false,
package/lib/appium.js CHANGED
@@ -3,10 +3,12 @@ import log from './logger';
3
3
  import { getBuildInfo, updateBuildInfo, APPIUM_VER } from './config';
4
4
  import { findMatchingDriver } from './drivers';
5
5
  import { BaseDriver, errors, isSessionCommand,
6
- CREATE_SESSION_COMMAND } from '@appium/base-driver';
6
+ CREATE_SESSION_COMMAND, DELETE_SESSION_COMMAND, GET_STATUS_COMMAND
7
+ } from '@appium/base-driver';
7
8
  import AsyncLock from 'async-lock';
8
9
  import { parseCapsForInnerDriver, pullSettings } from './utils';
9
10
  import { util } from '@appium/support';
11
+ import { getDefaultsForExtension } from './schema';
10
12
 
11
13
  const desiredCapabilityConstraints = {
12
14
  automationName: {
@@ -51,6 +53,7 @@ class AppiumDriver extends BaseDriver {
51
53
  // It is not recommended to access this property directly from the outside
52
54
  this.pendingDrivers = {};
53
55
 
56
+ /** @type {PluginExtensionClass[]} */
54
57
  this.pluginClasses = []; // list of which plugins are active
55
58
  this.sessionPlugins = {}; // map of sessions to actual plugin instances per session
56
59
  this.sessionlessPlugins = []; // some commands are sessionless, so we need a set of plugins for them
@@ -59,9 +62,12 @@ class AppiumDriver extends BaseDriver {
59
62
  updateBuildInfo();
60
63
  }
61
64
 
62
- /** @type {DriverConfig|undefined} */
65
+ /** @type {import('./driver-config').default|undefined} */
63
66
  driverConfig;
64
67
 
68
+ /** @type {import('express').Express|undefined} */
69
+ server;
70
+
65
71
  /**
66
72
  * Cancel commands queueing for the umbrella Appium driver
67
73
  */
@@ -118,14 +124,22 @@ class AppiumDriver extends BaseDriver {
118
124
  * Validate and assign CLI args for a driver or plugin
119
125
  *
120
126
  * If the extension has provided a schema, validation has already happened.
127
+ *
128
+ * Any arg which is equal to its default value will not be assigned to the extension.
121
129
  * @param {import('./ext-config-io').ExtensionType} extType 'driver' or 'plugin'
122
130
  * @param {string} extName the name of the extension
123
131
  * @param {Object} extInstance the driver or plugin instance
124
132
  */
125
133
  assignCliArgsToExtension (extType, extName, extInstance) {
126
- const cliArgs = this.args[extType]?.[extName];
127
- if (!_.isEmpty(cliArgs)) {
128
- extInstance.cliArgs = cliArgs;
134
+ const allCliArgsForExt = this.args[extType]?.[extName];
135
+ if (!_.isEmpty(allCliArgsForExt)) {
136
+ const defaults = getDefaultsForExtension(extType, extName);
137
+ const cliArgs = _.isEmpty(defaults)
138
+ ? allCliArgsForExt
139
+ : _.omitBy(allCliArgsForExt, (value, key) => _.isEqual(defaults[key], value));
140
+ if (!_.isEmpty(cliArgs)) {
141
+ extInstance.cliArgs = cliArgs;
142
+ }
129
143
  }
130
144
  }
131
145
 
@@ -216,6 +230,12 @@ class AppiumDriver extends BaseDriver {
216
230
 
217
231
  // This assignment is required for correct web sockets functionality inside the driver
218
232
  driverInstance.server = this.server;
233
+
234
+ // Drivers/plugins might also want to know where they are hosted
235
+ driverInstance.serverHost = this.args.address;
236
+ driverInstance.serverPort = this.args.port;
237
+ driverInstance.serverPath = this.args.basePath;
238
+
219
239
  try {
220
240
  runningDriversData = await this.curSessionDataForDriver(InnerDriver);
221
241
  } catch (e) {
@@ -437,9 +457,10 @@ class AppiumDriver extends BaseDriver {
437
457
  // The tricky part is that because we support command plugins, we need to wrap any of these
438
458
  // cases with plugin handling.
439
459
 
440
- const isGetStatus = cmd === 'getStatus';
460
+ const isGetStatus = cmd === GET_STATUS_COMMAND;
461
+ const isDeleteSession = cmd === DELETE_SESSION_COMMAND;
441
462
  const isUmbrellaCmd = !isGetStatus && isAppiumDriverCommand(cmd);
442
- const isSessionCmd = !isGetStatus && !isUmbrellaCmd;
463
+ const isSessionCmd = !isUmbrellaCmd || isDeleteSession;
443
464
 
444
465
  // if a plugin override proxying for this command and that is why we are here instead of just
445
466
  // letting the protocol proxy the command entirely, determine that, get the request object for
@@ -464,7 +485,9 @@ class AppiumDriver extends BaseDriver {
464
485
  }
465
486
  // now save the response protocol given that the session driver's protocol might differ
466
487
  protocol = dstSession.protocol;
467
- driver = dstSession;
488
+ if (!isUmbrellaCmd) {
489
+ driver = dstSession;
490
+ }
468
491
  }
469
492
 
470
493
  // get any plugins which are registered as handling this command
@@ -651,3 +674,23 @@ export class NoDriverProxyCommandError extends Error {
651
674
  }
652
675
 
653
676
  export { AppiumDriver };
677
+
678
+
679
+ /**
680
+ * @typedef {Object} StaticExtMembers
681
+ * @property {(app: import('express').Express, httpServer: import('http').Server) => import('type-fest').Promisable<void>} [updateServer]
682
+ * @property {import('@appium/base-driver').MethodMap} [newMethodMap]
683
+ */
684
+
685
+ /**
686
+ * @typedef {Object} StaticPluginMembers
687
+ * @property {string} pluginName
688
+ */
689
+
690
+ /**
691
+ * @typedef {import('type-fest').Class<unknown> & StaticPluginMembers & StaticExtMembers} PluginExtensionClass
692
+ */
693
+
694
+ /**
695
+ * @typedef {import('type-fest').Class<unknown> & StaticExtMembers} DriverExtensionClass
696
+ */
package/lib/cli/args.js CHANGED
@@ -1,7 +1,6 @@
1
1
  // @ts-check
2
2
 
3
3
  // @ts-ignore
4
- import { DEFAULT_BASE_PATH } from '@appium/base-driver';
5
4
  import _ from 'lodash';
6
5
  import DriverConfig from '../driver-config';
7
6
  import { APPIUM_HOME, DRIVER_TYPE, INSTALL_TYPES, PLUGIN_TYPE } from '../extension-config';
@@ -175,13 +174,7 @@ function makeRunArgs (type) {
175
174
  */
176
175
  function getServerArgs () {
177
176
  return new Map([
178
- ...toParserArgs({
179
- overrides: {
180
- basePath: {
181
- default: DEFAULT_BASE_PATH
182
- },
183
- }
184
- }),
177
+ ...toParserArgs(),
185
178
  ...serverArgsDisallowedInConfig,
186
179
  ]);
187
180
  }
@@ -195,21 +188,31 @@ const serverArgsDisallowedInConfig = new Map([
195
188
  ['--shell'],
196
189
  {
197
190
  required: false,
198
- default: null,
199
191
  help: 'Enter REPL mode',
200
- action: 'store_true',
192
+ action: 'store_const',
193
+ const: true,
201
194
  dest: 'shell',
202
195
  },
203
196
  ],
197
+ [
198
+ ['--show-build-info'],
199
+ {
200
+ dest: 'showBuildInfo',
201
+ action: 'store_const',
202
+ const: true,
203
+ required: false,
204
+ help: 'Show info about the Appium build and exit',
205
+ },
206
+ ],
204
207
  [
205
208
  ['--show-config'],
206
209
  {
207
- default: false,
208
210
  dest: 'showConfig',
209
- action: 'store_true',
211
+ action: 'store_const',
212
+ const: true,
210
213
  required: false,
211
- help: 'Show info about the appium server configuration and exit',
212
- },
214
+ help: 'Show the current Appium configuration and exit',
215
+ }
213
216
  ],
214
217
  [
215
218
  ['--config'],
package/lib/cli/npm.js CHANGED
@@ -1,3 +1,5 @@
1
+ // @ts-check
2
+
1
3
  import path from 'path';
2
4
  import semver from 'semver';
3
5
  import { exec } from 'teen_process';
@@ -8,10 +10,23 @@ const LINK_LOCKFILE = '.appium.link.lock';
8
10
 
9
11
  export default class NPM {
10
12
 
13
+ /**
14
+ * @param {string} appiumHome
15
+ */
11
16
  constructor (appiumHome) {
17
+ /** @type {string} */
12
18
  this.appiumHome = appiumHome;
13
19
  }
14
20
 
21
+ /**
22
+ * Execute `npm` with given args.
23
+ *
24
+ * If the process exits with a nonzero code, the contents of `STDOUT` and `STDERR` will be in the
25
+ * `message` of the {@link TeenProcessExecError} rejected.
26
+ * @param {string} cmd
27
+ * @param {string[]} args
28
+ * @param {{ json?: boolean; cwd?: string; lockFile?: string; }} opts
29
+ */
15
30
  async exec (cmd, args, opts, execOpts = {}) {
16
31
  let { cwd, json, lockFile } = opts;
17
32
  if (!cwd) {
@@ -33,7 +48,7 @@ export default class NPM {
33
48
 
34
49
  args.unshift(cmd);
35
50
  if (json) {
36
- args.push('-json');
51
+ args.push('--json');
37
52
  }
38
53
  const npmCmd = system.isWindows() ? 'npm.cmd' : 'npm';
39
54
  let runner = async () => await exec(npmCmd, args, execOpts);
@@ -42,27 +57,38 @@ export default class NPM {
42
57
  const _runner = runner;
43
58
  runner = async () => await acquireLock(_runner);
44
59
  }
45
- const {stdout, stderr, code} = await runner();
46
- const ret = {stdout, stderr, code, json: null};
47
60
 
48
- if (json) {
61
+ let ret;
62
+ try {
63
+ const {stdout, stderr, code} = await runner();
64
+ ret = /** @type {TeenProcessExecResult} */({stdout, stderr, code});
49
65
  // if possible, parse NPM's json output. During NPM install 3rd-party
50
66
  // packages can write to stdout, so sometimes the json output can't be
51
67
  // guaranteed to be parseable
52
68
  try {
53
69
  ret.json = JSON.parse(stdout);
54
70
  } catch (ign) {}
71
+ } catch (e) {
72
+ const {stdout, stderr, code} = /** @type {TeenProcessExecError} */(e);
73
+ const err = new Error(`npm command '${cmd} ${args.join(' ')}' failed with code ${code}.\n\nSTDOUT:\n${stdout.trim()}\n\nSTDERR:\n${stderr.trim()}`);
74
+ throw err;
55
75
  }
56
-
57
76
  return ret;
58
77
  }
59
78
 
79
+ /**
80
+ * @param {string} pkg
81
+ */
60
82
  async getLatestVersion (pkg) {
61
83
  return (await this.exec('view', [pkg, 'dist-tags'], {
62
84
  json: true
63
- })).json.latest;
85
+ })).json?.latest;
64
86
  }
65
87
 
88
+ /**
89
+ * @param {string} pkg
90
+ * @param {string} curVersion
91
+ */
66
92
  async getLatestSafeUpgradeVersion (pkg, curVersion) {
67
93
  const allVersions = (await this.exec('view', [pkg, 'versions'], {
68
94
  json: true
@@ -115,6 +141,11 @@ export default class NPM {
115
141
  return safeUpgradeVer;
116
142
  }
117
143
 
144
+ /**
145
+ *
146
+ * @param {{pkgDir: string, pkgName: string, pkgVer?: string}} param0
147
+ * @returns {Promise<import('type-fest').PackageJson>}
148
+ */
118
149
  async installPackage ({pkgDir, pkgName, pkgVer}) {
119
150
  const res = await this.exec('install', [
120
151
  '--no-save',
@@ -148,6 +179,9 @@ export default class NPM {
148
179
  }
149
180
  }
150
181
 
182
+ /**
183
+ * @param {string} pkgPath
184
+ */
151
185
  async linkPackage (pkgPath) {
152
186
  // from the path alone we don't know the npm package name, so we need to
153
187
  // look in package.json
@@ -180,6 +214,10 @@ export default class NPM {
180
214
  }
181
215
  }
182
216
 
217
+ /**
218
+ * @param {string} pkgDir
219
+ * @param {string} pkg
220
+ */
183
221
  async uninstallPackage (pkgDir, pkg) {
184
222
  await this.exec('uninstall', [pkg], {
185
223
  cwd: pkgDir,
@@ -187,3 +225,27 @@ export default class NPM {
187
225
  });
188
226
  }
189
227
  }
228
+
229
+
230
+ /**
231
+ * Result from a non-zero-exit execution of `appium`
232
+ * @typedef {Object} TeenProcessExecResult
233
+ * @property {string} stdout - Stdout
234
+ * @property {string} stderr - Stderr
235
+ * @property {number?} code - Exit code
236
+ * @property {any} json - JSON parsed from stdout
237
+ */
238
+
239
+ /**
240
+ * Extra props `teen_process.exec` adds to its error objects
241
+ * @typedef {Object} TeenProcessExecErrorProps
242
+ * @property {string} stdout - STDOUT
243
+ * @property {string} stderr - STDERR
244
+ * @property {number?} code - Exit code
245
+ */
246
+
247
+
248
+ /**
249
+ * Error thrown by `teen_process.exec`
250
+ * @typedef {Error & TeenProcessExecErrorProps} TeenProcessExecError
251
+ */