From 16eeb8638a901beca721cbde348ca0572dada265 Mon Sep 17 00:00:00 2001
From: ziajka <dominik@gns3.net>
Date: Thu, 25 Apr 2019 10:13:13 +0200
Subject: [PATCH] Console command tests

---
 .../helpers/drawings-factory.spec.ts          |   0
 .../console-device-action.component.spec.ts   | 101 ++++++++++++++++++
 .../console-device-action.component.ts        |   4 +-
 .../context-menu/context-menu.component.html  |   1 -
 .../context-menu.component.spec.ts            |  12 ++-
 .../console/console.component.spec.ts         |  47 ++++++++
 .../settings/settings.component.spec.ts       |  20 +++-
 src/app/services/server.service.spec.ts       |   4 +
 src/app/services/settings.service.spec.ts     |  16 ++-
 .../services/settings/console.service.spec.ts |  25 ++++-
 .../settings/default-console.service.spec.ts  |  39 ++++++-
 11 files changed, 253 insertions(+), 16 deletions(-)
 delete mode 100644 src/app/cartography/helpers/drawings-factory.spec.ts

diff --git a/src/app/cartography/helpers/drawings-factory.spec.ts b/src/app/cartography/helpers/drawings-factory.spec.ts
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/app/components/project-map/context-menu/actions/console-device-action/console-device-action.component.spec.ts b/src/app/components/project-map/context-menu/actions/console-device-action/console-device-action.component.spec.ts
index f254ff09..4d2dd290 100644
--- a/src/app/components/project-map/context-menu/actions/console-device-action/console-device-action.component.spec.ts
+++ b/src/app/components/project-map/context-menu/actions/console-device-action/console-device-action.component.spec.ts
@@ -1,13 +1,57 @@
 import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { MatIconModule } from '@angular/material';
+import { ElectronService } from 'ngx-electron';
 
 import { ConsoleDeviceActionComponent } from './console-device-action.component';
+import { ServerService } from '../../../../../services/server.service';
+import { MockedServerService } from '../../../../../services/server.service.spec';
+import { ToasterService } from '../../../../../services/toaster.service';
+import { MockedToasterService } from '../../../../../services/toaster.service.spec';
+import { SettingsService } from '../../../../../services/settings.service';
+import { MockedSettingsService } from '../../../../../services/settings.service.spec';
+import { Node } from '../../../../../cartography/models/node';
+import { Server } from '../../../../../models/server';
+
 
 describe('ConsoleDeviceActionComponent', () => {
   let component: ConsoleDeviceActionComponent;
   let fixture: ComponentFixture<ConsoleDeviceActionComponent>;
+  let electronService;
+  let server: Server;
+  let mockedSettingsService: MockedSettingsService;
+  let mockedServerService: MockedServerService;
+  let mockedToaster: MockedToasterService
+
+  beforeEach(() => {
+    electronService = {
+      isElectronApp: true,
+      remote: {
+        require: (file) => {
+          return {
+            openConsole() {}
+          }
+        }
+      }
+    };
+
+    mockedSettingsService = new MockedSettingsService();
+    mockedServerService = new MockedServerService();
+    mockedToaster = new MockedToasterService();
+
+    server = { host: 'localhost', 'port': 222} as Server;
+  })
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
+      providers: [
+        { provide: ElectronService, useValue: electronService },
+        { provide: ServerService, useValue: mockedServerService },
+        { provide: SettingsService, useValue: mockedSettingsService },
+        { provide: ToasterService, useValue: mockedToaster }
+      ],
+      imports: [
+        MatIconModule
+      ],
       declarations: [ ConsoleDeviceActionComponent ]
     })
     .compileComponents();
@@ -22,4 +66,61 @@ describe('ConsoleDeviceActionComponent', () => {
   it('should create', () => {
     expect(component).toBeTruthy();
   });
+
+  describe('console to nodes', () => {
+    let nodes: Node[];
+    
+    beforeEach(() => {
+      nodes = [{
+        status: 'started',
+        console_type: 'telnet',
+        console_host: 'host',
+        console: 999,
+        name: 'Node 1',
+        project_id: '1111',
+        node_id: '2222',
+      } as Node];
+      
+      component.nodes = nodes;
+      component.server = server;
+
+      mockedSettingsService.set('console_command', 'command');
+      spyOn(component, 'openConsole');
+    });
+
+    it('should console to device', async () => {
+      await component.console();
+
+      expect(component.openConsole).toHaveBeenCalledWith({
+        command: 'command',
+        type: 'telnet',
+        host: 'host',
+        port: 999,
+        name: 'Node 1',
+        project_id: '1111',
+        node_id: '2222',
+        server_url: 'localhost:222'
+      });
+    });
+
+    it('should show message when command is not defined', async () => {
+      mockedSettingsService.set('console_command', undefined);
+      await component.console();
+      expect(component.openConsole).not.toHaveBeenCalled();
+    });
+
+    it('should show message when there is no started nodes', async () => {
+      nodes[0]['status'] = 'stopped';
+      await component.console();
+      expect(component.openConsole).not.toHaveBeenCalled();
+    });
+
+    it('should only start running nodes', async () => {
+      nodes.push({
+        status: 'stopped'
+      } as Node);
+      await component.console();
+      expect(component.openConsole).toHaveBeenCalledTimes(1);
+    });
+  });
 });
