Skip to content

Commit

Permalink
Adds command 'tenant info get'. Closes pnp#5389
Browse files Browse the repository at this point in the history
  • Loading branch information
nanddeepn authored and martinlingstuyl committed Sep 14, 2023
1 parent 45fb2db commit d9f224d
Show file tree
Hide file tree
Showing 5 changed files with 410 additions and 1 deletion.
101 changes: 101 additions & 0 deletions docs/docs/cmd/tenant/info/info-get.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import Global from '/docs/cmd/_global.mdx';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# tenant info get

Gets information about any tenant

## Usage

```sh
m365 tenant info get [options]
```

## Options

```md definition-list
`-d, --domainName [domainName]`
: The primary domain name of a tenant. Optionally specify either `domainName` or `tenantId` but not both. If none are specified, the tenantId of the currently signed-in user is used.

`-i, --tenantId [tenantId]`
: The unique tenant identifier of a tenant. Optionally specify either `domainName` or `tenantId` but not both. If none are specified, the tenantId of the currently signed-in user is used.
```

<Global />

## Remarks

If no domain name or tenantId is specified, the command will return the tenant information of the currently signed in user.

## Examples

Get tenant information for the currently signed in user.

```sh
m365 tenant info get
```

Get tenant information for the Contoso tenant.

```sh
m365 tenant info get --domainName contoso.com
```

Get tenant information by id.

```sh
m365 tenant info get --tenantId e65b162c-6f87-4eb1-a24e-1b37d3504663
```

## Response

<Tabs>
<TabItem value="JSON">

```json
{
"tenantId": "e65b162c-6f87-4eb1-a24e-1b37d3504663",
"federationBrandName": null,
"displayName": "Contoso",
"defaultDomainName": "contoso.com"
}
```

</TabItem>
<TabItem value="Text">

```text
defaultDomainName : contoso.com
displayName : Contoso
federationBrandName : null
tenantId : e65b162c-6f87-4eb1-a24e-1b37d3504663
```

</TabItem>
<TabItem value="CSV">

```csv
tenantId,displayName,defaultDomainName
e65b162c-6f87-4eb1-a24e-1b37d3504663,Contoso,contoso.com
```

</TabItem>
<TabItem value="Markdown">

```md
# tenant info get

Date: 9/14/2023

## Contoso

Property | Value
---------|-------
tenantId | e65b162c-6f87-4eb1-a24e-1b37d3504663
displayName | Contoso
defaultDomainName | contoso.com
```

