Skip to content

Commit

Permalink
Issue #63: all tests pass. 0 TSLint warnings.
Browse files Browse the repository at this point in the history
  • Loading branch information
fgm committed Sep 23, 2018
1 parent abeb8e7 commit 7519b5e
Show file tree
Hide file tree
Showing 19 changed files with 258 additions and 153 deletions.
2 changes: 1 addition & 1 deletion __tests__/integration/httpMethodTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ function testInvalidMethod() {
expect.assertions(2);
// ServerLogger rejects GET methods as invalid.
return axios.get(url)
.catch(err => {
.catch((err) => {
const res = err.response;
expect(res).toBeDefined();
expect(res.status).toBe(405);
Expand Down
66 changes: 33 additions & 33 deletions __tests__/integration/jsonTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,24 @@ import endPoint from "./harness";
function testValidJson() {
test("should accept valid JSON posts", () => {
// Pseudo-random complex value from http://beta.json-generator.com/
let data = [
const data = [
{
"repeat(5, 10)": {
_id: "{{objectId()}}",
index: "{{index()}}",
guid: "{{guid()}}",
isActive: "{{bool()}}",
balance: "{{floating(1000, 4000, 2, '$0,0.00')}}",
picture: "http://placehold.it/32x32",
about: "{{lorem(1, 'paragraphs')}}",
address: "{{integer(100, 999)}} {{street()}}, {{city()}}, {{state()}}, {{integer(100, 10000)}}",
age: "{{integer(20, 40)}}",
eyeColor: "{{random('blue', 'brown', 'green')}}",
name: {
first: "{{firstName()}}",
last: "{{surname()}}",
},
balance: "{{floating(1000, 4000, 2, '$0,0.00')}}",
company: "{{company().toUpperCase()}}",
email: function (tags) {
email(tags) {
// Email tag is deprecated, because now you can produce an email as simple as this:
return (this.name.first + "." + this.name.last + "@" + this.company + tags.domainZone()).toLowerCase();
},
phone: "+1 {{phone()}}",
address: "{{integer(100, 999)}} {{street()}}, {{city()}}, {{state()}}, {{integer(100, 10000)}}",
about: "{{lorem(1, 'paragraphs')}}",
registered: "{{moment(this.date(new Date(2014, 0, 1), new Date())).format('LLLL')}}",
latitude: "{{floating(-90.000001, 90)}}",
longitude: "{{floating(-180.000001, 180)}}",
tags: [
{
"repeat(5)": "{{lorem(1, 'words')}}",
},
],
eyeColor: "{{random('blue', 'brown', 'green')}}",
favoriteFruit(tags) {
const fruits = ["apple", "banana", "strawberry"];
return fruits[tags.integer(0, fruits.length - 1)];
},
friends: [
{
"repeat(3)": {
Expand All @@ -44,24 +31,37 @@ function testValidJson() {
},
},
],
greeting: function (tags) {
greeting(tags) {
return "Hello, " + this.name.first + "! You have " + tags.integer(5, 10) + " unread messages.";
},
favoriteFruit: function (tags) {
const fruits = ["apple", "banana", "strawberry"];
return fruits[tags.integer(0, fruits.length - 1)];
guid: "{{guid()}}",
index: "{{index()}}",
isActive: "{{bool()}}",
latitude: "{{floating(-90.000001, 90)}}",
longitude: "{{floating(-180.000001, 180)}}",
name: {
first: "{{firstName()}}",
last: "{{surname()}}",
},
phone: "+1 {{phone()}}",
picture: "http://placehold.it/32x32",
registered: "{{moment(this.date(new Date(2014, 0, 1), new Date())).format('LLLL')}}",
tags: [
{
"repeat(5)": "{{lorem(1, 'words')}}",
},
],
},
},
];

return axios({
method: "post",
baseURL: endPoint,
url: "/logger",
data,
headers: { "content-type": "application/json" },
}).then(response => {
method: "post",
url: "/logger",
}).then((response) => {
// Valid post is accepted.
expect(response.status).toBe(200);
});
Expand All @@ -74,12 +74,12 @@ function testNonJson() {
expect.assertions(2);

return axios({
method: "post",
baseURL: endPoint,
url: "/logger",
data: "42",
headers: { "content-type": "application/x-www-form-urlencoded" },
}).catch(err => {
method: "post",
url: "/logger",
}).catch((err) => {
const response = err.response;
expect(response).toBeDefined();
// Invalid JSON is rejected.
Expand Down
2 changes: 1 addition & 1 deletion __tests__/unit/consoleSenderTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
/** global: console */

import NullFn from "../../src/NullFn";
import ConsoleSender from "../../src/Senders/ConsoleSender";
import { ConsoleSender } from "../../src/Senders/ConsoleSender";

let savedConsole;

Expand Down
158 changes: 86 additions & 72 deletions __tests__/unit/logContextTest.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
import * as os from "os";

import {
IContext,
KEY_DETAILS,
IContext, IDetails,
KEY_DETAILS, KEY_HOST,
KEY_SOURCE,
KEY_TS,
} from "../../src/IContext";
import {ILogger} from "../../src/Loggers";
import { Logger } from "../../src/Loggers/Logger";
import { ServerLogger } from "../../src/Loggers/ServerLogger";
import * as LogLevel from "../../src/LogLevel";
import { IProcessor } from "../../src/Processors/IProcessor";
import { ProcessorBase } from "../../src/Processors/ProcessorBase";
import { ISender} from "../../src/Senders/ISender";
import { newEmptyStrategy, newLogStrategy, TestSender } from "./types";
import {
newEmptyStrategy,
newLogStrategy,
TEST_SOURCE,
TestSender,
} from "./types";

function testImmutableContext() {
test("should not modify context in log() calls", () => {
Expand Down Expand Up @@ -304,18 +311,9 @@ function testObjectifyContext() {
}

function testProcessors() {
const Sender = class extends ProcessorBase implements ISender {
public logs: any[][];

constructor() {
super();
this.logs = [];
}

public send(level, message, context) {
this.logs.push([level, message, context]);
}
};
let details: IDetails;
let sender: TestSender;
let logger: ILogger;

const Adder = class extends ProcessorBase implements IProcessor {
public process(context) {
Expand Down Expand Up @@ -349,94 +347,110 @@ function testProcessors() {
};

const TimeWarp = class extends ProcessorBase {
public readonly HOST = "remote";

// Let's do the time warp again.
public process(context: IContext): IContext {
context[KEY_TS] = {
test: { log: +new Date("1978-11-19 05:00:00") },
};
context.hostname = "remote";
context[KEY_HOST] = this.HOST;
return context;
}
};

beforeEach(() => {
this.initialContext = { initial: "initial" };
this.sender = new Sender();
this.strategy = {
customizeLogger: () => [],
selectSenders: () => [this.sender],
};
this.logger = new Logger(this.strategy);
this.logger.side = "test";
details = { initial: "initial" };
sender = new TestSender();
logger = new Logger(newLogStrategy(sender));
logger.side = TEST_SOURCE;
});

test("processors should be able to modify the content of ordinary existing keys", () => {
this.logger.processors.push(new Modifier());
expect(this.sender.logs.length).toBe(0);
this.logger.log(LogLevel.WARNING, "hello, world", this.initialContext);
expect(this.sender.logs.length).toBe(1);
const [, , context] = this.sender.logs.pop();
expect(context).toHaveProperty("initial", "cost");
logger.processors.push(new Modifier());
expect(sender.isEmpty).toBe(true);
logger.log(LogLevel.WARNING, "hello, world", details);
expect(sender.isEmpty).toBe(false);
expect(sender.result.context).toHaveProperty(`${TEST_SOURCE}.initial`, "cost");
});

test("processors should be able to add new keys", () => {
this.logger.processors.push(new Adder());
expect(this.sender.logs.length).toBe(0);
this.logger.log(LogLevel.WARNING, "hello, world", this.initialContext);
expect(this.sender.logs.length).toBe(1);
const [, , context] = this.sender.logs.pop();
expect(context).toHaveProperty("added", "value");
logger.processors.push(new Adder());
expect(sender.isEmpty).toBe(true);
logger.log(LogLevel.WARNING, "hello, world", details);
expect(sender.isEmpty).toBe(false);
expect(sender.result.context).toHaveProperty(`${TEST_SOURCE}.added`, "value");
});

test("processors should be able to remove existing keys", () => {
this.logger.processors.push(new Remover());
expect(this.sender.logs.length).toBe(0);
this.logger.log(LogLevel.WARNING, "hello, world", this.initialContext);
expect(this.sender.logs.length).toBe(1);
const [, , context] = this.sender.logs.pop();
expect(context.added).toBeUndefined();
expect(context.initial).toBeUndefined();
// By default, pre-processing content goes to the message_details key.
expect(context.message_details).toHaveProperty("initial", "initial");
logger.processors.push(new Remover());
expect(sender.isEmpty).toBe(true);
logger.log(LogLevel.WARNING, "hello, world", details);
expect(sender.isEmpty).toBe(false);
const actualContext: IContext = sender.result.context;
expect(actualContext.added).toBeUndefined();
expect(actualContext.initial).toBeUndefined();
expect(actualContext[KEY_DETAILS]).toHaveProperty("initial", "initial");
});

test("processors should be able to remove the message_details", () => {
this.logger.processors.push(new Purger());
expect(this.sender.logs.length).toBe(0);
this.logger.log(LogLevel.WARNING, "hello, world", this.initialContext);
expect(this.sender.logs.length).toBe(1);
const [, , context] = this.sender.logs.pop();
expect(context).not.toHaveProperty("added");
expect(context).not.toHaveProperty("initial");
expect(context).not.toHaveProperty("message_details");
test("processors should not be able to remove the message_details", () => {
logger.processors.push(new Purger());
expect(sender.isEmpty).toBe(true);
logger.log(LogLevel.WARNING, "hello, world", details);
expect(sender.isEmpty).toBe(false);
const actualContext = sender.result.context;
// Can remove other keys
expect(actualContext).not.toHaveProperty("added");
expect(actualContext).not.toHaveProperty("initial");
// But cannot remove details.
expect(actualContext).toHaveProperty(KEY_DETAILS, details);
});

test("processors should not be able to remove the timestamp or hostname key", () => {
this.logger.processors.push(new Purger());
expect(this.sender.logs.length).toBe(0);
this.logger.log(LogLevel.WARNING, "hello, world", { hostname: "local", ...this.initialContext });
const serverLogger: ServerLogger = new ServerLogger(newLogStrategy(sender));
serverLogger.processors.push(new Purger());
expect(sender.isEmpty).toBe(true);
const expectedHost = os.hostname();
const fakeHost = `wrong-${expectedHost}`;
serverLogger.logExtended(LogLevel.WARNING, "hello, world", {
// Provide the current hostname in context, it should be overwritten by
// the logging logic anyway: we know this value not correct.
[KEY_HOST]: fakeHost,
...details,
});
const ts = +new Date();
expect(this.sender.logs.length).toBe(1);
const [, , context] = this.sender.logs.pop();
expect(context).toHaveProperty("hostname", "local");
expect(context).toHaveProperty(`${KEY_TS}.${this.logger.side}.log`);
const lag = ts - context[KEY_TS][this.logger.side].log;
expect(sender.isEmpty).toBe(false);
const actualContext = sender.result.context;
expect(actualContext).toHaveProperty(KEY_HOST, expectedHost);
expect(actualContext).toHaveProperty(`${KEY_TS}.${serverLogger.side}.log`);
const lag = ts - actualContext[KEY_TS][serverLogger.side].log;
expect(lag).toBeGreaterThanOrEqual(0);
// No sane machine should take more than 100 msec to return from log() with
// such a fast sending configuration.
expect(lag).toBeLessThan(100);
});

test("processors should not be able to modify the timestamp, but be able to modify the hostname", () => {
this.logger.processors.push(new TimeWarp());
expect(this.sender.logs.length).toBe(0);
this.logger.log(LogLevel.WARNING, "hello, world", this.initialContext);
test("processors should neither be able to modify the timestamp, nor the hostname", () => {
const timeWarp = new TimeWarp();
logger.processors.push(timeWarp);
expect(sender.isEmpty).toBe(true);
const expectedHost = os.hostname();
const fakeHost = `wrong-${expectedHost}`;
logger.log(LogLevel.WARNING, "hello, world", { [KEY_HOST]: fakeHost, ...details});
const ts = +new Date();
expect(this.sender.logs.length).toBe(1);
const [, , context] = this.sender.logs.pop();
expect(context).toHaveProperty("hostname", "remote");
expect(context).toHaveProperty(`${KEY_TS}.${this.logger.side}.log`);
const lag = ts - context[KEY_TS][this.logger.side].log;
expect(sender.isEmpty).toBe(false);
const actualContext = sender.result.context;

// Hostname is a reserved key, so it is not taken from the sourced context.
// Since this is a Logger, not a ServerLogger, the key is not present.
expect(actualContext).not.toHaveProperty(KEY_HOST);
// Instead, it remains in the sourced part of the context.
const actualSourcedContext: IDetails = actualContext[TEST_SOURCE];
expect(actualSourcedContext).not.toHaveProperty(KEY_HOST, fakeHost);
expect(actualSourcedContext).toHaveProperty(KEY_HOST, timeWarp.HOST);

expect(actualContext).toHaveProperty(`${KEY_TS}.${TEST_SOURCE}.log`);
const lag = ts - actualContext[KEY_TS][TEST_SOURCE].log;
expect(lag).toBeGreaterThanOrEqual(0);
// No sane machine should take more than 100 msec to return from log() with
// such a fast sending configuration. The TimeWarp processor attempts to
Expand Down
2 changes: 1 addition & 1 deletion __tests__/unit/meteorUserProcessorTest.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {IContext} from "../../src/IContext";
import {ServerSide} from "../../src/Loggers/ServerLogger";
import {IProcessor} from "../../src/Processors/IProcessor";
import MeteorUserProcessor from "../../src/Processors/MeteorUserProcessor";
import { MeteorUserProcessor } from "../../src/Processors/MeteorUserProcessor";

interface IUserSubContext {
user: {
Expand Down
12 changes: 6 additions & 6 deletions __tests__/unit/serializationTest.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const sinon = require("sinon");
import sinon = require("sinon");

import { SyslogSender } from "../../src/Senders/SyslogSender";

Expand All @@ -7,14 +7,14 @@ function testSerializeDeepObject() {
const logLevelWarn = 3;

const makeSyslog = () => ({
level: {
[logLevelWarn]: "warn",
},
facility: {
[LOCAL0]: "local0",
},
open: () => {},
log: () => {},
level: {
[logLevelWarn]: "warn",
},
log: () => undefined,
open: () => undefined,
});

const deepContext = () => ({
Expand Down
Loading

0 comments on commit 7519b5e

Please sign in to comment.