diff --git a/src/app/components/project-map/context-menu/actions/console-device-action/console-device-action.component.ts b/src/app/components/project-map/context-menu/actions/console-device-action/console-device-action.component.ts
index 64f0140a..2cf30188 100644
--- a/src/app/components/project-map/context-menu/actions/console-device-action/console-device-action.component.ts
+++ b/src/app/components/project-map/context-menu/actions/console-device-action/console-device-action.component.ts
@@ -2,7 +2,6 @@ import { Component, OnInit, Input } from '@angular/core';
 import { Node } from '../../../../../cartography/models/node';
 import { Server } from '../../../../../models/server';
 import { ElectronService } from 'ngx-electron';
-import { Project } from '../../../../../models/project';
 import { ServerService } from '../../../../../services/server.service';
 import { SettingsService } from '../../../../../services/settings.service';
 import { ToasterService } from '../../../../../services/toaster.service';
@@ -13,7 +12,6 @@ import { ToasterService } from '../../../../../services/toaster.service';
 })
 export class ConsoleDeviceActionComponent implements OnInit {
   @Input() server: Server;
-  @Input() project: Project;
   @Input() nodes: Node[];
 
   constructor(
@@ -52,7 +50,7 @@ export class ConsoleDeviceActionComponent implements OnInit {
         host: node.console_host,
         port: node.console,
         name: node.name,
-        project_id: this.project.project_id,
+        project_id: node.project_id,
         node_id: node.node_id,
         server_url: this.serverService.getServerUrl(this.server)
       };
diff --git a/src/app/components/project-map/context-menu/context-menu.component.html b/src/app/components/project-map/context-menu/context-menu.component.html
index 47ddcf68..0d80158f 100644
--- a/src/app/components/project-map/context-menu/context-menu.component.html
+++ b/src/app/components/project-map/context-menu/context-menu.component.html
@@ -5,7 +5,6 @@
     <app-stop-node-action *ngIf="nodes.length" [server]="server" [nodes]="nodes"></app-stop-node-action>
     <app-console-device-action
       *ngIf="!projectService.isReadOnly(project) && nodes.length && isElectronApp"
-      [project]="project"
       [server]="server"
       [nodes]="nodes"
     ></app-console-device-action>
diff --git a/src/app/components/project-map/context-menu/context-menu.component.spec.ts b/src/app/components/project-map/context-menu/context-menu.component.spec.ts
index 2fdfae66..ab01063f 100644
--- a/src/app/components/project-map/context-menu/context-menu.component.spec.ts
+++ b/src/app/components/project-map/context-menu/context-menu.component.spec.ts
@@ -9,17 +9,23 @@ import { Drawing } from '../../../cartography/models/drawing';
 import { RectElement } from '../../../cartography/models/drawings/rect-element';
 import { TextElement } from '../../../cartography/models/drawings/text-element';
 import { Server } from '../../../models/server';
+import { ElectronService } from 'ngx-electron';
 
 describe('ContextMenuComponent', () => {
   let component: ContextMenuComponent;
   let fixture: ComponentFixture<ContextMenuComponent>;
 
   beforeEach(async(() => {
+    const electronMock = {
+      isElectronApp: true
+    };
+
     TestBed.configureTestingModule({
       imports: [MatMenuModule, BrowserModule],
       providers: [
         { provide: ChangeDetectorRef }, 
-        { provide: ProjectService, useClass: MockedProjectService }
+        { provide: ProjectService, useClass: MockedProjectService },
+        { provide: ElectronService, useValue: electronMock}
       ],
       declarations: [ContextMenuComponent],
       schemas: [NO_ERRORS_SCHEMA]
@@ -37,6 +43,10 @@ describe('ContextMenuComponent', () => {
     expect(component).toBeTruthy();
   });
 
+  it('should define property if running in electron ', () => {
+    expect(component.isElectronApp).toBeTruthy();
+  });
+
   it('should reset capabilities while opening menu for node', () => {
     component.contextMenu = { openMenu() {} } as MatMenuTrigger;
     var spy = spyOn<any>(component, 'resetCapabilities');
diff --git a/src/app/components/settings/console/console.component.spec.ts b/src/app/components/settings/console/console.component.spec.ts
index e8ebf2a1..b79cf69e 100644
--- a/src/app/components/settings/console/console.component.spec.ts
+++ b/src/app/components/settings/console/console.component.spec.ts
@@ -1,13 +1,40 @@
 import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 
 import { ConsoleComponent } from './console.component';
+import { MatFormFieldModule, MatCardModule, MatInputModule } from '@angular/material';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { ConsoleService } from '../../../services/settings/console.service';
+import { ToasterService } from '../../../services/toaster.service';
+import { MockedToasterService } from '../../../services/toaster.service.spec';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { Router } from '@angular/router';
+
 
 describe('ConsoleComponent', () => {
   let component: ConsoleComponent;
   let fixture: ComponentFixture<ConsoleComponent>;
+  let consoleService;
+  let router;
+  let toaster: MockedToasterService;
 
   beforeEach(async(() => {
+    consoleService = {
+      command: 'command'
+    };
+
+    router = {
+      navigate: jasmine.createSpy('navigate')
+    };
+
+    toaster = new MockedToasterService();
+
     TestBed.configureTestingModule({
+      providers: [
+        { provide: ConsoleService, useValue: consoleService },
+        { provide: ToasterService, useValue: toaster },
+        { provide: Router, useValue: router}
+      ],
+      imports: [ FormsModule, ReactiveFormsModule, MatFormFieldModule, MatCardModule, MatInputModule, NoopAnimationsModule ],
       declarations: [ ConsoleComponent ]
     })
     .compileComponents();
@@ -22,4 +49,24 @@ describe('ConsoleComponent', () => {
   it('should create', () => {
     expect(component).toBeTruthy();
   });
+
+  it('should set default command', () => {
+    component.ngOnInit();
+    expect(component.consoleForm.value.command).toEqual('command');
+  })
+
+  it('should go back', () => {
+    component.goBack();
+    expect(router.navigate).toHaveBeenCalledWith(['/settings']);
+  });
+
+
+  it('should update console command', () => {
+    component.consoleForm.get('command').setValue('newCommand');
+    spyOn(component, 'goBack');
+    component.save();
+    expect(toaster.success.length).toEqual(1);
+    expect(component.goBack).toHaveBeenCalled();
+  });
+
 });
diff --git a/src/app/components/settings/settings.component.spec.ts b/src/app/components/settings/settings.component.spec.ts
index 3b0c7f31..ce8b4b3b 100644
--- a/src/app/components/settings/settings.component.spec.ts
+++ b/src/app/components/settings/settings.component.spec.ts
@@ -1,5 +1,5 @@
 import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import { MatCheckboxModule, MatExpansionModule } from '@angular/material';
+import { MatCheckboxModule, MatExpansionModule, MatIconModule, MatFormFieldModule, MatInputModule } from '@angular/material';
 import { FormsModule } from '@angular/forms';
 import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
 
@@ -9,16 +9,26 @@ import { SettingsComponent } from './settings.component';
 import { SettingsService } from '../../services/settings.service';
 import { ToasterService } from '../../services/toaster.service';
 import { MockedToasterService } from '../../services/toaster.service.spec';
+import { ConsoleService } from '../../services/settings/console.service';
 
 describe('SettingsComponent', () => {
   let component: SettingsComponent;
   let fixture: ComponentFixture<SettingsComponent>;
   let settingsService: SettingsService;
+  let consoleService;
 
   beforeEach(async(() => {
+    consoleService = {
+      command: 'command'
+    };
+
     TestBed.configureTestingModule({
-      imports: [MatExpansionModule, MatCheckboxModule, FormsModule, PersistenceModule, BrowserAnimationsModule],
-      providers: [SettingsService, { provide: ToasterService, useClass: MockedToasterService }],
+      imports: [MatExpansionModule, MatCheckboxModule, FormsModule, PersistenceModule, BrowserAnimationsModule, MatIconModule, MatFormFieldModule, MatInputModule],
+      providers: [
+        SettingsService,
+        { provide: ToasterService, useClass: MockedToasterService },
+        { provide: ConsoleService, useValue: consoleService}
+      ],
       declarations: [SettingsComponent]
     }).compileComponents();
 
@@ -39,7 +49,8 @@ describe('SettingsComponent', () => {
     const settings = {
       crash_reports: true,
       experimental_features: true,
-      angular_map: false
+      angular_map: false,
+      console_command: ''
     };
     const getAll = spyOn(settingsService, 'getAll').and.returnValue(settings);
     const setAll = spyOn(settingsService, 'setAll');
@@ -50,4 +61,5 @@ describe('SettingsComponent', () => {
     component.save();
     expect(setAll).toHaveBeenCalledWith(settings);
   });
+
 });
diff --git a/src/app/services/server.service.spec.ts b/src/app/services/server.service.spec.ts
index a1f0c437..64d98b18 100644
--- a/src/app/services/server.service.spec.ts
+++ b/src/app/services/server.service.spec.ts
@@ -35,6 +35,10 @@ export class MockedServerService {
       resolve(this.servers);
     });
   }
+
+  public getServerUrl(server: Server) {
+    return `${server.host}:${server.port}`;
+  }
 }
 
 describe('ServerService', () => {
diff --git a/src/app/services/settings.service.spec.ts b/src/app/services/settings.service.spec.ts
index b16bfc24..ec8f9ad7 100644
--- a/src/app/services/settings.service.spec.ts
+++ b/src/app/services/settings.service.spec.ts
@@ -4,10 +4,20 @@ import { PersistenceService, StorageType } from 'angular-persistence';
 import { Settings, SettingsService } from './settings.service';
 
 export class MockedSettingsService {
+  settings = {};
+
   isExperimentalEnabled() {
     return true;
   }
   getAll() {}
+
+  get(key: string) {
+    return this.settings[key];
+  }
+
+  set(key: string, value: any) {
+    this.settings[key] = value;
+  }
 }
 
 describe('SettingsService', () => {
@@ -50,7 +60,8 @@ describe('SettingsService', () => {
     expect(service.getAll()).toEqual({
       crash_reports: true,
       experimental_features: false,
-      angular_map: false
+      angular_map: false,
+      console_command: undefined
     });
   }));
 
@@ -63,7 +74,8 @@ describe('SettingsService', () => {
     expect(service.getAll()).toEqual({
       crash_reports: false,
       experimental_features: false,
-      angular_map: false
+      angular_map: false,
+      console_command: undefined
     });
   }));
 
diff --git a/src/app/services/settings/console.service.spec.ts b/src/app/services/settings/console.service.spec.ts
index 30a37977..1cbbd288 100644
--- a/src/app/services/settings/console.service.spec.ts
+++ b/src/app/services/settings/console.service.spec.ts
@@ -1,12 +1,33 @@
 import { TestBed } from '@angular/core/testing';
 
 import { ConsoleService } from './console.service';
+import { MockedSettingsService } from '../settings.service.spec';
+import { SettingsService } from '../settings.service';
+import { DefaultConsoleService } from './default-console.service';
 
 describe('ConsoleService', () => {
-  beforeEach(() => TestBed.configureTestingModule({}));
+  let service: ConsoleService;
+  let settings: MockedSettingsService;
+
+  beforeEach(() => {
+    let defaultConsoleService = {
+      get: () => 'default'
+    };
+    settings = new MockedSettingsService();
+    service = new ConsoleService(defaultConsoleService as any, settings as any);
+  });
 
   it('should be created', () => {
-    const service: ConsoleService = TestBed.get(ConsoleService);
     expect(service).toBeTruthy();
   });
+
+  it('should get command from settings if defined', () => {
+    settings.set('console_command', 'from_settings');
+    expect(service.command).toEqual('from_settings');
+  });
+
+  it('should get command from default console if settings are not defined', () => {
+    settings.set('console_command', undefined);
+    expect(service.command).toEqual('default');
+  });
 });
diff --git a/src/app/services/settings/default-console.service.spec.ts b/src/app/services/settings/default-console.service.spec.ts
index 167e0f02..df89f144 100644
--- a/src/app/services/settings/default-console.service.spec.ts
+++ b/src/app/services/settings/default-console.service.spec.ts
@@ -1,12 +1,45 @@
-import { TestBed } from '@angular/core/testing';
 
 import { DefaultConsoleService } from './default-console.service';
 
 describe('DefaultConsoleService', () => {
-  beforeEach(() => TestBed.configureTestingModule({}));
+  let electronService;
+  let service: DefaultConsoleService;
+  beforeEach(() => {
+    electronService = {
+      isElectronApp: false,
+      isWindows: false,
+      isLinux: false
+    };
+  });
+ 
+  beforeEach(() => {
+    service = new DefaultConsoleService(electronService);
+  });
 
   it('should be created', () => {
-    const service: DefaultConsoleService = TestBed.get(DefaultConsoleService);
     expect(service).toBeTruthy();
   });
+
+  it('should return undefined when not running in electron', () => {
+    electronService.isElectronApp = false;
+    expect(service.get()).toBeUndefined();
+  });
+
+  it('should return console for windows', () => {
+    electronService.isElectronApp = true;
+    electronService.isWindows = true;
+    expect(service.get()).toEqual('putty.exe -telnet %h %p -loghost "%d"');
+  })
+
+  it('should return console for linux', () => {
+    electronService.isElectronApp = true;
+    electronService.isLinux = true;
+    expect(service.get()).toEqual('xfce4-terminal --tab -T "%d" -e "telnet %h %p"');
+  })
+
+  it('should return undefined for other platforms', () => {
+    electronService.isElectronApp = true;
+    expect(service.get()).toBeUndefined();
+  })
+
 });