Skip to content

Commit

Permalink
feat: client support default headers
Browse files Browse the repository at this point in the history
  • Loading branch information
sigoden committed Jun 6, 2021
1 parent e58284c commit 58b2651
Show file tree
Hide file tree
Showing 11 changed files with 127 additions and 30 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,9 @@ The `http` client handles http/https requests/responses.
// `withCredentials` indicates whether or not cross-site Access-Control requests
// should be made using credentials
withCredentials: false, // default
// `headers` is default request headers
headers: {
}
}
```

Expand Down
3 changes: 3 additions & 0 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,9 @@ Apitest 提供两种客户端。
timeout: 1000, // default is `0` (no timeout)
// `withCredentials` 表示是否跨站访问控制请求
withCredentials: false, // default
// `headers` 默认请求头
headers: {
}
}
```

Expand Down
4 changes: 2 additions & 2 deletions src/Clients/EchoClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { Client } from ".";
import { Unit } from "../Cases";

export default class EchoClient implements Client {
public constructor(_options: any) {}
public get name() {
public constructor(_name: string, _options: any) {}
public get kind() {
return "echo";
}
public validate(_unit: Unit) {}
Expand Down
51 changes: 43 additions & 8 deletions src/Clients/HttpClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,54 @@ import axios, { AxiosRequestConfig } from "axios";
import * as _ from "lodash";
import { Client } from ".";
import { Unit } from "../Cases";
import { checkValue, existAnno, toPosString } from "../utils";
import { checkValue, existAnno, schemaValidate, toPosString } from "../utils";
import { JsonaObject, JsonaString, JsonaValue } from "jsona-js";

export interface HttpClientOptions {
baseUrl?: string;
timeout?: number;
withCredentials?: boolean;
headers?: Record<string, string>;
}

export const HTTP_OPTIONS_SCHEMA = {
type: "object",
properties: {
baseURL: {
type: "string",
},
timeout: {
type: "integer",
},
withCredentials: {
type: "boolean",
},
headers: {
type: "object",
anyProperties: {
type: "string",
},
},
},
};


export default class HttpClient implements Client {
private options: any;
public constructor(options: any) {
if (_.isObject(options)) {
this.options = _.pick(options, ["baseURL", "timeout", "withCredentials"]);
private options: HttpClientOptions;
public constructor(name: string, options: any) {
if (options) {
try {
schemaValidate(options, [], HTTP_OPTIONS_SCHEMA, true);
this.options = _.pick(options, ["baseURL", "timeout", "withCredentials", "headers"]);
} catch (err) {
throw new Error(`[main@client(${name})[${err.paths.join(".")}] ${err.message}`);
}
} else {
this.options = options;
this.options = {};
}
}
public get name() {

public get kind() {
return "http";
}

Expand All @@ -25,7 +60,7 @@ export default class HttpClient implements Client {

public async run(unit: Unit, req: any) {
const opts: AxiosRequestConfig = {
...(this.options || {}),
..._.clone(this.options),
...(unit.client.options || {}),
url: req.url,
method: req.method || "get",
Expand Down
18 changes: 9 additions & 9 deletions src/Clients/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import EchoClient from "./EchoClient";
import HttpClient from "./HttpClient";

export abstract class Client {
constructor(_options: any) {}
constructor(_name: string, _options: any) {}
abstract validate(unit: Unit);
abstract get name(): string;
abstract get kind(): string;
abstract run(unit: Unit, req: any): Promise<any>;
}

Expand All @@ -17,14 +17,14 @@ export default class Clients {
public addClient(anno: JsonaAnnotation) {
const { name, kind, options } = anno.value;
if (!name || !kind) {
throw new Error(`[main@client] should have name and kind${toPosString(anno.position)}`);
throw new Error(`main@client should have name and kind${toPosString(anno.position)}`);
}
if (kind === "echo") {
this.clients[name] = new EchoClient(options);
this.clients[name] = new EchoClient(name, options);
} else if (kind === "http") {
this.clients[name] = new HttpClient(options);
this.clients[name] = new HttpClient(name, options);
} else {
throw new Error(`[main@client] kind '${kind}' is unsupported${toPosString(anno.position)}`);
throw new Error(`main@client(${name}) kind '${kind}' is unsupported${toPosString(anno.position)}`);
}
}
public ensureDefault() {
Expand All @@ -35,15 +35,15 @@ export default class Clients {
if (name === "default") {
existDefault = true;
}
if (client.name === "echo") {
if (client.kind === "echo") {
existEcho = true;
}
}
if (!existEcho && !this.clients["echo"]) {
this.clients["echo"] = new EchoClient({});
this.clients["echo"] = new EchoClient("echo", {});
}
if (!existDefault) {
this.clients["default"] = new HttpClient({});
this.clients["default"] = new HttpClient("default", {});
}
}
public validateUnit(unit: Unit) {
Expand Down
4 changes: 2 additions & 2 deletions src/createRun.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as _ from "lodash";
import { Case } from "./Cases";
import { JsonaString, JsonaValue } from "jsona-js";
import { existAnno, evalValue, validate } from "./utils";
import { existAnno, evalValue, schemaValidate } from "./utils";
import { VmContext } from "./Session";
import { RunCaseError } from "./Reporter";

Expand Down Expand Up @@ -63,7 +63,7 @@ export default function createRun(testcase: Case, ctx: VmContext) {
const nextPaths = testcase.paths.concat(["run"]);
const run: CaseRun = createValue(nextPaths, ctx, testcase.run);
try {
validate(run, nextPaths, CASE_RUN_SCHEMA, false);
schemaValidate(run, nextPaths, CASE_RUN_SCHEMA, false);
} catch (err) {
if (err.paths) throw new RunCaseError(err.paths, "", err.message);
throw new RunCaseError(nextPaths, "", "run is invalid");
Expand Down
15 changes: 12 additions & 3 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export async function sleep(ms: number) {
});
}

export function validate(target: any, paths: string[], schema: any, required: boolean) {
export function schemaValidate(target: any, paths: string[], schema: any, required: boolean) {
const type = getType(target);
const schemaTypes = Array.isArray(schema?.type) ? schema.type : [schema?.type];
if (schemaTypes.indexOf(type) === -1) {
Expand All @@ -21,15 +21,24 @@ export function validate(target: any, paths: string[], schema: any, required: bo
}
if (type === "object") {
const required = schema?.required || [];
const keys = [];
if (schema?.properties) {
for (const key in schema.properties) {
validate(target[key], paths.concat(key), schema.properties[key], required.indexOf(key) > -1);
keys.push(key);
schemaValidate(target[key], paths.concat(key), schema.properties[key], required.indexOf(key) > -1);
}
}
if (schema?.anyProperties) {
for (const key in target) {
if (keys.indexOf(key) === -1) {
schemaValidate(target[key], paths.concat(key), schema.anyProperties, false);
}
}
}
} else if (type === "array") {
if (schema?.items) {
for (const [i, item] of target.entries()) {
validate(item, paths.concat(i), schema.items, true);
schemaValidate(item, paths.concat(i), schema.items, true);
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions tests/__snapshots__/loader.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ exports[`loader invalid client 1`] = `
"
`;

exports[`loader invalid client options 1`] = `
"[main@client(client1)[timeout] should be integer value
"
`;

exports[`loader invalid jslib 1`] = `
"[main@jslib] should have string value at line 2 col 4
"
Expand Down
9 changes: 9 additions & 0 deletions tests/fixtures/loader/invalid-client-options.jsona
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
@client({
name:"client1",
kind: "http",
options: {
timeout: "a",
}
})
}
5 changes: 5 additions & 0 deletions tests/loader.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
const { spwanTest } = require("./utils");

describe("loader", () => {
test("invalid client options", async () => {
const { stdout, code } = await spwanTest("loader/invalid-client-options.jsona", ["--ci"]);
expect(code).toEqual(1);
expect(stdout).toMatchSnapshot();
});
test("invalid client", async () => {
const { stdout, code } = await spwanTest("loader/invalid-client.jsona", ["--ci"]);
expect(code).toEqual(1);
Expand Down
40 changes: 34 additions & 6 deletions tests/utils.test.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
const { validate } = require("../dist/utils");
const { schemaValidate } = require("../dist/utils");
const { CASE_RUN_SCHEMA } = require("../dist/createRun");
const { HTTP_OPTIONS_SCHEMA } = require("../dist/Clients/HttpClient");
test("validate", () => {
expect(() => {
validate(
schemaValidate(
undefined,
[],
CASE_RUN_SCHEMA,
false,
);
}).not.toThrow();
expect(() => {
validate(
schemaValidate(
{
skip: true,
delay: 100,
Expand All @@ -30,7 +31,7 @@ test("validate", () => {
}).not.toThrow();

expect(() => {
validate(
schemaValidate(
{
skip: "abc",
},
Expand All @@ -41,7 +42,7 @@ test("validate", () => {
}).toThrow();

expect(() => {
validate(
schemaValidate(
{
retry: {
stop: "abc",
Expand All @@ -54,7 +55,7 @@ test("validate", () => {
);
}).toThrow();
expect(() => {
validate(
schemaValidate(
{
retry: {
delay: 100,
Expand All @@ -65,4 +66,31 @@ test("validate", () => {
false,
);
}).toThrow();
expect(() => {
schemaValidate(
{
baseURL: "abc",
timeout: 5000,
withCredentials: false,
headers: {
"x-key": "abc",
},
},
[],
HTTP_OPTIONS_SCHEMA,
true,
);
}).not.toThrow();
expect(() => {
schemaValidate(
{
headers: {
"x-key": [],
},
},
[],
HTTP_OPTIONS_SCHEMA,
true,
);
}).toThrow();
});

0 comments on commit 58b2651

Please sign in to comment.