Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 27 additions & 20 deletions src/m365/spo/commands/cdn/cdn-get.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ import { pid } from '../../../../utils/pid.js';
import { session } from '../../../../utils/session.js';
import { sinonUtil } from '../../../../utils/sinonUtil.js';
import commands from '../../commands.js';
import command from './cdn-get.js';
import command, { options } from './cdn-get.js';

describe(commands.CDN_GET, () => {
let log: any[];
let logger: Logger;
let commandInfo: CommandInfo;
let commandOptionsSchema: typeof options;
let loggerLogSpy: sinon.SinonSpy;
let loggerLogToStderrSpy: sinon.SinonSpy;
const spoAdminUrl = 'https://contoso-admin.sharepoint.com';
Expand All @@ -31,6 +32,7 @@ describe(commands.CDN_GET, () => {
auth.connection.spoUrl = 'https://contoso.sharepoint.com';
auth.connection.spoTenantId = 'abc';
commandInfo = cli.getCommandInfo(command);
commandOptionsSchema = commandInfo.command.getSchemaToParse() as typeof options;
});

beforeEach(() => {
Expand Down Expand Up @@ -93,7 +95,7 @@ describe(commands.CDN_GET, () => {
throw 'Invalid request ' + opts.url;
});

await command.action(logger, { options: { verbose: true, type: 'Public' } });
await command.action(logger, { options: commandOptionsSchema.parse({ verbose: true, type: 'Public' }) });
assert(loggerLogToStderrSpy.calledWithExactly(`Public CDN at ${spoAdminUrl} is enabled`));
});

Expand All @@ -119,7 +121,7 @@ describe(commands.CDN_GET, () => {
throw 'Invalid request';
});

await command.action(logger, { options: { type: 'Private' } });
await command.action(logger, { options: commandOptionsSchema.parse({ type: 'Private' }) });
assert(loggerLogSpy.calledOnceWithExactly(false));
});

Expand All @@ -145,7 +147,7 @@ describe(commands.CDN_GET, () => {
throw 'Invalid request';
});

await command.action(logger, { options: { verbose: true } });
await command.action(logger, { options: commandOptionsSchema.parse({ verbose: true }) });
assert(loggerLogSpy.calledOnceWithExactly(false));
});

Expand All @@ -171,7 +173,7 @@ describe(commands.CDN_GET, () => {
throw 'Invalid request';
});

await command.action(logger, { options: { verbose: true, type: 'Private' } });
await command.action(logger, { options: commandOptionsSchema.parse({ verbose: true, type: 'Private' }) });
assert(loggerLogToStderrSpy.calledWithExactly(`Private CDN at ${spoAdminUrl} is disabled`));
});

Expand All @@ -197,7 +199,7 @@ describe(commands.CDN_GET, () => {
throw 'Invalid request';
});

await command.action(logger, { options: { verbose: true } });
await command.action(logger, { options: commandOptionsSchema.parse({ verbose: true }) });
assert(loggerLogToStderrSpy.calledWithExactly(`Public CDN at ${spoAdminUrl} is enabled`));
});

Expand Down Expand Up @@ -231,33 +233,38 @@ describe(commands.CDN_GET, () => {
throw 'Invalid request';
});

await assert.rejects(command.action(logger, { options: { debug: true } } as any), new CommandError('An error has occurred'));
await assert.rejects(command.action(logger, { options: commandOptionsSchema.parse({ debug: true }) }), new CommandError('An error has occurred'));
});

it('correctly handles random API error', async () => {
sinonUtil.restore(request.post);
sinon.stub(request, 'post').rejects(new Error('An error has occurred'));

await assert.rejects(command.action(logger, { options: {} } as any), new CommandError('An error has occurred'));
await assert.rejects(command.action(logger, { options: commandOptionsSchema.parse({}) }), new CommandError('An error has occurred'));
});

