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.
- package/README.md +1 -2
- package/build/check-npm-pack-files.js +23 -0
- package/build/commands-yml/parse.js +319 -0
- package/build/commands-yml/validator.js +130 -0
- package/build/index.js +19 -0
- package/build/lib/appium.js +22 -7
- package/build/lib/cli/args.js +13 -15
- package/build/lib/cli/npm.js +27 -16
- package/build/lib/cli/parser.js +7 -3
- package/build/lib/config.js +27 -47
- package/build/lib/extension-config.js +1 -1
- package/build/lib/main.js +29 -28
- package/build/lib/plugin-config.js +2 -2
- package/build/lib/plugins.js +4 -2
- package/build/lib/schema/appium-config-schema.js +3 -2
- package/build/lib/schema/arg-spec.js +5 -3
- package/build/lib/schema/cli-args.js +25 -16
- package/build/lib/schema/keywords.js +14 -4
- package/build/lib/schema/schema.js +80 -9
- package/build/lib/utils.js +16 -36
- package/build/postinstall.js +90 -0
- package/build/test/cli/cli-e2e-specs.js +221 -0
- package/build/test/cli/cli-helpers.js +86 -0
- package/build/test/cli/cli-specs.js +71 -0
- package/build/test/cli/fixtures/test-driver/package.json +27 -0
- package/build/test/cli/schema-args-specs.js +48 -0
- package/build/test/cli/schema-e2e-specs.js +47 -0
- package/build/test/config-e2e-specs.js +112 -0
- package/build/test/config-file-e2e-specs.js +209 -0
- package/build/test/config-file-specs.js +281 -0
- package/build/test/config-specs.js +246 -0
- package/build/test/driver-e2e-specs.js +435 -0
- package/build/test/driver-specs.js +386 -0
- package/build/test/ext-config-io-specs.js +181 -0
- package/build/test/extension-config-specs.js +365 -0
- package/build/test/fixtures/allow-feat.txt +5 -0
- package/build/test/fixtures/caps.json +3 -0
- package/build/test/fixtures/config/allow-insecure.txt +3 -0
- package/build/test/fixtures/config/appium.config.bad-nodeconfig.json +5 -0
- package/build/test/fixtures/config/appium.config.bad.json +32 -0
- package/build/test/fixtures/config/appium.config.ext-good.json +9 -0
- package/build/test/fixtures/config/appium.config.ext-unknown-props.json +10 -0
- package/build/test/fixtures/config/appium.config.good.js +40 -0
- package/build/test/fixtures/config/appium.config.good.json +33 -0
- package/build/test/fixtures/config/appium.config.good.yaml +30 -0
- package/build/test/fixtures/config/appium.config.invalid.json +31 -0
- package/build/test/fixtures/config/appium.config.security-array.json +5 -0
- package/build/test/fixtures/config/appium.config.security-delimited.json +5 -0
- package/build/test/fixtures/config/appium.config.security-path.json +5 -0
- package/build/test/fixtures/config/driver-fake.config.json +8 -0
- package/build/test/fixtures/config/nodeconfig.json +3 -0
- package/build/test/fixtures/config/plugin-fake.config.json +0 -0
- package/build/test/fixtures/default-args.js +35 -0
- package/build/test/fixtures/deny-feat.txt +5 -0
- package/build/test/fixtures/driver.schema.js +20 -0
- package/build/test/fixtures/extensions.yaml +27 -0
- package/build/test/fixtures/flattened-schema.js +532 -0
- package/build/test/fixtures/plugin.schema.js +20 -0
- package/build/test/fixtures/schema-with-extensions.js +28 -0
- package/build/test/grid-register-specs.js +74 -0
- package/build/test/helpers.js +75 -0
- package/build/test/logger-specs.js +76 -0
- package/build/test/npm-specs.js +20 -0
- package/build/test/parser-specs.js +319 -0
- package/build/test/plugin-e2e-specs.js +316 -0
- package/build/test/schema/arg-spec-specs.js +70 -0
- package/build/test/schema/cli-args-specs.js +408 -0
- package/build/test/schema/schema-specs.js +407 -0
- package/build/test/utils-specs.js +288 -0
- package/index.js +11 -0
- package/lib/appium-config.schema.json +2 -1
- package/lib/appium.js +51 -8
- package/lib/cli/args.js +17 -14
- package/lib/cli/npm.js +68 -6
- package/lib/cli/parser.js +5 -2
- package/lib/config.js +72 -54
- package/lib/extension-config.js +1 -1
- package/lib/main.js +93 -40
- package/lib/plugin-config.js +1 -1
- package/lib/plugins.js +2 -0
- package/lib/schema/appium-config-schema.js +1 -0
- package/lib/schema/arg-spec.js +12 -2
- package/lib/schema/cli-args.js +22 -34
- package/lib/schema/keywords.js +20 -4
- package/lib/schema/schema.js +142 -22
- package/lib/utils.js +28 -29
- package/package.json +10 -14
- package/types/types.d.ts +5 -0
- package/build/lib/cli/argparse-actions.js +0 -104
- 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
|
@@ -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
|
|
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 {
|
|
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
|
|
127
|
-
if (!_.isEmpty(
|
|
128
|
-
|
|
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 ===
|
|
460
|
+
const isGetStatus = cmd === GET_STATUS_COMMAND;
|
|
461
|
+
const isDeleteSession = cmd === DELETE_SESSION_COMMAND;
|
|
441
462
|
const isUmbrellaCmd = !isGetStatus && isAppiumDriverCommand(cmd);
|
|
442
|
-
const isSessionCmd = !
|
|
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
|
-
|
|
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: '
|
|
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: '
|
|
211
|
+
action: 'store_const',
|
|
212
|
+
const: true,
|
|
210
213
|
required: false,
|
|
211
|
-
help: 'Show
|
|
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('
|
|
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
|
-
|
|
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
|
|
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
|
+
*/
|