added svcapi ui and camunda code
[it/otf.git] / otf-frontend / client / src / app / layout / components / stats / stats.service.ts
1 /*  Copyright (c) 2019 AT&T Intellectual Property.                             #\r
2 #                                                                              #\r
3 #   Licensed under the Apache License, Version 2.0 (the "License");            #\r
4 #   you may not use this file except in compliance with the License.           #\r
5 #   You may obtain a copy of the License at                                    #\r
6 #                                                                              #\r
7 #       http://www.apache.org/licenses/LICENSE-2.0                             #\r
8 #                                                                              #\r
9 #   Unless required by applicable law or agreed to in writing, software        #\r
10 #   distributed under the License is distributed on an "AS IS" BASIS,          #\r
11 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #\r
12 #   See the License for the specific language governing permissions and        #\r
13 #   limitations under the License.                                             #\r
14 ##############################################################################*/\r
15 \r
16 \r
17 import { Injectable } from '@angular/core';\r
18 import { FeathersService } from 'app/shared/services/feathers.service';\r
19 import { TestExecutionService } from 'app/shared/services/test-execution.service';\r
20 import { Observable, Subject, from } from 'rxjs';\r
21 import { MatDialog } from '@angular/material';\r
22 import { GroupService } from 'app/shared/services/group.service';\r
23 import * as moment from 'moment';\r
24 import { SchedulingService } from 'app/shared/services/scheduling.service';\r
25 import { TestInstanceService } from 'app/shared/services/test-instance.service';\r
26 import { string, number } from '@amcharts/amcharts4/core';\r
27 import { group } from '@angular/animations';\r
28 export interface StatsFilter {\r
29   startDate?: Date,\r
30   endDate?: Date,\r
31   selectedTestDefinitions?: Array<any>,\r
32   selectedTestInstances?: Array<any>\r
33 }\r
34 \r
35 @Injectable({\r
36   providedIn: 'root'\r
37 })\r
38 \r
39 //this service serves as the controller between the dashboard's data management and the components' UI.\r
40 export class StatsService {\r
41 \r
42   //set default filters\r
43   public filters: StatsFilter = {\r
44     startDate: moment().subtract(1, 'weeks').toDate(),\r
45     endDate: moment().toDate()\r
46   }\r
47 \r
48   public executionList: Array<any> = [];\r
49 \r
50   public testDefinitionData = {\r
51     //Executions Array thats made of objects with date, test definition name, and count\r
52     "Executions": [],\r
53     //Array of Results for the Pie Chart\r
54     "Results": [],\r
55   }\r
56   public testInstanceData = {\r
57     //Executions for Each Test Instance\r
58     "Executions": [],\r
59     //For multilinechart, objects made of test instance names, and execution count for each one.\r
60     "Individual_Exec": []\r
61   };\r
62 \r
63   //list if test instance names\r
64   public testInstances = [];\r
65   //list of scheduled tests gotten from agenda in db.\r
66   public scheduledTests = [];\r
67 \r
68   //these are filter objects attached to stats service that are updated whenever user confirms from filter modal. \r
69   //They are updated in the filter functions below.\r
70   // public tdFilters = {\r
71   //   startDate: {},\r
72   //   endDate: {},\r
73   //   selected: [],\r
74   // }\r
75   // public tiFilters = {\r
76   //   startDate: {},\r
77   //   endDate: {},\r
78   //   selectedTDs: [],\r
79   //   selectedTIs: [],\r
80   //   //this limit is for the amount of multiple series being displayed on the multiline chart according to default/filters.\r
81   //   multiLineLimit: 5,\r
82   // }\r
83   // public scheduleFilters = {\r
84   //   startDate: {},\r
85   //   endDate: {},\r
86   //   timeRangeStart: {},\r
87   //   timeRangeEnd: {},\r
88   //   selectedInstances: [],\r
89   // }\r
90 \r
91   //these are for triggering the listeners located in the chart components.\r
92   //executionsChange subjects are triggered when user filters.\r
93   public tdExecutionsChange: Subject<Object> = new Subject<Object>();\r
94   public tiExecutionsChange: Subject<Object> = new Subject<Object>();\r
95   public scheduleChange: Subject<Object> = new Subject<Object>();\r
96   public finishedDefaultData: Subject<Object> = new Subject<Object>();\r
97   public startDefaultData: Subject<Object> = new Subject<Object>();\r
98   public startTDExecutionCall: Subject<Object> = new Subject<Object>();\r
99   public startTIExecutionCall: Subject<Object> = new Subject<Object>();\r
100   public windowResized: Subject<Object> = new Subject<Object>();\r
101   public startScheduleCall: Subject<Object> = new Subject<Object>();\r
102 \r
103   constructor(public feathers: FeathersService, public testExecution: TestExecutionService,\r
104     public _groups: GroupService, public testInstanceService: TestInstanceService, public schedService: SchedulingService) {\r
105 \r
106     //listening for whether user changes group, if so, variables are reset (rest are inside defaultData, we can work on consistency).\r
107     //and we get default data for the new group passed in.\r
108     // this.getDefaultData(this._groups.getGroup());\r
109     // this._groups.groupChange().subscribe(group => {\r
110     //   this.getDefaultData(group);\r
111     // });\r
112 \r
113   }\r
114 \r
115   \r
116 \r
117   //these are trigger functions that we call in the data manipulating functions below.\r
118   //the purpose of these functions is to let the listeners set up in the chart components know that the data has been updated.\r
119   //then the chart components recall the data using getData().\r
120   checkWindow() {\r
121     return this.windowResized;\r
122   }\r
123 \r
124   onDefaultDataCallStarted() {\r
125     return this.startDefaultData;\r
126   }\r
127 \r
128   onTDExecutionChangeStarted() {\r
129     return this.startTDExecutionCall;\r
130   }\r
131 \r
132   onTIExecutionChangeStarted() {\r
133     return this.startTIExecutionCall;\r
134   }\r
135 \r
136   onScheduleChangeStarted() {\r
137     return this.startScheduleCall;\r
138   }\r
139 \r
140   onDefaultDataCallFinished() {\r
141     return this.finishedDefaultData;\r
142   }\r
143 \r
144   onTDExecutionChangeFinished() {\r
145     return this.tdExecutionsChange;\r
146   }\r
147 \r
148   onTIExecutionChangeFinished() {\r
149     return this.tiExecutionsChange;\r
150   }\r
151 \r
152   onScheduleChangeFinished() {\r
153     return this.scheduleChange;\r
154   }\r
155 \r
156   //one giant getter where we pass in the name of what we want and switch case it.\r
157 \r
158   //This function is called in the components and returns the relavent array for the component.\r
159   getData(name: string) {\r
160     let outputData = {};\r
161 \r
162     switch (name) {\r
163       case "TD_Executions":\r
164         return this.testDefinitionData.Executions;\r
165       case "TD_Results":\r
166         return this.testDefinitionData.Results;\r
167       case "testInstances":\r
168         return this.testInstanceData.Executions;\r
169       case "Schedule":\r
170         return this.scheduledTests;\r
171       // case "multiLineData":\r
172       //   //limitting the series being displayed.\r
173       //   return this.testInstanceData.Individual_Exec.slice(0, this.tiFilters.multiLineLimit);\r
174     }\r
175     //console.log(outputData);\r
176     return outputData;\r
177   }\r
178 \r
179   //this gets called from the filter modal when the user confirms their filters.\r
180   filterData(allFilters, tdFilters, tiFilters, schedFilters) {\r
181     //this.filterAll(allFilters);\r
182     this.filterTDs(tdFilters);\r
183     this.filterTIs(tiFilters);\r
184     this.filterSchedule(schedFilters)\r
185   }\r
186 \r
187   //this is still under the works, the purpose of this is to filter ALL the components of the dashboard if they have common filtering grounds.\r
188   filterAll(allFilters) {\r
189     //console.log('Filtering everything')\r
190     //console.log(allFilters);\r
191     if (allFilters.startDate != "" || allFilters.endDate != "") {\r
192       if (allFilters.endDate == "") {\r
193         this.testDefinitionData.Executions = this.testDefinitionData.Executions.filter(execution => (\r
194           execution.startTime >= allFilters.startDate\r
195         ))\r
196       } else if (allFilters.startDate == "") {\r
197         this.testDefinitionData.Executions = this.testDefinitionData.Executions.filter(execution => (\r
198           execution.startTime <= allFilters.endDate\r
199         ))\r
200       } else {\r
201         this.testDefinitionData.Executions = this.testDefinitionData.Executions.filter(execution => (\r
202           execution.startTime >= allFilters.startDate &&\r
203           execution.date <= allFilters.endDate\r
204         ))\r
205       }\r
206     }\r
207   }\r
208 \r
209   /*\r
210     this function takes in test definition filters and queries data accordingly.\r
211     improvement needed: if the filters provided do not require querying at all, the function should narrow the currently existing data. This\r
212     will be faster than requerying in those cases and improve loading times.\r
213   */\r
214   async filterTDs(tdFilters) {\r
215 \r
216     /*\r
217       checking if the filters passed in are empty, if so do nothing, if not, trigger a start call that lets the components know querying is going to begin.\r
218       these start..Call() functions are so chart components can turn on their loading indicators.\r
219     */\r
220     // if (tdFilters.startDate == "" && tdFilters.endDate == "" && tdFilters.selected.length == 0) return;\r
221     // else this.startTDExecutionCall.next(tdFilters);\r
222 \r
223     // //updating filter objects attached to stats service so we can use the service getters to get them where we want in the charts component code.\r
224     // this.tdFilters = tdFilters;\r
225 \r
226     // //if no range is passed in we use the default range of past 2 months.\r
227     // let startDate = tdFilters.startDate == "" ? new Date(moment().subtract(2, 'weeks').format('L')) : new Date(tdFilters.startDate);\r
228     // let endDate = tdFilters.endDate == "" ? moment().toDate() : new Date(tdFilters.endDate);\r
229     // //update service filters accordingly. \r
230     // this.tdFilters.startDate = startDate;\r
231     // this.tdFilters.endDate = endDate;\r
232     //variable of id's of the test definitions selected in the filters.\r
233     let selectedIDs = this.filters.selectedTestDefinitions.map(item => item.id);\r
234 \r
235     //Promise that queries the data according the filters. We use a promise so we wait for the data to query before the components render.\r
236     await new Promise((resolve, reject) => {\r
237 \r
238       //feathers query time.\r
239       this.testExecution.find({\r
240         //get the data relevant to the group.\r
241         groupId: this._groups.getGroup()["_id"],\r
242         //thse are gonna go in the data objects.\r
243         $select: [\r
244           'historicTestDefinition.testName',\r
245           'startTime',\r
246           'testResult'\r
247         ],\r
248         //UNLIMITED DATA BABY.\r
249         $limit: -1,\r
250         //sort according to ascending dates.\r
251         $sort: {\r
252           startTime: 1,\r
253         },\r
254         //select the start and end dates from the filter dates.\r
255         startTime: {\r
256           $gte: this.filters.startDate,\r
257           $lte: this.filters.endDate,\r
258         },\r
259         //select the test definitions according to the selected ones in the filters.\r
260         'historicTestDefinition._id': {\r
261           $in: selectedIDs\r
262         }\r
263       }).subscribe(result => {\r
264 \r
265         //console.log(result)\r
266 \r
267         //resetting real quick cuz why not.\r
268         this.testDefinitionData = {\r
269           "Executions": [],\r
270           "Results": [],\r
271         }\r
272 \r
273         //pretty self explanitory.\r
274         let fetchedData = result as Array<any>;\r
275         let currentExecutionsData = this.testDefinitionData.Executions;\r
276 \r
277         /*\r
278           for each new fetched json we got with the selected stuff we specified in the feathers query,\r
279           we need to organize and distribute them accordingly to our service's data objects. For example, the json objects consist of\r
280           'historicTestDefinition.testName',\r
281           'startTime',\r
282           'testResult',\r
283           test results belong in the results array, the rest needs to be organzied in the executions array,\r
284           thats what the populate methods are for.\r
285         */\r
286         for (let index in fetchedData) {\r
287           let newItem = fetchedData[index];\r
288 \r
289           //for consistency we're supposed to pass current data to both we'll fix that later, but for now the piechart one just calls the current results data\r
290           //inside itself.\r
291           this.populateLineChartData(newItem, currentExecutionsData);\r
292           this.populatePieChartData(newItem);\r
293         }\r
294         resolve();\r
295       })\r
296     }).then(res => {\r
297       //console.log(res);\r
298 \r
299       //trigger that querying is done and the test definition executions data has been changed. Line chart and pie chart listen for this.\r
300       this.tdExecutionsChange.next(res);\r
301     })\r
302   }\r
303 \r
304   //similar stuffies. just small differences.\r
305   async filterTIs(tiFilters) {\r
306 \r
307     // if (tiFilters.startDate == "" && tiFilters.endDate == "" && tiFilters.selectedTDs.length == 0 && tiFilters.selectedTIs.length == 0) return;\r
308     // else this.startTIExecutionCall.next(tiFilters);\r
309 \r
310     // this.tiFilters = tiFilters;\r
311     // if (tiFilters.selectedTIs.length > 0 && tiFilters.selectedTDs.length > 0) this.tiFilters.multiLineLimit = tiFilters.selectedTIs.length + tiFilters.selectedTDs.length;\r
312     // else if (tiFilters.selectedTIs.length > 0) this.tiFilters.multiLineLimit = tiFilters.selectedTIs.length;\r
313     // else if (tiFilters.selectedTDs.length > 0) this.tiFilters.multiLineLimit = tiFilters.selectedTDs.length;\r
314     // else this.tiFilters.multiLineLimit = 5;\r
315 \r
316     // let startDate = tiFilters.startDate == "" ? new Date(moment().subtract(2, 'weeks').format('L')) : new Date(tiFilters.startDate);\r
317     // let endDate = tiFilters.endDate == "" ? moment().toDate() : new Date(tiFilters.endDate);\r
318 \r
319     // this.tiFilters.startDate = startDate;\r
320     // this.tiFilters.endDate = endDate;\r
321     // console.log(tiFilters.selectedTDs)\r
322 \r
323     await new Promise((resolve, reject) => {\r
324       this.testExecution.find({\r
325         groupId: this._groups.getGroup()["_id"],\r
326         $limit: -1,\r
327         startTime: {\r
328           $gte: this.filters.startDate,\r
329           $lte: this.filters.endDate,\r
330         },\r
331         $select: [\r
332           'startTime',\r
333           'endTime',\r
334           'historicTestDefinition.testName',\r
335           'historicTestInstance.testInstanceName',\r
336         ],\r
337         $or: [\r
338           {\r
339             'historicTestDefinition._id': {\r
340               $in: tiFilters.selectedTDs\r
341             }\r
342           },\r
343           {\r
344             'historicTestInstance._id': {\r
345               $in: tiFilters.selectedTIs\r
346             }\r
347           }\r
348         ]\r
349 \r
350       }).subscribe(result => {\r
351         this.testInstanceData = {\r
352           "Executions": [],\r
353           "Individual_Exec": []\r
354         }\r
355         //console.log(result)\r
356         let fetchedData = result as Array<any>;\r
357         for (let index in fetchedData) {\r
358           let newItem = fetchedData[index];\r
359           this.populateBarChartData(newItem);\r
360           this.populateMultiLineChartData(newItem);\r
361         }\r
362         this.testInstanceData.Executions.sort((a, b) => b.Count - a.Count);\r
363         this.testInstanceData.Individual_Exec.sort((a, b) => b.total - a.total);\r
364 \r
365         resolve();\r
366       })\r
367     }).then(res => {\r
368       this.tiExecutionsChange.next(res);\r
369       //console.log(this.testInstanceData.Executions);\r
370     })\r
371 \r
372   }\r
373 \r
374   //similar stuffies just smol differneces.\r
375   async filterSchedule(schedFilters) {\r
376 \r
377     //console.log(schedFilters);\r
378     // this.scheduleFilters = schedFilters;\r
379     // //console.log(schedFilters.selectedInstances);\r
380 \r
381     // if (schedFilters.startDate == "" &&\r
382     //   schedFilters.endDate == "" &&\r
383     //   schedFilters.selectedInstances.length == 0) {\r
384     //   return;\r
385     // } else this.startScheduleCall.next(schedFilters);\r
386 \r
387     // let startDate = schedFilters.startDate == "" ? new Date(moment().toDate()) : new Date(schedFilters.startDate);\r
388     // let endDate = schedFilters.endDate == "" ? new Date(moment().add(2, 'weeks').format('L')) : new Date(schedFilters.endDate);\r
389 \r
390     // this.scheduleFilters.startDate = startDate;\r
391     // this.scheduleFilters.endDate = endDate;\r
392 \r
393     \r
394     this.schedService.find({\r
395       $select: ["data.testSchedule._testInstanceId", 'nextRunAt'],\r
396       $limit: -1,\r
397     }).subscribe(result => {\r
398       this.scheduledTests = [];\r
399       //console.log(result);\r
400       let fetchedData = result as Array<any>;\r
401       let resultingData: Array<any> = fetchedData;\r
402       if (schedFilters.selectedInstances.length !== 0) {\r
403         resultingData = fetchedData.filter(el => {\r
404           let fetchedID = el.data.testSchedule._testInstanceId;\r
405           let selectedIDs = schedFilters.selectedInstances as Array<any>;\r
406           let condition = selectedIDs.includes(fetchedID.toString());\r
407           //console.log(condition);\r
408           return condition;\r
409         })\r
410       }\r
411 \r
412       resultingData = resultingData.filter(el => {\r
413         let schedDate = new Date(el.nextRunAt);\r
414         return schedDate >= this.filters.startDate && schedDate <= this.filters.endDate;\r
415       })\r
416 \r
417       for (let index in resultingData) {\r
418         let checkIfTestBelongsToUserGroup = this.testInstances.findIndex(testInstances => testInstances.id === resultingData[index].data.testSchedule._testInstanceId);\r
419         if (checkIfTestBelongsToUserGroup >= 0) {\r
420           if (resultingData[index].nextRunAt) {\r
421             let d1 = new Date(resultingData[index].nextRunAt);\r
422             this.scheduledTests.push({\r
423               id: resultingData[index].data.testSchedule._testInstanceId,\r
424               name: this.testInstances[checkIfTestBelongsToUserGroup].name,\r
425               dateExec: d1.toDateString(),\r
426               timeExec: d1.toLocaleTimeString()\r
427             })\r
428           }\r
429         }\r
430       }\r
431       this.scheduleChange.next();\r
432     });\r
433     \r
434 \r
435 \r
436   }\r
437 \r
438   //getters for the filter objects.\r
439   // getTDFilters() {\r
440   //   return this.tdFilters;\r
441   // }\r
442 \r
443   // getTIFilters() {\r
444   //   return this.tiFilters;\r
445   // }\r
446 \r
447   // getSchedFilters() {\r
448   //   return this.scheduleFilters;\r
449   // }\r
450 \r
451   calcTime(execution) {\r
452     var end = new Date(execution.endTime);\r
453     var start = new Date(execution.startTime);\r
454     var executionTime = (end.getTime() - start.getTime()) / 1000;\r
455     return executionTime;\r
456   }\r
457 \r
458   //This function takes an execution that was retrieved from the Database and takes the data it needs for the line chart. \r
459   populateLineChartData(execution, currentData) {\r
460     let executionDate = new Date(execution.startTime)\r
461 \r
462     // Looks to see if the date already has an execution./\r
463     let indexOfItemFound = currentData.findIndex((element) => {\r
464 \r
465       return (\r
466         executionDate.getFullYear() === element.date.getFullYear() &&\r
467         executionDate.getMonth() === element.date.getMonth() &&\r
468         executionDate.getDate() === element.date.getDate()\r
469       )\r
470     })\r
471 \r
472     //If the date is not found. Push a new date into the array with a count of one\r
473     if (currentData[indexOfItemFound] == undefined) {\r
474       currentData.push({\r
475         date: new Date(executionDate.getFullYear(), executionDate.getMonth(), executionDate.getDate()),\r
476         count: 1\r
477       })\r
478     // else update the count\r
479     } else currentData[indexOfItemFound].count += 1;\r
480   }\r
481 \r
482 \r
483   //Takes an execution and  pushes the result/count or updates the count. For the Pie Chart\r
484   populatePieChartData(execution) {\r
485 \r
486     //Check if result is already present in the array. \r
487     var checkIfPresent = this.testDefinitionData.Results.find(Results => Results.Name === execution.testResult);\r
488    \r
489     //If not present, add it to TOPSTATs with a default count of 1.    \r
490     if (!checkIfPresent) {\r
491       \r
492       var color;\r
493       //Set the color for the pie chart.\r
494       if (execution.testResult == "COMPLETED"){\r
495         color = "#0D47A1";\r
496       }else if (execution.testResult == "FAILED")\r
497         color = "#DD2C00";\r
498       else if (execution.testResult == "UNKNOWN")\r
499         color = "#C4CBD4";\r
500       else if (execution.testResult == "SUCCESS")\r
501         color = "#42d660";\r
502       else if (execution.testResult == "success")\r
503         color = "#42d660";\r
504       else if (execution.testResult == "STARTED")\r
505         color = "#29E3E8";\r
506       else if (execution.testResult == "FAILURE")\r
507         color = "#FC9100";\r
508       else if (execution.testResult == "STOPPED")\r
509         color = "#900C3F";\r
510       else if (execution.testResult == "TERMINATED")\r
511         color = "#AC00FC";\r
512       else if (execution.testResult == "UNAUTHORIZED")\r
513         color = "#7A6E6E";\r
514       else if (execution.testResult == "DOES_NOT_EXIST")\r
515         color = "#000000";\r
516       else if (execution.testResult == "ERROR")\r
517         color = "#eb2acd"\r
518       else if (execution.testResult == "WORKFLOW_ERROR")\r
519         color = "#194f24"\r
520       else\r
521         color = "#000000".replace(/0/g, function () { return (~~(Math.random() * 16)).toString(16); });\r
522 \r
523       //Push the execution with the count and color.\r
524       this.testDefinitionData.Results.push({ Name: execution.testResult, Count: 1, color: color });\r
525     } else {\r
526 \r
527       //Find index of the testResult and update the count by 1.\r
528       var position = this.testDefinitionData.Results.findIndex(Results => Results.Name === execution.testResult);\r
529       this.testDefinitionData.Results[position].Count += 1;\r
530     }\r
531   }\r
532 \r
533   //Takes an execution and pushes result into the barchart. \r
534   populateBarChartData(execution) {\r
535 \r
536     //check if test instance is present in the array. \r
537     var checkIfPresent = this.testInstanceData.Executions.find(Instances => Instances.id === execution.historicTestInstance._id);\r
538 \r
539     //calculates the time it took for the execution/\r
540     var executionTime = this.calcTime(execution);\r
541     \r
542     //If execution is not present, push the test instance with a count of 1.\r
543     if (!checkIfPresent) {\r
544       //If not present, add it to testInstanceData with a default count of 1. \r
545 \r
546       this.testInstanceData.Executions.push({\r
547         Name: execution.historicTestInstance.testInstanceName,\r
548         id: execution.historicTestInstance._id,\r
549         testResult: execution.testResult,\r
550         executionTime: executionTime,\r
551         Count: 1,\r
552         Average: executionTime\r
553       });\r
554     } else {\r
555       // If Present update count and execution time. \r
556       var position = this.testInstanceData.Executions.findIndex(Instances => Instances.id === execution.historicTestInstance._id);\r
557       this.testInstanceData.Executions[position].Count += 1;\r
558       this.testInstanceData.Executions[position].executionTime += executionTime;\r
559       this.testInstanceData.Executions[position].Average = this.testInstanceData.Executions[position].executionTime / this.testInstanceData.Executions[position].Count;\r
560     }\r
561 \r
562   }\r
563 \r
564   //queries data for the scheduled tests. \r
565   getScheduledTests(groupId) {\r
566 \r
567     //Queries a list of test instances by group ID\r
568     this.testInstanceService.find({\r
569       groupId: groupId['_id'],\r
570       $select: ["_id", "testInstanceName", "groupId"],\r
571       $limit: -1\r
572     }).subscribe(result => {\r
573 \r
574       //Iterate through the list and add the test instances to the list. \r
575       for (var index in result) {\r
576         var checkIfPresent = this.testInstances.find(id => id === result[index]._id);\r
577         if (!checkIfPresent)\r
578           this.testInstances.push({ id: result[index]._id, name: result[index].testInstanceName });\r
579       }\r
580     });\r
581 \r
582     //Queries all of the scheduled tests. \r
583     this.schedService.find({\r
584 \r
585       $select: ["data.testSchedule._testInstanceId", 'nextRunAt'],\r
586       $limit: -1,\r
587       $sort: {\r
588         startTime: 1\r
589       },\r
590 \r
591     }).subscribe(result => {\r
592 \r
593       this.scheduledTests = [];\r
594       for (var index in result) {\r
595 \r
596         //If the scheduled testinstance is owned by the group, push the result. \r
597         var checkIfTestBelongsToUserGroup = this.testInstances.findIndex(testInstances => testInstances.id === result[index].data.testSchedule._testInstanceId);\r
598         if (checkIfTestBelongsToUserGroup >= 0) {\r
599 \r
600           //If the next run at is valid, the test is scheduled.\r
601           if (result[index].nextRunAt) {\r
602             let d1 = new Date(result[index].nextRunAt);\r
603             this.scheduledTests.push({\r
604               id: result[index].data.testSchedule._testInstanceId,\r
605               name: this.testInstances[checkIfTestBelongsToUserGroup].name,\r
606               dateExec: d1.toDateString(),\r
607               timeExec: d1.toLocaleTimeString()\r
608             });\r
609           }\r
610         }\r
611       }\r
612     });\r
613   }\r
614 \r
615   //populate multi line chart\r
616   populateMultiLineChartData(execution) {\r
617 \r
618     let executionDate = new Date(execution.startTime)\r
619     let currentData = this.testInstanceData.Individual_Exec;\r
620     let count = 1;\r
621     //find if Instance is already present in the array. \r
622     let position = this.testInstanceData.Individual_Exec.findIndex(Instances => Instances.id === execution.historicTestInstance._id);\r
623 \r
624     //First execution for this instance\r
625     if (currentData[position] == undefined) {\r
626       currentData.push({\r
627         testInstanceName: execution.historicTestInstance.testInstanceName,\r
628         testDefinitionName: execution.historicTestDefinition.testDefintionName,\r
629         id: execution.historicTestInstance._id,\r
630         dateData: [{ date: executionDate, count: count, name: execution.historicTestInstance.testInstanceName }],\r
631         total: 1\r
632       })\r
633       //execution already present\r
634     } else {\r
635       //find index of Date\r
636       let indexOfDate = currentData[position].dateData.findIndex((element) => {\r
637         return (\r
638           executionDate.getFullYear() === element.date.getFullYear() &&\r
639           executionDate.getMonth() === element.date.getMonth() &&\r
640           executionDate.getDate() === element.date.getDate()\r
641         )\r
642       });\r
643 \r
644       //Check if the exeuction date is valid for this instance. If it is not present, push a new date and count. \r
645       if (currentData[position].dateData[indexOfDate] == undefined) {\r
646         let count = 1;\r
647         //Push the new Date\r
648         currentData[position].dateData.push({ date: executionDate, count: count, name: execution.historicTestInstance.testInstanceName, id: execution.historicTestInstance._id});\r
649         currentData[position].total++;\r
650       } else {\r
651         //date is already present\r
652         currentData[position].dateData[indexOfDate].count++;\r
653         currentData[position].total++;\r
654       }\r
655     }\r
656   }\r
657   //Gets the initial data for the default page. \r
658   async getDefaultData(group, query?) { \r
659     if(!group){\r
660       return;\r
661     }\r
662     \r
663     this.scheduledTests = [];\r
664 \r
665     this.startDefaultData.next(group);\r
666     let groupId = group;\r
667     //let startDate = moment().subtract(2, 'weeks').toDate();\r
668     \r
669     //query sheduled tests\r
670     //this.getScheduledTests(group);\r
671 \r
672     if(!query){\r
673       query = {\r
674         groupId: groupId['_id'],\r
675         $select: [\r
676           'startTime',\r
677           'endTime',\r
678           "historicTestDefinition._id",\r
679           "historicTestDefinition.testName",\r
680           "historicTestInstance._id",\r
681           "historicTestInstance.testInstanceName",\r
682           "testHeadResults.startTime",\r
683           "testHeadResults.endTime",\r
684           "testHeadResults.testHeadName",\r
685           "testHeadResults.testHeadId",\r
686           "testHeadResults.testHeadGroupId",\r
687           "testHeadResults.statusCode",\r
688           'testResult'\r
689         ],\r
690         $limit: -1,\r
691         $sort: {\r
692           startTime: 1\r
693         },\r
694         startTime: {\r
695           $gte: this.filters.startDate,\r
696           $lte: this.filters.endDate\r
697         }\r
698       }\r
699     }\r
700 \r
701     //Query test Executions\r
702     await new Promise((resolve, reject) => {\r
703       this.testExecution.find(query).subscribe(result => {\r
704 \r
705         //reset arrays\r
706         this.testDefinitionData = {\r
707           //Executions Array thats made of objects with date, tdName, result\r
708           "Executions": [],\r
709           "Results": [],\r
710         }\r
711         this.testInstanceData = {\r
712           "Executions": [],\r
713           "Individual_Exec": []\r
714         };\r
715 \r
716         this.executionList = result as Array<any>;\r
717         let currentData = this.testDefinitionData.Executions;\r
718 \r
719         \r
720 \r
721         //iterate through the results and populate the appropriate arrays. \r
722         for (let index in this.executionList) {\r
723 \r
724           let newItem = this.executionList[index];\r
725 \r
726           //get default line chart Data\r
727           this.populateLineChartData(newItem, currentData);\r
728 \r
729           //get pie chart data. \r
730           this.populatePieChartData(newItem);\r
731 \r
732           //Get BarChart Data\r
733           //this.populateBarChartData(newItem);\r
734 \r
735           //get multi line chart data\r
736           //this.populateMultiLineChartData(newItem);\r
737         }\r
738 \r
739         //sort the two arrays descending.\r
740         this.testInstanceData.Executions.sort((a, b) => b.Count - a.Count);\r
741         this.testInstanceData.Individual_Exec.sort((a, b) => b.total - a.total);\r
742         resolve();\r
743       }, err => {\r
744         reject(err);\r
745       });\r
746     }).then(res => {\r
747 \r
748       // this.tdFilters = {\r
749       //   startDate: moment().subtract(2, 'weeks').toDate(),\r
750       //   endDate: moment().toDate(),\r
751       //   selected: [],\r
752       // };\r
753       // this.tiFilters = {\r
754       //   startDate: moment().subtract(2, 'weeks').toDate(),\r
755       //   endDate: moment().toDate(),\r
756       //   selectedTDs: [],\r
757       //   selectedTIs: [],\r
758       //   multiLineLimit: 5,\r
759       // }\r
760       this.finishedDefaultData.next(res);\r
761     })\r
762   }\r
763 \r
764 \r
765 }\r