Skip to content

Commit

Permalink
feat: core/cloudwatch-logging (aws-amplify#8588)
Browse files Browse the repository at this point in the history
  • Loading branch information
eddiekeller authored Jul 14, 2021
1 parent 3618b7b commit 6f28c7e
Show file tree
Hide file tree
Showing 17 changed files with 988 additions and 15 deletions.
2 changes: 1 addition & 1 deletion packages/amplify-ui-vue/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"esModuleInterop": true,
"lib": ["dom", "es2015"],
"lib": ["dom", "es2015", "es2018.asynciterable", "es2018.asyncgenerator"],
"module": "es2015",
"moduleResolution": "node",
"noImplicitAny": true,
Expand Down
1 change: 1 addition & 0 deletions packages/aws-amplify/__tests__/exports-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ describe('aws-amplify', () => {
"Signer",
"I18n",
"ServiceWorker",
"AWSCloudWatchProvider",
"withSSRContext",
"default",
]
Expand Down
1 change: 1 addition & 0 deletions packages/aws-amplify/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export {
Signer,
I18n,
ServiceWorker,
AWSCloudWatchProvider,
} from '@aws-amplify/core';
export { withSSRContext } from './withSSRContext';

Expand Down
50 changes: 50 additions & 0 deletions packages/core/__tests__/ConsoleLogger-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
AWSCloudWatchProvider,
AWS_CLOUDWATCH_PROVIDER_NAME,
Logger,
} from '../src';

describe('ConsoleLogger', () => {
describe('pluggables', () => {
it('should store pluggables correctly when addPluggable is called', () => {
const provider = new AWSCloudWatchProvider();
const logger = new Logger('name');
logger.addPluggable(provider);
const pluggables = logger.listPluggables();

expect(pluggables).toHaveLength(1);
expect(pluggables[0].getProviderName()).toEqual(
AWS_CLOUDWATCH_PROVIDER_NAME
);
});

it('should do nothing when no plugin is provided to addPluggable', () => {
const logger = new Logger('name');
logger.addPluggable();
const pluggables = logger.listPluggables();

expect(pluggables).toHaveLength(0);
});

it('should do nothing when a non-logging category plugin is provided to addPluggable', () => {
const provider = {
getCategoryName: function() {
return 'non-logging';
},
getProviderName: function() {
return 'lol';
},
configure: function() {
return {};
},
pushLogs: null,
};

const logger = new Logger('name');
logger.addPluggable(provider);
const pluggables = logger.listPluggables();

expect(pluggables).toHaveLength(0);
});
});
});
248 changes: 248 additions & 0 deletions packages/core/__tests__/Providers/AWSCloudWatchProvider-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
import { AWSCloudWatchProvider } from '../../src/Providers/AWSCloudWatchProvider';
import { AWSCloudWatchProviderOptions } from '../../src/types';
import {
AWS_CLOUDWATCH_CATEGORY,
AWS_CLOUDWATCH_PROVIDER_NAME,
} from '../../src/Util/Constants';
import { Credentials } from '../..';
import { CloudWatchLogsClient } from '@aws-sdk/client-cloudwatch-logs';

const credentials = {
accessKeyId: 'accessKeyId',
sessionToken: 'sessionToken',
secretAccessKey: 'secretAccessKey',
identityId: 'identityId',
authenticated: true,
};

const testConfig: AWSCloudWatchProviderOptions = {
logGroupName: 'logGroup',
logStreamName: 'logStream',
region: 'us-west-2',
};

describe('AWSCloudWatchProvider', () => {
it('should initiate a timer when the provider is created', () => {
const timer_spy = jest.spyOn(
AWSCloudWatchProvider.prototype,
'_initiateLogPushInterval'
);
const provider = new AWSCloudWatchProvider();
expect(timer_spy).toBeCalled();
});

describe('getCategoryName()', () => {
it('should return the AWS_CLOUDWATCH_CATEGORY', () => {
const provider = new AWSCloudWatchProvider();
expect(provider.getCategoryName()).toBe(AWS_CLOUDWATCH_CATEGORY);
});
});

describe('getProviderName()', () => {
it('should return the AWS_CLOUDWATCH_PROVIDER_NAME', () => {
const provider = new AWSCloudWatchProvider();
expect(provider.getProviderName()).toBe(AWS_CLOUDWATCH_PROVIDER_NAME);
});
});

describe('configure()', () => {
it('should return a config with logGroupName, logStreamName, and region when given a config input', () => {
const provider = new AWSCloudWatchProvider();
const config = provider.configure(testConfig);

expect(config).toStrictEqual(testConfig);
expect(config).toHaveProperty('logGroupName');
expect(config).toHaveProperty('logStreamName');
expect(config).toHaveProperty('region');
});

it('should return an empty object when given no config input', () => {
const provider = new AWSCloudWatchProvider();
expect(provider.configure()).toStrictEqual({});
});
});

describe('credentials test', () => {
it('without credentials', async () => {
const provider = new AWSCloudWatchProvider();
provider.configure(testConfig);
const spyon = jest.spyOn(Credentials, 'get').mockImplementation(() => {
return Promise.reject('err');
});

const action = async () => {
await provider.createLogGroup({
logGroupName: testConfig.logGroupName,
});
};

expect(action()).rejects.toThrowError();
spyon.mockRestore();
});
});

describe('CloudWatch api tests', () => {
beforeEach(() => {
jest.spyOn(Credentials, 'get').mockImplementation(() => {
return Promise.resolve(credentials);
});
});

describe('createLogGroup test', () => {
const createLogGroupParams = { logGroupName: 'group-name' };

it('should send a valid request to the client without error', async () => {
const provider = new AWSCloudWatchProvider(testConfig);
const clientSpy = jest
.spyOn(CloudWatchLogsClient.prototype, 'send')
.mockImplementationOnce(async params => {
return 'data';
});

await provider.createLogGroup(createLogGroupParams);
expect(clientSpy.mock.calls[0][0].input).toEqual(createLogGroupParams);

clientSpy.mockRestore();
});
});

describe('createLogStream test', () => {
const params = {
logGroupName: 'group-name',
logStreamName: 'stream-name',
};

it('should send a valid request to the client without error', async () => {
const provider = new AWSCloudWatchProvider(testConfig);
const clientSpy = jest
.spyOn(CloudWatchLogsClient.prototype, 'send')
.mockImplementationOnce(async params => {
return 'data';
});

await provider.createLogStream(params);
expect(clientSpy.mock.calls[0][0].input).toEqual(params);

clientSpy.mockRestore();
});
});

describe('getLogGroups test', () => {
const params = {
logGroupNamePrefix: 'group-name',
};

it('should send a valid request to the client without error', async () => {
const provider = new AWSCloudWatchProvider(testConfig);
const clientSpy = jest
.spyOn(CloudWatchLogsClient.prototype, 'send')
.mockImplementationOnce(async params => {
return 'data';
});

await provider.getLogGroups(params);
expect(clientSpy.mock.calls[0][0].input).toEqual(params);

clientSpy.mockRestore();
});
});

describe('getLogStreams test', () => {
const params = {
logGroupName: 'group-name',
logStreamNamePrefix: 'stream-name',
};

it('should send a valid request to the client without error', async () => {
const provider = new AWSCloudWatchProvider(testConfig);
const clientSpy = jest
.spyOn(CloudWatchLogsClient.prototype, 'send')
.mockImplementationOnce(async params => {
return 'data';
});

await provider.getLogStreams(params);
expect(clientSpy.mock.calls[0][0].input).toEqual(params);

clientSpy.mockRestore();
});
});

describe('pushLogs test', () => {
it('should add the provided logs to the log queue', () => {
const provider = new AWSCloudWatchProvider(testConfig);
provider.pushLogs([{ message: 'hello', timestamp: 1111 }]);

let logQueue = provider.getLogQueue();

expect(logQueue).toHaveLength(1);

provider.pushLogs([
{
message: 'goodbye',
timestamp: 1112,
},
{
message: 'ohayou',
timestamp: 1113,
},
{
message: 'konbanwa',
timestamp: 1114,
},
]);

logQueue = provider.getLogQueue();

expect(logQueue).toHaveLength(4);
});
});

describe('_safeUploadLogEvents test', () => {
it('should send a valid request to the client without error', async () => {
const params = [{ message: 'hello', timestamp: 1111 }];
const provider = new AWSCloudWatchProvider(testConfig);
const clientSpy = jest
.spyOn(CloudWatchLogsClient.prototype, 'send')
.mockImplementation(async params => {
return 'data';
});

provider['_currentLogBatch'] = params;
await provider['_safeUploadLogEvents']();

// DescribeLogGroups command
expect(clientSpy.mock.calls[0][0].input).toEqual({
logGroupNamePrefix: testConfig.logGroupName,
});

// CreateLogGroup command
expect(clientSpy.mock.calls[1][0].input).toEqual({
logGroupName: testConfig.logGroupName,
});

// DescribeLogStreams command
expect(clientSpy.mock.calls[2][0].input).toEqual({
logGroupName: testConfig.logGroupName,
logStreamNamePrefix: testConfig.logStreamName,
});

// CreateLogStream command
expect(clientSpy.mock.calls[3][0].input).toEqual({
logGroupName: testConfig.logGroupName,
logStreamName: testConfig.logStreamName,
});

// PutLogEvents command
expect(clientSpy.mock.calls[4][0].input).toEqual({
logGroupName: testConfig.logGroupName,
logStreamName: testConfig.logStreamName,
logEvents: params,
sequenceToken: '',
});

clientSpy.mockRestore();
});
});
});
});
1 change: 1 addition & 0 deletions packages/core/__tests__/parseMobileHubConfig-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ describe('Parser', () => {
aws_user_pools_id: 'b',
aws_user_pools_web_client_id: '',
},
Logging: {},
});
});
});
1 change: 1 addition & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
"@aws-sdk/client-cognito-identity": "3.6.1",
"@aws-sdk/credential-provider-cognito-identity": "3.6.1",
"@aws-sdk/types": "3.6.1",
"@aws-sdk/client-cloudwatch-logs": "3.6.1",
"@aws-sdk/util-hex-encoding": "3.6.1",
"universal-cookie": "^4.0.4",
"zen-observable-ts": "0.8.19"
Expand Down
Loading

0 comments on commit 6f28c7e

Please sign in to comment.