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
12 changes: 9 additions & 3 deletions src/m365/spe/commands/container/container-activate.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@ 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 './container-activate.js';
import command, { options } from './container-activate.js';
import { CommandError } from '../../../../Command.js';
import { formatting } from '../../../../utils/formatting.js';
import { CommandInfo } from '../../../../cli/CommandInfo.js';
import { cli } from '../../../../cli/cli.js';

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

const containerId = 'b!ISJs1WRro0y0EWgkUYcktDa0mE8zSlFEqFzqRn70Zwp1CEtDEBZgQICPkRbil_5Z';

Expand All @@ -24,6 +28,8 @@ describe(commands.CONTAINER_ACTIVATE, () => {
sinon.stub(pid, 'getProcessName').returns('');
sinon.stub(session, 'getId').returns('');
auth.connection.active = true;
commandInfo = cli.getCommandInfo(command);
commandOptionsSchema = commandInfo.command.getSchemaToParse() as typeof options;
});

beforeEach(() => {
Expand Down Expand Up @@ -69,7 +75,7 @@ describe(commands.CONTAINER_ACTIVATE, () => {
throw 'Invalid request';
});

await command.action(logger, { options: { id: containerId, verbose: true } });
await command.action(logger, { options: commandOptionsSchema.parse({ id: containerId, verbose: true }) });
Comment thread
MartinM85 marked this conversation as resolved.
assert(postStub.calledOnce);
});

Expand All @@ -94,7 +100,7 @@ describe(commands.CONTAINER_ACTIVATE, () => {
throw 'Invalid request';
});

await assert.rejects(command.action(logger, { options: { id: containerId, verbose: true } } as any),
await assert.rejects(command.action(logger, { options: commandOptionsSchema.parse({ id: containerId, verbose: true }) }),
new CommandError(error.error.message));
});
});
31 changes: 11 additions & 20 deletions src/m365/spe/commands/container/container-activate.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import GlobalOptions from '../../../../GlobalOptions.js';
import { z } from 'zod';
import { Logger } from '../../../../cli/Logger.js';
import { globalOptionsZod } from '../../../../Command.js';
import GraphCommand from '../../../base/GraphCommand.js';
import commands from '../../commands.js';
import request, { CliRequestOptions } from '../../../../request.js';
import { formatting } from '../../../../utils/formatting.js';

export const options = z.strictObject({
...globalOptionsZod.shape,
id: z.string().alias('i')
});

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

interface CommandArgs {
options: Options;
}

interface Options extends GlobalOptions {
id: string;
}

class SpeContainerActivateCommand extends GraphCommand {
public get name(): string {
return commands.CONTAINER_ACTIVATE;
Expand All @@ -22,21 +26,8 @@ class SpeContainerActivateCommand extends GraphCommand {
return 'Activates a container';
}

constructor() {
super();

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

#initOptions(): void {
this.options.unshift(
{ option: '-i, --id <id>' }
);
}

#initTypes(): void {
this.types.string.push('id');
public get schema(): z.ZodTypeAny {
return options;
}

public async commandAction(logger: Logger, args: CommandArgs): Promise<void> {
Expand Down
10 changes: 5 additions & 5 deletions src/m365/spe/commands/container/container-get.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ describe(commands.CONTAINER_GET, () => {
throw 'Invalid GET request: ' + opts.url;
});

await command.action(logger, { options: { name: containerName, containerTypeId: containerTypeId } });
await command.action(logger, { options: commandOptionsSchema.parse({ name: containerName, containerTypeId: containerTypeId }) });
assert.deepStrictEqual(loggerLogSpy.lastCall.args[0], containerResponse);
});

Expand All @@ -197,7 +197,7 @@ describe(commands.CONTAINER_GET, () => {
throw 'Invalid GET request: ' + opts.url;
});

await command.action(logger, { options: { name: containerName, containerTypeName: containerTypeName, verbose: true } });
await command.action(logger, { options: commandOptionsSchema.parse({ name: containerName, containerTypeName: containerTypeName, verbose: true }) });
assert.deepStrictEqual(loggerLogSpy.lastCall.args[0], containerResponse);
});

Expand All @@ -206,7 +206,7 @@ describe(commands.CONTAINER_GET, () => {
value: deletedContainersResponse
});

await assert.rejects(command.action(logger, { options: { name: 'Non-existing container', containerTypeId: containerTypeId } }),
await assert.rejects(command.action(logger, { options: commandOptionsSchema.parse({ name: 'Non-existing container', containerTypeId: containerTypeId }) }),
new CommandError(`The specified container 'Non-existing container' does not exist.`));
});

Expand All @@ -232,7 +232,7 @@ describe(commands.CONTAINER_GET, () => {
});

