/* * Copyright (C) 2015 Centro de Computacao Cientifica e Software Livre * Departamento de Informatica - Universidade Federal do Parana * * This file is part of blendb. * * blendb is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * blendb is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with blendb. If not, see <http://www.gnu.org/licenses/>. */ import { expect } from "chai"; import { Engine } from "./engine"; import { Metric } from "./metric"; import { Dimension } from "./dimension"; import { View } from "./view"; import { AggregationType } from "../common/types"; describe("engine class", () => { const engine = new Engine(); const met1 = new Metric({ name: "met:1", aggregation: AggregationType.SUM }); const met2 = new Metric({ name: "met:2", aggregation: AggregationType.AVG }); const met3 = new Metric({ name: "met:3", aggregation: AggregationType.AVG }); const met4 = new Metric({ name: "met:4", aggregation: AggregationType.SUM }); const met5 = new Metric({ name: "met:5", aggregation: AggregationType.SUM }); const met6 = new Metric({ name: "met:6", aggregation: AggregationType.AVG }); const met7 = new Metric({ name: "met:7", aggregation: AggregationType.COUNT }); const met8 = new Metric({ name: "met:8", aggregation: AggregationType.COUNT }); const met9 = new Metric({ name: "met:9", aggregation: AggregationType.SUM }); const met10 = new Metric({ name: "met:10", aggregation: AggregationType.COUNT }); const met11 = new Metric({ name: "met:11", aggregation: AggregationType.COUNT }); const dim1 = new Dimension({ name: "dim:1" }); const dim2 = new Dimension({ name: "dim:2" }); const dim3 = new Dimension({ name: "dim:3" }); const dim4 = new Dimension({ name: "dim:4" }); const dim5 = new Dimension({ name: "dim:5" }); const dim6 = new Dimension({ name: "dim:6" }); const dim7 = new Dimension({ name: "dim:7" }); const dim8 = new Dimension({ name: "dim:8" }); const dim9 = new Dimension({ name: "dim:9" }); const dim10 = new Dimension({ name: "dim:10" }); const dim11 = new Dimension({ name: "dim:11" }); engine.addMetric(met1); engine.addMetric(met2); engine.addMetric(met3); engine.addMetric(met4); engine.addMetric(met5); engine.addMetric(met6); engine.addMetric(met7); engine.addMetric(met8); engine.addMetric(met9); engine.addMetric(met10); engine.addDimension(dim1); engine.addDimension(dim2); engine.addDimension(dim3); engine.addDimension(dim4); engine.addDimension(dim5); engine.addDimension(dim6); engine.addDimension(dim7); engine.addDimension(dim8); engine.addDimension(dim9); engine.addDimension(dim10); let views: View[] = [ new View({ metrics: [met1, met2, met3], dimensions: [dim1, dim2]}), new View({ metrics: [met1, met3, met5], dimensions: [dim1, dim2]}), new View({ metrics: [met3, met4, met7], dimensions: [dim4, dim5]}), new View({ metrics: [met6, met7], dimensions: [dim3, dim4, dim5, dim6]}), new View({ metrics: [met8, met2, met3], dimensions: [dim1, dim2, dim7]}), new View({ metrics: [met1, met2, met3], dimensions: [dim1, dim2]}), new View({ metrics: [met2, met4], dimensions: [dim1, dim2]}), new View({ metrics: [met8], dimensions: [dim8, dim9, dim10]}), new View({ metrics: [met9], dimensions: [dim8, dim9, dim10]}), new View({ metrics: [met10], dimensions: [dim8, dim9, dim10]}) ]; views.push(new View({ metrics: [met1, met2, met3, met4, met5], dimensions: [dim1, dim2], materialized: false, childViews: [views[0], views[6]] })); views.push(new View({ metrics: [met8, met9, met10], dimensions: [dim8, dim9, dim10], materialized: false, childViews: [views[7], views[8], views[9]] })); views.forEach((view) => engine.addView(view)); it("should be create a fill that cover the query and has 4 children", () => { let query = { metrics : [met1, met2, met3, met4, met5, met6, met7, met8, met9, met10] , dimensions : [dim1, dim2, dim3, dim4, dim5, dim6, dim7, dim8, dim9, dim10] }; let optimalView = engine.query(query); expect(optimalView).to.be.an("object"); expect(optimalView).to.have.property("metrics"); expect(optimalView).to.have.property("dimensions"); expect(optimalView).to.have.property("childViews"); expect(optimalView.metrics).to.be.an("array"); expect(optimalView.dimensions).to.be.an("array"); expect(optimalView.childViews).to.be.an("array"); expect(optimalView.metrics.length === 10); expect(optimalView.dimensions.length === 10); expect(optimalView.childViews.length === 4); let metAux: number[] = optimalView.metrics.sort().map((met: Metric) => { return Number(met.name.split(":")[1]); }); let dimAux: number[] = optimalView.dimensions.sort().map((dim: Dimension) => { return Number(dim.name.split(":")[1]); }); for (let i: number = 1; i <= 10; ++i) { expect(dimAux[i] === i); expect(metAux[i] === i); } }); it("should throw an exception, query with non-existent metric", () => { let error: boolean = false; try { engine.query({metrics: [met11], dimensions: [dim1]}); } catch (e){ error = true; expect(e.message).to.be.equal("Engine views cannot cover the query"); } expect(error); }); it("should throw an exception, query with non-existent dimension", () => { let error: boolean = false; try { engine.query({metrics: [met1], dimensions: [dim11]}); } catch (e){ error = true; expect(e.message).to.be.equal("Engine views cannot cover the query"); } expect(error); }); });