Compare commits
1 Commits
api-unit-t
...
v2.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 487afb08d6 |
@@ -10,7 +10,7 @@ on:
|
|||||||
type: string
|
type: string
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build-and-test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
environment: ${{ inputs.environment_name }}
|
environment: ${{ inputs.environment_name }}
|
||||||
steps:
|
steps:
|
||||||
@@ -38,6 +38,10 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
npm run build -w api
|
npm run build -w api
|
||||||
|
|
||||||
|
- name: Test API
|
||||||
|
run: |
|
||||||
|
npm run test -w api
|
||||||
|
|
||||||
- name: Build Client
|
- name: Build Client
|
||||||
env:
|
env:
|
||||||
VITE_API_URL: ${{ vars.VITE_API_URL }}
|
VITE_API_URL: ${{ vars.VITE_API_URL }}
|
||||||
2
.github/workflows/main.yaml
vendored
2
.github/workflows/main.yaml
vendored
@@ -13,7 +13,7 @@ jobs:
|
|||||||
name: build
|
name: build
|
||||||
needs:
|
needs:
|
||||||
- changes
|
- changes
|
||||||
uses: ./.github/workflows/build.yaml
|
uses: ./.github/workflows/build_and_test.yaml
|
||||||
with:
|
with:
|
||||||
environment_name: test
|
environment_name: test
|
||||||
version_number: ${{ github.run_id }}
|
version_number: ${{ github.run_id }}
|
||||||
|
|||||||
2
.github/workflows/pull_request.yaml
vendored
2
.github/workflows/pull_request.yaml
vendored
@@ -12,7 +12,7 @@ jobs:
|
|||||||
name: build
|
name: build
|
||||||
needs:
|
needs:
|
||||||
- changes
|
- changes
|
||||||
uses: ./.github/workflows/build.yaml
|
uses: ./.github/workflows/build_and_test.yaml
|
||||||
with:
|
with:
|
||||||
environment_name: pull_request
|
environment_name: pull_request
|
||||||
version_number: ${{ github.run_id }}
|
version_number: ${{ github.run_id }}
|
||||||
|
|||||||
2
.github/workflows/tag.yaml
vendored
2
.github/workflows/tag.yaml
vendored
@@ -7,7 +7,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: build
|
name: build
|
||||||
uses: ./.github/workflows/build.yaml
|
uses: ./.github/workflows/build_and_test.yaml
|
||||||
with:
|
with:
|
||||||
environment_name: prod
|
environment_name: prod
|
||||||
version_number: ${{ github.ref_name }}
|
version_number: ${{ github.ref_name }}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "api",
|
"name": "api",
|
||||||
"version": "2.0.0-beta-4",
|
"version": "2.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"author": "",
|
"author": "",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { PilotEntity } from 'src/pilot/pilot.entity';
|
import { PilotEntity } from '../pilot/pilot.entity';
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';
|
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';
|
||||||
|
|
||||||
@Entity({ name: 'endorsements' })
|
@Entity({ name: 'endorsements' })
|
||||||
|
|||||||
@@ -48,10 +48,10 @@ import { ConfigService } from '@nestjs/config';
|
|||||||
return fileUrl;
|
return fileUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
async downloadFile(containerName: string, rowKey: string, fileName: string): Promise<string> {
|
async downloadFile(containerName: string, logId: string, fileName: string): Promise<string> {
|
||||||
this.containerName = containerName;
|
this.containerName = containerName;
|
||||||
|
|
||||||
const blockBlobClient = await this.getBlobClient(`${rowKey}/${fileName}`);
|
const blockBlobClient = await this.getBlobClient(`${logId}/${fileName}`);
|
||||||
const downloadBlockBlobResponse = await blockBlobClient.download();
|
const downloadBlockBlobResponse = await blockBlobClient.download();
|
||||||
const downloaded: string = (await this.streamToBuffer(downloadBlockBlobResponse.readableStreamBody)).toString()
|
const downloaded: string = (await this.streamToBuffer(downloadBlockBlobResponse.readableStreamBody)).toString()
|
||||||
|
|
||||||
|
|||||||
@@ -1,42 +1,25 @@
|
|||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from "@nestjs/testing";
|
||||||
import { HealthController } from './health.controller';
|
import { HealthController } from "./health.controller"
|
||||||
import { HealthService } from './health.service';
|
import { HttpStatus } from "@nestjs/common";
|
||||||
|
|
||||||
describe('HealthController', () => {
|
describe('HealthController', () => {
|
||||||
let controller; HealthController;
|
let controller: HealthController;
|
||||||
|
|
||||||
const mockHealthService = {
|
|
||||||
isDatabaseConnected: jest.fn()
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
controllers: [HealthController],
|
controllers: [HealthController]
|
||||||
providers: [HealthService]
|
|
||||||
}).compile();
|
}).compile();
|
||||||
|
|
||||||
controller = module.get<HealthController>(HealthController);
|
controller = module.get<HealthController>(HealthController);
|
||||||
})
|
})
|
||||||
|
|
||||||
it('isHealthy => should return true', () => {
|
it('should be defined', () => {
|
||||||
expect(controller).toBeDefined();
|
expect(controller).toBeDefined();
|
||||||
});
|
|
||||||
|
|
||||||
it('should return database connected', async () => {
|
|
||||||
jest.spyOn(mockHealthService, 'isDatabaseConnected').mockReturnValue(true);
|
|
||||||
|
|
||||||
const result = await controller.isHealthy();
|
|
||||||
|
|
||||||
expect(mockHealthService.isDatabaseConnected).toHaveBeenCalled();
|
|
||||||
expect(result).toEqual(true);
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('isHealthy => should return error', async () => {
|
it('isHealth => should return status ok', async () => {
|
||||||
jest.spyOn(mockHealthService, 'isDatabaseConnected').mockReturnValue(false);
|
|
||||||
|
|
||||||
const result = await controller.isHealthy();
|
const result = await controller.isHealthy();
|
||||||
|
|
||||||
expect(mockHealthService.isDatabaseConnected).toHaveBeenCalled();
|
expect(result).toEqual(HttpStatus.OK);
|
||||||
expect(result).toEqual(false);
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -1,27 +1,13 @@
|
|||||||
import {
|
import {
|
||||||
Controller,
|
Controller,
|
||||||
Get,
|
Get,
|
||||||
HttpException,
|
HttpStatus,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { HealthService } from './health.service';
|
|
||||||
import { CustomError } from 'src/error/customError';
|
|
||||||
|
|
||||||
|
|
||||||
@Controller('health')
|
@Controller('health')
|
||||||
export class HealthController {
|
export class HealthController {
|
||||||
constructor(
|
|
||||||
private readonly healthService: HealthService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
|
|
||||||
@Get()
|
@Get()
|
||||||
async isHealthy(): Promise<boolean> {
|
async isHealthy(): Promise<HttpStatus> {
|
||||||
try {
|
return HttpStatus.OK
|
||||||
return await this.healthService.isDatabaseConnected();
|
|
||||||
} catch (error) {
|
|
||||||
const customError = error as CustomError;
|
|
||||||
|
|
||||||
throw new HttpException(customError.message, customError.statusCode);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { HealthController } from './health.controller';
|
import { HealthController } from './health.controller';
|
||||||
import { HealthService } from './health.service';
|
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [HealthController],
|
controllers: [HealthController],
|
||||||
providers: [
|
|
||||||
HealthService
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
export class HealthModule {}
|
export class HealthModule {}
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
import { Test, TestingModule } from '@nestjs/testing';
|
|
||||||
import { HealthService } from './health.service';
|
|
||||||
|
|
||||||
describe('HealthService', () => {
|
|
||||||
let service: HealthService;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
|
||||||
providers: [HealthService]
|
|
||||||
}).compile();
|
|
||||||
|
|
||||||
service = module.get<HealthService>(HealthService);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
|
||||||
import { CustomError } from '../error/customError';
|
|
||||||
import { DataSource } from 'typeorm';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class HealthService {
|
|
||||||
constructor(private dataSource: DataSource) {}
|
|
||||||
|
|
||||||
async isDatabaseConnected(): Promise<boolean> {
|
|
||||||
try {
|
|
||||||
const isDatabaseConnected: boolean = this.dataSource.isInitialized;
|
|
||||||
|
|
||||||
if (isDatabaseConnected) {
|
|
||||||
return isDatabaseConnected;
|
|
||||||
} else {
|
|
||||||
throw new CustomError('Database not connected', 'Database not connected', 400)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
200
api/src/log/log.controller.spec.ts
Normal file
200
api/src/log/log.controller.spec.ts
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { LogController } from './log.controller';
|
||||||
|
import { LogService } from './log.service';
|
||||||
|
import { LogDto } from './log.dto';
|
||||||
|
import { LogEntity } from './log.entity';
|
||||||
|
import { FileService } from '../file/file.service';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
|
||||||
|
describe('LogController', () => {
|
||||||
|
let controller: LogController;
|
||||||
|
|
||||||
|
const mockLogService = {
|
||||||
|
create: jest.fn(),
|
||||||
|
delete: jest.fn(),
|
||||||
|
find: jest.fn(),
|
||||||
|
findAll: jest.fn(),
|
||||||
|
update: jest.fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
controllers: [LogController],
|
||||||
|
providers: [
|
||||||
|
ConfigService,
|
||||||
|
FileService,
|
||||||
|
{
|
||||||
|
provide: LogService,
|
||||||
|
useValue: mockLogService
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}).compile()
|
||||||
|
|
||||||
|
controller = module.get<LogController>(LogController);
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(controller).toBeDefined();
|
||||||
|
})
|
||||||
|
|
||||||
|
it('find => should find a log by id', async () => {
|
||||||
|
const id: string = '95834f84-0a02-44d3-884e-a20237adeca0';
|
||||||
|
const log = {
|
||||||
|
|
||||||
|
} as LogEntity
|
||||||
|
|
||||||
|
jest.spyOn(mockLogService, 'find').mockReturnValue(log);
|
||||||
|
|
||||||
|
const result = await controller.find(id);
|
||||||
|
|
||||||
|
expect(result).toEqual(log);
|
||||||
|
expect(mockLogService.find).toHaveBeenCalled();
|
||||||
|
expect(mockLogService.find).toHaveBeenCalledWith(id);
|
||||||
|
})
|
||||||
|
|
||||||
|
it('find => should fail to find a log by id', async () => {
|
||||||
|
const id: string = '95834f84-0a02-44d3-884e-a20237adeca0';
|
||||||
|
|
||||||
|
jest.spyOn(mockLogService, 'find').mockRejectedValue(new Error('Log not found'))
|
||||||
|
|
||||||
|
try {
|
||||||
|
await controller.find(id);
|
||||||
|
|
||||||
|
fail('find did not throw error')
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toBeInstanceOf(Error);
|
||||||
|
expect(mockLogService.find).toHaveBeenCalled();
|
||||||
|
expect(mockLogService.find).toHaveBeenCalledWith(id);
|
||||||
|
expect(mockLogService.find).rejects.toThrow('Log not found')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('findAll => should find all logs', async () => {
|
||||||
|
const id: string = '95834f84-0a02-44d3-884e-a20237adeca0';
|
||||||
|
const log = {
|
||||||
|
|
||||||
|
} as LogEntity;
|
||||||
|
const logs = [log]
|
||||||
|
|
||||||
|
jest.spyOn(mockLogService, 'findAll').mockReturnValue(logs);
|
||||||
|
|
||||||
|
const result = await controller.findAll();
|
||||||
|
|
||||||
|
expect(result).toEqual(logs);
|
||||||
|
expect(mockLogService.findAll).toHaveBeenCalled();
|
||||||
|
})
|
||||||
|
|
||||||
|
it('findAll => should fail to find all logs', async () => {
|
||||||
|
jest.spyOn(mockLogService, 'findAll').mockRejectedValue(new Error('Logs not found'))
|
||||||
|
|
||||||
|
try {
|
||||||
|
await controller.findAll();
|
||||||
|
|
||||||
|
fail('findAll did not throw error');
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toBeInstanceOf(Error);
|
||||||
|
expect(mockLogService.findAll).toHaveBeenCalled();
|
||||||
|
expect(mockLogService.findAll).rejects.toThrow('Logs not found')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('create => should create a new log', async () => {
|
||||||
|
const logDto = {
|
||||||
|
|
||||||
|
} as LogDto;
|
||||||
|
|
||||||
|
const log = {
|
||||||
|
|
||||||
|
} as LogEntity;
|
||||||
|
|
||||||
|
jest.spyOn(mockLogService, 'create').mockReturnValue(log);
|
||||||
|
|
||||||
|
const result = await controller.create(logDto);
|
||||||
|
|
||||||
|
expect(mockLogService.create).toHaveBeenCalled();
|
||||||
|
expect(mockLogService.create).toHaveBeenCalledWith(logDto);
|
||||||
|
expect(result).toEqual(log);
|
||||||
|
})
|
||||||
|
|
||||||
|
it('create => should failt to create a new log', async () => {
|
||||||
|
const logDto = {
|
||||||
|
|
||||||
|
} as LogDto;
|
||||||
|
|
||||||
|
jest.spyOn(mockLogService, 'create').mockRejectedValue(new Error('Log failed to create'))
|
||||||
|
|
||||||
|
try {
|
||||||
|
await controller.create(logDto);
|
||||||
|
|
||||||
|
fail('create did not throw error')
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toBeInstanceOf(Error);
|
||||||
|
expect(mockLogService.create).toHaveBeenCalled();
|
||||||
|
expect(mockLogService.create).toHaveBeenCalledWith(logDto);
|
||||||
|
expect(mockLogService.create).rejects.toThrow('Log failed to create')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('update => should update an existing log', async () => {
|
||||||
|
const id: string = '95834f84-0a02-44d3-884e-a20237adeca0';
|
||||||
|
const logDto = {
|
||||||
|
|
||||||
|
} as LogDto
|
||||||
|
|
||||||
|
jest.spyOn(mockLogService, 'update').mockReturnValue(logDto);
|
||||||
|
|
||||||
|
const result = await controller.update(id, logDto);
|
||||||
|
|
||||||
|
expect(result).toEqual(logDto);
|
||||||
|
expect(mockLogService.update).toHaveBeenCalled();
|
||||||
|
expect(mockLogService.update).toHaveBeenCalledWith(id, logDto);
|
||||||
|
})
|
||||||
|
|
||||||
|
it('update => should fail to update an exising log', async () => {
|
||||||
|
const id: string = '95834f84-0a02-44d3-884e-a20237adeca0';
|
||||||
|
const logDto = {
|
||||||
|
|
||||||
|
} as LogDto;
|
||||||
|
|
||||||
|
jest.spyOn(mockLogService, 'update').mockRejectedValue(new Error('Log failed to update'))
|
||||||
|
|
||||||
|
try {
|
||||||
|
await controller.update(id, logDto);
|
||||||
|
|
||||||
|
fail('update did not throw error')
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toBeInstanceOf(Error);
|
||||||
|
expect(mockLogService.update).toHaveBeenCalled();
|
||||||
|
expect(mockLogService.update).toHaveBeenCalledWith(id, logDto);
|
||||||
|
expect(mockLogService.update).rejects.toThrow('Log failed to update')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('delete => should delete and existing log', async () => {
|
||||||
|
const id: string = '95834f84-0a02-44d3-884e-a20237adeca0';
|
||||||
|
|
||||||
|
jest.spyOn(mockLogService, 'delete');
|
||||||
|
|
||||||
|
const result = await controller.delete(id);
|
||||||
|
|
||||||
|
expect(mockLogService.delete).toHaveBeenCalled();
|
||||||
|
expect(mockLogService.delete).toHaveBeenCalledWith(id);
|
||||||
|
})
|
||||||
|
|
||||||
|
it('delete => should fail to delete and exising log', async () => {
|
||||||
|
const id: string = '95834f84-0a02-44d3-884e-a20237adeca0';
|
||||||
|
|
||||||
|
jest.spyOn(mockLogService, 'delete').mockRejectedValue(new Error('Log failed to delete'));
|
||||||
|
|
||||||
|
try {
|
||||||
|
await controller.delete(id);
|
||||||
|
|
||||||
|
fail('delete did not throw error')
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toBeInstanceOf(Error);
|
||||||
|
expect(mockLogService.delete).toHaveBeenCalled();
|
||||||
|
expect(mockLogService.delete).toHaveBeenCalledWith(id);
|
||||||
|
expect(mockLogService.delete).rejects.toThrow('Log failed to delete')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -60,12 +60,12 @@ export class LogController {
|
|||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
@UseGuards(AuthGuard)
|
@UseGuards(AuthGuard)
|
||||||
async create(@Body() logDto: LogDto): Promise<InsertResult> {
|
async create(@Body() logDto: LogDto) {
|
||||||
try {
|
try {
|
||||||
return await this.logService.create(logDto);
|
return await this.logService.create(logDto);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const customError = error as CustomError;
|
const customError = error as CustomError;
|
||||||
console.log(error)
|
|
||||||
throw new HttpException(customError.message, customError.statusCode);
|
throw new HttpException(customError.message, customError.statusCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,13 +75,12 @@ export class LogController {
|
|||||||
async update(
|
async update(
|
||||||
@Param('id') id: string,
|
@Param('id') id: string,
|
||||||
@Body() logDto: LogDto
|
@Body() logDto: LogDto
|
||||||
): Promise<UpdateResult> {
|
) {
|
||||||
try {
|
try {
|
||||||
console.log(logDto);
|
|
||||||
return await this.logService.update(id, logDto);
|
return await this.logService.update(id, logDto);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const customError = error as CustomError;
|
const customError = error as CustomError;
|
||||||
console.log(customError)
|
|
||||||
throw new HttpException(customError.message, customError.statusCode);
|
throw new HttpException(customError.message, customError.statusCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { PilotEntity } from "src/pilot/pilot.entity";
|
|
||||||
|
|
||||||
export class LogDto {
|
export class LogDto {
|
||||||
pilotId: string;
|
pilotId: string;
|
||||||
date: Date;
|
date: Date;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { PilotEntity } from 'src/pilot/pilot.entity';
|
import { PilotEntity } from '../pilot/pilot.entity';
|
||||||
import { TrackEntity } from 'src/track/track.entity';
|
import { TrackEntity } from '../track/track.entity';
|
||||||
import { ColumnNumericTransformer } from 'src/transformers/columnNumeric.transformer';
|
import { ColumnNumericTransformer } from '../transformers/columnNumeric.transformer';
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn, OneToMany } from 'typeorm';
|
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn, OneToMany } from 'typeorm';
|
||||||
|
|
||||||
@Entity({ name: 'logs' })
|
@Entity({ name: 'logs' })
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { LogEntity } from './log.entity';
|
|||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { FileService } from '../file/file.service';
|
import { FileService } from '../file/file.service';
|
||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
import { PilotModule } from 'src/pilot/pilot.module';
|
import { PilotModule } from '../pilot/pilot.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
|
|||||||
288
api/src/log/log.service.spec.ts
Normal file
288
api/src/log/log.service.spec.ts
Normal file
@@ -0,0 +1,288 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { LogService } from './log.service';
|
||||||
|
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||||
|
import { LogEntity } from './log.entity';
|
||||||
|
import { LogDto } from './log.dto';
|
||||||
|
import { FileService } from '../file/file.service';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
import { PilotService } from '../pilot/pilot.service';
|
||||||
|
import { PilotEntity } from '../pilot/pilot.entity';
|
||||||
|
|
||||||
|
describe('LogService', () => {
|
||||||
|
let service: LogService;
|
||||||
|
|
||||||
|
const mockFileService = {
|
||||||
|
deleteFolder: jest.fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
const mockLogRepository = {
|
||||||
|
delete: jest.fn(),
|
||||||
|
find: jest.fn(),
|
||||||
|
findOne: jest.fn(),
|
||||||
|
findOneBy: jest.fn(),
|
||||||
|
save: jest.fn(),
|
||||||
|
}
|
||||||
|
|
||||||
|
const mockPilotRepository = {
|
||||||
|
create: jest.fn(),
|
||||||
|
delete: jest.fn(),
|
||||||
|
find: jest.fn(),
|
||||||
|
findAll: jest.fn(),
|
||||||
|
update: jest.fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
providers: [
|
||||||
|
ConfigService,
|
||||||
|
LogService,
|
||||||
|
PilotService,
|
||||||
|
{
|
||||||
|
provide: FileService,
|
||||||
|
useValue: mockFileService
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: getRepositoryToken(LogEntity),
|
||||||
|
useValue: mockLogRepository
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: getRepositoryToken(PilotEntity),
|
||||||
|
useValue: mockPilotRepository
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
service = module.get<LogService>(LogService);
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(service).toBeDefined();
|
||||||
|
})
|
||||||
|
|
||||||
|
it('create => shoule create a log entry', async () => {
|
||||||
|
const logDto = {
|
||||||
|
pilotId: '7c4bae6b-9ec4-469e-8e16-fcbf0b940936',
|
||||||
|
date: new Date('2026-02-21'),
|
||||||
|
aircraftMakeModel: 'Cessna 172M',
|
||||||
|
aircraftIdentity: 'N12345',
|
||||||
|
routeFrom: 'KMSP',
|
||||||
|
routeTo: 'KMSP',
|
||||||
|
durationOfFlight: 1,
|
||||||
|
singleEngineLand: 1,
|
||||||
|
simulatorAtd: null,
|
||||||
|
landingsDay: 1,
|
||||||
|
landingsNight: null,
|
||||||
|
groundTrainingReceived: null,
|
||||||
|
flightTrainingReceived: null,
|
||||||
|
crossCountry: 1,
|
||||||
|
night: null,
|
||||||
|
solo: 1,
|
||||||
|
pilotInCommand: 1,
|
||||||
|
instrumentActual: null,
|
||||||
|
instrumentSimulated: null,
|
||||||
|
instrumentApproaches: null,
|
||||||
|
instrumentHolds: null,
|
||||||
|
instrumentNavTrack: null,
|
||||||
|
notes: 'This is a test'
|
||||||
|
} as LogDto
|
||||||
|
|
||||||
|
jest.spyOn(mockLogRepository, 'save').mockReturnValue(logDto);
|
||||||
|
|
||||||
|
const result = await service.create(logDto);
|
||||||
|
|
||||||
|
expect(mockLogRepository.save).toHaveBeenCalled();
|
||||||
|
expect(mockLogRepository.save).toHaveBeenCalledWith(logDto);
|
||||||
|
})
|
||||||
|
|
||||||
|
it('delete => should delete a log entry', async () => {
|
||||||
|
const id: string = '';
|
||||||
|
const log = {
|
||||||
|
id: 'd685f1ca-28e0-40b9-8713-74467db12965',
|
||||||
|
pilotId: '7c4bae6b-9ec4-469e-8e16-fcbf0b940936',
|
||||||
|
date: new Date('2026-02-21'),
|
||||||
|
aircraftMakeModel: 'Cessna 172M',
|
||||||
|
aircraftIdentity: 'N12345',
|
||||||
|
routeFrom: 'KMSP',
|
||||||
|
routeTo: 'KMSP',
|
||||||
|
durationOfFlight: 1,
|
||||||
|
singleEngineLand: 1,
|
||||||
|
simulatorAtd: null,
|
||||||
|
landingsDay: 1,
|
||||||
|
landingsNight: null,
|
||||||
|
groundTrainingReceived: null,
|
||||||
|
flightTrainingReceived: null,
|
||||||
|
crossCountry: 1,
|
||||||
|
night: null,
|
||||||
|
solo: 1,
|
||||||
|
pilotInCommand: 1,
|
||||||
|
instrumentActual: null,
|
||||||
|
instrumentSimulated: null,
|
||||||
|
instrumentApproaches: null,
|
||||||
|
instrumentHolds: null,
|
||||||
|
instrumentNavTrack: null,
|
||||||
|
notes: 'This is a test',
|
||||||
|
tracks: []
|
||||||
|
} as LogEntity;
|
||||||
|
|
||||||
|
jest.spyOn(mockFileService, 'deleteFolder').mockReturnValue(undefined);
|
||||||
|
jest.spyOn(mockLogRepository, 'delete').mockReturnValue(log);
|
||||||
|
|
||||||
|
const result = await service.delete(id);
|
||||||
|
|
||||||
|
expect(result).toEqual(log);
|
||||||
|
expect(mockLogRepository.delete).toHaveBeenCalled();
|
||||||
|
expect(mockLogRepository.delete).toHaveBeenCalledWith({ id: id })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('find => should find a log entry by id', async () => {
|
||||||
|
const id: string = 'd685f1ca-28e0-40b9-8713-74467db12965';
|
||||||
|
const log = {
|
||||||
|
id: 'd685f1ca-28e0-40b9-8713-74467db12965',
|
||||||
|
pilotId: '7c4bae6b-9ec4-469e-8e16-fcbf0b940936',
|
||||||
|
date: new Date('2026-02-21'),
|
||||||
|
aircraftMakeModel: 'Cessna 172M',
|
||||||
|
aircraftIdentity: 'N12345',
|
||||||
|
routeFrom: 'KMSP',
|
||||||
|
routeTo: 'KMSP',
|
||||||
|
durationOfFlight: 1,
|
||||||
|
singleEngineLand: 1,
|
||||||
|
simulatorAtd: null,
|
||||||
|
landingsDay: 1,
|
||||||
|
landingsNight: null,
|
||||||
|
groundTrainingReceived: null,
|
||||||
|
flightTrainingReceived: null,
|
||||||
|
crossCountry: 1,
|
||||||
|
night: null,
|
||||||
|
solo: 1,
|
||||||
|
pilotInCommand: 1,
|
||||||
|
instrumentActual: null,
|
||||||
|
instrumentSimulated: null,
|
||||||
|
instrumentApproaches: null,
|
||||||
|
instrumentHolds: null,
|
||||||
|
instrumentNavTrack: null,
|
||||||
|
notes: 'This is a test',
|
||||||
|
tracks: []
|
||||||
|
} as LogEntity;
|
||||||
|
|
||||||
|
jest.spyOn(mockLogRepository, 'findOne').mockReturnValue(log);
|
||||||
|
|
||||||
|
const result = await service.find(id);
|
||||||
|
|
||||||
|
expect(result).toEqual(log);
|
||||||
|
expect(mockLogRepository.findOne).toHaveBeenCalled();
|
||||||
|
expect(mockLogRepository.findOne).toHaveBeenCalledWith({
|
||||||
|
relations: [
|
||||||
|
'pilot',
|
||||||
|
'tracks'
|
||||||
|
],
|
||||||
|
where: {
|
||||||
|
id: id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('findAll => should find all log entries', async () => {
|
||||||
|
const log = {
|
||||||
|
id: 'd685f1ca-28e0-40b9-8713-74467db12965',
|
||||||
|
pilotId: '7c4bae6b-9ec4-469e-8e16-fcbf0b940936',
|
||||||
|
date: new Date('2026-02-21'),
|
||||||
|
aircraftMakeModel: 'Cessna 172M',
|
||||||
|
aircraftIdentity: 'N12345',
|
||||||
|
routeFrom: 'KMSP',
|
||||||
|
routeTo: 'KMSP',
|
||||||
|
durationOfFlight: 1,
|
||||||
|
singleEngineLand: 1,
|
||||||
|
simulatorAtd: null,
|
||||||
|
landingsDay: 1,
|
||||||
|
landingsNight: null,
|
||||||
|
groundTrainingReceived: null,
|
||||||
|
flightTrainingReceived: null,
|
||||||
|
crossCountry: 1,
|
||||||
|
night: null,
|
||||||
|
solo: 1,
|
||||||
|
pilotInCommand: 1,
|
||||||
|
instrumentActual: null,
|
||||||
|
instrumentSimulated: null,
|
||||||
|
instrumentApproaches: null,
|
||||||
|
instrumentHolds: null,
|
||||||
|
instrumentNavTrack: null,
|
||||||
|
notes: 'This is a test',
|
||||||
|
tracks: []
|
||||||
|
} as LogEntity;
|
||||||
|
const logs = [log]
|
||||||
|
|
||||||
|
jest.spyOn(mockLogRepository, 'find').mockReturnValue(logs);
|
||||||
|
|
||||||
|
const result = await service.findAll();
|
||||||
|
|
||||||
|
expect(result).toEqual(logs);
|
||||||
|
expect(mockLogRepository.find).toHaveBeenCalled();
|
||||||
|
})
|
||||||
|
|
||||||
|
it('update => should update a log entry', async () => {
|
||||||
|
const id: string = 'd685f1ca-28e0-40b9-8713-74467db12965';
|
||||||
|
const logDto = {
|
||||||
|
pilotId: '7c4bae6b-9ec4-469e-8e16-fcbf0b940936',
|
||||||
|
date: new Date('2026-02-21'),
|
||||||
|
aircraftMakeModel: 'Cessna 172M',
|
||||||
|
aircraftIdentity: 'N12345',
|
||||||
|
routeFrom: 'KMSP',
|
||||||
|
routeTo: 'KMSP',
|
||||||
|
durationOfFlight: 1,
|
||||||
|
singleEngineLand: 1,
|
||||||
|
simulatorAtd: null,
|
||||||
|
landingsDay: 1,
|
||||||
|
landingsNight: null,
|
||||||
|
groundTrainingReceived: null,
|
||||||
|
flightTrainingReceived: null,
|
||||||
|
crossCountry: 1,
|
||||||
|
night: null,
|
||||||
|
solo: 1,
|
||||||
|
pilotInCommand: 1,
|
||||||
|
instrumentActual: null,
|
||||||
|
instrumentSimulated: null,
|
||||||
|
instrumentApproaches: null,
|
||||||
|
instrumentHolds: null,
|
||||||
|
instrumentNavTrack: null,
|
||||||
|
notes: 'This is a test'
|
||||||
|
} as LogDto
|
||||||
|
const log = {
|
||||||
|
id: 'd685f1ca-28e0-40b9-8713-74467db12965',
|
||||||
|
pilotId: '7c4bae6b-9ec4-469e-8e16-fcbf0b940936',
|
||||||
|
date: new Date('2026-02-21'),
|
||||||
|
aircraftMakeModel: 'Cessna 172M',
|
||||||
|
aircraftIdentity: 'N12345',
|
||||||
|
routeFrom: 'KMSP',
|
||||||
|
routeTo: 'KMSP',
|
||||||
|
durationOfFlight: 1,
|
||||||
|
singleEngineLand: 1,
|
||||||
|
simulatorAtd: null,
|
||||||
|
landingsDay: 1,
|
||||||
|
landingsNight: null,
|
||||||
|
groundTrainingReceived: null,
|
||||||
|
flightTrainingReceived: null,
|
||||||
|
crossCountry: 1,
|
||||||
|
night: null,
|
||||||
|
solo: 1,
|
||||||
|
pilotInCommand: 1,
|
||||||
|
instrumentActual: null,
|
||||||
|
instrumentSimulated: null,
|
||||||
|
instrumentApproaches: null,
|
||||||
|
instrumentHolds: null,
|
||||||
|
instrumentNavTrack: null,
|
||||||
|
notes: 'This is a test',
|
||||||
|
tracks: []
|
||||||
|
} as LogEntity;
|
||||||
|
|
||||||
|
jest.spyOn(mockLogRepository, 'findOneBy').mockReturnValue(log);
|
||||||
|
jest.spyOn(mockLogRepository, 'save').mockReturnValue(logDto);
|
||||||
|
|
||||||
|
const result = await service.update(id, logDto);
|
||||||
|
|
||||||
|
expect(result).toEqual(logDto);
|
||||||
|
expect(mockLogRepository.findOneBy).toHaveBeenCalled();
|
||||||
|
expect(mockLogRepository.findOneBy).toHaveBeenCalledWith({ id: id });
|
||||||
|
expect(mockLogRepository.save).toHaveBeenCalled();
|
||||||
|
expect(mockLogRepository.save).toHaveBeenCalledWith(logDto);
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -3,10 +3,10 @@ import { InjectRepository } from '@nestjs/typeorm';
|
|||||||
import { LogEntity } from './log.entity';
|
import { LogEntity } from './log.entity';
|
||||||
import { DeleteResult, InsertResult, Repository, UpdateResult } from 'typeorm';
|
import { DeleteResult, InsertResult, Repository, UpdateResult } from 'typeorm';
|
||||||
import { LogDto } from './log.dto';
|
import { LogDto } from './log.dto';
|
||||||
import { PilotService } from 'src/pilot/pilot.service';
|
import { PilotService } from '../pilot/pilot.service';
|
||||||
import { PilotEntity } from 'src/pilot/pilot.entity';
|
import { PilotEntity } from '../pilot/pilot.entity';
|
||||||
import { CustomError } from 'src/error/customError';
|
import { CustomError } from '../error/customError';
|
||||||
import { FileService } from 'src/file/file.service';
|
import { FileService } from '../file/file.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class LogService {
|
export class LogService {
|
||||||
@@ -31,32 +31,17 @@ export class LogService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async create(logDto: LogDto): Promise<InsertResult> {
|
async create(logDto: LogDto): Promise<LogDto> {
|
||||||
try{
|
return this.logRepository.save(logDto);
|
||||||
const pilotEntity: PilotEntity = await this.pilotService.find(logDto.pilotId);
|
|
||||||
|
|
||||||
if (pilotEntity) {
|
|
||||||
const { pilotId, ...newLogDto } = logDto;
|
|
||||||
const log = this.logRepository.create({
|
|
||||||
...newLogDto,
|
|
||||||
pilot: pilotEntity
|
|
||||||
})
|
|
||||||
|
|
||||||
return this.logRepository.insert(log);
|
|
||||||
} else {
|
|
||||||
throw new CustomError('Pilot not found', 'Not found', 404);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async update(id: string, logDto: LogDto): Promise<UpdateResult> {
|
async update(id: string, logDto: LogDto): Promise<LogDto> {
|
||||||
const log = logDto
|
const logEntity: LogEntity = await this.logRepository.findOneBy({ id });
|
||||||
|
const logEntityUpdated = Object.assign(logEntity, logDto)
|
||||||
|
|
||||||
delete log.tracks;
|
delete logEntityUpdated.tracks;
|
||||||
|
|
||||||
return await this.logRepository.update(id, log);
|
return await this.logRepository.save(logEntityUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
async delete(id: string): Promise<DeleteResult> {
|
async delete(id: string): Promise<DeleteResult> {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { PilotEntity } from 'src/pilot/pilot.entity';
|
import { PilotEntity } from '../pilot/pilot.entity';
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';
|
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';
|
||||||
|
|
||||||
@Entity({ name: 'medical' })
|
@Entity({ name: 'medical' })
|
||||||
|
|||||||
260
api/src/pilot/pilot.controller.spec.ts
Normal file
260
api/src/pilot/pilot.controller.spec.ts
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { PilotController } from "./pilot.controller";
|
||||||
|
import { PilotService } from './pilot.service';
|
||||||
|
import { PilotDto } from './pilot.dto';
|
||||||
|
import { PilotEntity } from './pilot.entity';
|
||||||
|
import { CustomError } from '../error/customError';
|
||||||
|
import { HttpException } from '@nestjs/common';
|
||||||
|
|
||||||
|
describe('PilotController', () => {
|
||||||
|
let controller: PilotController;
|
||||||
|
|
||||||
|
const mockPilotService = {
|
||||||
|
create: jest.fn(),
|
||||||
|
delete: jest.fn(),
|
||||||
|
find: jest.fn(),
|
||||||
|
findAll: jest.fn(),
|
||||||
|
update: jest.fn(),
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
controllers: [PilotController],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: PilotService,
|
||||||
|
useValue: mockPilotService
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
controller = module.get<PilotController>(PilotController);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(controller).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('find => should find a pilot by id', async () => {
|
||||||
|
const id: string = '39465ae3-7947-4cc2-b565-ca00a982fdd8'
|
||||||
|
const pilot = {
|
||||||
|
id: '39465ae3-7947-4cc2-b565-ca00a982fdd8',
|
||||||
|
name: 'Test pilot',
|
||||||
|
address: '123 Any Street',
|
||||||
|
city: 'Any Town',
|
||||||
|
state: 'Minnesota',
|
||||||
|
postalCode: '55123',
|
||||||
|
email: 'user@example.com',
|
||||||
|
phone: '555-555-1234',
|
||||||
|
userId: 'user@example.com',
|
||||||
|
logs: [],
|
||||||
|
certificates: [],
|
||||||
|
endorsements: [],
|
||||||
|
medical: []
|
||||||
|
} as PilotEntity;
|
||||||
|
|
||||||
|
jest.spyOn(mockPilotService, 'find').mockReturnValue(pilot);
|
||||||
|
|
||||||
|
const result = await controller.find(id);
|
||||||
|
|
||||||
|
expect(result).toEqual(pilot);
|
||||||
|
expect(mockPilotService.find).toHaveBeenCalled();
|
||||||
|
expect(mockPilotService.find).toHaveBeenCalledWith(id)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
it('find => should fail to find a pilot by id', async () => {
|
||||||
|
const id: string = '39465ae3-7947-4cc2-b565-ca00a982fdd8'
|
||||||
|
|
||||||
|
jest.spyOn(mockPilotService, 'find').mockRejectedValue(new Error('Pilot not found'));
|
||||||
|
|
||||||
|
try {
|
||||||
|
await controller.find(id);
|
||||||
|
|
||||||
|
fail('find did not throw error')
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toBeInstanceOf(Error)
|
||||||
|
expect(mockPilotService.find).toHaveBeenCalled();
|
||||||
|
expect(mockPilotService.find).toHaveBeenCalledWith(id);
|
||||||
|
expect(mockPilotService.find).rejects.toThrow('Pilot not found')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('findAll => should find all pilots', async () => {
|
||||||
|
const pilot = {
|
||||||
|
id: '39465ae3-7947-4cc2-b565-ca00a982fdd8',
|
||||||
|
name: 'Test pilot',
|
||||||
|
address: '123 Any Street',
|
||||||
|
city: 'Any Town',
|
||||||
|
state: 'Minnesota',
|
||||||
|
postalCode: '55123',
|
||||||
|
email: 'user@example.com',
|
||||||
|
phone: '555-555-1234',
|
||||||
|
userId: 'user@example.com',
|
||||||
|
logs: [],
|
||||||
|
certificates: [],
|
||||||
|
endorsements: [],
|
||||||
|
medical: []
|
||||||
|
} as PilotEntity;
|
||||||
|
const pilots = [pilot];
|
||||||
|
|
||||||
|
jest.spyOn(mockPilotService, 'findAll').mockReturnValue(pilots);
|
||||||
|
|
||||||
|
const result = await controller.findAll();
|
||||||
|
|
||||||
|
expect(result).toEqual(pilots);
|
||||||
|
expect(mockPilotService.findAll).toHaveBeenCalled();
|
||||||
|
})
|
||||||
|
|
||||||
|
it('findAll => should fail to find all pilots', async () => {
|
||||||
|
jest.spyOn(mockPilotService, 'findAll').mockRejectedValue(new Error('Pilots not found'));
|
||||||
|
|
||||||
|
try {
|
||||||
|
await controller.findAll();
|
||||||
|
|
||||||
|
fail('findAll did not throw error')
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toBeInstanceOf(Error)
|
||||||
|
expect(mockPilotService.findAll).toHaveBeenCalled();
|
||||||
|
expect(mockPilotService.findAll).rejects.toThrow('Pilots not found')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('create => should create a new pilot', async () => {
|
||||||
|
const pilotDto = {
|
||||||
|
name: 'Test pilot',
|
||||||
|
address: '123 Any Street',
|
||||||
|
city: 'Any Town',
|
||||||
|
state: 'Minnesota',
|
||||||
|
postalCode: '55123',
|
||||||
|
email: 'user@example.com',
|
||||||
|
phone: '555-555-1234'
|
||||||
|
} as PilotDto
|
||||||
|
|
||||||
|
const pilot = {
|
||||||
|
id: '39465ae3-7947-4cc2-b565-ca00a982fdd8',
|
||||||
|
name: 'Test pilot',
|
||||||
|
address: '123 Any Street',
|
||||||
|
city: 'Any Town',
|
||||||
|
state: 'Minnesota',
|
||||||
|
postalCode: '55123',
|
||||||
|
email: 'user@example.com',
|
||||||
|
phone: '555-555-1234',
|
||||||
|
userId: 'user@example.com',
|
||||||
|
logs: [],
|
||||||
|
certificates: [],
|
||||||
|
endorsements: [],
|
||||||
|
medical: []
|
||||||
|
} as PilotEntity
|
||||||
|
|
||||||
|
jest.spyOn(mockPilotService, 'create').mockReturnValue(pilot);
|
||||||
|
|
||||||
|
const result = await controller.create(pilotDto);
|
||||||
|
|
||||||
|
expect(mockPilotService.create).toHaveBeenCalled();
|
||||||
|
expect(mockPilotService.create).toHaveBeenCalledWith(pilotDto)
|
||||||
|
expect(result).toEqual(pilot);
|
||||||
|
})
|
||||||
|
|
||||||
|
it('create => should fail to create a new pilot', async () => {
|
||||||
|
const pilotDto = {
|
||||||
|
name: 'Test pilot',
|
||||||
|
address: '123 Any Street',
|
||||||
|
city: 'Any Town',
|
||||||
|
state: 'Minnesota',
|
||||||
|
postalCode: '55123',
|
||||||
|
email: 'user@example.com',
|
||||||
|
phone: '555-555-1234'
|
||||||
|
} as PilotDto
|
||||||
|
|
||||||
|
jest.spyOn(mockPilotService, 'create').mockRejectedValue(new Error('Pilot failed to create'));
|
||||||
|
|
||||||
|
try {
|
||||||
|
await controller.create(pilotDto);
|
||||||
|
|
||||||
|
fail('create did not throw error')
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toBeInstanceOf(Error)
|
||||||
|
expect(mockPilotService.create).toHaveBeenCalled();
|
||||||
|
expect(mockPilotService.create).toHaveBeenCalledWith(pilotDto);
|
||||||
|
expect(mockPilotService.create).rejects.toThrow('Pilot failed to create')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('update => should update an existing pilot', async () => {
|
||||||
|
const id: string = '39465ae3-7947-4cc2-b565-ca00a982fdd8'
|
||||||
|
const pilotDto = {
|
||||||
|
id: '39465ae3-7947-4cc2-b565-ca00a982fdd8',
|
||||||
|
name: 'Test pilot',
|
||||||
|
address: '123 Any Street',
|
||||||
|
city: 'Any Town',
|
||||||
|
state: 'Minnesota',
|
||||||
|
postalCode: '55123',
|
||||||
|
email: 'user@example.com',
|
||||||
|
phone: '555-555-1234'
|
||||||
|
} as PilotDto
|
||||||
|
|
||||||
|
jest.spyOn(mockPilotService, 'update').mockReturnValue(pilotDto);
|
||||||
|
|
||||||
|
const result = await controller.update(id, pilotDto);
|
||||||
|
|
||||||
|
expect(result).toEqual(pilotDto);
|
||||||
|
expect(mockPilotService.update).toHaveBeenCalled();
|
||||||
|
expect(mockPilotService.update).toHaveBeenCalledWith(id, pilotDto)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('update => should fail to update an existing pilot', async () => {
|
||||||
|
const id: string = '39465ae3-7947-4cc2-b565-ca00a982fdd8'
|
||||||
|
const pilotDto = {
|
||||||
|
id: '39465ae3-7947-4cc2-b565-ca00a982fdd8',
|
||||||
|
name: 'Test pilot',
|
||||||
|
address: '123 Any Street',
|
||||||
|
city: 'Any Town',
|
||||||
|
state: 'Minnesota',
|
||||||
|
postalCode: '55123',
|
||||||
|
email: 'user@example.com',
|
||||||
|
phone: '555-555-1234'
|
||||||
|
} as PilotDto
|
||||||
|
|
||||||
|
jest.spyOn(mockPilotService, 'update').mockRejectedValue(new Error('Pilot failed to update'))
|
||||||
|
|
||||||
|
try {
|
||||||
|
await controller.update(id, pilotDto);
|
||||||
|
|
||||||
|
fail('update function did not throw error')
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toBeInstanceOf(Error)
|
||||||
|
expect(mockPilotService.update).toHaveBeenCalled();
|
||||||
|
expect(mockPilotService.update).toHaveBeenCalledWith(id, pilotDto);
|
||||||
|
expect(mockPilotService.update).rejects.toThrow('Pilot failed to update')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('delete => should delete an existing pilot', async () => {
|
||||||
|
const id = '39465ae3-7947-4cc2-b565-ca00a982fdd8';
|
||||||
|
|
||||||
|
jest.spyOn(mockPilotService, 'delete');
|
||||||
|
|
||||||
|
const result = await controller.delete(id);
|
||||||
|
|
||||||
|
expect(mockPilotService.delete).toHaveBeenCalled();
|
||||||
|
expect(mockPilotService.delete).toHaveBeenCalledWith(id);
|
||||||
|
})
|
||||||
|
|
||||||
|
it('delete => should fail to delete an existing pilot', async () => {
|
||||||
|
const id = '39465ae3-7947-4cc2-b565-ca00a982fdd8';
|
||||||
|
|
||||||
|
jest.spyOn(mockPilotService, 'delete').mockRejectedValue(new Error('Pilot failed to delete'));
|
||||||
|
|
||||||
|
try {
|
||||||
|
await controller.delete(id);
|
||||||
|
|
||||||
|
fail('delete function did not throw error')
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toBeInstanceOf(Error)
|
||||||
|
expect(mockPilotService.delete).toHaveBeenCalled();
|
||||||
|
expect(mockPilotService.delete).toHaveBeenCalledWith(id);
|
||||||
|
expect(mockPilotService.delete).rejects.toThrow('Pilot failed to delete')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -50,9 +50,8 @@ export class PilotController {
|
|||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
@UseGuards(AuthGuard)
|
@UseGuards(AuthGuard)
|
||||||
async create(@Body() pilotDto: PilotDto) {
|
async create(@Body() pilotDto: PilotDto): Promise<PilotDto> {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
return await this.pilotService.create(pilotDto);
|
return await this.pilotService.create(pilotDto);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const customError = error as CustomError;
|
const customError = error as CustomError;
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { LogEntity } from "src/log/log.entity";
|
|
||||||
|
|
||||||
export class PilotDto {
|
export class PilotDto {
|
||||||
name: string;
|
name: string;
|
||||||
address: string;
|
address: string;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { LogEntity } from 'src/log/log.entity';
|
import { LogEntity } from '../log/log.entity';
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';
|
import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';
|
||||||
import { CertificateEntity } from '../certificate/certificate.entity';
|
import { CertificateEntity } from '../certificate/certificate.entity';
|
||||||
import { EndorsementEntity } from 'src/endorsement/endorsement.entity';
|
import { EndorsementEntity } from '../endorsement/endorsement.entity';
|
||||||
import { MedicalEntity } from 'src/medical/medical.entity';
|
import { MedicalEntity } from '../medical/medical.entity';
|
||||||
|
|
||||||
@Entity({ name: 'pilots' })
|
@Entity({ name: 'pilots' })
|
||||||
export class PilotEntity {
|
export class PilotEntity {
|
||||||
|
|||||||
206
api/src/pilot/pilot.service.spec.ts
Normal file
206
api/src/pilot/pilot.service.spec.ts
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { PilotService } from './pilot.service';
|
||||||
|
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||||
|
import { PilotEntity } from './pilot.entity';
|
||||||
|
import { PilotDto } from './pilot.dto';
|
||||||
|
import { CustomError } from '../error/customError';
|
||||||
|
|
||||||
|
describe('PilotService', () => {
|
||||||
|
let service: PilotService;
|
||||||
|
|
||||||
|
const mockPilotRepository = {
|
||||||
|
delete: jest.fn(),
|
||||||
|
find: jest.fn(),
|
||||||
|
findOneBy: jest.fn(),
|
||||||
|
save: jest.fn(),
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
providers: [
|
||||||
|
PilotService,
|
||||||
|
{
|
||||||
|
provide: getRepositoryToken(PilotEntity),
|
||||||
|
useValue: mockPilotRepository
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
service = module.get<PilotService>(PilotService);
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(service).toBeDefined();
|
||||||
|
})
|
||||||
|
|
||||||
|
it('find => should find one pilot by id', async () => {
|
||||||
|
const id: string = '39465ae3-7947-4cc2-b565-ca00a982fdd8'
|
||||||
|
const pilot = {
|
||||||
|
id: '39465ae3-7947-4cc2-b565-ca00a982fdd8',
|
||||||
|
name: 'Test pilot',
|
||||||
|
address: '123 Any Street',
|
||||||
|
city: 'Any Town',
|
||||||
|
state: 'Minnesota',
|
||||||
|
postalCode: '55123',
|
||||||
|
email: 'user@example.com',
|
||||||
|
phone: '555-555-1234',
|
||||||
|
userId: 'user@example.com',
|
||||||
|
logs: [],
|
||||||
|
certificates: [],
|
||||||
|
endorsements: [],
|
||||||
|
medical: []
|
||||||
|
} as PilotEntity;
|
||||||
|
|
||||||
|
jest.spyOn(mockPilotRepository, 'findOneBy').mockReturnValue(pilot);
|
||||||
|
|
||||||
|
const result = await service.find(id);
|
||||||
|
|
||||||
|
expect(result).toEqual(pilot);
|
||||||
|
expect(mockPilotRepository.findOneBy).toHaveBeenCalled();
|
||||||
|
expect(mockPilotRepository.findOneBy).toHaveBeenCalledWith({ id: id });
|
||||||
|
})
|
||||||
|
|
||||||
|
it('find => should fail to find one pilot by id', async () => {
|
||||||
|
const id: string = '39465ae3-7947-4cc2-b565-ca00a982fdd8';
|
||||||
|
const mockCustomError = new CustomError('Pilot not found', 'Not found', 404)
|
||||||
|
|
||||||
|
jest.spyOn(mockPilotRepository, 'findOneBy').mockReturnValue(undefined);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await service.find(id);
|
||||||
|
|
||||||
|
fail('find did not throw error')
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toBeInstanceOf(CustomError);
|
||||||
|
expect(mockPilotRepository.findOneBy).toHaveBeenCalled();
|
||||||
|
expect(mockPilotRepository.findOneBy).toHaveBeenCalledWith({ id: id });
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('findAll => should find all pilots', async () => {
|
||||||
|
const pilot = {
|
||||||
|
id: '39465ae3-7947-4cc2-b565-ca00a982fdd8',
|
||||||
|
name: 'Test pilot',
|
||||||
|
address: '123 Any Street',
|
||||||
|
city: 'Any Town',
|
||||||
|
state: 'Minnesota',
|
||||||
|
postalCode: '55123',
|
||||||
|
email: 'user@example.com',
|
||||||
|
phone: '555-555-1234',
|
||||||
|
userId: 'user@example.com',
|
||||||
|
logs: [],
|
||||||
|
certificates: [],
|
||||||
|
endorsements: [],
|
||||||
|
medical: []
|
||||||
|
} as PilotEntity;
|
||||||
|
const pilots = [pilot];
|
||||||
|
|
||||||
|
jest.spyOn(mockPilotRepository, 'find').mockReturnValue(pilots);
|
||||||
|
|
||||||
|
const result = await service.findAll();
|
||||||
|
|
||||||
|
expect(result).toEqual(pilots);
|
||||||
|
expect(mockPilotRepository.find).toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('create => should create a new pilot', async () => {
|
||||||
|
const pilotDto = {
|
||||||
|
name: 'Test pilot',
|
||||||
|
address: '123 Any Street',
|
||||||
|
city: 'Any Town',
|
||||||
|
state: 'Minnesota',
|
||||||
|
postalCode: '55123',
|
||||||
|
email: 'user@example.com',
|
||||||
|
phone: '555-555-1234'
|
||||||
|
} as PilotDto
|
||||||
|
|
||||||
|
const pilot = {
|
||||||
|
id: '39465ae3-7947-4cc2-b565-ca00a982fdd8',
|
||||||
|
name: 'Test pilot',
|
||||||
|
address: '123 Any Street',
|
||||||
|
city: 'Any Town',
|
||||||
|
state: 'Minnesota',
|
||||||
|
postalCode: '55123',
|
||||||
|
email: 'user@example.com',
|
||||||
|
phone: '555-555-1234',
|
||||||
|
userId: 'user@example.com',
|
||||||
|
logs: [],
|
||||||
|
certificates: [],
|
||||||
|
endorsements: [],
|
||||||
|
medical: []
|
||||||
|
} as PilotEntity
|
||||||
|
|
||||||
|
jest.spyOn(mockPilotRepository, 'save').mockReturnValue(pilot);
|
||||||
|
|
||||||
|
const result = await service.create(pilotDto);
|
||||||
|
|
||||||
|
expect(mockPilotRepository.save).toHaveBeenCalled();
|
||||||
|
expect(mockPilotRepository.save).toHaveBeenCalledWith(pilotDto);
|
||||||
|
})
|
||||||
|
|
||||||
|
it('update => should update a pilot', async () => {
|
||||||
|
const id: string = '39465ae3-7947-4cc2-b565-ca00a982fdd8'
|
||||||
|
const pilotDto = {
|
||||||
|
name: 'Test pilot',
|
||||||
|
address: '123 Any Street',
|
||||||
|
city: 'Any Town',
|
||||||
|
state: 'Minnesota',
|
||||||
|
postalCode: '55123',
|
||||||
|
email: 'user@example.com',
|
||||||
|
phone: '555-555-1234'
|
||||||
|
} as PilotDto
|
||||||
|
const pilot = {
|
||||||
|
id: '39465ae3-7947-4cc2-b565-ca00a982fdd8',
|
||||||
|
name: 'Test pilot',
|
||||||
|
address: '123 Any Street',
|
||||||
|
city: 'Any Town',
|
||||||
|
state: 'Minnesota',
|
||||||
|
postalCode: '55123',
|
||||||
|
email: 'user@example.com',
|
||||||
|
phone: '555-555-1234',
|
||||||
|
userId: 'user@example.com',
|
||||||
|
logs: [],
|
||||||
|
certificates: [],
|
||||||
|
endorsements: [],
|
||||||
|
medical: []
|
||||||
|
} as PilotEntity
|
||||||
|
|
||||||
|
jest.spyOn(mockPilotRepository, 'findOneBy').mockReturnValue(pilot)
|
||||||
|
jest.spyOn(mockPilotRepository, 'save').mockReturnValue(pilotDto);
|
||||||
|
|
||||||
|
const result = await service.update(id, pilotDto)
|
||||||
|
|
||||||
|
expect(result).toEqual(pilotDto);
|
||||||
|
expect(mockPilotRepository.findOneBy).toHaveBeenCalled();
|
||||||
|
expect(mockPilotRepository.findOneBy).toHaveBeenCalledWith({ id: id });
|
||||||
|
expect(mockPilotRepository.save).toHaveBeenCalled();
|
||||||
|
expect(mockPilotRepository.save).toHaveBeenCalledWith(pilotDto)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('delete => should delete a pilot', async () => {
|
||||||
|
const id: string = '39465ae3-7947-4cc2-b565-ca00a982fdd8'
|
||||||
|
const pilot = {
|
||||||
|
id: '39465ae3-7947-4cc2-b565-ca00a982fdd8',
|
||||||
|
name: 'Test pilot',
|
||||||
|
address: '123 Any Street',
|
||||||
|
city: 'Any Town',
|
||||||
|
state: 'Minnesota',
|
||||||
|
postalCode: '55123',
|
||||||
|
email: 'user@example.com',
|
||||||
|
phone: '555-555-1234',
|
||||||
|
userId: 'user@example.com',
|
||||||
|
logs: [],
|
||||||
|
certificates: [],
|
||||||
|
endorsements: [],
|
||||||
|
medical: []
|
||||||
|
} as PilotEntity
|
||||||
|
|
||||||
|
jest.spyOn(mockPilotRepository, 'delete').mockReturnValue(pilot);
|
||||||
|
|
||||||
|
const result = await service.delete(id);
|
||||||
|
|
||||||
|
expect(result).toEqual(pilot);
|
||||||
|
expect(mockPilotRepository.delete).toHaveBeenCalled();
|
||||||
|
expect(mockPilotRepository.delete).toHaveBeenCalledWith({ id: id });
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -3,7 +3,7 @@ import { PilotEntity } from './pilot.entity';
|
|||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { DeleteResult, InsertResult, Repository, UpdateResult } from 'typeorm';
|
import { DeleteResult, InsertResult, Repository, UpdateResult } from 'typeorm';
|
||||||
import { PilotDto } from './pilot.dto';
|
import { PilotDto } from './pilot.dto';
|
||||||
import { CustomError } from 'src/error/customError';
|
import { CustomError } from '../error/customError';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PilotService {
|
export class PilotService {
|
||||||
@@ -13,7 +13,7 @@ export class PilotService {
|
|||||||
|
|
||||||
async find(id: string): Promise<PilotEntity> {
|
async find(id: string): Promise<PilotEntity> {
|
||||||
try {
|
try {
|
||||||
const pilotEntity = await this.pilotRepository.findOneBy({ id });
|
const pilotEntity: PilotEntity = await this.pilotRepository.findOneBy({ id });
|
||||||
|
|
||||||
if (pilotEntity) {
|
if (pilotEntity) {
|
||||||
return pilotEntity
|
return pilotEntity
|
||||||
@@ -29,15 +29,18 @@ export class PilotService {
|
|||||||
return await this.pilotRepository.find();
|
return await this.pilotRepository.find();
|
||||||
}
|
}
|
||||||
|
|
||||||
async create(pilot: PilotDto): Promise<InsertResult> {
|
async create(pilot: PilotDto): Promise<PilotDto> {
|
||||||
return await this.pilotRepository.insert(pilot);
|
return await this.pilotRepository.save(pilot);
|
||||||
}
|
}
|
||||||
|
|
||||||
async update(
|
async update(
|
||||||
id: string,
|
id: string,
|
||||||
pilot: PilotDto
|
pilotDto: PilotDto
|
||||||
): Promise<UpdateResult> {
|
): Promise<PilotDto> {
|
||||||
return await this.pilotRepository.update(id, pilot);
|
const pilotEntity: PilotEntity = await this.pilotRepository.findOneBy({ id })
|
||||||
|
const pilotEntityUpdated = Object.assign(pilotEntity, pilotDto)
|
||||||
|
|
||||||
|
return await this.pilotRepository.save(pilotEntityUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
async delete(id: string): Promise<DeleteResult> {
|
async delete(id: string): Promise<DeleteResult> {
|
||||||
|
|||||||
218
api/src/track/track.controller.spec.ts
Normal file
218
api/src/track/track.controller.spec.ts
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { TrackController } from './track.controller';
|
||||||
|
import { TrackService } from './track.service';
|
||||||
|
import { TrackDto } from './track.dto';
|
||||||
|
import { TrackEntity } from './track.entity';
|
||||||
|
import { FileService } from '../file/file.service';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
import { HttpException } from '@nestjs/common';
|
||||||
|
import { Readable } from 'stream';
|
||||||
|
import { DeleteResult, InsertResult } from 'typeorm';
|
||||||
|
|
||||||
|
describe('TrackController', () => {
|
||||||
|
let controller: TrackController;
|
||||||
|
|
||||||
|
const mockTrackService = {
|
||||||
|
create: jest.fn(),
|
||||||
|
delete: jest.fn(),
|
||||||
|
downloadTrackFile: jest.fn(),
|
||||||
|
find: jest.fn(),
|
||||||
|
findAll: jest.fn(),
|
||||||
|
update: jest.fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
controllers: [TrackController],
|
||||||
|
providers: [
|
||||||
|
ConfigService,
|
||||||
|
FileService,
|
||||||
|
{
|
||||||
|
provide: TrackService,
|
||||||
|
useValue: mockTrackService
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
controller = module.get<TrackController>(TrackController);
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(controller).toBeDefined();
|
||||||
|
})
|
||||||
|
|
||||||
|
it('findAll => should find all tracks by log id', async () => {
|
||||||
|
const logId = '094ec69c-72c4-4995-8821-79d5b79bedda';
|
||||||
|
const track = {
|
||||||
|
id: 'a6973d91-629f-4e10-aa28-016076a21fde',
|
||||||
|
url: 'http://track.example.com',
|
||||||
|
order: 1
|
||||||
|
} as TrackEntity
|
||||||
|
const tracks = [track]
|
||||||
|
|
||||||
|
jest.spyOn(mockTrackService, 'findAll').mockReturnValue(tracks);
|
||||||
|
|
||||||
|
const result = await controller.findAll(logId);
|
||||||
|
|
||||||
|
expect(result).toEqual(tracks);
|
||||||
|
expect(mockTrackService.findAll).toHaveBeenCalled();
|
||||||
|
expect(mockTrackService.findAll).toHaveBeenLastCalledWith(logId);
|
||||||
|
})
|
||||||
|
|
||||||
|
it('findAll => should fail to find all tracks by log id', async () => {
|
||||||
|
const logId = '094ec69c-72c4-4995-8821-79d5b79bedda';
|
||||||
|
|
||||||
|
jest.spyOn(mockTrackService, 'findAll').mockRejectedValue(new Error('Tracks not found'))
|
||||||
|
|
||||||
|
try {
|
||||||
|
await controller.findAll(logId);
|
||||||
|
|
||||||
|
fail('findAll did not throw error');
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toBeInstanceOf(HttpException);
|
||||||
|
expect(mockTrackService.findAll).toHaveBeenCalled();
|
||||||
|
expect(mockTrackService.findAll).rejects.toThrow('Tracks not found')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('create => create a track by a log id', async () => {
|
||||||
|
const logId = '094ec69c-72c4-4995-8821-79d5b79bedda';
|
||||||
|
const order = 1;
|
||||||
|
const file: Express.Multer.File = {
|
||||||
|
fieldname: 'file',
|
||||||
|
originalname: 'test_track.kml',
|
||||||
|
encoding: 'utf-8',
|
||||||
|
mimetype: 'application/vnd.google-earth.kml+xml',
|
||||||
|
size: 12345,
|
||||||
|
destination: '/tmp/uploads',
|
||||||
|
filename: 'unique-filename-123.kml',
|
||||||
|
path: '/tmp/uploads/unique-filename-123.kml',
|
||||||
|
buffer: Buffer.from('<kml xmlns="http://www.opengis.net"></kml>'),
|
||||||
|
stream: new Readable()
|
||||||
|
}
|
||||||
|
const mockInsertResult: InsertResult = {
|
||||||
|
identifiers: [
|
||||||
|
{
|
||||||
|
id: 'a6973d91-629f-4e10-aa28-016076a21fde'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
generatedMaps: [
|
||||||
|
{
|
||||||
|
id: 'a6973d91-629f-4e10-aa28-016076a21fde',
|
||||||
|
createdAd: new Date()
|
||||||
|
}
|
||||||
|
],
|
||||||
|
raw: {
|
||||||
|
affectedRows: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jest.spyOn(mockTrackService, 'create').mockReturnValue(mockInsertResult);
|
||||||
|
|
||||||
|
const result = await controller.create(logId, order, file);
|
||||||
|
|
||||||
|
expect(result).toEqual(mockInsertResult);
|
||||||
|
expect(mockTrackService.create).toHaveBeenCalled();
|
||||||
|
expect(mockTrackService.create).toHaveBeenCalledWith(logId, order, file)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('create => should fail to create a track by log id', async () => {
|
||||||
|
const logId = '094ec69c-72c4-4995-8821-79d5b79bedda';
|
||||||
|
const order = 1;
|
||||||
|
const file: Express.Multer.File = {
|
||||||
|
fieldname: 'file',
|
||||||
|
originalname: 'test_track.kml',
|
||||||
|
encoding: 'utf-8',
|
||||||
|
mimetype: 'application/vnd.google-earth.kml+xml',
|
||||||
|
size: 12345,
|
||||||
|
destination: '/tmp/uploads',
|
||||||
|
filename: 'unique-filename-123.kml',
|
||||||
|
path: '/tmp/uploads/unique-filename-123.kml',
|
||||||
|
buffer: Buffer.from('<kml xmlns="http://www.opengis.net"></kml>'),
|
||||||
|
stream: new Readable()
|
||||||
|
}
|
||||||
|
|
||||||
|
jest.spyOn(mockTrackService, 'create').mockRejectedValue(new Error('Track failed to create'))
|
||||||
|
|
||||||
|
try {
|
||||||
|
await controller.create(logId, order, file)
|
||||||
|
|
||||||
|
fail('create did not throw error')
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toBeInstanceOf(HttpException);
|
||||||
|
expect(mockTrackService.create).toHaveBeenCalled();
|
||||||
|
expect(mockTrackService.create).toHaveBeenCalledWith(logId, order, file);
|
||||||
|
expect(mockTrackService.create).rejects.toThrow('Track failed to create')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('delete => should delete a track by log id', async () => {
|
||||||
|
const id = 'a6973d91-629f-4e10-aa28-016076a21fde'
|
||||||
|
const logId: string = '95834f84-0a02-44d3-884e-a20237adeca0';
|
||||||
|
const fileName = 'test_track.kml';
|
||||||
|
const mockDeleteResult: DeleteResult ={
|
||||||
|
raw: [],
|
||||||
|
affected: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
jest.spyOn(mockTrackService, 'delete').mockReturnValue(mockDeleteResult);
|
||||||
|
|
||||||
|
const result = await controller.delete(id, fileName, logId);
|
||||||
|
|
||||||
|
expect(result).toEqual(mockDeleteResult);
|
||||||
|
expect(mockTrackService.delete).toHaveBeenCalled();
|
||||||
|
expect(mockTrackService.delete).toHaveBeenCalledWith(id, logId, fileName);
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
it('delete => should fail to delete a track by log id', async () => {
|
||||||
|
const id = 'a6973d91-629f-4e10-aa28-016076a21fde'
|
||||||
|
const logId: string = '95834f84-0a02-44d3-884e-a20237adeca0';
|
||||||
|
const fileName = 'test_track.kml';
|
||||||
|
|
||||||
|
jest.spyOn(mockTrackService, 'delete').mockRejectedValue(new Error('Track failed to delete'));
|
||||||
|
|
||||||
|
try {
|
||||||
|
await controller.delete(id, fileName, logId);
|
||||||
|
|
||||||
|
fail('delete did not throw error')
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toBeInstanceOf(HttpException);
|
||||||
|
expect(mockTrackService.delete).toHaveBeenCalled();
|
||||||
|
expect(mockTrackService.delete).toHaveBeenCalledWith(id, logId, fileName);
|
||||||
|
expect(mockTrackService.delete).rejects.toThrow('Track failed to delete')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('downloadTrack => should download a track by log id', async () => {
|
||||||
|
const logId: string = '95834f84-0a02-44d3-884e-a20237adeca0';
|
||||||
|
const fileName = 'test_track.kml';
|
||||||
|
const mockStreamToBufferString = 'fake-stream-to-buffer-string'
|
||||||
|
|
||||||
|
jest.spyOn(mockTrackService, 'downloadTrackFile').mockReturnValue(mockStreamToBufferString);
|
||||||
|
|
||||||
|
const result = await controller.downloadTrack(logId, fileName);
|
||||||
|
|
||||||
|
expect(result).toEqual(mockStreamToBufferString);
|
||||||
|
expect(mockTrackService.downloadTrackFile).toHaveBeenCalled();
|
||||||
|
expect(mockTrackService.downloadTrackFile).toHaveBeenCalledWith(logId, fileName)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('downloadTrack => should fail to download a track by log id', async () => {
|
||||||
|
const logId: string = '95834f84-0a02-44d3-884e-a20237adeca0';
|
||||||
|
const fileName = 'test_track.kml';
|
||||||
|
|
||||||
|
jest.spyOn(mockTrackService, 'downloadTrackFile').mockRejectedValue(new Error('Track failed to download'));
|
||||||
|
|
||||||
|
try {
|
||||||
|
await controller.downloadTrack(logId, fileName);
|
||||||
|
|
||||||
|
fail('downloadTrack did not throw error')
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toBeInstanceOf(HttpException);
|
||||||
|
expect(mockTrackService.downloadTrackFile).toHaveBeenCalled();
|
||||||
|
expect(mockTrackService.downloadTrackFile).toHaveBeenCalledWith(logId, fileName);
|
||||||
|
expect(mockTrackService.downloadTrackFile).rejects.toThrow('Track failed to download')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { LogEntity } from 'src/log/log.entity';
|
import { LogEntity } from '../log/log.entity';
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';
|
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';
|
||||||
|
|
||||||
@Entity({ name: 'tracks' })
|
@Entity({ name: 'tracks' })
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { TrackEntity } from "./track.entity";
|
|||||||
import { TrackController } from "./track.controller";
|
import { TrackController } from "./track.controller";
|
||||||
import { FileService } from "../file/file.service";
|
import { FileService } from "../file/file.service";
|
||||||
import { TrackService } from './track.service';
|
import { TrackService } from './track.service';
|
||||||
import { LogModule } from 'src/log/log.module';
|
import { LogModule } from '../log/log.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
|
|||||||
346
api/src/track/track.service.spec.ts
Normal file
346
api/src/track/track.service.spec.ts
Normal file
@@ -0,0 +1,346 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { TrackService } from './track.service';
|
||||||
|
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||||
|
import { TrackEntity } from './track.entity'
|
||||||
|
import { TrackDto } from './track.dto';
|
||||||
|
import { FileService } from '../file/file.service';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
import { LogService } from '../log/log.service';
|
||||||
|
import { LogEntity } from '../log/log.entity';
|
||||||
|
import { PilotService } from '../pilot/pilot.service';
|
||||||
|
import { PilotEntity } from '../pilot/pilot.entity';
|
||||||
|
import { Readable } from 'stream';
|
||||||
|
import { DeleteResult, InsertResult, UpdateResult } from 'typeorm';
|
||||||
|
import { CustomError } from '../error/customError';
|
||||||
|
|
||||||
|
describe('TrackService', () => {
|
||||||
|
let service: TrackService;
|
||||||
|
|
||||||
|
const mockFileService = {
|
||||||
|
deleteFile: jest.fn(),
|
||||||
|
downloadFile: jest.fn(),
|
||||||
|
uploadFile: jest.fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
const mockLogService = {
|
||||||
|
create: jest.fn(),
|
||||||
|
delete: jest.fn(),
|
||||||
|
find: jest.fn(),
|
||||||
|
findAll: jest.fn(),
|
||||||
|
update: jest.fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
const mockPilotRepository = {
|
||||||
|
create: jest.fn(),
|
||||||
|
delete: jest.fn(),
|
||||||
|
find: jest.fn(),
|
||||||
|
findAll: jest.fn(),
|
||||||
|
update: jest.fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
const mockTrackRepository = {
|
||||||
|
create: jest.fn(),
|
||||||
|
delete: jest.fn(),
|
||||||
|
downloadTrackFile: jest.fn(),
|
||||||
|
findOneBy: jest.fn(),
|
||||||
|
find: jest.fn(),
|
||||||
|
insert: jest.fn(),
|
||||||
|
update: jest.fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
providers: [
|
||||||
|
ConfigService,
|
||||||
|
LogService,
|
||||||
|
PilotService,
|
||||||
|
TrackService,
|
||||||
|
{
|
||||||
|
provide: FileService,
|
||||||
|
useValue: mockFileService
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: LogService,
|
||||||
|
useValue: mockLogService
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: getRepositoryToken(PilotEntity),
|
||||||
|
useValue: mockPilotRepository
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: getRepositoryToken(TrackEntity),
|
||||||
|
useValue: mockTrackRepository
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}).compile()
|
||||||
|
|
||||||
|
service = module.get<TrackService>(TrackService);
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(service).toBeDefined();
|
||||||
|
})
|
||||||
|
|
||||||
|
it('create => should upload a track file', async () => {
|
||||||
|
const logId = '094ec69c-72c4-4995-8821-79d5b79bedda';
|
||||||
|
const log = {
|
||||||
|
id: '094ec69c-72c4-4995-8821-79d5b79bedda',
|
||||||
|
pilotId: '7c4bae6b-9ec4-469e-8e16-fcbf0b940936',
|
||||||
|
date: new Date('2026-02-21'),
|
||||||
|
aircraftMakeModel: 'Cessna 172M',
|
||||||
|
aircraftIdentity: 'N12345',
|
||||||
|
routeFrom: 'KMSP',
|
||||||
|
routeTo: 'KMSP',
|
||||||
|
durationOfFlight: 1,
|
||||||
|
singleEngineLand: 1,
|
||||||
|
simulatorAtd: null,
|
||||||
|
landingsDay: 1,
|
||||||
|
landingsNight: null,
|
||||||
|
groundTrainingReceived: null,
|
||||||
|
flightTrainingReceived: null,
|
||||||
|
crossCountry: 1,
|
||||||
|
night: null,
|
||||||
|
solo: 1,
|
||||||
|
pilotInCommand: 1,
|
||||||
|
instrumentActual: null,
|
||||||
|
instrumentSimulated: null,
|
||||||
|
instrumentApproaches: null,
|
||||||
|
instrumentHolds: null,
|
||||||
|
instrumentNavTrack: null,
|
||||||
|
notes: 'This is a test',
|
||||||
|
tracks: []
|
||||||
|
} as LogEntity;
|
||||||
|
const order = 1;
|
||||||
|
const file: Express.Multer.File = {
|
||||||
|
fieldname: 'file',
|
||||||
|
originalname: 'test_track.kml',
|
||||||
|
encoding: 'utf-8',
|
||||||
|
mimetype: 'application/vnd.google-earth.kml+xml',
|
||||||
|
size: 12345,
|
||||||
|
destination: '/tmp/uploads',
|
||||||
|
filename: 'unique-filename-123.kml',
|
||||||
|
path: '/tmp/uploads/unique-filename-123.kml',
|
||||||
|
buffer: Buffer.from('<kml xmlns="http://www.opengis.net"></kml>'),
|
||||||
|
stream: new Readable()
|
||||||
|
}
|
||||||
|
const mockInsertResult: InsertResult = {
|
||||||
|
identifiers: [
|
||||||
|
{
|
||||||
|
id: 'a6973d91-629f-4e10-aa28-016076a21fde'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
generatedMaps: [
|
||||||
|
{
|
||||||
|
id: 'a6973d91-629f-4e10-aa28-016076a21fde',
|
||||||
|
createdAd: new Date()
|
||||||
|
}
|
||||||
|
],
|
||||||
|
raw: {
|
||||||
|
affectedRows: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const track = {
|
||||||
|
id: 'a6973d91-629f-4e10-aa28-016076a21fde',
|
||||||
|
url: 'http://track.example.com',
|
||||||
|
order: 1
|
||||||
|
} as TrackEntity
|
||||||
|
|
||||||
|
jest.spyOn(mockLogService, 'find').mockReturnValue(log)
|
||||||
|
jest.spyOn(mockTrackRepository, 'create').mockReturnValue(track)
|
||||||
|
jest.spyOn(mockTrackRepository, 'insert').mockReturnValue(mockInsertResult);
|
||||||
|
|
||||||
|
const result = await service.create(logId, order, file);
|
||||||
|
|
||||||
|
expect(result).toEqual(mockInsertResult)
|
||||||
|
expect(mockTrackRepository.insert).toHaveBeenCalled();
|
||||||
|
expect(mockTrackRepository.insert).toHaveBeenCalledWith({
|
||||||
|
id: track.id,
|
||||||
|
order: track.order,
|
||||||
|
url: track.url
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('create => should fail to find log', async () => {
|
||||||
|
const logId = '094ec69c-72c4-4995-8821-79d5b79bedda';
|
||||||
|
const order = 1;
|
||||||
|
const file: Express.Multer.File = {
|
||||||
|
fieldname: 'file',
|
||||||
|
originalname: 'test_track.kml',
|
||||||
|
encoding: 'utf-8',
|
||||||
|
mimetype: 'application/vnd.google-earth.kml+xml',
|
||||||
|
size: 12345,
|
||||||
|
destination: '/tmp/uploads',
|
||||||
|
filename: 'unique-filename-123.kml',
|
||||||
|
path: '/tmp/uploads/unique-filename-123.kml',
|
||||||
|
buffer: Buffer.from('<kml xmlns="http://www.opengis.net"></kml>'),
|
||||||
|
stream: new Readable()
|
||||||
|
}
|
||||||
|
|
||||||
|
jest.spyOn(mockLogService, 'find').mockReturnValue(undefined);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await service.create(logId, order, file);
|
||||||
|
|
||||||
|
fail('find failed to throw error')
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toBeInstanceOf(CustomError);
|
||||||
|
expect(mockLogService.find).toHaveBeenCalled();
|
||||||
|
expect(mockLogService.find).toHaveBeenCalledWith(logId);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('delete => should delete a track file', async () => {
|
||||||
|
const id = 'a6973d91-629f-4e10-aa28-016076a21fde';
|
||||||
|
const logId = '094ec69c-72c4-4995-8821-79d5b79bedda';
|
||||||
|
const fileName = 'test_track.kml'
|
||||||
|
const mockDeleteResult: DeleteResult ={
|
||||||
|
raw: [],
|
||||||
|
affected: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
jest.spyOn(mockTrackRepository, 'delete').mockReturnValue(mockDeleteResult);
|
||||||
|
|
||||||
|
const result = await service.delete(id, logId, fileName)
|
||||||
|
|
||||||
|
expect(result).toEqual(mockDeleteResult);
|
||||||
|
expect(mockTrackRepository.delete).toHaveBeenCalled();
|
||||||
|
expect(mockTrackRepository.delete).toHaveBeenCalledWith({ id: id })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('delete => should fail to delete file in file service', async () => {
|
||||||
|
const id = 'a6973d91-629f-4e10-aa28-016076a21fde';
|
||||||
|
const logId = '094ec69c-72c4-4995-8821-79d5b79bedda';
|
||||||
|
const fileName = 'test_track.kml'
|
||||||
|
|
||||||
|
jest.spyOn(mockFileService, 'deleteFile').mockRejectedValue(new Error('Failed to delete file'))
|
||||||
|
|
||||||
|
try {
|
||||||
|
await service.delete(id, logId, fileName)
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toBeInstanceOf(Error);
|
||||||
|
expect(mockFileService.deleteFile).toHaveBeenCalled();
|
||||||
|
expect(mockFileService.deleteFile).toHaveBeenCalledWith('tracks', logId, fileName)
|
||||||
|
expect(mockFileService.deleteFile).rejects.toThrow('Failed to delete file')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('downloadTrackFile => should download a track file by log id and filename', async () => {
|
||||||
|
const logId: string = '95834f84-0a02-44d3-884e-a20237adeca0';
|
||||||
|
const fileName = 'test_track.kml';
|
||||||
|
const mockStreamToBufferString = 'fake-stream-to-buffer-string'
|
||||||
|
|
||||||
|
jest.spyOn(mockFileService, 'downloadFile').mockReturnValue(mockStreamToBufferString);
|
||||||
|
|
||||||
|
const result = await service.downloadTrackFile(logId, fileName);
|
||||||
|
|
||||||
|
expect(result).toEqual(mockStreamToBufferString);
|
||||||
|
expect(mockFileService.downloadFile).toHaveBeenCalled();
|
||||||
|
expect(mockFileService.downloadFile).toHaveBeenCalledWith('tracks', logId, fileName);
|
||||||
|
})
|
||||||
|
|
||||||
|
it('find => should find a track file by id', async () => {
|
||||||
|
const id = 'a6973d91-629f-4e10-aa28-016076a21fde';
|
||||||
|
const track = {
|
||||||
|
id: 'a6973d91-629f-4e10-aa28-016076a21fde',
|
||||||
|
url: 'http://track.example.com',
|
||||||
|
order: 1
|
||||||
|
} as TrackEntity
|
||||||
|
|
||||||
|
jest.spyOn(mockTrackRepository, 'findOneBy').mockReturnValue(track)
|
||||||
|
|
||||||
|
const result = await service.find(id);
|
||||||
|
|
||||||
|
expect(result).toEqual(track);
|
||||||
|
expect(mockTrackRepository.findOneBy).toHaveBeenCalled();
|
||||||
|
expect(mockTrackRepository.findOneBy).toHaveBeenCalledWith({ id: id })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('findAll => should find all track files by log id', async () => {
|
||||||
|
const logId = '094ec69c-72c4-4995-8821-79d5b79bedda';
|
||||||
|
const log = {
|
||||||
|
id: '094ec69c-72c4-4995-8821-79d5b79bedda',
|
||||||
|
pilotId: '7c4bae6b-9ec4-469e-8e16-fcbf0b940936',
|
||||||
|
date: new Date('2026-02-21'),
|
||||||
|
aircraftMakeModel: 'Cessna 172M',
|
||||||
|
aircraftIdentity: 'N12345',
|
||||||
|
routeFrom: 'KMSP',
|
||||||
|
routeTo: 'KMSP',
|
||||||
|
durationOfFlight: 1,
|
||||||
|
singleEngineLand: 1,
|
||||||
|
simulatorAtd: null,
|
||||||
|
landingsDay: 1,
|
||||||
|
landingsNight: null,
|
||||||
|
groundTrainingReceived: null,
|
||||||
|
flightTrainingReceived: null,
|
||||||
|
crossCountry: 1,
|
||||||
|
night: null,
|
||||||
|
solo: 1,
|
||||||
|
pilotInCommand: 1,
|
||||||
|
instrumentActual: null,
|
||||||
|
instrumentSimulated: null,
|
||||||
|
instrumentApproaches: null,
|
||||||
|
instrumentHolds: null,
|
||||||
|
instrumentNavTrack: null,
|
||||||
|
notes: 'This is a test',
|
||||||
|
tracks: []
|
||||||
|
} as LogEntity;
|
||||||
|
const track = {
|
||||||
|
id: 'a6973d91-629f-4e10-aa28-016076a21fde',
|
||||||
|
url: 'http://track.example.com',
|
||||||
|
order: 1
|
||||||
|
} as TrackEntity;
|
||||||
|
const tracks = [track]
|
||||||
|
|
||||||
|
jest.spyOn(mockLogService, 'find').mockReturnValue(log)
|
||||||
|
jest.spyOn(mockTrackRepository, 'find').mockReturnValue(tracks);
|
||||||
|
|
||||||
|
const result = await service.findAll(logId);
|
||||||
|
|
||||||
|
expect(result).toEqual(tracks);
|
||||||
|
expect(mockTrackRepository.find).toHaveBeenCalled();
|
||||||
|
expect(mockTrackRepository.find).toHaveBeenCalledWith(
|
||||||
|
{
|
||||||
|
where: {
|
||||||
|
log: {
|
||||||
|
id: logId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('findAll => should fail to find log', async () => {
|
||||||
|
const logId = '094ec69c-72c4-4995-8821-79d5b79bedda';
|
||||||
|
|
||||||
|
jest.spyOn(mockLogService, 'find').mockReturnValue(undefined);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await service.findAll(logId);
|
||||||
|
|
||||||
|
fail('find failed to throw error')
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toBeInstanceOf(CustomError);
|
||||||
|
expect(mockLogService.find).toHaveBeenCalled();
|
||||||
|
expect(mockLogService.find).toHaveBeenCalledWith(logId);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('update => should update a track', async () => {
|
||||||
|
const id = 'a6973d91-629f-4e10-aa28-016076a21fde';
|
||||||
|
const track = {
|
||||||
|
|
||||||
|
} as TrackDto;
|
||||||
|
const mockUpdateResult: UpdateResult = {
|
||||||
|
affected: 1,
|
||||||
|
raw: [],
|
||||||
|
generatedMaps: []
|
||||||
|
}
|
||||||
|
|
||||||
|
jest.spyOn(mockTrackRepository, 'update').mockReturnValue(mockUpdateResult)
|
||||||
|
|
||||||
|
const result = await service.update(id, track);
|
||||||
|
|
||||||
|
expect(result).toEqual(mockUpdateResult);
|
||||||
|
expect(mockTrackRepository.update).toHaveBeenCalled();
|
||||||
|
expect(mockTrackRepository.update).toHaveBeenCalledWith(id, track)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -3,10 +3,10 @@ import { TrackDto } from "./track.dto";
|
|||||||
import { TrackEntity } from "./track.entity";
|
import { TrackEntity } from "./track.entity";
|
||||||
import { InjectRepository } from "@nestjs/typeorm";
|
import { InjectRepository } from "@nestjs/typeorm";
|
||||||
import { Injectable } from "@nestjs/common";
|
import { Injectable } from "@nestjs/common";
|
||||||
import { LogService } from "src/log/log.service";
|
import { LogService } from "../log/log.service";
|
||||||
import { LogEntity } from "src/log/log.entity";
|
import { LogEntity } from "../log/log.entity";
|
||||||
import { CustomError } from "src/error/customError";
|
import { CustomError } from "../error/customError";
|
||||||
import { FileService } from "src/file/file.service";
|
import { FileService } from "../file/file.service";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TrackService {
|
export class TrackService {
|
||||||
@@ -19,11 +19,7 @@ export class TrackService {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
async find(id: string): Promise<TrackEntity> {
|
async find(id: string): Promise<TrackEntity> {
|
||||||
try {
|
|
||||||
return await this.trackRepository.findOneBy({ id });
|
return await this.trackRepository.findOneBy({ id });
|
||||||
} catch (error) {
|
|
||||||
throw new CustomError('Track not found', 'Not found', 404)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async findAll(logId: string): Promise<TrackEntity[]> {
|
async findAll(logId: string): Promise<TrackEntity[]> {
|
||||||
@@ -40,10 +36,11 @@ export class TrackService {
|
|||||||
})
|
})
|
||||||
|
|
||||||
return tracks;
|
return tracks;
|
||||||
|
} else {
|
||||||
|
throw new CustomError('Tracks not found', 'Not found', 404);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
throw error
|
||||||
throw new CustomError('Tracks not found', 'Not found', 404);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,21 +66,11 @@ export class TrackService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async update(id: string, track: TrackDto): Promise<UpdateResult> {
|
async update(id: string, track: TrackDto): Promise<UpdateResult> {
|
||||||
try {
|
|
||||||
return await this.trackRepository.update(id, track);
|
return await this.trackRepository.update(id, track);
|
||||||
} catch(error) {
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async downloadTrackFile(logId: string, fileName: string): Promise<string> {
|
async downloadTrackFile(logId: string, fileName: string): Promise<string> {
|
||||||
try {
|
return await this.fileService.downloadFile(this.containerName, logId, fileName);
|
||||||
const downloadedFile: string = await this.fileService.downloadFile(this.containerName, logId, fileName);
|
|
||||||
|
|
||||||
return downloadedFile;
|
|
||||||
} catch (error) {
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async delete(id: string, logId: string, fileName: string): Promise<DeleteResult> {
|
async delete(id: string, logId: string, fileName: string): Promise<DeleteResult> {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "client",
|
"name": "client",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "2.0.0-beta-4",
|
"version": "2.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -3,11 +3,13 @@ import { useEffect, useReducer } from "react";
|
|||||||
import { useLogs } from "../../hooks/logs/UseLogs";
|
import { useLogs } from "../../hooks/logs/UseLogs";
|
||||||
import { LogbookEntry } from "../logbook/LogbookEntry.interface";
|
import { LogbookEntry } from "../logbook/LogbookEntry.interface";
|
||||||
import { initialState, reducer } from "./reducer";
|
import { initialState, reducer } from "./reducer";
|
||||||
|
import { useOidc } from "../../auth/oidcConfig";
|
||||||
import Alert from "../alert/Alert";
|
import Alert from "../alert/Alert";
|
||||||
|
|
||||||
const Flights = () => {
|
const Flights = () => {
|
||||||
const [state, dispatch] = useReducer(reducer, initialState);
|
const [state, dispatch] = useReducer(reducer, initialState);
|
||||||
const { logs, logsLoading } = useLogs();
|
const { logs, logsLoading } = useLogs();
|
||||||
|
const { isUserLoggedIn } = useOidc();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
@@ -19,7 +21,12 @@ const Flights = () => {
|
|||||||
|
|
||||||
if (flights && flights.length > 0) {
|
if (flights && flights.length > 0) {
|
||||||
dispatch({ type: 'SET_FLIGHTS', payload: flights})
|
dispatch({ type: 'SET_FLIGHTS', payload: flights})
|
||||||
|
|
||||||
|
if (!isUserLoggedIn && flights.length >= 5) {
|
||||||
|
dispatch({ type: 'SET_ALERT', payload: { severity: 'info', message: 'A limited number of flights displayed. Sign in to view all flights.'}})
|
||||||
|
} else {
|
||||||
dispatch({ type: 'SET_ALERT', payload: undefined })
|
dispatch({ type: 'SET_ALERT', payload: undefined })
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
dispatch({ type: 'SET_ALERT', payload: { severity: 'info', message: 'No flights found' }})
|
dispatch({ type: 'SET_ALERT', payload: { severity: 'info', message: 'No flights found' }})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ const LogForm = () => {
|
|||||||
`api/logs/${logbookContext.state.selectedLogId}`
|
`api/logs/${logbookContext.state.selectedLogId}`
|
||||||
);
|
);
|
||||||
const log = response.data;
|
const log = response.data;
|
||||||
console.log(log)
|
|
||||||
reset(log);
|
reset(log);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const axiosError = error as AxiosError;
|
const axiosError = error as AxiosError;
|
||||||
@@ -53,11 +53,16 @@ const LogForm = () => {
|
|||||||
if (pilots && FormMode.ADD) {
|
if (pilots && FormMode.ADD) {
|
||||||
const newPilotsOptions = pilots.map((pilot) => {
|
const newPilotsOptions = pilots.map((pilot) => {
|
||||||
return {
|
return {
|
||||||
key: pilot.id,
|
|
||||||
label: pilot.name,
|
label: pilot.name,
|
||||||
|
value: pilot.id,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
newPilotsOptions.unshift({
|
||||||
|
label: '',
|
||||||
|
value: '',
|
||||||
|
})
|
||||||
|
|
||||||
dispatch({ type: 'SET_PILOT_OPTIONS', payload: newPilotsOptions });
|
dispatch({ type: 'SET_PILOT_OPTIONS', payload: newPilotsOptions });
|
||||||
}
|
}
|
||||||
}, [pilots]);
|
}, [pilots]);
|
||||||
@@ -80,9 +85,9 @@ const LogForm = () => {
|
|||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
value={[value]}
|
value={[value]}
|
||||||
>
|
>
|
||||||
{state.pilotOptions?.map((pilotOption: { key: string; label: string, }) => {
|
{state.pilotOptions?.map((pilotOption: { label: string, value: string; }) => {
|
||||||
return (
|
return (
|
||||||
<option key={pilotOption.key}>{pilotOption.label}</option>
|
<option value={pilotOption.value}>{pilotOption.label}</option>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</select>
|
</select>
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ export interface LogFormState {
|
|||||||
alert: Alert | undefined;
|
alert: Alert | undefined;
|
||||||
isDisabled: boolean;
|
isDisabled: boolean;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
pilotOptions: { key: string; label: string; }[];
|
pilotOptions: { label: string; value: string; }[];
|
||||||
selectedPilotName: string;
|
selectedPilotName: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ type Action =
|
|||||||
| { type: 'SET_ALERT'; payload: Alert | undefined }
|
| { type: 'SET_ALERT'; payload: Alert | undefined }
|
||||||
| { type: 'SET_IS_DISABLED'; payload: boolean }
|
| { type: 'SET_IS_DISABLED'; payload: boolean }
|
||||||
| { type: 'SET_IS_LOADING'; payload: boolean }
|
| { type: 'SET_IS_LOADING'; payload: boolean }
|
||||||
| { type: 'SET_PILOT_OPTIONS'; payload: { key: string, label: string; }[] }
|
| { type: 'SET_PILOT_OPTIONS'; payload: { label: string; value: string }[] }
|
||||||
| { type: 'SET_SELECTED_PILOT_NAME'; payload: string };
|
| { type: 'SET_SELECTED_PILOT_NAME'; payload: string };
|
||||||
|
|
||||||
export const initialState: LogFormState = {
|
export const initialState: LogFormState = {
|
||||||
|
|||||||
@@ -377,7 +377,9 @@ const Logbook: React.FC<unknown> = () => {
|
|||||||
setColumnVisibility(columnVisibility)
|
setColumnVisibility(columnVisibility)
|
||||||
dispatch({ type: 'SET_ENTRIES', payload: entries });
|
dispatch({ type: 'SET_ENTRIES', payload: entries });
|
||||||
|
|
||||||
if (state.alert) {
|
if (!isUserLoggedIn && response.data.length >= 5) {
|
||||||
|
dispatch({ type: 'SET_ALERT', payload: { severity: 'info', message: 'A limited number of log entries displayed. Sign in to view all log entries.'}})
|
||||||
|
} else {
|
||||||
dispatch({ type: 'SET_ALERT', payload: undefined})
|
dispatch({ type: 'SET_ALERT', payload: undefined})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Binary file not shown.
@@ -60,7 +60,7 @@ resource "azurerm_container_app" "container_app" {
|
|||||||
|
|
||||||
container {
|
container {
|
||||||
cpu = 0.25
|
cpu = 0.25
|
||||||
image = "noahspan/flying:20588458616"
|
image = "noahspan/flying:20589367895"
|
||||||
memory = "0.5Gi"
|
memory = "0.5Gi"
|
||||||
name = "flying"
|
name = "flying"
|
||||||
|
|
||||||
@@ -99,6 +99,11 @@ resource "azurerm_container_app" "container_app" {
|
|||||||
value = var.JWKS_URI
|
value = var.JWKS_URI
|
||||||
}
|
}
|
||||||
|
|
||||||
|
env {
|
||||||
|
name = "NODE_ENV"
|
||||||
|
value = "test"
|
||||||
|
}
|
||||||
|
|
||||||
env {
|
env {
|
||||||
name = "SESSION_SECRET"
|
name = "SESSION_SECRET"
|
||||||
secret_name = "session-secret"
|
secret_name = "session-secret"
|
||||||
@@ -116,13 +121,13 @@ resource "azurerm_container_app" "container_app" {
|
|||||||
|
|
||||||
env {
|
env {
|
||||||
name = "DB_SYNC"
|
name = "DB_SYNC"
|
||||||
value = "false"
|
value = "true"
|
||||||
}
|
}
|
||||||
|
|
||||||
startup_probe {
|
startup_probe {
|
||||||
failure_count_threshold = 10
|
failure_count_threshold = 3
|
||||||
initial_delay = 1
|
initial_delay = 15
|
||||||
interval_seconds = 2
|
interval_seconds = 30
|
||||||
path = "/api/health"
|
path = "/api/health"
|
||||||
port = 3000
|
port = 3000
|
||||||
transport = "HTTP"
|
transport = "HTTP"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@noahspan/flying",
|
"name": "@noahspan/flying",
|
||||||
"version": "2.0.0-beta-4",
|
"version": "2.0.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node api/dist/main",
|
"start": "node api/dist/main",
|
||||||
"format": "prettier --write \"**/src/**/*.ts\" \"**/test/**/*.ts\"",
|
"format": "prettier --write \"**/src/**/*.ts\" \"**/test/**/*.ts\"",
|
||||||
|
|||||||
Reference in New Issue
Block a user