Skip to content
Snippets Groups Projects
Commit cb51ec04 authored by Yoan Vallet's avatar Yoan Vallet
Browse files

feat: tests for query runner

parent 32eb67aa
No related branches found
No related tags found
1 merge request!139Features/unit tests
......@@ -5,3 +5,16 @@ export interface Dataload {
value: number
valueDetail?: number[] | null
}
export interface DataloadEntity {
id: string
_id?: string
_type?: string
_rev?: string
day: number
hour: number
load: number
minute: number
month: number
year: number
}
[
{
"id": "bf1ce3a5774e140056714c4c200c093e",
"_id": "bf1ce3a5774e140056714c4c200c093e",
"_type": "com.grandlyon.enedis.day",
"_rev": "1-4fe971dff073a3c3c6cc12a0246e642e",
"day": 1,
"hour": 0,
"load": 25.25,
"minute": 0,
"month": 11,
"year": 2020
},
{
"id": "cf7dc6f44a19b354f99b01ba1a0b4840",
"_id": "cf7dc6f44a19b354f99b01ba1a0b4840",
"_type": "com.grandlyon.enedis.day",
"_rev": "1-4fe971dff073a3c3c6cc12a0246e642e",
"day": 2,
"hour": 0,
"load": 20.5,
"minute": 0,
"month": 11,
"year": 2020
},
{
"id": "cf7dc6f44a19b354f99b01ba1a0b4840",
"_id": "cf7dc6f44a19b354f99b01ba1a0b4840",
"_type": "com.grandlyon.enedis.day",
"_rev": "1-4fe971dff073a3c3c6cc12a0246e642e",
"day": 3,
"hour": 0,
"load": 30.33,
"minute": 0,
"month": 11,
"year": 2020
},
{
"id": "cf7dc6f44a19b354f99b01ba1a0b4840",
"_id": "cf7dc6f44a19b354f99b01ba1a0b4840",
"_type": "com.grandlyon.enedis.day",
"_rev": "1-4fe971dff073a3c3c6cc12a0246e642e",
"day": 4,
"hour": 0,
"load": 1.22,
"minute": 0,
"month": 11,
"year": 2020
}
]
[
{
"id": "bf1ce3a5774e140056714c4c200c093e",
"_id": "bf1ce3a5774e140056714c4c200c093e",
"_type": "com.grandlyon.enedis.minute",
"_rev": "1-4fe971dff073a3c3c6cc12a0246e642e",
"day": 1,
"hour": 23,
"load": 2.25,
"minute": 30,
"month": 11,
"year": 2020
},
{
"id": "cf7dc6f44a19b354f99b01ba1a0b4840",
"_id": "cf7dc6f44a19b354f99b01ba1a0b4840",
"_type": "com.grandlyon.enedis.minute",
"_rev": "1-4fe971dff073a3c3c6cc12a0246e642e",
"day": 2,
"hour": 0,
"load": 4.5,
"minute": 0,
"month": 11,
"year": 2020
},
{
"id": "cf7dc6f44a19b354f99b01ba1a0b4840",
"_id": "cf7dc6f44a19b354f99b01ba1a0b4840",
"_type": "com.grandlyon.enedis.minute",
"_rev": "1-4fe971dff073a3c3c6cc12a0246e642e",
"day": 2,
"hour": 0,
"load": 1.33,
"minute": 30,
"month": 11,
"year": 2020
},
{
"id": "cf7dc6f44a19b354f99b01ba1a0b4840",
"_id": "cf7dc6f44a19b354f99b01ba1a0b4840",
"_type": "com.grandlyon.enedis.minute",
"_rev": "1-4fe971dff073a3c3c6cc12a0246e642e",
"day": 2,
"hour": 1,
"load": 3.22,
"minute": 0,
"month": 11,
"year": 2020
},
{
"id": "cf7dc6f44a19b354f99b01ba1a0b4840",
"_id": "cf7dc6f44a19b354f99b01ba1a0b4840",
"_type": "com.grandlyon.enedis.minute",
"_rev": "1-4fe971dff073a3c3c6cc12a0246e642e",
"day": 2,
"hour": 1,
"load": 7.82,
"minute": 30,
"month": 11,
"year": 2020
},
{
"id": "cf7dc6f44a19b354f99b01ba1a0b4840",
"_id": "cf7dc6f44a19b354f99b01ba1a0b4840",
"_type": "com.grandlyon.enedis.minute",
"_rev": "1-4fe971dff073a3c3c6cc12a0246e642e",
"day": 2,
"hour": 2,
"load": 1.23,
"minute": 0,
"month": 11,
"year": 2020
}
]
import { QueryResult } from 'cozy-client'
import { FluidType } from 'enum/fluid.enum'
import { TimeStep } from 'enum/timeStep.enum'
import { DateTime } from 'luxon'
import { DataloadEntity } from 'models'
import QueryRunner from './queryRunner.service'
import mockClient from './__mocks__/client'
const mockTimePeriod = {
startDate: DateTime.fromISO('2020-11-01T00:00:00.000+01:00'),
endDate: DateTime.fromISO('2020-11-30T23:59:59.999+01:00'),
}
const queryResult = {
data: [
{
id: 'bf1ce3a5774e140056714c4c200c093e',
_id: 'bf1ce3a5774e140056714c4c200c093e',
_type: 'com.grandlyon.egl.day',
_rev: '1-4fe971dff073a3c3c6cc12a0246e642e',
day: 1,
hour: 0,
load: 257.25,
minute: 0,
month: 11,
year: 2020,
},
{
id: 'cf7dc6f44a19b354f99b01ba1a0b4840',
_id: 'cf7dc6f44a19b354f99b01ba1a0b4840',
_type: 'com.grandlyon.egl.day',
_rev: '1-4fe971dff073a3c3c6cc12a0246e642e',
day: 1,
hour: 0,
load: 257.25,
minute: 0,
month: 11,
year: 2020,
},
],
next: false,
skip: 0,
bookmark:
'g2wAAAACaAJkAA5zdGFydGtleV9kb2NpZG0AAAAgY2Y3ZGM2ZjQ0YTE5YjM1NGY5OWIwMWJhMWEwYjI3ZjhoAmQACHN0YXJ0a2V5bAAAAANiAAAH5GELYQRqag',
}
import enedisDayData from './__mocks__/enedisDayData.json'
import enedisMinuteData from './__mocks__/enedisMinuteData.json'
describe('queryRunner service', () => {
const queryRunner = new QueryRunner(mockClient)
const fluidType = 0
describe('fetchFluidData', () => {
describe('fetchFluidData method', () => {
const mockTimePeriod = {
startDate: DateTime.fromISO('2020-11-01T00:00:00.000+01:00'),
endDate: DateTime.fromISO('2020-11-30T23:59:59.999+01:00'),
}
const expectedResult = [
{
date: DateTime.fromISO('2020-11-01T00:00:00.000+01:00'),
value: 257.25,
value: 25.25,
},
{
date: DateTime.fromISO('2020-11-01T00:00:00.000+01:00'),
value: 257.25,
date: DateTime.fromISO('2020-11-02T00:00:00.000+01:00'),
value: 20.5,
},
{
date: DateTime.fromISO('2020-11-03T00:00:00.000+01:00'),
value: 30.33,
},
{
date: DateTime.fromISO('2020-11-04T00:00:00.000+01:00'),
value: 1.22,
},
]
it('should return the data of the selected Fluid', async () => {
mockClient.query.mockImplementation(() => Promise.resolve(queryResult))
it('should return the data of the selected Fluid', async () => {
const mockQueryResult: QueryResult<DataloadEntity[]> = {
data: enedisDayData,
bookmark: '',
next: false,
skip: 0,
}
mockClient.query.mockResolvedValue(mockQueryResult)
const result = await queryRunner.fetchFluidData(
mockTimePeriod,
TimeStep.DAY,
fluidType
FluidType.ELECTRICITY
)
expect(result).toEqual(expectedResult)
})
it('should return null', async () => {
mockClient.query.mockImplementationOnce(() => Promise.resolve(null))
it('should return null when fetch data failed', async () => {
mockClient.query.mockRejectedValue(new Error())
const result = await queryRunner.fetchFluidData(
mockTimePeriod,
TimeStep.DAY,
fluidType
FluidType.ELECTRICITY
)
expect(result).toBeNull()
})
})
describe('fetchFluidMaxData', () => {
it('should return the max data of the selected Fluid', async () => {
it('should return null when unknown fluid type', async () => {
const result = await queryRunner.fetchFluidData(
mockTimePeriod,
TimeStep.DAY,
99
)
expect(result).toBeNull()
})
it('should return null when unknown time step', async () => {
const result = await queryRunner.fetchFluidData(
mockTimePeriod,
99,
FluidType.ELECTRICITY
)
expect(result).toBeNull()
})
})
describe('fetchFluidMaxData method', () => {
it('should return the max load for elec fluid with day timestep', async () => {
const mockTimePeriod = {
startDate: DateTime.fromISO('2020-11-01T00:00:00.000+01:00'),
endDate: DateTime.fromISO('2020-11-30T23:59:59.999+01:00'),
}
const mockQueryResult: QueryResult<DataloadEntity[]> = {
data: enedisDayData.sort((a, b) => b.load - a.load),
bookmark: '',
next: false,
skip: 0,
}
mockClient.query.mockResolvedValue(mockQueryResult)
const result = await queryRunner.fetchFluidMaxData(
mockTimePeriod,
TimeStep.DAY,
FluidType.ELECTRICITY
)
expect(result).toBe(30.33)
})
it('should return the max load for elec fluid with half an hour timestep', async () => {
const mockTimePeriod = {
startDate: DateTime.fromISO('2020-11-02T00:00:00.000+01:00'),
endDate: DateTime.fromISO('2020-11-2T23:59:59.999+01:00'),
}
const mockQueryResult: QueryResult<DataloadEntity[]> = {
data: [enedisMinuteData[4]],
bookmark: '',
next: false,
skip: 0,
}
const mockQueryResult2: QueryResult<DataloadEntity[]> = {
data: [enedisMinuteData[0]],
bookmark: '',
next: false,
skip: 0,
}
mockClient.query
.mockResolvedValueOnce(mockQueryResult)
.mockResolvedValueOnce(mockQueryResult2)
const result = await queryRunner.fetchFluidMaxData(
mockTimePeriod,
TimeStep.HALF_AN_HOUR,
FluidType.ELECTRICITY
)
expect(result).toBe(7.82)
})
it('should return null when fetch data failed', async () => {
const mockTimePeriod = {
startDate: DateTime.fromISO('2020-11-01T00:00:00.000+01:00'),
endDate: DateTime.fromISO('2020-11-30T23:59:59.999+01:00'),
}
mockClient.query.mockRejectedValue(new Error())
const result = await queryRunner.fetchFluidMaxData(
mockTimePeriod,
TimeStep.DAY,
fluidType
FluidType.ELECTRICITY
)
expect(result).toBeNull()
})
it('should return null when unknown fluid type', async () => {
const mockTimePeriod = {
startDate: DateTime.fromISO('2020-11-01T00:00:00.000+01:00'),
endDate: DateTime.fromISO('2020-11-30T23:59:59.999+01:00'),
}
const result = await queryRunner.fetchFluidMaxData(
mockTimePeriod,
TimeStep.DAY,
99
)
expect(result).toBeNull()
})
it('should return null when unknown time step', async () => {
const mockTimePeriod = {
startDate: DateTime.fromISO('2020-11-01T00:00:00.000+01:00'),
endDate: DateTime.fromISO('2020-11-30T23:59:59.999+01:00'),
}
const result = await queryRunner.fetchFluidMaxData(
mockTimePeriod,
99,
FluidType.ELECTRICITY
)
expect(result).toBeNull()
})
})
describe('getLastDateData method', () => {
it('should return the last load for elec fluid', async () => {
const lastMockData = [...enedisDayData]
lastMockData.sort(
(a, b) =>
(b.year - a.year) * 100 + (b.month - a.month) * 10 + (b.day - a.day)
)
const mockQueryResult: QueryResult<DataloadEntity[]> = {
data: [lastMockData[0]],
bookmark: '',
next: false,
skip: 0,
}
mockClient.query.mockResolvedValue(mockQueryResult)
const result = await queryRunner.getLastDateData(FluidType.ELECTRICITY)
expect(result).toEqual(
DateTime.local(
enedisDayData[3].year,
enedisDayData[3].month,
enedisDayData[3].day
)
)
})
it('should return null when fetch data failed', async () => {
mockClient.query.mockRejectedValue(new Error())
const result = await queryRunner.getLastDateData(FluidType.ELECTRICITY)
expect(result).toBeNull()
})
})
describe('getEntries method', () => {
it('should return query result for elec fluid with day timestep', async () => {
const mockQueryResult: QueryResult<DataloadEntity[]> = {
data: enedisDayData,
bookmark: '',
next: false,
skip: 0,
}
mockClient.query.mockResolvedValue(mockQueryResult)
const result = await queryRunner.getEntries(
FluidType.ELECTRICITY,
TimeStep.DAY
)
expect(result).toEqual(mockQueryResult)
})
it('should return null when fetch data failed', async () => {
mockClient.query.mockRejectedValue(new Error())
const result = await queryRunner.getEntries(
FluidType.ELECTRICITY,
TimeStep.DAY
)
expect(result).toBeNull()
})
it('should return null when unknown fluid type', async () => {
const result = await queryRunner.getEntries(99, TimeStep.DAY)
expect(result).toBeNull()
})
it('should return null when unknown time step', async () => {
const result = await queryRunner.getEntries(FluidType.ELECTRICITY, 99)
expect(result).toBeNull()
})
})
})
......@@ -62,103 +62,54 @@ export default class QueryRunner {
this._client = _client
}
public async fetchFluidData(
timePeriod: TimePeriod,
private buildListQuery(
timeStep: TimeStep,
fluidType: FluidType
): Promise<Dataload[] | null> {
const result = await this.fetchData(
this.buildListQuery(timeStep, timePeriod, fluidType, this._max_limit)
)
if (result && result.data) {
const filteredResult = this.filterDataList(result, timePeriod)
const mappedResult = this.mapDataList(filteredResult)
return mappedResult
}
timePeriod: TimePeriod,
fluidType: FluidType,
limit: number
) {
const doctype = this.getRelevantDoctype(fluidType, timeStep)
return null
return Q(doctype)
.where(this.getPredicate(timePeriod, timeStep))
.limitBy(limit)
}
public async fetchFluidMaxData(
maxTimePeriod: TimePeriod,
private buildMaxQuery(
timeStep: TimeStep,
fluidType: FluidType
): Promise<number | null> {
const result = await this.fetchData(
this.buildMaxQuery(timeStep, maxTimePeriod, fluidType, this._max_limit)
)
maxTimePeriod: TimePeriod,
fluidType: FluidType,
limit: number
) {
const doctype = this.getRelevantDoctype(fluidType, timeStep)
if (timeStep === TimeStep.HALF_AN_HOUR) {
const lastDayOfPreviousMonth = {
startDate: maxTimePeriod.startDate.plus({ day: -1 }),
endDate: maxTimePeriod.startDate.plus({ day: -1 }).endOf('days'),
}
const lastDayOfPreviousMonthResult = await this.fetchData(
this.buildMaxQuery(
timeStep,
lastDayOfPreviousMonth,
fluidType,
this._max_limit
)
)
return Math.max(
lastDayOfPreviousMonthResult.data[0]
? lastDayOfPreviousMonthResult.data[0].load
: 0,
result.data[0] ? result.data[0].load : 0
)
}
if (result && result.data) {
const filteredResult = this.filterDataList(result, maxTimePeriod)
const mappedResult = this.mapDataList(filteredResult)
return mappedResult && mappedResult[0] && mappedResult[0].value
return Q(doctype)
.where(this.getPredicate(maxTimePeriod, TimeStep.HALF_AN_HOUR))
.limitBy(1)
.sortBy([{ load: 'desc' }])
}
return null
return Q(doctype)
.where(this.getPredicate(maxTimePeriod, timeStep))
.limitBy(limit)
.sortBy([{ load: 'desc' }])
}
public async getLastDateData(fluidType: FluidType): Promise<DateTime | null> {
const result = await this.fetchData(this.buildLastDateQuery(fluidType, 1))
if (
result &&
result.data &&
result.data[0] &&
result.data[0].year &&
result.data[0].month &&
result.data[0].day
) {
return DateTime.local(
result.data[0].year,
result.data[0].month,
result.data[0].day
)
}
return null
private buildLastDateQuery(fluidType: FluidType, limit: number) {
const doctype = this.getRelevantDoctype(fluidType, TimeStep.DAY)
return Q(doctype)
.where({})
.indexFields(['year', 'month', 'day'])
.sortBy([{ year: 'desc' }, { month: 'desc' }, { day: 'desc' }])
.limitBy(limit)
}
private async fetchData(query: QueryDefinition) {
let result = null
try {
result = await this._client.query(query)
console.log(result)
} catch (error) {
// log stuff
//throw new Error("Cozy Cient Error");
return null
}
return result
}
public async getEntries(fluidType: FluidType, timeStep: TimeStep) {
let result = null
const doctype = this.getRelevantDoctype(fluidType, timeStep)
try {
result = await this._client.query(this._client.find(doctype).where({}))
} catch (error) {
return null
// throw new Error('Fetch data failed in query runner')
}
return result
}
......@@ -193,40 +144,6 @@ export default class QueryRunner {
return mappedResult
}
private buildListQuery(
timeStep: TimeStep,
timePeriod: TimePeriod,
fluidType: FluidType,
limit: number
) {
const doctype = this.getRelevantDoctype(fluidType, timeStep)
return Q(doctype)
.where(this.getPredicate(timePeriod, timeStep))
.limitBy(limit)
}
private buildMaxQuery(
timeStep: TimeStep,
maxTimePeriod: TimePeriod,
fluidType: FluidType,
limit: number
) {
const doctype = this.getRelevantDoctype(fluidType, timeStep)
if (timeStep === TimeStep.HALF_AN_HOUR) {
return this._client
.find(doctype)
.where(this.getPredicate(maxTimePeriod, 20))
.limitBy(1)
.sortBy([{ load: 'desc' }])
}
return this._client
.find(doctype)
.where(this.getPredicate(maxTimePeriod, timeStep))
.limitBy(limit)
.sortBy([{ load: 'desc' }])
}
private withinDateBoundaries(dateTime: DateTime, timePeriod: TimePeriod) {
return dateTime <= timePeriod.endDate && dateTime >= timePeriod.startDate
}
......@@ -273,17 +190,6 @@ export default class QueryRunner {
return dayList
}
private buildLastDateQuery(fluidType: FluidType, limit: number) {
const doctype = this.getRelevantDoctype(fluidType, TimeStep.DAY)
return this._client
.find(doctype)
.where({})
.indexFields(['year', 'month', 'day'])
.sortBy([{ year: 'desc' }, { month: 'desc' }, { day: 'desc' }])
.limitBy(limit)
}
private getPredicate(timePeriod: TimePeriod, timeStep: TimeStep) {
let predicate = {}
......@@ -409,4 +315,96 @@ export default class QueryRunner {
return doctype
}
public async fetchFluidData(
timePeriod: TimePeriod,
timeStep: TimeStep,
fluidType: FluidType
): Promise<Dataload[] | null> {
const query: QueryDefinition = this.buildListQuery(
timeStep,
timePeriod,
fluidType,
this._max_limit
)
const result = await this.fetchData(query)
if (result && result.data) {
const filteredResult = this.filterDataList(result, timePeriod)
const mappedResult = this.mapDataList(filteredResult)
return mappedResult
}
return null
}
public async fetchFluidMaxData(
maxTimePeriod: TimePeriod,
timeStep: TimeStep,
fluidType: FluidType
): Promise<number | null> {
const query: QueryDefinition = this.buildMaxQuery(
timeStep,
maxTimePeriod,
fluidType,
this._max_limit
)
const result = await this.fetchData(query)
if (timeStep === TimeStep.HALF_AN_HOUR) {
const lastDayOfPreviousMonth = {
startDate: maxTimePeriod.startDate.plus({ day: -1 }),
endDate: maxTimePeriod.startDate.plus({ day: -1 }).endOf('days'),
}
const lastDayOfPreviousMonthQuery: QueryDefinition = this.buildMaxQuery(
timeStep,
lastDayOfPreviousMonth,
fluidType,
this._max_limit
)
const lastDayOfPreviousMonthResult = await this.fetchData(
lastDayOfPreviousMonthQuery
)
return Math.max(
lastDayOfPreviousMonthResult && lastDayOfPreviousMonthResult.data[0]
? lastDayOfPreviousMonthResult.data[0].load
: 0,
result && result.data[0] ? result.data[0].load : 0
)
}
if (result && result.data) {
const filteredResult = this.filterDataList(result, maxTimePeriod)
const mappedResult = this.mapDataList(filteredResult)
return mappedResult && mappedResult[0] && mappedResult[0].value
}
return null
}
public async getLastDateData(fluidType: FluidType): Promise<DateTime | null> {
const query: QueryDefinition = this.buildLastDateQuery(fluidType, 1)
const result = await this.fetchData(query)
if (
result &&
result.data &&
result.data[0] &&
result.data[0].year &&
result.data[0].month &&
result.data[0].day
) {
return DateTime.local(
result.data[0].year,
result.data[0].month,
result.data[0].day
)
}
return null
}
public async getEntries(fluidType: FluidType, timeStep: TimeStep) {
const doctype = this.getRelevantDoctype(fluidType, timeStep)
try {
const query = Q(doctype).where({})
const result = await this._client.query(query)
return result
} catch (error) {
return null
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment