@adobe/ccweb-add-on-ssl 2.4.1 → 3.0.0
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/.mocharc.json +9 -2
- package/README.md +5 -4
- package/bin/run.js +3 -2
- package/dist/AnalyticsMarkers.d.ts +5 -2
- package/dist/AnalyticsMarkers.d.ts.map +1 -1
- package/dist/AnalyticsMarkers.js +3 -0
- package/dist/app/CommandExecutor.d.ts +1 -1
- package/dist/app/CommandExecutor.d.ts.map +1 -1
- package/dist/app/PurgeCommandExecutor.d.ts +53 -0
- package/dist/app/PurgeCommandExecutor.d.ts.map +1 -0
- package/dist/app/PurgeCommandExecutor.js +125 -0
- package/dist/app/SSLReader.d.ts +2 -1
- package/dist/app/SSLReader.d.ts.map +1 -1
- package/dist/app/SetupCommandExecutor.d.ts.map +1 -1
- package/dist/app/SetupCommandExecutor.js +10 -7
- package/dist/app/WxpSSLReader.d.ts +8 -1
- package/dist/app/WxpSSLReader.d.ts.map +1 -1
- package/dist/app/WxpSSLReader.js +59 -5
- package/dist/app/index.d.ts +2 -1
- package/dist/app/index.d.ts.map +1 -1
- package/dist/app/index.js +2 -1
- package/dist/commands/purge.d.ts +41 -0
- package/dist/commands/purge.d.ts.map +1 -0
- package/dist/commands/purge.js +56 -0
- package/dist/commands/setup.d.ts +5 -10
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +5 -32
- package/dist/config/inversify.config.d.ts +2 -1
- package/dist/config/inversify.config.d.ts.map +1 -1
- package/dist/config/inversify.config.js +6 -1
- package/dist/config/inversify.types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/models/Types.d.ts +0 -1
- package/dist/models/Types.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +14 -12
- package/src/AnalyticsMarkers.ts +5 -2
- package/src/app/CommandExecutor.ts +1 -1
- package/src/app/PurgeCommandExecutor.ts +144 -0
- package/src/app/SSLReader.ts +2 -1
- package/src/app/SetupCommandExecutor.ts +10 -7
- package/src/app/WxpSSLReader.ts +71 -5
- package/src/app/index.ts +2 -1
- package/src/commands/purge.ts +72 -0
- package/src/commands/setup.ts +12 -40
- package/src/config/inversify.config.ts +9 -2
- package/src/config/inversify.types.ts +5 -1
- package/src/index.ts +2 -0
- package/src/test/app/PurgeCommandExecutor.spec.ts +195 -0
- package/src/test/app/SetupCommandExecutor.spec.ts +141 -34
- package/src/test/app/WxpSSLReader.spec.ts +107 -33
- package/src/test/commands/command.spec.ts +108 -0
- package/src/test/commands/purge.spec.ts +132 -0
- package/src/test/commands/setup.spec.ts +28 -29
- package/tsconfig.json +3 -1
|
@@ -22,10 +22,11 @@
|
|
|
22
22
|
* SOFTWARE.
|
|
23
23
|
********************************************************************************/
|
|
24
24
|
|
|
25
|
-
import type {
|
|
25
|
+
import type { Logger, Preferences } from "@adobe/ccweb-add-on-core";
|
|
26
26
|
import { ADD_ON_PREFERENCES_FILE, PreferenceJson } from "@adobe/ccweb-add-on-core";
|
|
27
|
-
import { assert } from "chai";
|
|
28
27
|
import devcert from "@adobe/ccweb-add-on-devcert";
|
|
28
|
+
import chai, { assert, expect } from "chai";
|
|
29
|
+
import chaiAsPromised from "chai-as-promised";
|
|
29
30
|
import type { Stats } from "fs-extra";
|
|
30
31
|
import fs from "fs-extra";
|
|
31
32
|
import "mocha";
|
|
@@ -35,6 +36,8 @@ import { stubInterface } from "ts-sinon";
|
|
|
35
36
|
import type { SSLReader } from "../../app/index.js";
|
|
36
37
|
import { WxpSSLReader } from "../../app/index.js";
|
|
37
38
|
|
|
39
|
+
chai.use(chaiAsPromised);
|
|
40
|
+
|
|
38
41
|
describe("WxpSSLReader", () => {
|
|
39
42
|
let sandbox: sinon.SinonSandbox;
|
|
40
43
|
|
|
@@ -42,11 +45,14 @@ describe("WxpSSLReader", () => {
|
|
|
42
45
|
let logger: StubbedInstance<Logger>;
|
|
43
46
|
let sslReader: SSLReader;
|
|
44
47
|
|
|
48
|
+
const hostname = "localhost.adobe.com";
|
|
49
|
+
const port = 5241;
|
|
50
|
+
|
|
45
51
|
beforeEach(() => {
|
|
46
52
|
sandbox = sinon.createSandbox();
|
|
47
53
|
|
|
48
|
-
preferences = stubInterface
|
|
49
|
-
logger = stubInterface
|
|
54
|
+
preferences = stubInterface();
|
|
55
|
+
logger = stubInterface();
|
|
50
56
|
sslReader = new WxpSSLReader(preferences, logger);
|
|
51
57
|
});
|
|
52
58
|
|
|
@@ -56,7 +62,6 @@ describe("WxpSSLReader", () => {
|
|
|
56
62
|
|
|
57
63
|
describe("isCustomSSL", () => {
|
|
58
64
|
it(`should return false if SSL settings are not present in '${ADD_ON_PREFERENCES_FILE}' for the provided hostname.`, async () => {
|
|
59
|
-
const hostname = "localhost";
|
|
60
65
|
const userPreference = new PreferenceJson({});
|
|
61
66
|
|
|
62
67
|
preferences.get.returns(userPreference);
|
|
@@ -67,7 +72,6 @@ describe("WxpSSLReader", () => {
|
|
|
67
72
|
});
|
|
68
73
|
|
|
69
74
|
it(`should return true if SSL settings are present in '${ADD_ON_PREFERENCES_FILE}' for the provided hostname.`, async () => {
|
|
70
|
-
const hostname = "localhost";
|
|
71
75
|
const userPreference = new PreferenceJson({
|
|
72
76
|
ssl: {
|
|
73
77
|
[hostname]: {
|
|
@@ -87,8 +91,6 @@ describe("WxpSSLReader", () => {
|
|
|
87
91
|
|
|
88
92
|
describe("isWxpSSL", () => {
|
|
89
93
|
it("should return false if devcert SSL certificate is not present for the provided hostname.", async () => {
|
|
90
|
-
const hostname = "localhost";
|
|
91
|
-
|
|
92
94
|
sandbox.stub(devcert, "hasCertificateFor").withArgs(hostname).returns(false);
|
|
93
95
|
|
|
94
96
|
const isWxpSSL = sslReader.isWxpSSL(hostname);
|
|
@@ -97,8 +99,6 @@ describe("WxpSSLReader", () => {
|
|
|
97
99
|
});
|
|
98
100
|
|
|
99
101
|
it("should return false if devcert SSL certificate is not present for the provided hostname.", async () => {
|
|
100
|
-
const hostname = "localhost";
|
|
101
|
-
|
|
102
102
|
sandbox.stub(devcert, "hasCertificateFor").withArgs(hostname).returns(false);
|
|
103
103
|
|
|
104
104
|
const isWxpSSL = sslReader.isWxpSSL(hostname);
|
|
@@ -109,8 +109,6 @@ describe("WxpSSLReader", () => {
|
|
|
109
109
|
|
|
110
110
|
describe("read", async () => {
|
|
111
111
|
it("should log error and exit when SSL certificate path is invalid for manually set up SSL.", async () => {
|
|
112
|
-
const hostname = "localhost";
|
|
113
|
-
|
|
114
112
|
const certificatePath = "/some-directory/localhost/ssl/";
|
|
115
113
|
const keyPath = "/some-directory/localhost/ssl/private-key.key";
|
|
116
114
|
const userPreference = new PreferenceJson({
|
|
@@ -128,18 +126,15 @@ describe("WxpSSLReader", () => {
|
|
|
128
126
|
lstatStub.withArgs(certificatePath).returns(certificateStats);
|
|
129
127
|
lstatStub.withArgs(keyPath).returns(keyStats);
|
|
130
128
|
|
|
131
|
-
logger.error.returns();
|
|
132
129
|
const exitStub = sandbox.stub(process, "exit");
|
|
133
130
|
|
|
134
|
-
await sslReader.read(hostname);
|
|
131
|
+
await sslReader.read(hostname, port);
|
|
135
132
|
|
|
136
133
|
assert.equal(logger.error.calledOnceWith("Invalid SSL certificate file path."), true);
|
|
137
134
|
assert.equal(exitStub.calledWith(1), true);
|
|
138
135
|
});
|
|
139
136
|
|
|
140
137
|
it("should log error and exit when SSL key path is invalid for manually set up SSL.", async () => {
|
|
141
|
-
const hostname = "localhost";
|
|
142
|
-
|
|
143
138
|
const certificatePath = "/some-directory/localhost/ssl/certificate.cert";
|
|
144
139
|
const keyPath = "/some-directory/localhost/ssl/";
|
|
145
140
|
const userPreference = new PreferenceJson({
|
|
@@ -157,18 +152,15 @@ describe("WxpSSLReader", () => {
|
|
|
157
152
|
lstatStub.withArgs(certificatePath).returns(certificateStats);
|
|
158
153
|
lstatStub.withArgs(keyPath).returns(keyStats);
|
|
159
154
|
|
|
160
|
-
logger.error.returns();
|
|
161
155
|
const exitStub = sandbox.stub(process, "exit");
|
|
162
156
|
|
|
163
|
-
await sslReader.read(hostname);
|
|
157
|
+
await sslReader.read(hostname, port);
|
|
164
158
|
|
|
165
159
|
assert.equal(logger.error.calledOnceWith("Invalid SSL key file path."), true);
|
|
166
160
|
assert.equal(exitStub.calledWith(1), true);
|
|
167
161
|
});
|
|
168
162
|
|
|
169
|
-
it("should read and return SSL
|
|
170
|
-
const hostname = "localhost";
|
|
171
|
-
|
|
163
|
+
it("should read and return SSL data for manually set up SSL.", async () => {
|
|
172
164
|
const certificatePath = "/some-directory/localhost/ssl/certificate.cert";
|
|
173
165
|
const keyPath = "/some-directory/localhost/ssl/private-key.key";
|
|
174
166
|
const userPreference = new PreferenceJson({
|
|
@@ -191,19 +183,97 @@ describe("WxpSSLReader", () => {
|
|
|
191
183
|
readFileStub.withArgs(certificatePath).returns(certificateData);
|
|
192
184
|
readFileStub.withArgs(keyPath).returns(keyData);
|
|
193
185
|
|
|
194
|
-
const sslData = await sslReader.read(hostname);
|
|
186
|
+
const sslData = await sslReader.read(hostname, port);
|
|
187
|
+
|
|
188
|
+
assert.equal(sslData.cert, certificateData);
|
|
189
|
+
assert.equal(sslData.key, keyData);
|
|
190
|
+
|
|
191
|
+
assert.equal(
|
|
192
|
+
logger.warning.getCall(0).calledWith("Could not determine the expiry of your SSL certificate."),
|
|
193
|
+
true
|
|
194
|
+
);
|
|
195
|
+
assert.equal(
|
|
196
|
+
logger.warning
|
|
197
|
+
.getCall(1)
|
|
198
|
+
.calledWith("If you are unable to sideload your add-on, please check the validity of:"),
|
|
199
|
+
true
|
|
200
|
+
);
|
|
201
|
+
assert.equal(
|
|
202
|
+
logger.warning.getCall(2).calledWith(`https://${hostname}:${port} certificate in your browser.`),
|
|
203
|
+
true
|
|
204
|
+
);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it("should read and return SSL data for automatically set up, valid SSL.", async () => {
|
|
208
|
+
const userPreference = new PreferenceJson({});
|
|
209
|
+
preferences.get.returns(userPreference);
|
|
210
|
+
|
|
211
|
+
sandbox.stub(devcert, "hasCertificateFor").withArgs(hostname).returns(true);
|
|
212
|
+
sandbox.stub(devcert, "caExpiryInDays").returns(50);
|
|
213
|
+
sandbox.stub(devcert, "certificateExpiryInDays").returns(100);
|
|
214
|
+
|
|
215
|
+
const certificateData = <Buffer>{};
|
|
216
|
+
const keyData = <Buffer>{};
|
|
217
|
+
|
|
218
|
+
const certificateForStub = sandbox.stub(devcert, "certificateFor");
|
|
219
|
+
// @ts-ignore -- IReturnData mock response
|
|
220
|
+
certificateForStub.withArgs(hostname).returns({ cert: certificateData, key: keyData });
|
|
221
|
+
|
|
222
|
+
const sslData = await sslReader.read(hostname, port);
|
|
195
223
|
|
|
196
224
|
assert.equal(sslData.cert, certificateData);
|
|
197
225
|
assert.equal(sslData.key, keyData);
|
|
198
226
|
});
|
|
199
227
|
|
|
200
|
-
it("should
|
|
201
|
-
const
|
|
228
|
+
it("should log error and exit when automatically set up SSL has expired.", async () => {
|
|
229
|
+
const userPreference = new PreferenceJson({});
|
|
230
|
+
preferences.get.returns(userPreference);
|
|
231
|
+
|
|
232
|
+
sandbox.stub(devcert, "hasCertificateFor").withArgs(hostname).returns(true);
|
|
233
|
+
sandbox.stub(devcert, "caExpiryInDays").returns(0);
|
|
234
|
+
sandbox.stub(devcert, "certificateExpiryInDays").returns(100);
|
|
235
|
+
|
|
236
|
+
const exitStub = sandbox.stub(process, "exit");
|
|
237
|
+
exitStub.throws();
|
|
238
|
+
|
|
239
|
+
await expect(sslReader.read(hostname, port)).to.be.rejectedWith();
|
|
202
240
|
|
|
241
|
+
assert.equal(
|
|
242
|
+
logger.error.getCall(0).calledWith("Could not locate a valid SSL certificate to host the add-on."),
|
|
243
|
+
true
|
|
244
|
+
);
|
|
245
|
+
assert.equal(logger.error.getCall(1).calledWith("The SSL certificate has expired."), true);
|
|
246
|
+
assert.equal(
|
|
247
|
+
logger.warning
|
|
248
|
+
.getCall(0)
|
|
249
|
+
.calledWith("To re-create the SSL certificate, you may run:", { prefix: "\n" }),
|
|
250
|
+
true
|
|
251
|
+
);
|
|
252
|
+
assert.equal(
|
|
253
|
+
logger.information
|
|
254
|
+
.getCall(0)
|
|
255
|
+
.calledWith("npx @adobe/ccweb-add-on-ssl setup --hostname [hostname]", { prefix: " " }),
|
|
256
|
+
true
|
|
257
|
+
);
|
|
258
|
+
assert.equal(logger.warning.getCall(1).calledWith("Example:", { prefix: "\n" }), true);
|
|
259
|
+
assert.equal(
|
|
260
|
+
logger.information.getCall(1).calledWith("npx @adobe/ccweb-add-on-ssl setup --hostname localhost", {
|
|
261
|
+
prefix: " ",
|
|
262
|
+
postfix: "\n"
|
|
263
|
+
}),
|
|
264
|
+
true
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
assert.equal(exitStub.calledWith(1), true);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it("should read and return SSL data for automatically set up, valid SSL nearing expiry.", async () => {
|
|
203
271
|
const userPreference = new PreferenceJson({});
|
|
204
272
|
preferences.get.returns(userPreference);
|
|
205
273
|
|
|
206
274
|
sandbox.stub(devcert, "hasCertificateFor").withArgs(hostname).returns(true);
|
|
275
|
+
sandbox.stub(devcert, "caExpiryInDays").returns(5);
|
|
276
|
+
sandbox.stub(devcert, "certificateExpiryInDays").returns(100);
|
|
207
277
|
|
|
208
278
|
const certificateData = <Buffer>{};
|
|
209
279
|
const keyData = <Buffer>{};
|
|
@@ -212,30 +282,34 @@ describe("WxpSSLReader", () => {
|
|
|
212
282
|
// @ts-ignore -- IReturnData mock response
|
|
213
283
|
certificateForStub.withArgs(hostname).returns({ cert: certificateData, key: keyData });
|
|
214
284
|
|
|
215
|
-
const sslData = await sslReader.read(hostname);
|
|
285
|
+
const sslData = await sslReader.read(hostname, port);
|
|
286
|
+
|
|
287
|
+
assert.equal(logger.warning.calledWith("Your SSL certificate will expire in 5 days."), true);
|
|
216
288
|
|
|
217
289
|
assert.equal(sslData.cert, certificateData);
|
|
218
290
|
assert.equal(sslData.key, keyData);
|
|
219
291
|
});
|
|
220
292
|
|
|
221
293
|
it("should log error and exit when SSL is not set up.", async () => {
|
|
222
|
-
const hostname = "localhost";
|
|
223
|
-
|
|
224
294
|
const userPreference = new PreferenceJson({});
|
|
225
295
|
preferences.get.returns(userPreference);
|
|
226
296
|
|
|
227
297
|
sandbox.stub(devcert, "hasCertificateFor").returns(false);
|
|
228
298
|
|
|
229
|
-
logger.error.returns();
|
|
230
299
|
const exitStub = sandbox.stub(process, "exit");
|
|
231
300
|
|
|
232
|
-
await sslReader.read(hostname);
|
|
301
|
+
await sslReader.read(hostname, port);
|
|
233
302
|
|
|
234
303
|
assert.equal(
|
|
235
|
-
logger.error.
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
304
|
+
logger.error.getCall(0).calledWith("Could not locate a valid SSL certificate to host the add-on."),
|
|
305
|
+
true
|
|
306
|
+
);
|
|
307
|
+
assert.equal(
|
|
308
|
+
logger.error
|
|
309
|
+
.getCall(1)
|
|
310
|
+
.calledWith(
|
|
311
|
+
"If you had previously set it up, it may have been invalidated due to a version upgrade."
|
|
312
|
+
),
|
|
239
313
|
true
|
|
240
314
|
);
|
|
241
315
|
assert.equal(exitStub.calledWith(1), true);
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* MIT License
|
|
3
|
+
|
|
4
|
+
* © Copyright 2025 Adobe. All rights reserved.
|
|
5
|
+
|
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
* in the Software without restriction, including without limitation the rights
|
|
9
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
* furnished to do so, subject to the following conditions:
|
|
12
|
+
*
|
|
13
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
* copies or substantial portions of the Software.
|
|
15
|
+
*
|
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
* SOFTWARE.
|
|
23
|
+
********************************************************************************/
|
|
24
|
+
|
|
25
|
+
import type { AnalyticsConsent, AnalyticsService } from "@adobe/ccweb-add-on-analytics";
|
|
26
|
+
import { ITypes as IAnalyticsTypes } from "@adobe/ccweb-add-on-analytics";
|
|
27
|
+
import { runCommand } from "@oclif/test";
|
|
28
|
+
import { assert } from "chai";
|
|
29
|
+
import "mocha";
|
|
30
|
+
import sinon from "sinon";
|
|
31
|
+
import type { StubbedInstance } from "ts-sinon";
|
|
32
|
+
import { stubInterface } from "ts-sinon";
|
|
33
|
+
import type { PurgeCommandExecutor, SetupCommandExecutor } from "../../app/index.js";
|
|
34
|
+
import { IContainer, ITypes } from "../../config/index.js";
|
|
35
|
+
import { SetupCommandOptions } from "../../models/SetupCommandOptions.js";
|
|
36
|
+
import type { SetupCommandValidator } from "../../validators/SetupCommandValidator.js";
|
|
37
|
+
|
|
38
|
+
describe("ccweb-add-on-ssl", () => {
|
|
39
|
+
let sandbox: sinon.SinonSandbox;
|
|
40
|
+
|
|
41
|
+
let container: sinon.SinonStub;
|
|
42
|
+
let namedContainer: sinon.SinonStub;
|
|
43
|
+
|
|
44
|
+
let analyticsConsent: StubbedInstance<AnalyticsConsent>;
|
|
45
|
+
let analyticsService: StubbedInstance<AnalyticsService>;
|
|
46
|
+
|
|
47
|
+
beforeEach(() => {
|
|
48
|
+
sandbox = sinon.createSandbox();
|
|
49
|
+
|
|
50
|
+
namedContainer = sandbox.stub(IContainer, "getNamed");
|
|
51
|
+
|
|
52
|
+
analyticsConsent = stubInterface();
|
|
53
|
+
analyticsService = stubInterface();
|
|
54
|
+
|
|
55
|
+
container = sandbox.stub(IContainer, "get");
|
|
56
|
+
container.withArgs(IAnalyticsTypes.AnalyticsConsent).returns(analyticsConsent);
|
|
57
|
+
container.withArgs(IAnalyticsTypes.AnalyticsService).returns(analyticsService);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
afterEach(() => {
|
|
61
|
+
sandbox.restore();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe("setup", () => {
|
|
65
|
+
let commandExecutor: StubbedInstance<SetupCommandExecutor>;
|
|
66
|
+
let commandValidator: StubbedInstance<SetupCommandValidator>;
|
|
67
|
+
|
|
68
|
+
beforeEach(() => {
|
|
69
|
+
commandExecutor = stubInterface();
|
|
70
|
+
commandExecutor.execute.resolves();
|
|
71
|
+
|
|
72
|
+
commandValidator = stubInterface();
|
|
73
|
+
commandValidator.validate.resolves();
|
|
74
|
+
|
|
75
|
+
namedContainer.withArgs(ITypes.CommandValidator, "setup").returns(commandValidator);
|
|
76
|
+
namedContainer.withArgs(ITypes.CommandExecutor, "setup").returns(commandExecutor);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("should execute succesfully when correct parameters are passed.", async () => {
|
|
80
|
+
analyticsConsent.set.resolves();
|
|
81
|
+
|
|
82
|
+
await runCommand(["setup", "--hostname=localhost", "--analytics=on", "--verbose"], { root: "." });
|
|
83
|
+
|
|
84
|
+
const options = new SetupCommandOptions("localhost", false, true);
|
|
85
|
+
assert.equal(commandValidator.validate.calledOnceWith(options), true);
|
|
86
|
+
assert.equal(commandExecutor.execute.calledOnceWith(options), true);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe("purge", () => {
|
|
91
|
+
let commandExecutor: StubbedInstance<PurgeCommandExecutor>;
|
|
92
|
+
|
|
93
|
+
beforeEach(() => {
|
|
94
|
+
commandExecutor = stubInterface();
|
|
95
|
+
commandExecutor.execute.resolves();
|
|
96
|
+
|
|
97
|
+
namedContainer.withArgs(ITypes.CommandExecutor, "purge").returns(commandExecutor);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("should execute succesfully when correct parameters are passed.", async () => {
|
|
101
|
+
analyticsConsent.set.resolves();
|
|
102
|
+
|
|
103
|
+
await runCommand(["purge", "--analytics=on", "--verbose"], { root: "." });
|
|
104
|
+
|
|
105
|
+
assert.equal(commandExecutor.execute.calledOnce, true);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
});
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* MIT License
|
|
3
|
+
|
|
4
|
+
* © Copyright 2023 Adobe. All rights reserved.
|
|
5
|
+
|
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
* in the Software without restriction, including without limitation the rights
|
|
9
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
* furnished to do so, subject to the following conditions:
|
|
12
|
+
*
|
|
13
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
* copies or substantial portions of the Software.
|
|
15
|
+
*
|
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
* SOFTWARE.
|
|
23
|
+
********************************************************************************/
|
|
24
|
+
|
|
25
|
+
import type { AnalyticsConsent, AnalyticsService } from "@adobe/ccweb-add-on-analytics";
|
|
26
|
+
import { ITypes as IAnalyticsTypes } from "@adobe/ccweb-add-on-analytics";
|
|
27
|
+
import { Config } from "@oclif/core";
|
|
28
|
+
import chai, { assert, expect } from "chai";
|
|
29
|
+
import chaiAsPromised from "chai-as-promised";
|
|
30
|
+
import "mocha";
|
|
31
|
+
import sinon from "sinon";
|
|
32
|
+
import type { StubbedInstance } from "ts-sinon";
|
|
33
|
+
import { stubInterface } from "ts-sinon";
|
|
34
|
+
import { AnalyticsErrorMarkers } from "../../AnalyticsMarkers.js";
|
|
35
|
+
import { PurgeCommandExecutor } from "../../app/index.js";
|
|
36
|
+
import { Purge } from "../../commands/purge.js";
|
|
37
|
+
import { IContainer, ITypes } from "../../config/index.js";
|
|
38
|
+
import { PROGRAM_NAME } from "../../constants.js";
|
|
39
|
+
|
|
40
|
+
chai.use(chaiAsPromised);
|
|
41
|
+
|
|
42
|
+
describe("Purge", () => {
|
|
43
|
+
let sandbox: sinon.SinonSandbox;
|
|
44
|
+
|
|
45
|
+
let container: sinon.SinonStub;
|
|
46
|
+
let namedContainer: sinon.SinonStub;
|
|
47
|
+
|
|
48
|
+
let commandExecutor: StubbedInstance<PurgeCommandExecutor>;
|
|
49
|
+
|
|
50
|
+
let analyticsConsent: StubbedInstance<AnalyticsConsent>;
|
|
51
|
+
let analyticsService: StubbedInstance<AnalyticsService>;
|
|
52
|
+
|
|
53
|
+
beforeEach(() => {
|
|
54
|
+
sandbox = sinon.createSandbox();
|
|
55
|
+
|
|
56
|
+
commandExecutor = stubInterface();
|
|
57
|
+
commandExecutor.execute.resolves();
|
|
58
|
+
|
|
59
|
+
namedContainer = sandbox.stub(IContainer, "getNamed");
|
|
60
|
+
|
|
61
|
+
namedContainer.withArgs(ITypes.CommandExecutor, "purge").returns(commandExecutor);
|
|
62
|
+
|
|
63
|
+
analyticsConsent = stubInterface();
|
|
64
|
+
analyticsService = stubInterface();
|
|
65
|
+
|
|
66
|
+
container = sandbox.stub(IContainer, "get");
|
|
67
|
+
container.withArgs(IAnalyticsTypes.AnalyticsConsent).returns(analyticsConsent);
|
|
68
|
+
container.withArgs(IAnalyticsTypes.AnalyticsService).returns(analyticsService);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
afterEach(() => {
|
|
72
|
+
sandbox.restore();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe("run", () => {
|
|
76
|
+
it("should execute succesfully when correct parameters are passed without analytics.", async () => {
|
|
77
|
+
analyticsConsent.get.resolves(true);
|
|
78
|
+
|
|
79
|
+
const hostname = "localhost";
|
|
80
|
+
const purge = new Purge(["--verbose"], new Config({ name: PROGRAM_NAME, version: "1.0.0", root: "." }));
|
|
81
|
+
sandbox
|
|
82
|
+
// @ts-ignore - Sidestep `this.parse()` error when calling `run()` directly.
|
|
83
|
+
.stub(purge, "parse")
|
|
84
|
+
.resolves({
|
|
85
|
+
flags: { hostname, useExisting: false, analytics: undefined, verbose: false }
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
await purge.run();
|
|
89
|
+
|
|
90
|
+
assert.equal(analyticsConsent.get.callCount, 1);
|
|
91
|
+
|
|
92
|
+
assert.equal(commandExecutor.execute.calledOnce, true);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("should execute succesfully when correct parameters are passed with analytics.", async () => {
|
|
96
|
+
analyticsConsent.get.resolves(true);
|
|
97
|
+
analyticsConsent.set.withArgs(false).resolves();
|
|
98
|
+
|
|
99
|
+
const hostname = "localhost";
|
|
100
|
+
const purge = new Purge(
|
|
101
|
+
["--analytics", "off", "--verbose"],
|
|
102
|
+
new Config({ name: PROGRAM_NAME, version: "1.0.0", root: "." })
|
|
103
|
+
);
|
|
104
|
+
sandbox
|
|
105
|
+
// @ts-ignore - Sidestep `this.parse()` error when calling `run()` directly.
|
|
106
|
+
.stub(purge, "parse")
|
|
107
|
+
.resolves({
|
|
108
|
+
flags: { hostname, useExisting: false, analytics: "off", verbose: true }
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
await purge.run();
|
|
112
|
+
|
|
113
|
+
assert.equal(analyticsConsent.set.calledOnceWith(false), true);
|
|
114
|
+
|
|
115
|
+
assert.equal(commandExecutor.execute.calledOnce, true);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe("catch", () => {
|
|
120
|
+
it("should fail for any errors in command execution.", async () => {
|
|
121
|
+
const purge = new Purge([], new Config({ name: PROGRAM_NAME, version: "1.0.0", root: "." }));
|
|
122
|
+
|
|
123
|
+
const error = new Error("Something went wrong.");
|
|
124
|
+
await expect(purge.catch(error)).to.be.rejectedWith(error);
|
|
125
|
+
|
|
126
|
+
assert.equal(
|
|
127
|
+
analyticsService.postEvent.calledOnceWith(AnalyticsErrorMarkers.ERROR_SSL_PURGE, error.message, false),
|
|
128
|
+
true
|
|
129
|
+
);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
});
|
|
@@ -28,30 +28,27 @@ import { Config } from "@oclif/core";
|
|
|
28
28
|
import chai, { assert, expect } from "chai";
|
|
29
29
|
import chaiAsPromised from "chai-as-promised";
|
|
30
30
|
import "mocha";
|
|
31
|
-
import { createRequire } from "module";
|
|
32
31
|
import sinon from "sinon";
|
|
33
32
|
import type { StubbedInstance } from "ts-sinon";
|
|
34
33
|
import { stubInterface } from "ts-sinon";
|
|
35
34
|
import { AnalyticsErrorMarkers } from "../../AnalyticsMarkers.js";
|
|
36
|
-
import type {
|
|
35
|
+
import type { SetupCommandExecutor } from "../../app/index.js";
|
|
37
36
|
import { Setup } from "../../commands/setup.js";
|
|
38
37
|
import { IContainer, ITypes } from "../../config/index.js";
|
|
38
|
+
import { PROGRAM_NAME } from "../../constants.js";
|
|
39
39
|
import { SetupCommandOptions } from "../../models/SetupCommandOptions.js";
|
|
40
|
-
import type { CommandValidator } from "../../validators/CommandValidator.js";
|
|
41
40
|
import type { SetupCommandValidator } from "../../validators/SetupCommandValidator.js";
|
|
42
41
|
|
|
43
42
|
chai.use(chaiAsPromised);
|
|
44
43
|
|
|
45
|
-
const { test } = createRequire(import.meta.url)("@oclif/test");
|
|
46
|
-
|
|
47
44
|
describe("Setup", () => {
|
|
48
45
|
let sandbox: sinon.SinonSandbox;
|
|
49
46
|
|
|
50
47
|
let container: sinon.SinonStub;
|
|
51
48
|
let namedContainer: sinon.SinonStub;
|
|
52
49
|
|
|
53
|
-
let commandExecutor: StubbedInstance<
|
|
54
|
-
let commandValidator: StubbedInstance<
|
|
50
|
+
let commandExecutor: StubbedInstance<SetupCommandExecutor>;
|
|
51
|
+
let commandValidator: StubbedInstance<SetupCommandValidator>;
|
|
55
52
|
|
|
56
53
|
let analyticsConsent: StubbedInstance<AnalyticsConsent>;
|
|
57
54
|
let analyticsService: StubbedInstance<AnalyticsService>;
|
|
@@ -59,10 +56,10 @@ describe("Setup", () => {
|
|
|
59
56
|
beforeEach(() => {
|
|
60
57
|
sandbox = sinon.createSandbox();
|
|
61
58
|
|
|
62
|
-
commandExecutor = stubInterface
|
|
59
|
+
commandExecutor = stubInterface();
|
|
63
60
|
commandExecutor.execute.resolves();
|
|
64
61
|
|
|
65
|
-
commandValidator = stubInterface
|
|
62
|
+
commandValidator = stubInterface();
|
|
66
63
|
commandValidator.validate.resolves();
|
|
67
64
|
|
|
68
65
|
namedContainer = sandbox.stub(IContainer, "getNamed");
|
|
@@ -81,30 +78,27 @@ describe("Setup", () => {
|
|
|
81
78
|
sandbox.restore();
|
|
82
79
|
});
|
|
83
80
|
|
|
84
|
-
describe("setup", () => {
|
|
85
|
-
test.stdout()
|
|
86
|
-
.command(["setup", "--hostname=localhost", "--analytics=on", "--verbose"])
|
|
87
|
-
.it("should execute succesfully when correct parameters are passed.", async () => {
|
|
88
|
-
analyticsConsent.set.resolves();
|
|
89
|
-
|
|
90
|
-
const options = new SetupCommandOptions("localhost", false, true);
|
|
91
|
-
assert.equal(commandValidator.validate.calledOnceWith(options), true);
|
|
92
|
-
assert.equal(commandExecutor.execute.calledOnceWith(options), true);
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
|
|
96
81
|
describe("run", () => {
|
|
97
82
|
it("should execute succesfully when correct parameters are passed without analytics.", async () => {
|
|
98
83
|
analyticsConsent.get.resolves(true);
|
|
99
84
|
|
|
100
85
|
const hostname = "localhost";
|
|
101
|
-
const setup = new Setup(
|
|
86
|
+
const setup = new Setup(
|
|
87
|
+
["--hostname", hostname, "--verbose"],
|
|
88
|
+
new Config({ name: PROGRAM_NAME, version: "1.0.0", root: "." })
|
|
89
|
+
);
|
|
90
|
+
sandbox
|
|
91
|
+
// @ts-ignore - Sidestep `this.parse()` error when calling `run()` directly.
|
|
92
|
+
.stub(setup, "parse")
|
|
93
|
+
.resolves({
|
|
94
|
+
flags: { hostname, useExisting: false, analytics: undefined, verbose: false }
|
|
95
|
+
});
|
|
102
96
|
|
|
103
97
|
await setup.run();
|
|
104
98
|
|
|
105
99
|
assert.equal(analyticsConsent.get.callCount, 1);
|
|
106
100
|
|
|
107
|
-
const options = new SetupCommandOptions(hostname, false,
|
|
101
|
+
const options = new SetupCommandOptions(hostname, false, false);
|
|
108
102
|
assert.equal(commandValidator.validate.calledOnceWith(options), true);
|
|
109
103
|
assert.equal(commandExecutor.execute.calledOnceWith(options), true);
|
|
110
104
|
});
|
|
@@ -116,8 +110,14 @@ describe("Setup", () => {
|
|
|
116
110
|
const hostname = "localhost";
|
|
117
111
|
const setup = new Setup(
|
|
118
112
|
["--hostname", hostname, "--analytics", "off", "--verbose"],
|
|
119
|
-
new Config({ root: "." })
|
|
113
|
+
new Config({ name: PROGRAM_NAME, version: "1.0.0", root: "." })
|
|
120
114
|
);
|
|
115
|
+
sandbox
|
|
116
|
+
// @ts-ignore - Sidestep `this.parse()` error when calling `run()` directly.
|
|
117
|
+
.stub(setup, "parse")
|
|
118
|
+
.resolves({
|
|
119
|
+
flags: { hostname, useExisting: false, analytics: "off", verbose: true }
|
|
120
|
+
});
|
|
121
121
|
|
|
122
122
|
await setup.run();
|
|
123
123
|
|
|
@@ -130,12 +130,11 @@ describe("Setup", () => {
|
|
|
130
130
|
});
|
|
131
131
|
|
|
132
132
|
describe("catch", () => {
|
|
133
|
-
it("should fail
|
|
134
|
-
const setup = new Setup([
|
|
135
|
-
|
|
136
|
-
const error = new Error("Nonexistent flag: --incorrect-flag\nSee more help with --help");
|
|
133
|
+
it("should fail for any errors in command execution.", async () => {
|
|
134
|
+
const setup = new Setup([], new Config({ name: PROGRAM_NAME, version: "1.0.0", root: "." }));
|
|
137
135
|
|
|
138
|
-
|
|
136
|
+
const error = new Error("Something went wrong.");
|
|
137
|
+
await expect(setup.catch(error)).to.be.rejectedWith(error);
|
|
139
138
|
|
|
140
139
|
assert.equal(
|
|
141
140
|
analyticsService.postEvent.calledOnceWith(AnalyticsErrorMarkers.ERROR_SSL_SETUP, error.message, false),
|
package/tsconfig.json
CHANGED
|
@@ -17,11 +17,13 @@
|
|
|
17
17
|
"outDir": "dist",
|
|
18
18
|
"preserveConstEnums": true,
|
|
19
19
|
"resolveJsonModule": true,
|
|
20
|
+
"skipLibCheck": true,
|
|
20
21
|
"sourceMap": true,
|
|
21
22
|
"strict": true,
|
|
22
23
|
"target": "ESNext",
|
|
23
24
|
"types": ["reflect-metadata"],
|
|
24
|
-
"useUnknownInCatchVariables": false
|
|
25
|
+
"useUnknownInCatchVariables": false,
|
|
26
|
+
"isolatedDeclarations": true
|
|
25
27
|
},
|
|
26
28
|
"exclude": ["node_modules", "src/test/**/*"],
|
|
27
29
|
"include": ["src/**/*"],
|