All files / test-session test-session.service.ts

98.07% Statements 51/52
92.3% Branches 12/13
94.11% Functions 16/17
98% Lines 49/50

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 1313x     3x   3x 2x 1x     2x 2x   2x       3x   13x   13x         13x   13x           13x             9x 9x       9x 9x     9x   1x     8x   2x 2x     6x         9x   8x 8x     8x         22x 58x 49x   58x 49x   58x         3x   3x 11x 9x   9x 6x         3x       1x   5x     8x       1x     5x         1x       1x 1x      
import { Injectable, Logger } from '@nestjs/common';
import { TestSessionChange } from 'testcenter-common/interfaces/test-session-change.interface';
import { Monitor } from '../monitor/monitor.interface';
import { WebsocketGateway } from '../common/websocket.gateway';
 
const mergeSessionChanges = (testSession: TestSessionChange, sessionChange: TestSessionChange): TestSessionChange => {
  if ((sessionChange.unitName) && (sessionChange.unitName !== testSession.unitName)) {
    testSession.unitState = {};
  }
 
  sessionChange.unitState = { ...testSession.unitState, ...sessionChange.unitState };
  sessionChange.testState = { ...testSession.testState, ...sessionChange.testState };
 
  return { ...testSession, ...sessionChange };
};
 
@Injectable()
export class TestSessionService {
  constructor(
    private readonly websocketGateway: WebsocketGateway
  ) {
    this.websocketGateway.getDisconnectionObservable().subscribe((disconnected: string) => {
      this.removeMonitor(disconnected);
    });
  }
 
  private readonly logger = new Logger(TestSessionService.name);
 
  private testSessions: {
    [group: string]: {
      [sessionId: string]: TestSessionChange
    }
  } = {};
 
  private monitors: {
    [group: string]: {
      [token: string]: Monitor
    }
  } = {};
 
  applySessionChange(sessionChange: TestSessionChange): void {
    this.addSessionChange(sessionChange);
    this.broadcastTestSessionsToGroupMonitors(sessionChange.groupName);
  }
 
  private addSessionChange(sessionChange: TestSessionChange): void {
    const group: string = sessionChange.groupName;
    const testId = sessionChange.testId;
 
    // testSession is first of group
    if (typeof this.testSessions[group] === 'undefined') {
      // this.logger.log("skipping group hence not monitored: " + group);
      return;
    }
 
    if (typeof this.testSessions[group][testId] !== 'undefined') {
      // testSession is already known and needs to be updated
      const testSession = this.testSessions[group][testId];
      this.testSessions[group][testId] = mergeSessionChanges(testSession, sessionChange);
    } else {
      // formally unknown testSession
      this.testSessions[group][testId] = sessionChange;
    }
  }
 
  private broadcastTestSessionsToGroupMonitors(groupName: string) {
    if (typeof this.monitors[groupName] !== 'undefined') {
      // this.logger.log("broadcasting data about group: " + groupName);
      const tokens = Object.keys(this.monitors[groupName]);
      const sessions = (typeof this.testSessions[groupName] !== 'undefined') ?
        Object.values(this.testSessions[groupName]) :
        [];
      this.websocketGateway.broadcastToRegistered(tokens, 'test-sessions', sessions);
    }
  }
 
  addMonitor(monitor: Monitor): void {
    monitor.groups.forEach((group: string) => {
      if (typeof this.monitors[group] === 'undefined') {
        this.monitors[group] = {};
      }
      if (typeof this.testSessions[group] === 'undefined') {
        this.testSessions[group] = {};
      }
      this.monitors[group][monitor.token] = monitor;
    });
  }
 
  removeMonitor(monitorToken: string): void {
    this.logger.log(`remove monitor: ${monitorToken}`);
 
    Object.keys(this.monitors).forEach((group: string) => {
      if (typeof this.monitors[group][monitorToken] !== 'undefined') {
        delete this.monitors[group][monitorToken];
 
        if (Object.keys(this.monitors[group]).length === 0) {
          delete this.testSessions[group];
        }
      }
    });
 
    this.websocketGateway.disconnectClient(monitorToken);
  }
 
  getMonitors(): Monitor[] {
    return Object.values(this.monitors)
      .reduce(
        (allMonitors: Monitor[], groupMonitors: { [g: string]: Monitor }): Monitor[] => allMonitors
          .concat(Object.values(groupMonitors)), []
      )
      .filter((v: Monitor, i: number, a: Monitor[]) => a.indexOf(v) === i);
  }
 
  getTestSessions(): TestSessionChange[] {
    return Object.values(this.testSessions)
      .reduce(
        // eslint-disable-next-line max-len
        (allTestSessions: TestSessionChange[], groupTestSessions: { [g: string]: TestSessionChange }): TestSessionChange[] => allTestSessions.concat(Object.values(groupTestSessions)), []
      );
  }
 
  getClientTokens(): string[] {
    return this.websocketGateway.getClientTokens();
  }
 
  clean(): void {
    this.monitors = {};
    this.testSessions = {};
  }
}