Skip to content

Commit

Permalink
fix(tests): cover token entity, github client
Browse files Browse the repository at this point in the history
  • Loading branch information
ssube committed Oct 12, 2019
1 parent 8513783 commit 4e0f1bb
Show file tree
Hide file tree
Showing 7 changed files with 184 additions and 58 deletions.
2 changes: 1 addition & 1 deletion config/tslint.cc.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
],
"arrow-parens": true,
"arrow-return-shorthand": true,
"await-promise": true,
"await-promise": [true, "PromiseLike"],
"ban": [true, {
"message": "use lodash isString",
"name": ["util", "isString"]
Expand Down
10 changes: 10 additions & 0 deletions src/interval/MessageInterval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { IntervalData } from '.';
import { Context } from '../entity/Context';
import { Message, MessageEntityOptions } from '../entity/Message';
import { Tick } from '../entity/Tick';
import { NotInitializedError } from '../error/NotInitializedError';
import { ServiceDefinition } from '../Service';
import { Transform, TransformData } from '../transform';
import { applyTransforms } from '../transform/helpers';
Expand All @@ -16,11 +17,13 @@ export interface MessageIntervalData extends IntervalData {
}

export class MessageInterval extends BaseInterval<MessageIntervalData> {
protected started: boolean;
protected readonly transforms: Array<Transform>;

constructor(options: BaseIntervalOptions<MessageIntervalData>) {
super(options, 'isolex#/definitions/service-interval-message');

this.started = false;
this.transforms = [];
}

Expand All @@ -31,15 +34,22 @@ export class MessageInterval extends BaseInterval<MessageIntervalData> {
const transform = await this.services.createService<Transform, TransformData>(def);
this.transforms.push(transform);
}

this.started = true;
}

public async stop() {
this.started = false;
this.transforms.length = 0;

return super.stop();
}

public async tick(context: Context, next: Tick, last?: Tick): Promise<number> {
if (!this.started) {
throw new NotInitializedError('message interval has not been started');
}

const initial = new Message({
...this.data.defaultMessage,
context,
Expand Down
30 changes: 20 additions & 10 deletions src/utils/github/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,33 +18,43 @@ export interface GithubClientData {

export interface GithubClientOptions extends BaseOptions {
[INJECT_LOGGER]: Logger;
app: typeof App;
data: GithubClientData;
kit: typeof Octokit;
}

@Inject(INJECT_LOGGER)
export class GithubClient {
public readonly client: Octokit;
protected app: App;
protected readonly app: App;
protected readonly data: GithubClientData;

constructor(options: GithubClientOptions) {
const {
app = App,
data,
kit = Octokit,
} = options;

this.app = new App({
this.app = new app({
id: options.data.app.id,
privateKey: options.data.app.key,
});

this.client = new Octokit({
auth: async () => {
const token = await this.app.getInstallationAccessToken({
installationId: options.data.installation.id,
});
return `token ${token}`;
},
this.client = new kit({
auth: () => this.renewToken(),
previews: [
'application/vnd.github.machine-man-preview+json',
'application/vnd.github.ocelot-preview+json',
],
userAgent: options.data.agent,
});
this.data = data;
}

public async renewToken() {
const token = await this.app.getInstallationAccessToken({
installationId: this.data.installation.id,
});
return `token ${token}`;
}
}
23 changes: 23 additions & 0 deletions test/entity/auth/TestToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { expect } from 'chai';

import { Token, TokenOptions } from '../../../src/entity/auth/Token';
import { describeLeaks, itLeaks } from '../../helpers/async';

describeLeaks('token entity', async () => {
itLeaks('should copy options', async () => {
const testProps = {
audience: ['test'],
expiresAt: new Date(),
issuer: 'test',
subject: 'test',
};
const data: TokenOptions = {
...testProps,
data: {},
grants: [],
labels: {},
};
const token = new Token(data);
expect(token).to.deep.include(testProps);
});
});
31 changes: 31 additions & 0 deletions test/interval/TestMessageInterval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Bot } from '../../src/Bot';
import { INJECT_BOT } from '../../src/BotService';
import { Context } from '../../src/entity/Context';
import { Tick } from '../../src/entity/Tick';
import { NotInitializedError } from '../../src/error/NotInitializedError';
import { MessageInterval } from '../../src/interval/MessageInterval';
import { TransformModule } from '../../src/module/TransformModule';
import { Schema } from '../../src/schema';
Expand Down Expand Up @@ -124,4 +125,34 @@ describeLeaks('message interval', async () => {
expect(interval.tick(ineeda<Context>(), ineeda<Tick>({}))).to.eventually.be.rejectedWith(BaseError);
expect(sendMessage).to.have.callCount(0);
});

itLeaks('should throw if not started', async () => {
const sendMessage = spy();
const bot = ineeda<Bot>({
sendMessage,
});
const { container, services } = await createServiceContainer(new TransformModule());
services.bind(INJECT_SCHEMA).toInstance(new Schema());
services.bind(INJECT_BOT).toInstance(bot);
services.addService(ineeda<Service>({
kind: TEST_SVC2,
name: TEST_TARGET,
}));
const interval = await createService(container, MessageInterval, {
[INJECT_BOT]: bot,
[INJECT_CLOCK]: ineeda<Clock>({
setInterval() { /* noop */ },
}),
data: {
...TEST_CONFIG.data,
transforms: [],
},
metadata: TEST_CONFIG.metadata,
});

await expect(interval.tick(ineeda<Context>(), ineeda<Tick>({}))).to.eventually.be.rejectedWith(NotInitializedError);
await interval.start();
await interval.stop();
await expect(interval.tick(ineeda<Context>(), ineeda<Tick>({}))).to.eventually.be.rejectedWith(NotInitializedError);
});
});
90 changes: 43 additions & 47 deletions test/interval/TestMetricsInterval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,44 @@ import { match, spy } from 'sinon';

import { Context } from '../../src/entity/Context';
import { Tick } from '../../src/entity/Tick';
import { MetricsInterval } from '../../src/interval/MetricsInterval';
import { InvalidArgumentError } from '../../src/error/InvalidArgumentError';
import { MetricsInterval, MetricsIntervalData } from '../../src/interval/MetricsInterval';
import { defer } from '../../src/utils/Async';
import { describeLeaks, itLeaks } from '../helpers/async';
import { createService, createServiceContainer } from '../helpers/container';

const TEST_TARGET = 'test-target';
const TEST_INTERVAL = 'metrics-interval';
const TEST_DATA: MetricsIntervalData = {
defaultContext: {
channel: {
id: '',
thread: '',
},
name: '',
uid: '',
},
defaultTarget: {
kind: TEST_TARGET,
name: TEST_TARGET,
},
filters: [],
frequency: {
time: '100ms',
},
strict: false,
};
const TEST_METADATA = {
kind: TEST_INTERVAL,
name: TEST_INTERVAL,
};

describeLeaks('metrics interval', async () => {
itLeaks('should succeed each tick', async () => {
const { container } = await createServiceContainer();
const interval = await createService(container, MetricsInterval, {
data: {
defaultContext: {
channel: {
id: '',
thread: '',
},
name: '',
uid: '',
},
defaultTarget: {
kind: TEST_TARGET,
name: TEST_TARGET,
},
filters: [],
frequency: {
time: '100ms',
},
strict: false,
},
metadata: {
kind: TEST_INTERVAL,
name: TEST_INTERVAL,
}
data: TEST_DATA,
metadata: TEST_METADATA,
});
const status = await interval.tick(ineeda<Context>(), ineeda<Tick>(), ineeda<Tick>());
expect(status).to.equal(0);
Expand All @@ -49,33 +52,26 @@ describeLeaks('metrics interval', async () => {
const collector = spy();
const interval = await createService(container, MetricsInterval, {
collector,
data: {
defaultContext: {
channel: {
id: '',
thread: '',
},
name: '',
uid: '',
},
defaultTarget: {
kind: TEST_TARGET,
name: TEST_TARGET,
},
filters: [],
frequency: {
time: '10ms',
},
strict: false,
},
metadata: {
kind: TEST_INTERVAL,
name: TEST_INTERVAL,
}
data: TEST_DATA,
metadata: TEST_METADATA,
});
await interval.startInterval();
await defer(50);
expect(collector).to.have.been.calledWithMatch(match.has('register'));
expect(collector).to.have.been.calledWithMatch(match.has('timeout'));
});

itLeaks('must have a frequency', async () => {
const { container } = await createServiceContainer();
const interval = await createService(container, MetricsInterval, {
data: {
...TEST_DATA,
frequency: {
cron: '* * * * *',
},
},
metadata: TEST_METADATA,
});
expect(interval.startInterval()).to.eventually.be.rejectedWith(InvalidArgumentError);
});
});
56 changes: 56 additions & 0 deletions test/utils/github/TestClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { App } from '@octokit/app';
import Octokit from '@octokit/rest';
import { expect } from 'chai';
import { ineeda } from 'ineeda';
import { match, stub } from 'sinon';

import { GithubClient } from '../../../src/utils/github';
import { describeLeaks, itLeaks } from '../../helpers/async';
import { createServiceContainer } from '../../helpers/container';

// tslint:disable:no-any
describeLeaks('github client', async () => {
itLeaks('should poll for new tokens', async () => {
const getInstallationAccessToken = stub().returns('test');
const app = stub().returns(ineeda<App>({
getInstallationAccessToken,
})) as any;
const { container } = await createServiceContainer();
const client = await container.create(GithubClient, {
app,
data: {
agent: '',
app: {
id: 0,
key: '',
},
installation: {
id: 0,
},
},
});
const token = await client.renewToken();

expect(getInstallationAccessToken).to.have.callCount(1);
expect(token).to.equal('token test');
});

itLeaks('should poll for new tokens', async () => {
const kit = stub().returns(ineeda<Octokit>()) as any;
const { container } = await createServiceContainer();
await container.create(GithubClient, {
data: {
agent: '',
app: {
id: 0,
key: '',
},
installation: {
id: 0,
},
},
kit,
});
expect(kit).to.have.been.calledWithMatch(match.has('auth', match.func));
});
});

0 comments on commit 4e0f1bb

Please sign in to comment.