const stubMultiResults = sinon.stub(cli, 'handleMultipleResultsFound').resolves(deletedContainersResponse.find(c => c.id === containerId)!);
await command.action(logger, { options: { name: containerName, containerTypeId: containerTypeId } });
await command.action(logger, { options: commandOptionsSchema.parse({ name: containerName, containerTypeId: containerTypeId }) });
assert(stubMultiResults.calledOnce);
});

Expand All @@ -245,7 +245,7 @@ describe(commands.CONTAINER_GET, () => {
}
});

await assert.rejects(command.action(logger, { options: { id: containerId } }),
await assert.rejects(command.action(logger, { options: commandOptionsSchema.parse({ id: containerId }) }),
new CommandError(errorMessage));
});
});
24 changes: 13 additions & 11 deletions src/m365/spe/commands/container/container-list.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ 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 './container-list.js';
import command, { options } from './container-list.js';
import { CommandError } from '../../../../Command.js';
import { CommandInfo } from '../../../../cli/CommandInfo.js';
import { cli } from '../../../../cli/cli.js';
Expand All @@ -19,6 +19,7 @@ describe(commands.CONTAINER_LIST, () => {
let logger: Logger;
let loggerLogSpy: sinon.SinonSpy;
let commandInfo: CommandInfo;
let commandOptionsSchema: typeof options;

const containersList = [{
"id": "b!ISJs1WRro0y0EWgkUYcktDa0mE8zSlFEqFzqRn70Zwp1CEtDEBZgQICPkRbil_5Z",
Expand All @@ -41,6 +42,7 @@ describe(commands.CONTAINER_LIST, () => {

auth.connection.active = true;
commandInfo = cli.getCommandInfo(command);
commandOptionsSchema = commandInfo.command.getSchemaToParse() as typeof options;
});

beforeEach(() => {
Expand Down Expand Up @@ -86,14 +88,14 @@ describe(commands.CONTAINER_LIST, () => {
assert.deepStrictEqual(command.defaultProperties(), ['id', 'displayName', 'containerTypeId', 'createdDateTime']);
});

it('fails validation if the containerTypeId is not a valid guid', async () => {
const actual = await command.validate({ options: { containerTypeId: 'abc' } }, commandInfo);
assert.notStrictEqual(actual, true);
it('fails validation if the containerTypeId is not a valid guid', () => {
const result = commandOptionsSchema.safeParse({ containerTypeId: 'abc' });
assert.strictEqual(result.success, false);
});

Comment thread
MartinM85 marked this conversation as resolved.
it('passes validation if valid containerTypeId is specified', async () => {
const actual = await command.validate({ options: { containerTypeId: "e2756c4d-fa33-4452-9c36-2325686e1082" } }, commandInfo);
assert.strictEqual(actual, true);
it('passes validation if valid containerTypeId is specified', () => {
const result = commandOptionsSchema.safeParse({ containerTypeId: "e2756c4d-fa33-4452-9c36-2325686e1082" });
assert.strictEqual(result.success, true);
});

it('retrieves list of container type by id', async () => {
Expand All @@ -105,7 +107,7 @@ describe(commands.CONTAINER_LIST, () => {
throw 'Invalid request';
});

await command.action(logger, { options: { containerTypeId: "e2756c4d-fa33-4452-9c36-2325686e1082", verbose: true } });
await command.action(logger, { options: commandOptionsSchema.parse({ containerTypeId: "e2756c4d-fa33-4452-9c36-2325686e1082", verbose: true }) });
assert(loggerLogSpy.calledWith(containersList));
});

Expand All @@ -118,7 +120,7 @@ describe(commands.CONTAINER_LIST, () => {
throw 'Invalid request';
});

await command.action(logger, { options: { containerTypeName: "standard container", verbose: true } });
await command.action(logger, { options: commandOptionsSchema.parse({ containerTypeName: "standard container", verbose: true }) });
assert(loggerLogSpy.calledWith(containersList));
});

Expand All @@ -128,10 +130,10 @@ describe(commands.CONTAINER_LIST, () => {
sinon.stub(spe, 'getContainerTypeIdByName').rejects(new Error(error));

await assert.rejects(command.action(logger, {
options: {
options: commandOptionsSchema.parse({
containerTypeName: "nonexisting container",
verbose: true
}
})
}), new CommandError('An error has occurred'));
});
});
76 changes: 22 additions & 54 deletions src/m365/spe/commands/container/container-list.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import { z } from 'zod';
import { Logger } from '../../../../cli/Logger.js';
import GlobalOptions from '../../../../GlobalOptions.js';
import { globalOptionsZod } from '../../../../Command.js';
import { formatting } from '../../../../utils/formatting.js';
import { odata } from '../../../../utils/odata.js';
import { validation } from '../../../../utils/validation.js';
import GraphCommand from '../../../base/GraphCommand.js';
import commands from '../../commands.js';
import { SpeContainer, spe } from '../../../../utils/spe.js';

export const options = z.strictObject({
...globalOptionsZod.shape,
containerTypeId: z.uuid().optional(),
containerTypeName: z.string().optional()
});

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

interface CommandArgs {
options: Options;
}

export interface Options extends GlobalOptions {
containerTypeId?: string;
containerTypeName?: string;
}

class SpeContainerListCommand extends GraphCommand {
public get name(): string {
return commands.CONTAINER_LIST;
Expand All @@ -25,58 +28,23 @@ class SpeContainerListCommand extends GraphCommand {
return 'Lists all Container Types';
}
Comment thread
MartinM85 marked this conversation as resolved.

public defaultProperties(): string[] | undefined {
return ['id', 'displayName', 'containerTypeId', 'createdDateTime'];
}

constructor() {
super();

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

#initTelemetry(): void {
this.telemetry.push((args: CommandArgs) => {
Object.assign(this.telemetryProperties, {
containerTypeId: typeof args.options.containerTypeId !== 'undefined',
containerTypeName: typeof args.options.containerTypeName !== 'undefined'
});
});
}

#initOptions(): void {
this.options.unshift(
{
option: '--containerTypeId [containerTypeId]'
},
{
option: '--containerTypeName [containerTypeName]'
}
);
public get schema(): z.ZodTypeAny {
return options;
}

#initValidators(): void {
this.validators.push(
async (args: CommandArgs) => {
if (args.options.containerTypeId && !validation.isValidGuid(args.options.containerTypeId as string)) {
return `${args.options.containerTypeId} is not a valid GUID`;
public getRefinedSchema(schema: typeof options): z.ZodObject<any> | undefined {
return schema
.refine(opts => [opts.containerTypeId, opts.containerTypeName].filter(o => o !== undefined).length <= 1, {
message: 'Specify either containerTypeId or containerTypeName, but not both.',
Comment thread
MartinM85 marked this conversation as resolved.
Outdated
params: {
customCode: 'optionSet',
options: ['containerTypeId', 'containerTypeName']
}

return true;
}
);
}

#initOptionSets(): void {
this.optionSets.push({ options: ['containerTypeId', 'containerTypeName'] });
});
}

#initTypes(): void {
this.types.string.push('containerTypeId', 'containerTypeName');
public defaultProperties(): string[] | undefined {
return ['id', 'displayName', 'containerTypeId', 'createdDateTime'];
}

public async commandAction(logger: Logger, args: CommandArgs): Promise<void> {
Expand Down
14 changes: 10 additions & 4 deletions src/m365/spe/commands/containertype/containertype-list.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ 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 './containertype-list.js';
import command, { options } from './containertype-list.js';
import { CommandError } from '../../../../Command.js';
import { odata } from '../../../../utils/odata.js';
import { accessToken } from '../../../../utils/accessToken.js';
import { cli } from '../../../../cli/cli.js';
import { CommandInfo } from '../../../../cli/CommandInfo.js';

const containerTypeData = [
{
Expand Down Expand Up @@ -57,6 +59,8 @@ describe(commands.CONTAINERTYPE_LIST, () => {
let log: string[];
let logger: Logger;
let loggerLogSpy: sinon.SinonSpy;
let commandInfo: CommandInfo;
let commandOptionsSchema: typeof options;

before(() => {
sinon.stub(auth, 'restoreAuth').resolves();
Expand All @@ -65,6 +69,8 @@ describe(commands.CONTAINERTYPE_LIST, () => {
sinon.stub(session, 'getId').returns('');
sinon.stub(accessToken, 'assertAccessTokenType').withArgs('delegated').returns();
auth.connection.active = true;
commandInfo = cli.getCommandInfo(command);
commandOptionsSchema = commandInfo.command.getSchemaToParse() as typeof options;
});

beforeEach(() => {
Expand Down Expand Up @@ -115,7 +121,7 @@ describe(commands.CONTAINERTYPE_LIST, () => {
throw 'Invalid GET request ' + url;
});

await command.action(logger, { options: { verbose: true } });
await command.action(logger, { options: commandOptionsSchema.parse({ verbose: true }) });
Comment thread
MartinM85 marked this conversation as resolved.
assert(loggerLogSpy.calledOnceWith(containerTypeData));
});

Expand All @@ -124,9 +130,9 @@ describe(commands.CONTAINERTYPE_LIST, () => {
sinon.stub(odata, 'getAllItems').rejects(new Error(error));

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