Skip to content

Commit

Permalink
Merge 3e5ebde into c6db508
Browse files Browse the repository at this point in the history
  • Loading branch information
rogelio-o committed Feb 7, 2018
2 parents c6db508 + 3e5ebde commit 61ab6e1
Show file tree
Hide file tree
Showing 8 changed files with 232 additions and 54 deletions.
74 changes: 66 additions & 8 deletions src/lib/App.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as fs from "fs";
import configuration from "./configuration/configuration";
import defaultConfiguration from "./configuration/defaultConfiguration";
import eventFinalHandler from "./event/eventFinalHandler";
Expand Down Expand Up @@ -29,13 +30,17 @@ export default class App implements IApp {
private _settings: object;
private _router: IRouter;

constructor() {
constructor(settings?: object) {
this._settings = {};
this._router = new Router();
}

public init(settings?: object): void {
this.initDefaultConfiguration(settings);
this.initEnvConfiguration();
this.initParamsConfiguration(settings);
this.initEnvFileConfiguration();
this.initDefaultFileConfiguration();
this.initDefaultConfiguration();

this._router = new Router({
subpath: this.get(configuration.PATH_CONTEXT)
});
}

public enable(key: string): void {
Expand Down Expand Up @@ -107,8 +112,61 @@ export default class App implements IApp {
return this;
}

private initDefaultConfiguration(settings: object): void {
this._settings = settings ? settings : defaultConfiguration;
private initEnvConfiguration(): void {
const settings = {};

for (const key of Object.keys(process.env)) {
settings[key] = process.env[key];
}

this.initConfiguration(settings);
}

private initParamsConfiguration(settings: {[name: string]: any}): void {
this.initConfiguration(settings);
}

private initEnvFileConfiguration(): void {
const env = this.get(configuration.ENVIRONMENT) || defaultConfiguration[configuration.ENVIRONMENT];

if (env) {
this.initFileConfiguration(env);
}
}

private initDefaultFileConfiguration(): void {
this.initFileConfiguration("application");
}

private initFileConfiguration(fileName: string): void {
const path = this.getProjectBasePath() + "/conf/" + fileName + ".json";

if (fs.existsSync(path)) {
const rawSetting = fs.readFileSync(path, "utf8");
this.initConfiguration(JSON.parse(rawSetting));
}
}

private getProjectBasePath(): string {
if (!process.env.PWD) {
return process.cwd();
} else {
return process.env.PWD;
}
}

private initDefaultConfiguration(): void {
this.initConfiguration(defaultConfiguration);
}

private initConfiguration(settings: {[name: string]: any}): void {
if (settings) {
for (const key of Object.keys(settings)) {
if (!this._settings[key]) {
this._settings[key] = settings[key];
}
}
}
}

private logError(req: IHttpRequest|IEventRequest, err: Error): void {
Expand Down
1 change: 1 addition & 0 deletions src/lib/Router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export default class Router implements IRouter {
this._eventStack = [];
this._caseSensitive = options.caseSensitive || false;
this._strict = options.strict || false;
this._subpath = options.subpath;
}

get subrouters(): IRouter[] {
Expand Down
17 changes: 9 additions & 8 deletions src/lib/configuration/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
*/

const configuration = {
DEFAULT_MYME_TYPE: "default_myme_type",
ENVIRONMENT: "environment",
TRUST_PROXY: "trus_proxy",
ETAG_FN: "etag_fn",
COOKIE_SECRET: "cookie_secret",
JSON_REPLACER: "json_replacer",
JSON_SPACES: "json_spaces",
JSON_ESCAPE: "json_escape"
DEFAULT_MYME_TYPE: "DEFAULT_MYME_TYPE",
ENVIRONMENT: "ENVIRONMENT",
TRUST_PROXY: "TRUST_PROXY",
ETAG_FN: "ETAG_FN",
COOKIE_SECRET: "COOKIE_SECRET",
JSON_REPLACER: "JSON_REPLACER",
JSON_SPACES: "JSON_SPACES",
JSON_ESCAPE: "JSON_ESCAPE",
PATH_CONTEXT: "PATH_CONTEXT"
};

export default configuration;
6 changes: 4 additions & 2 deletions src/lib/http/HttpRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ export default class HttpRequest implements IHttpRequest {
this.params = mergeParams(event);

this._headers = {};
for (const key of Object.keys(this._event.headers)) {
this._headers[key.toLowerCase()] = this._event.headers[key];
if (this._event.headers) {
for (const key of Object.keys(this._event.headers)) {
this._headers[key.toLowerCase()] = this._event.headers[key];
}
}

this._cookies = getCookiesFromHeader(this._headers.cookie, app.get(configuration.COOKIE_SECRET));
Expand Down
9 changes: 0 additions & 9 deletions src/lib/types/IApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,6 @@ import IRouter from "./IRouter";
*/
export default interface IApp {

/**
* Initialize the framework with the configuration of `settings`. If
* no `settings`are given, the framework is initialized with the
* default configuration.
*
* @param {object} settings
*/
init(settings?: object): void;

/**
* Set to _true_ the configuration param `key`.
*
Expand Down
163 changes: 136 additions & 27 deletions test/app.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* tslint:disable:no-unused-expression */
import * as Chai from "chai";
import { stub } from "sinon";
import * as fs from "fs";
import { SinonStub, stub } from "sinon";
import { App } from "../src/index";
import { configuration } from "../src/index";
import defaultConfiguration from "../src/lib/configuration/defaultConfiguration";
Expand All @@ -13,53 +14,161 @@ import otherEvent from "./utils/otherEvent";
* Test for App.
*/
describe("App", () => {
let app: App;
let defaultApp: App;
let readFileStub: SinonStub;
let existsStub: SinonStub;

const mockFile = (file, config) => {
const path = process.env.PWD + "/conf/" + file + ".json";
readFileStub.withArgs(path, "utf8").returns(JSON.stringify(config));
existsStub.withArgs(path).returns(true);
};

beforeEach(() => {
app = new App();
defaultApp = new App();
readFileStub = stub(fs, "readFileSync");
existsStub = stub(fs, "existsSync");
});

it("#init without settings should init with default configuration", async () => {
app.init();
Object.keys(defaultConfiguration)
.forEach((param) => Chai.expect(defaultConfiguration[param]).to.be.equal(app.get(param)));
afterEach(() => {
readFileStub.restore();
existsStub.restore();

delete process.env.ENVIRONMENT;
delete process.env.TEST;
});

it("#init with settings should init with custom configuration", async () => {
const settings = {};
settings[configuration.DEFAULT_MYME_TYPE] = "text/html";
describe("#constructor", () => {
it("without settings should init with default configuration", async () => {
const app = new App();
Object.keys(defaultConfiguration)
.forEach((param) => Chai.expect(defaultConfiguration[param]).to.be.equal(app.get(param)));
});

it("with settings should init with custom configuration", async () => {
const settings = {};
settings[configuration.DEFAULT_MYME_TYPE] = "text/html";

const app = new App(settings);
Object.keys(settings)
.forEach((param) => Chai.expect(settings[param]).to.be.equal(app.get(param)));
});

it("should set env variables as app settings", async () => {
process.env.TEST = "test";

const app = new App();
Chai.expect(app.get("TEST")).to.be.equal("test");
});

it("should set the settings in the env file", async () => {
process.env.ENVIRONMENT = "test";
const config: {[name: string]: any} = {TEST: "test"};
mockFile("test", config);

const app = new App();
Chai.expect(app.get("TEST")).to.be.equal("test");
});

it("should set the settings in the 'development' env file by default", async () => {
const config: {[name: string]: any} = {TEST: "test"};
mockFile("development", config);

const app = new App();
Chai.expect(app.get("TEST")).to.be.equal("test");
});

it("should set the settings in the default file", async () => {
const config: {[name: string]: any} = {TEST: "test"};
mockFile("application", config);

const app = new App();
Chai.expect(app.get("TEST")).to.be.equal("test");
});

it("should set the default configuration", async () => {
const app = new App();
Chai.expect(app.get(configuration.ENVIRONMENT)).to.be.equal("development");
});

app.init(settings);
Object.keys(settings)
.forEach((param) => Chai.expect(settings[param]).to.be.equal(app.get(param)));
it("should set the env settings before others", async () => {
process.env.ENVIRONMENT = "test1";

const envConfig: {[name: string]: any} = {ENVIRONMENT: "test2"};
mockFile("test1", envConfig);

const appConfig: {[name: string]: any} = {ENVIRONMENT: "test3"};
mockFile("application", appConfig);

const paramConfig: {[name: string]: any} = {ENVIRONMENT: "test4"};

const app = new App(paramConfig);
Chai.expect(app.get(configuration.ENVIRONMENT)).to.be.equal("test1");
});

it("should set the params settings before files and default configuration", async () => {
process.env.ENVIRONMENT = "test1";

const envConfig: {[name: string]: any} = {COOKIE_SECRET: "1"};
mockFile("test1", envConfig);

const appConfig: {[name: string]: any} = {COOKIE_SECRET: "2"};
mockFile("application", appConfig);

const paramConfig: {[name: string]: any} = {COOKIE_SECRET: "3"};

const app = new App(paramConfig);
Chai.expect(app.get(configuration.COOKIE_SECRET)).to.be.equal("3");
});

it("should set the env file settings before default file and default configuration", async () => {
process.env.ENVIRONMENT = "test1";

const envConfig: {[name: string]: any} = {COOKIE_SECRET: "1"};
mockFile("test1", envConfig);

const appConfig: {[name: string]: any} = {COOKIE_SECRET: "2"};
mockFile("application", appConfig);

const app = new App();
Chai.expect(app.get(configuration.COOKIE_SECRET)).to.be.equal("1");
});

it("should set the default file settings before default configuration", async () => {
const appConfig: {[name: string]: any} = {COOKIE_SECRET: "1"};
mockFile("application", appConfig);

const app = new App();
Chai.expect(app.get(configuration.COOKIE_SECRET)).to.be.equal("1");
});
});

it("#enable should set the param as true", async () => {
app.enable("option1");
Chai.expect(app.get("option1")).to.be.true;
defaultApp.enable("option1");
Chai.expect(defaultApp.get("option1")).to.be.true;
});

it("#disable should set the param as false", async () => {
app.disable("option1");
Chai.expect(app.get("option1")).to.be.false;
defaultApp.disable("option1");
Chai.expect(defaultApp.get("option1")).to.be.false;
});

it("#set should set the param with the indicated value", async () => {
app.set("option1", "value1");
Chai.expect(app.get("option1")).to.be.equal("value1");
defaultApp.set("option1", "value1");
Chai.expect(defaultApp.get("option1")).to.be.equal("value1");
});

describe("#handle", () => {
it("should call the router httpHandle if the event type is HTTP.", () => {
const httpHandleStub = stub(Router.prototype, "httpHandle");
app.handle(httpEvent, new DefaultCallback());
defaultApp.handle(httpEvent, new DefaultCallback());
Chai.expect(httpHandleStub.calledOnce).to.be.true;
httpHandleStub.restore();
});

it("should call the router eventHandle if the event type is NOT HTTP.", () => {
const eventHandleStub = stub(Router.prototype, "eventHandle");
app.handle(otherEvent, new DefaultCallback());
defaultApp.handle(otherEvent, new DefaultCallback());
Chai.expect(eventHandleStub.calledOnce).to.be.true;
eventHandleStub.restore();
});
Expand All @@ -68,7 +177,7 @@ describe("App", () => {
describe("#use", () => {
it("should delegate the action to the default router.", () => {
const useStub = stub(Router.prototype, "use");
app.use(null);
defaultApp.use(null);
Chai.expect(useStub.calledOnce).to.be.true;
useStub.restore();
});
Expand All @@ -77,7 +186,7 @@ describe("App", () => {
describe("#mount", () => {
it("should delegate the action to the default router.", () => {
const mountStub = stub(Router.prototype, "mount");
app.mount(null);
defaultApp.mount(null);
Chai.expect(mountStub.calledOnce).to.be.true;
mountStub.restore();
});
Expand All @@ -86,7 +195,7 @@ describe("App", () => {
describe("#param", () => {
it("should delegate the action to the default router.", () => {
const paramStub = stub(Router.prototype, "param");
app.param(null, null);
defaultApp.param(null, null);
Chai.expect(paramStub.calledOnce).to.be.true;
paramStub.restore();
});
Expand All @@ -95,7 +204,7 @@ describe("App", () => {
describe("#route", () => {
it("should delegate the action to the default router.", () => {
const routeStub = stub(Router.prototype, "route");
app.route(null);
defaultApp.route(null);
Chai.expect(routeStub.calledOnce).to.be.true;
routeStub.restore();
});
Expand All @@ -104,7 +213,7 @@ describe("App", () => {
describe("#event", () => {
it("should delegate the action to the default router.", () => {
const eventStub = stub(Router.prototype, "event");
app.event(null, null);
defaultApp.event(null, null);
Chai.expect(eventStub.calledOnce).to.be.true;
eventStub.restore();
});
Expand All @@ -113,7 +222,7 @@ describe("App", () => {
describe("#addTemplateEngine", () => {
it("should delegate the action to the default router.", () => {
const addTepmlateEngineStub = stub(Router.prototype, "addTemplateEngine");
app.addTemplateEngine(null);
defaultApp.addTemplateEngine(null);
Chai.expect(addTepmlateEngineStub.calledOnce).to.be.true;
addTepmlateEngineStub.restore();
});
Expand Down

0 comments on commit 61ab6e1

Please sign in to comment.