it('accepts Public SharePoint Online CDN type', async () => {
const actual = await command.validate({ options: { type: 'Public' } }, commandInfo);
assert.strictEqual(actual, true);
it('passes validation with no options', () => {
const actual = commandOptionsSchema.safeParse({});
assert.strictEqual(actual.success, true);
});

it('accepts Private SharePoint Online CDN type', async () => {
const actual = await command.validate({ options: { type: 'Private' } }, commandInfo);
assert.strictEqual(actual, true);
it('accepts Public SharePoint Online CDN type', () => {
const actual = commandOptionsSchema.safeParse({ type: 'Public' });
assert.strictEqual(actual.success, true);
});

it('rejects invalid SharePoint Online CDN type', async () => {
const actual = await command.validate({ options: { type: 'foo' } }, commandInfo);
assert.notStrictEqual(actual, true);
it('accepts Private SharePoint Online CDN type', () => {
const actual = commandOptionsSchema.safeParse({ type: 'Private' });
assert.strictEqual(actual.success, true);
});

it('doesn\'t fail validation if the optional type option not specified', async () => {
const actual = await command.validate({ options: {} }, commandInfo);
assert.strictEqual(actual, true);
it('rejects invalid SharePoint Online CDN type', () => {
const actual = commandOptionsSchema.safeParse({ type: 'foo' });
assert.strictEqual(actual.success, false);
});

it('fails validation with unknown options', () => {
const actual = commandOptionsSchema.safeParse({ unknownOption: 'value' });
assert.strictEqual(actual.success, false);
});
});
58 changes: 11 additions & 47 deletions src/m365/spo/commands/cdn/cdn-get.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
import { z } from 'zod';
import { globalOptionsZod } from '../../../../Command.js';
import { Logger } from '../../../../cli/Logger.js';
import config from '../../../../config.js';
import GlobalOptions from '../../../../GlobalOptions.js';
import request, { CliRequestOptions } from '../../../../request.js';
import { ClientSvcResponse, ClientSvcResponseContents, spo } from '../../../../utils/spo.js';
import SpoCommand from '../../../base/SpoCommand.js';
import commands from '../../commands.js';

export const options = z.strictObject({
...globalOptionsZod.shape,
type: z.enum(['Public', 'Private']).optional().alias('t')
});

declare type Options = z.infer<typeof options>;

interface CommandArgs {
options: Options;
}

interface Options extends GlobalOptions {
type?: string;
}

class SpoCdnGetCommand extends SpoCommand {
private readonly validTypes: string[] = ['Public', 'Private'];

public get name(): string {
return commands.CDN_GET;
}
Expand All @@ -25,46 +27,8 @@ class SpoCdnGetCommand extends SpoCommand {
return 'View current status of the specified Microsoft 365 CDN';
}

constructor() {
super();

this.#initTelemetry();
this.#initOptions();
this.#initValidators();
this.#initTypes();
}

#initTelemetry(): void {
this.telemetry.push((args: CommandArgs) => {
Object.assign(this.telemetryProperties, {
cdnType: args.options.type || 'Public'
});
});
}

#initOptions(): void {
this.options.unshift(
{
option: '-t, --type [type]',
autocomplete: this.validTypes
}
);
}

#initValidators(): void {
this.validators.push(
async (args: CommandArgs) => {
if (args.options.type && !this.validTypes.includes(args.options.type)) {
return `'${args.options.type}' is not a valid CDN type. Allowed values are: ${this.validTypes.join(', ')}.`;
}

return true;
}
);
}

#initTypes(): void {
this.types.string.push('type');
public get schema(): z.ZodType | undefined {
return options;
}

public async commandAction(logger: Logger, args: CommandArgs): Promise<void> {
Expand Down
53 changes: 24 additions & 29 deletions src/m365/spo/commands/cdn/cdn-origin-add.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ import { session } from '../../../../utils/session.js';
import { sinonUtil } from '../../../../utils/sinonUtil.js';
import { spo } from '../../../../utils/spo.js';
import commands from '../../commands.js';
import command from './cdn-origin-add.js';
import command, { options } from './cdn-origin-add.js';

describe(commands.CDN_ORIGIN_ADD, () => {
let log: string[];
let logger: Logger;
let commandInfo: CommandInfo;
let commandOptionsSchema: typeof options;
let requests: any[];

before(() => {
Expand Down Expand Up @@ -59,6 +60,7 @@ describe(commands.CDN_ORIGIN_ADD, () => {
throw 'Invalid request';
});
commandInfo = cli.getCommandInfo(command);
commandOptionsSchema = commandInfo.command.getSchemaToParse() as typeof options;
});

beforeEach(() => {
Expand Down Expand Up @@ -93,7 +95,7 @@ describe(commands.CDN_ORIGIN_ADD, () => {
});

it('sets CDN origin on the public CDN when Public type specified', async () => {
await command.action(logger, { options: { debug: true, origin: '*/cdn', type: 'Public' } });
await command.action(logger, { options: commandOptionsSchema.parse({ debug: true, origin: '*/cdn', type: 'Public' }) });
let setRequestIssued = false;
requests.forEach(r => {
if (r.url.indexOf('/_vti_bin/client.svc/ProcessQuery') > -1 &&
Expand All @@ -107,7 +109,7 @@ describe(commands.CDN_ORIGIN_ADD, () => {
});

it('sets CDN origin on the private CDN when Private type specified', async () => {
await assert.rejects(command.action(logger, { options: { debug: true, origin: '*/cdn', type: 'Private' } }));
await assert.rejects(command.action(logger, { options: commandOptionsSchema.parse({ debug: true, origin: '*/cdn', type: 'Private' }) }));
let setRequestIssued = false;
requests.forEach(r => {
if (r.url.indexOf('/_vti_bin/client.svc/ProcessQuery') > -1 &&
Expand All @@ -121,7 +123,7 @@ describe(commands.CDN_ORIGIN_ADD, () => {
});

it('sets CDN origin on the public CDN when no type specified', async () => {
await command.action(logger, { options: { origin: '*/cdn' } });
await command.action(logger, { options: commandOptionsSchema.parse({ origin: '*/cdn' }) });
let setRequestIssued = false;
requests.forEach(r => {
if (r.url.indexOf('/_vti_bin/client.svc/ProcessQuery') > -1 &&
Expand Down Expand Up @@ -165,14 +167,14 @@ describe(commands.CDN_ORIGIN_ADD, () => {

throw 'Invalid request';
});
await assert.rejects(command.action(logger, { options: { debug: true, origin: '*/cdn', type: 'Public' } } as any),
await assert.rejects(command.action(logger, { options: commandOptionsSchema.parse({ debug: true, origin: '*/cdn', type: 'Public' }) }),
new CommandError('The library is already registered as a CDN origin.'));
});

it('correctly handles random API error', async () => {
sinonUtil.restore(request.post);
sinon.stub(request, 'post').rejects(new Error('An error has occurred'));
await assert.rejects(command.action(logger, { options: { debug: true, origin: '*/cdn', type: 'Public' } } as any),
await assert.rejects(command.action(logger, { options: commandOptionsSchema.parse({ debug: true, origin: '*/cdn', type: 'Public' }) }),
new CommandError('An error has occurred'));
});

Expand Down Expand Up @@ -208,7 +210,7 @@ describe(commands.CDN_ORIGIN_ADD, () => {
throw 'Invalid request';
});

await command.action(logger, { options: { debug: true, origin: '<*/CDN>' } });
await command.action(logger, { options: commandOptionsSchema.parse({ debug: true, origin: '<*/CDN>' }) });
let isDone = false;
log.forEach(l => {
if (l && typeof l === 'string' && l.indexOf('DONE')) {
Expand All @@ -219,35 +221,28 @@ describe(commands.CDN_ORIGIN_ADD, () => {
assert(isDone);
});

it('requires CDN origin name', () => {
const options = command.options;
let requiresCdnOriginName = false;
options.forEach(o => {
if (o.option.indexOf('<origin>') > -1) {
requiresCdnOriginName = true;
}
});
assert(requiresCdnOriginName);
it('accepts Public SharePoint Online CDN type', () => {
const actual = commandOptionsSchema.safeParse({ type: 'Public', origin: '*/CDN' });
assert.strictEqual(actual.success, true);
});

it('accepts Public SharePoint Online CDN type', async () => {
const actual = await command.validate({ options: { type: 'Public', origin: '*/CDN' } }, commandInfo);
assert.strictEqual(actual, true);
it('accepts Private SharePoint Online CDN type', () => {
const actual = commandOptionsSchema.safeParse({ type: 'Private', origin: '*/CDN' });
assert.strictEqual(actual.success, true);
});

it('accepts Private SharePoint Online CDN type', async () => {
const actual = await command.validate({ options: { type: 'Private', origin: '*/CDN' } }, commandInfo);
assert.strictEqual(actual, true);
it('rejects invalid SharePoint Online CDN type', () => {
const actual = commandOptionsSchema.safeParse({ type: 'foo', origin: '*/CDN' });
assert.strictEqual(actual.success, false);
});

it('rejects invalid SharePoint Online CDN type', async () => {
const type = 'foo';
const actual = await command.validate({ options: { type: type, origin: '*/CDN' } }, commandInfo);
assert.strictEqual(actual, `${type} is not a valid CDN type. Allowed values are Public|Private`);
it('doesn\'t fail validation if the optional type option not specified', () => {
const actual = commandOptionsSchema.safeParse({ origin: '*/CDN' });
assert.strictEqual(actual.success, true);
});
Comment thread
MartinM85 marked this conversation as resolved.

it('doesn\'t fail validation if the optional type option not specified', async () => {
const actual = await command.validate({ options: { origin: '*/CDN' } }, commandInfo);
assert.strictEqual(actual, true);
it('fails validation with unknown options', () => {
const actual = commandOptionsSchema.safeParse({ origin: '*/CDN', unknownOption: 'value' });
assert.strictEqual(actual.success, false);
});
});
Loading
Loading