</TabItem>
</Tabs>
9 changes: 9 additions & 0 deletions docs/src/config/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,15 @@ const sidebars = {
}
]
},
{
info: [
{
type: 'doc',
label: 'info get',
id: 'cmd/tenant/info/info-get'
}
]
},
{
report: [
{
Expand Down
3 changes: 2 additions & 1 deletion src/m365/tenant/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ const prefix: string = 'tenant';

export default {
ID_GET: `${prefix} id get`,
INFO_GET: `${prefix} info get`,
REPORT_ACTIVEUSERCOUNTS: `${prefix} report activeusercounts`,
REPORT_ACTIVEUSERDETAIL: `${prefix} report activeuserdetail`,
REPORT_OFFICE365ACTIVATIONCOUNTS: `${prefix} report office365activationcounts`,
REPORT_OFFICE365ACTIVATIONSUSERDETAIL: `${prefix} report office365activationsuserdetail`,
REPORT_OFFICE365ACTIVATIONSUSERCOUNTS: `${prefix} report office365activationsusercounts`,
REPORT_SERVICESUSERCOUNTS: `${prefix} report servicesusercounts`,
SECURITY_ALERTS_LIST:`${prefix} security alerts list`,
SECURITY_ALERTS_LIST: `${prefix} security alerts list`,
SERVICEANNOUNCEMENT_HEALTHISSUE_GET: `${prefix} serviceannouncement healthissue get`,
SERVICEANNOUNCEMENT_HEALTH_GET: `${prefix} serviceannouncement health get`,
SERVICEANNOUNCEMENT_HEALTH_LIST: `${prefix} serviceannouncement health list`,
Expand Down
189 changes: 189 additions & 0 deletions src/m365/tenant/commands/info/info-get.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import assert from 'assert';
import sinon from 'sinon';
import auth from '../../../../Auth.js';
import { Cli } from '../../../../cli/Cli.js';
import { CommandInfo } from '../../../../cli/CommandInfo.js';
import { Logger } from '../../../../cli/Logger.js';
import { CommandError } from '../../../../Command.js';
import request from '../../../../request.js';
import { telemetry } from '../../../../telemetry.js';
import { accessToken } from '../../../../utils/accessToken.js';
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 './info-get.js';

describe(commands.INFO_GET, () => {
const domainName = 'contoso.com';
const tenantId = 'e65b162c-6f87-4eb1-a24e-1b37d3504663';
const tenantInfoResponse = {
tenantId: tenantId,
federationBrandName: null,
displayName: "Contoso",
defaultDomainName: domainName
};

let log: any[];
let loggerLogSpy: sinon.SinonSpy;
let logger: Logger;
let commandInfo: CommandInfo;

before(() => {
sinon.stub(auth, 'restoreAuth').resolves();
sinon.stub(telemetry, 'trackEvent').returns();
sinon.stub(pid, 'getProcessName').returns('');
sinon.stub(session, 'getId').returns('');
auth.service.connected = true;
commandInfo = Cli.getCommandInfo(command);
if (!auth.service.accessTokens[auth.defaultResource]) {
auth.service.accessTokens[auth.defaultResource] = {
expiresOn: '123',
accessToken: 'abc'
};
}
});

beforeEach(() => {
log = [];
logger = {
log: async (msg: string) => {
log.push(msg);
},
logRaw: async (msg: string) => {
log.push(msg);
},
logToStderr: async (msg: string) => {
log.push(msg);
}
};
loggerLogSpy = sinon.spy(logger, 'log');
});

afterEach(() => {
sinonUtil.restore([
request.get
]);
});

after(() => {
sinon.restore();
auth.service.connected = false;
});

it('has correct name', () => {
assert.strictEqual(command.name, commands.INFO_GET);
});

it('has a description', () => {
assert.notStrictEqual(command.description, null);
});

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

it('passes validation when the tenantId is a valid GUID', async () => {
const actual = await command.validate({ options: { tenantId: tenantId } }, commandInfo);
assert.strictEqual(actual, true);
});

it('fails validation if both domainName and tenantId are specified', async () => {
const actual = await command.validate({ options: { domainName: domainName, tenantId: tenantId } }, commandInfo);
assert.notStrictEqual(actual, true);
});

it('gets tenant information for the currently signed in user if no domain name or tenantId is passed', async () => {
sinon.stub(accessToken, 'getUserNameFromAccessToken').callsFake(() => {
return '[email protected]';
});

sinon.stub(request, 'get').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/v1.0/tenantRelationships/findTenantInformationByDomainName(domainName='contoso.com')`) {
return tenantInfoResponse;
}

throw 'Invalid Request';
});

await command.action(logger, { options: { verbose: true } });
assert(loggerLogSpy.calledOnceWithExactly(tenantInfoResponse));
sinonUtil.restore(accessToken.getUserNameFromAccessToken);
});

it('gets tenant information with correct domain name', async () => {
sinon.stub(request, 'get').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/v1.0/tenantRelationships/findTenantInformationByDomainName(domainName='contoso.com')`) {
return tenantInfoResponse;
}

throw 'Invalid Request';
});

await command.action(logger, { options: { verbose: true, domainName: domainName } });
assert(loggerLogSpy.calledOnceWithExactly(tenantInfoResponse));
});

it('gets tenant information with correct tenant id', async () => {
sinon.stub(request, 'get').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/v1.0/tenantRelationships/findTenantInformationByTenantId(tenantId='e65b162c-6f87-4eb1-a24e-1b37d3504663')`) {
return tenantInfoResponse;
}

throw 'Invalid Request';
});

await command.action(logger, { options: { verbose: true, tenantId: tenantId } });
assert(loggerLogSpy.calledOnceWithExactly(tenantInfoResponse));
});

it('handles error when trying to retrieve information for a non-existant tenant by id', async () => {
sinon.stub(request, 'get').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/v1.0/tenantRelationships/findTenantInformationByTenantId(tenantId='e65b162c-6f87-4eb1-a24e-1b37d3504663')`) {
throw {
"error": {
"code": "Directory_ObjectNotFound",
"message": "Unable to read the company information from the directory.",
"innerError": {
"date": "2023-09-14T14:07:47",
"request-id": "3b91132c-5c79-454b-8dd4-06964e788a24",
"client-request-id": "2147e6c6-8036-cc2f-f4d0-eec89dbc48d7"
}
}
};
}

throw 'Invalid Request';
});

await assert.rejects(command.action(logger, { options: { tenantId: tenantId } } as any), new CommandError("Unable to read the company information from the directory."));
});

it('handles error when trying to retrieve information for a non-existant tenant by domain name', async () => {
sinon.stub(request, 'get').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/v1.0/tenantRelationships/findTenantInformationByDomainName(domainName='xyz.com')`) {
throw {
"error": {
"code": "Directory_ObjectNotFound",
"message": "Unable to read the company information from the directory.",
"innerError": {
"date": "2023-09-14T14:07:47",
"request-id": "3b91132c-5c79-454b-8dd4-06964e788a24",
"client-request-id": "2147e6c6-8036-cc2f-f4d0-eec89dbc48d7"
}
}
};
}

throw 'Invalid Request';
});

await assert.rejects(command.action(logger, { options: { domainName: 'xyz.com' } } as any), new CommandError("Unable to read the company information from the directory."));
});

it('correctly handles random API error', async () => {
sinon.stub(request, 'get').rejects(new Error('An error has occurred'));
await assert.rejects(command.action(logger, { options: { domainName: 'xyz.com' } } as any), new CommandError('An error has occurred'));
});
});
Loading

0 comments on commit d9f224d

Please sign in to comment.