// (C) 2007-2019 GoodData Corporation import { Application } from "express"; import * as HttpStatusCodes from "http-status-codes"; import * as request from "supertest"; import { cleanOldCache, exportReport, hasCachedResult } from "../exportReport"; import { IConfig } from "../../../model/Config"; import { IExportConfig, IExportResultRequest } from "../../../model/ExportReport"; import { createEndpoint } from "../../../utils/tests"; import { schema } from "../../../schema/fixtures/dummySchema"; const EXPORT_RESULT_URI = "/gdc/internal/projects/mockproject/exportResult"; // tslint:disable-next-line:max-line-length const EXECUTION_RESULT_URI = '/gdc/app/projects/mockproject/executionResults/7176209489712217088?q=eAGdkc1uwjAQhF%2FFMj1GJA00FKSq4tBWXKqqhRPKwYmXJNSOo%2FWaKkK8e20o%2FTnSm727%2FnZmvOcI%0AnUF6Fhr4jK9aakiB5BEvjXK6tXy23nNBhE3hCJah6%2Bde0EhXkh%2BzTmuBva%2F5i2xsp0T%2FaFAvpC%2FF%0AlSxjLWONRbbdjIROJ%2FXknZIaJV1nWePMeNT1NcSm2MbTm9QjCmHhQYGGllavi4sZ42kMp9f2vpF3%0AHng09Efyt5t%2FaBxPA9KQUCGZdR6t8%2FyQR1yDT6g8pXXe%2BOY0Mxs218a1xA%2FRnm98MIK8mKtBNBgk%0AwyTxtJ8ElzUwsQMUFTDThW9xbUM9E0dCYAmlmAS%2FPGIIlUCpwNrQsHR8hOFAzg5%2FGZ%2FvquFZxFno%0A5c6z9Dad8GAVzUfw%2BWX5CY3reH74BPm6w8o%3D%0A&c=c62d02d1174a49a10ff4759f89732305&offset=0%2C0&limit=1000%2C1000&dimensions=2&totals=0%2C0"'; const SUPPORTED_STATUS_CODE = [ HttpStatusCodes.OK, HttpStatusCodes.NO_CONTENT, HttpStatusCodes.REQUEST_TOO_LONG, HttpStatusCodes.BAD_REQUEST, ]; let requestIndex = 0; async function getExportResult( app: Application, executionResult: string, exportConfig?: IExportConfig, expectedStatus: number = HttpStatusCodes.CREATED, ): Promise { requestIndex++; const data: IExportResultRequest = { resultExport: { executionResult, exportConfig, }, }; return request(app) .post(EXPORT_RESULT_URI) .send(data) .expect(expectedStatus); } interface IResult { result: request.Response; pollCount: number; } function isSupportedStatus(status: number) { return SUPPORTED_STATUS_CODE.some(endStatus => endStatus === status); } async function pollForResult(app: Application, pollUri: string, pollCount: number = 0): Promise { const response = await request(app).head(pollUri); if (response.status === HttpStatusCodes.ACCEPTED) { return pollForResult(app, pollUri, pollCount + 1); } if (isSupportedStatus(response.status)) { return Promise.resolve({ result: response, pollCount, }); } throw new Error(`Unsupported status code: ${response.status}`); } describe("exportReport", () => { it("should return error when executionResult is empty", async () => { const app = createEndpoint(exportReport, schema); const response = await getExportResult(app, "", null, HttpStatusCodes.BAD_REQUEST); expect(response.body.error.message).toEqual("BAD_REQUEST"); }); it("should return uri when post to exportResult", async () => { const app = createEndpoint(exportReport, schema); const response = await getExportResult(app, EXECUTION_RESULT_URI, null, HttpStatusCodes.CREATED); expect(response.body.uri).toBeDefined(); }); it("should return Ok status when polling successfully", async () => { const app = createEndpoint(exportReport, schema); const response = await getExportResult(app, EXECUTION_RESULT_URI, null, HttpStatusCodes.CREATED); const pollResponse = await pollForResult(app, response.body.uri); expect(pollResponse.result.status).toEqual(HttpStatusCodes.OK); }); it("should return correct format and title", async () => { const app = createEndpoint(exportReport, schema); const exportConfig: IExportConfig = { format: "xlsx", title: "TestTitle", }; const response = await getExportResult( app, EXECUTION_RESULT_URI, exportConfig, HttpStatusCodes.CREATED, ); const pollResponse = await pollForResult(app, response.body.uri); const header = pollResponse.result.header["content-disposition"]; expect(header).toEqual("attachment; filename=\"TestTitle.xlsx\"; filename*=UTF-8''TestTitle.xlsx"); }); it("should be possible to set pollCount in config", async () => { const config: IConfig = { pollCount: 4 }; const app = createEndpoint(exportReport, schema, config); const response = await getExportResult(app, EXECUTION_RESULT_URI, null, HttpStatusCodes.CREATED); const pollResponse = await pollForResult(app, response.body.uri); expect(pollResponse.pollCount).toEqual(4); }); describe("cache cleaning", () => { // tslint:disable-next-line no-string-based-set-timeout const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); it("should clean old entries in cache after given time", async () => { const app = createEndpoint(exportReport, schema); await getExportResult(app, EXECUTION_RESULT_URI, null, HttpStatusCodes.CREATED); await sleep(200); cleanOldCache(100); expect(hasCachedResult(requestIndex + "")).toBeFalsy(); }); }); });