tests(@nestjs) push basic integration tests

This commit is contained in:
Kamil Myśliwiec
2018-03-17 15:01:17 +01:00
parent 43da706a61
commit a18e4c69ee
44 changed files with 1453 additions and 1 deletions

1
.gitignore vendored
View File

@@ -24,7 +24,6 @@ yarn-error.log
# tests
/test
/integration
/coverage
/.nyc_output
build/config\.gypi

View File

@@ -0,0 +1,18 @@
version: "3"
services:
redis:
container_name: redis_integration
image: redis
ports:
- "6379:6379"
restart: always
nats:
container_name: nats_integration
image: nats
expose:
- "4222"
ports:
- "8222:8222"
- "4222:4222"
restart: always

21
integration/hello-world/.gitignore vendored Normal file
View File

@@ -0,0 +1,21 @@
# dependencies
/node_modules
# IDE
/.idea
/.awcache
/.vscode
# misc
npm-debug.log
# example
/quick-start
# tests
/test
/coverage
/.nyc_output
# dist
/dist

View File

@@ -0,0 +1,56 @@
import { expect } from 'chai';
import * as fastify from 'fastify';
import * as request from 'supertest';
import * as express from 'express';
import { Test } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import { ApplicationModule } from './../src/app.module';
import { FastifyAdapter } from '@nestjs/core/adapters/fastify-adapter';
import { ExpressAdapter } from '@nestjs/core/adapters/express-adapter';
import { HelloService } from '../src/hello/hello.service';
describe('Hello world (fastify adapter)', () => {
let server;
let app: INestApplication;
beforeEach(async () => {
const module = await Test.createTestingModule({
imports: [ApplicationModule],
}).compile();
server = fastify();
app = module.createNestApplication(new FastifyAdapter(server));
await app.init();
});
it(`/GET`, () => {
return server
.inject({
method: 'GET',
url: '/hello',
})
.then(({ payload }) => expect(payload).to.be.eql('Hello world!'));
});
it(`/GET (Promise/async)`, () => {
return server
.inject({
method: 'GET',
url: '/hello/async',
})
.then(({ payload }) => expect(payload).to.be.eql('Hello world!'));
});
it(`/GET (Observable stream)`, () => {
return server
.inject({
method: 'GET',
url: '/hello/stream',
})
.then(({ payload }) => expect(payload).to.be.eql('Hello world!'));
});
afterEach(async () => {
await app.close();
});
});

View File

@@ -0,0 +1,60 @@
import * as request from 'supertest';
import { Test } from '@nestjs/testing';
import { INestApplication, Injectable, UnauthorizedException } from '@nestjs/common';
import { ApplicationModule } from './../src/app.module';
import { APP_GUARD } from '@nestjs/core';
@Injectable()
export class Guard {
canActivate() {
return false;
}
}
@Injectable()
export class AuthGuard {
canActivate() {
const x = true;
if (x) {
throw new UnauthorizedException();
}
}
}
function createTestModule(guard) {
return Test.createTestingModule({
imports: [ApplicationModule],
providers: [
{
provide: APP_GUARD,
useValue: guard,
},
],
}).compile();
}
describe('Guards', () => {
let app: INestApplication;
it(`should prevent access (forbidden)`, async () => {
app = (await createTestModule(
new Guard(),
)).createNestApplication();
await app.init();
return request(app.getHttpServer())
.get('/hello')
.expect(403);
});
it(`should prevent access (unauthorized)`, async () => {
app = (await createTestModule(
new AuthGuard(),
)).createNestApplication();
await app.init();
return request(app.getHttpServer())
.get('/hello')
.expect(401);
});
});

View File

@@ -0,0 +1,45 @@
import * as request from 'supertest';
import { Test } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import { ApplicationModule } from './../src/app.module';
describe('Hello world (default adapter)', () => {
let server;
let app: INestApplication;
beforeEach(async () => {
const module = await Test.createTestingModule({
imports: [ApplicationModule],
})
.compile();
app = module.createNestApplication();
server = app.getHttpServer();
await app.init();
});
it(`/GET`, () => {
return request(server)
.get('/hello')
.expect(200)
.expect('Hello world!');
});
it(`/GET (Promise/async)`, () => {
return request(server)
.get('/hello/async')
.expect(200)
.expect('Hello world!');
});
it(`/GET (Observable stream)`, () => {
return request(server)
.get('/hello/stream')
.expect(200)
.expect('Hello world!');
});
afterEach(async () => {
await app.close();
});
});

View File

@@ -0,0 +1,87 @@
import * as request from 'supertest';
import { Test } from '@nestjs/testing';
import { INestApplication, Injectable } from '@nestjs/common';
import { ApplicationModule } from './../src/app.module';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { of } from 'rxjs/observable/of';
import { map } from 'rxjs/operators';
const RETURN_VALUE = 'test';
@Injectable()
export class OverrideInterceptor {
intercept(data, context, stream) {
return of(RETURN_VALUE);
}
}
@Injectable()
export class TransformInterceptor {
intercept(data, context, stream) {
return stream.pipe(map(data => ({ data })));
}
}
function createTestModule(interceptor) {
return Test.createTestingModule({
imports: [ApplicationModule],
providers: [
{
provide: APP_INTERCEPTOR,
useValue: interceptor,
},
],
}).compile();
}
describe('Interceptors', () => {
let app: INestApplication;
it(`should transform response (sync)`, async () => {
app = (await createTestModule(
new OverrideInterceptor(),
)).createNestApplication();
await app.init();
return request(app.getHttpServer())
.get('/hello')
.expect(200, RETURN_VALUE);
});
it(`should map response`, async () => {
app = (await createTestModule(
new TransformInterceptor(),
)).createNestApplication();
await app.init();
return request(app.getHttpServer())
.get('/hello')
.expect(200, { data: 'Hello world!' });
});
it(`should map response (async)`, async () => {
app = (await createTestModule(
new TransformInterceptor(),
)).createNestApplication();
await app.init();
return request(app.getHttpServer())
.get('/hello/stream')
.expect(200, { data: 'Hello world!' });
});
it(`should map response (stream)`, async () => {
app = (await createTestModule(
new TransformInterceptor(),
)).createNestApplication();
await app.init();
return request(app.getHttpServer())
.get('/hello/async')
.expect(200, { data: 'Hello world!' });
});
afterEach(async () => {
await app.close();
});
});

View File

@@ -0,0 +1,28 @@
{
"name": "nest-typescript-starter",
"version": "1.0.0",
"description": "Nest TypeScript starter repository",
"license": "MIT",
"scripts": {
"start": "ts-node src/main"
},
"dependencies": {
"@nestjs/common": "^4.3.0",
"@nestjs/core": "^4.3.0",
"@nestjs/microservices": "^4.3.0",
"@nestjs/testing": "^4.3.0",
"@nestjs/websockets": "^4.3.0",
"class-transformer": "^0.1.7",
"class-validator": "^0.7.2",
"fastify": "^1.1.1",
"redis": "^2.7.1",
"reflect-metadata": "^0.1.10",
"rxjs": "^5.4.3",
"typescript": "^2.4.2"
},
"devDependencies": {
"@types/node": "^7.0.41",
"supertest": "^3.0.0",
"ts-node": "^3.3.0"
}
}

View File

@@ -0,0 +1,7 @@
import { Module } from '@nestjs/common';
import { HelloModule } from './hello/hello.module';
@Module({
imports: [HelloModule],
})
export class ApplicationModule {}

View File

@@ -0,0 +1,10 @@
import { IsString, IsNotEmpty, IsNumber } from 'class-validator';
export class TestDto {
@IsString()
@IsNotEmpty()
string: string;
@IsNumber()
number: number;
}

View File

@@ -0,0 +1,24 @@
import { HelloService } from './hello.service';
import { Controller, Get, Post, Body } from '@nestjs/common';
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
@Controller('hello')
export class HelloController {
constructor(private readonly helloService: HelloService) {}
@Get()
greeting(): string {
return this.helloService.greeting();
}
@Get('async')
async asyncGreeting(): Promise<string> {
return await this.helloService.greeting();
}
@Get('stream')
streamGreeting(): Observable<string> {
return of(this.helloService.greeting());
}
}

View File

@@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { HelloController } from './hello.controller';
import { HelloService } from './hello.service';
@Module({
controllers: [HelloController],
providers: [HelloService],
})
export class HelloModule {}

View File

@@ -0,0 +1,8 @@
import { Injectable } from '@nestjs/common';
@Injectable()
export class HelloService {
greeting(): string {
return 'Hello world!';
}
}

View File

@@ -0,0 +1,22 @@
{
"compilerOptions": {
"module": "commonjs",
"declaration": false,
"noImplicitAny": false,
"removeComments": true,
"noLib": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es6",
"sourceMap": true,
"allowJs": true,
"outDir": "./dist"
},
"include": [
"src/**/*",
"e2e/**/*"
],
"exclude": [
"node_modules",
]
}

View File

@@ -0,0 +1,53 @@
{
"defaultSeverity": "error",
"extends": [
"tslint:recommended"
],
"jsRules": {
"no-unused-expression": true
},
"rules": {
"eofline": false,
"quotemark": [
true,
"single"
],
"ordered-imports": [
false
],
"max-line-length": [
150
],
"member-ordering": [
false
],
"curly": false,
"interface-name": [
false
],
"array-type": [
false
],
"member-access": [
false
],
"no-empty-interface": false,
"no-empty": false,
"arrow-parens": false,
"object-literal-sort-keys": false,
"no-unused-expression": false,
"max-classes-per-file": [
false
],
"variable-name": [
false
],
"one-line": [
false
],
"one-variable-per-declaration": [
false
]
},
"rulesDirectory": []
}

21
integration/injector/.gitignore vendored Normal file
View File

@@ -0,0 +1,21 @@
# dependencies
/node_modules
# IDE
/.idea
/.awcache
/.vscode
# misc
npm-debug.log
# example
/quick-start
# tests
/test
/coverage
/.nyc_output
# dist
/dist

View File

@@ -0,0 +1,37 @@
import { expect } from 'chai';
import { Test, TestingModuleBuilder } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import { ExportsModule } from '../src/exports/exports.module';
import { TestingModule } from '@nestjs/testing/testing-module';
import { UnknownExportException } from '@nestjs/core/errors/exceptions/unknown-export.exception';
import { UndefinedDependencyException } from '@nestjs/core/errors/exceptions/undefined-dependency.exception';
import { InjectModule } from '../src/inject/inject.module';
import { RuntimeException } from '@nestjs/core/errors/exceptions/runtime.exception';
describe('Injector', () => {
describe('when "providers" and "exports" properties are inconsistent', () => {
it(`should fail with "UnknownExportException"`, async () => {
try {
const builder = Test.createTestingModule({
imports: [ExportsModule],
});
await builder.compile();
} catch (err) {
expect(err).to.be.instanceof(UnknownExportException);
}
});
});
describe('when Nest cannot resolve dependencies', () => {
it(`should fail with "RuntimeException"`, async () => {
try {
const builder = Test.createTestingModule({
imports: [InjectModule],
});
await builder.compile();
} catch (err) {
expect(err).to.be.instanceof(RuntimeException);
}
});
});
});

View File

@@ -0,0 +1,27 @@
{
"name": "nest-typescript-starter",
"version": "1.0.0",
"description": "Nest TypeScript starter repository",
"license": "MIT",
"scripts": {
"start": "ts-node src/main"
},
"dependencies": {
"@nestjs/common": "^4.3.0",
"@nestjs/core": "^4.3.0",
"@nestjs/microservices": "^4.3.0",
"@nestjs/testing": "^4.3.0",
"@nestjs/websockets": "^4.3.0",
"class-transformer": "^0.1.7",
"class-validator": "^0.7.2",
"redis": "^2.7.1",
"reflect-metadata": "^0.1.10",
"rxjs": "^5.4.3",
"typescript": "^2.4.2"
},
"devDependencies": {
"@types/node": "^7.0.41",
"supertest": "^3.0.0",
"ts-node": "^3.3.0"
}
}

View File

@@ -0,0 +1,7 @@
import { Module } from '@nestjs/common';
import { ExportsModule } from './exports/exports.module';
@Module({
imports: [ExportsModule],
})
export class ApplicationModule {}

View File

@@ -0,0 +1,7 @@
import { Module } from '@nestjs/common';
import { ExportsService } from './exports.service';
@Module({
exports: [ExportsService],
})
export class ExportsModule {}

View File

@@ -0,0 +1,4 @@
import { Injectable } from '@nestjs/common';
@Injectable()
export class ExportsService {}

View File

@@ -0,0 +1,4 @@
import { Injectable } from '@nestjs/common';
@Injectable()
export class CoreService {}

View File

@@ -0,0 +1,7 @@
import { Module } from '@nestjs/common';
import { InjectService } from './inject.service';
@Module({
providers: [InjectService],
})
export class InjectModule {}

View File

@@ -0,0 +1,7 @@
import { Injectable } from '@nestjs/common';
import { CoreService } from './core.service';
@Injectable()
export class InjectService {
constructor(private readonly coreService: CoreService) {}
}

View File

@@ -0,0 +1,22 @@
{
"compilerOptions": {
"module": "commonjs",
"declaration": false,
"noImplicitAny": false,
"removeComments": true,
"noLib": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es6",
"sourceMap": true,
"allowJs": true,
"outDir": "./dist"
},
"include": [
"src/**/*",
"e2e/**/*"
],
"exclude": [
"node_modules",
]
}

View File

@@ -0,0 +1,53 @@
{
"defaultSeverity": "error",
"extends": [
"tslint:recommended"
],
"jsRules": {
"no-unused-expression": true
},
"rules": {
"eofline": false,
"quotemark": [
true,
"single"
],
"ordered-imports": [
false
],
"max-line-length": [
150
],
"member-ordering": [
false
],
"curly": false,
"interface-name": [
false
],
"array-type": [
false
],
"member-access": [
false
],
"no-empty-interface": false,
"no-empty": false,
"arrow-parens": false,
"object-literal-sort-keys": false,
"no-unused-expression": false,
"max-classes-per-file": [
false
],
"variable-name": [
false
],
"one-line": [
false
],
"one-variable-per-declaration": [
false
]
},
"rulesDirectory": []
}

21
integration/microservices/.gitignore vendored Normal file
View File

@@ -0,0 +1,21 @@
# dependencies
/node_modules
# IDE
/.idea
/.awcache
/.vscode
# misc
npm-debug.log
# example
/quick-start
# tests
/test
/coverage
/.nyc_output
# dist
/dist

View File

@@ -0,0 +1,39 @@
import * as express from 'express';
import * as request from 'supertest';
import { Test } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import { Transport } from '@nestjs/microservices';
import { NatsMulticastController } from '../src/nats/nats-multicast.controller';
describe('NATS transport', () => {
let server;
let app: INestApplication;
beforeEach(async () => {
const module = await Test.createTestingModule({
controllers: [NatsMulticastController],
}).compile();
server = express();
app = module.createNestApplication(server);
app.connectMicroservice({
transport: Transport.NATS,
url: 'nats://localhost:4222'
});
app.connectMicroservice({
transport: Transport.NATS,
});
await app.startAllMicroservicesAsync();
await app.init();
});
it(`Multicast (2 subscribers)`, () => {
return request(server)
.get('/multicast')
.expect(200, '2');
});
afterEach(async () => {
await app.close();
});
});

View File

@@ -0,0 +1,39 @@
import * as express from 'express';
import * as request from 'supertest';
import { Test } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import { Transport } from '@nestjs/microservices';
import { RedisController } from '../src/redis/redis.controller';
import { RedisMulticastController } from '../src/redis/redis-multicast.controller';
describe('REDIS transport', () => {
let server;
let app: INestApplication;
beforeEach(async () => {
const module = await Test.createTestingModule({
controllers: [RedisMulticastController],
}).compile();
server = express();
app = module.createNestApplication(server);
app.connectMicroservice({
transport: Transport.REDIS,
});
app.connectMicroservice({
transport: Transport.REDIS,
});
await app.startAllMicroservicesAsync();
await app.init();
});
it(`Multicast (2 subscribers)`, () => {
return request(server)
.get('/multicast')
.expect(200, '2');
});
afterEach(async () => {
await app.close();
});
});

View File

@@ -0,0 +1,59 @@
import * as express from 'express';
import * as request from 'supertest';
import { Test } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import { Transport } from '@nestjs/microservices';
import { NatsController } from '../src/nats/nats.controller';
describe('NATS transport', () => {
let server;
let app: INestApplication;
beforeEach(async () => {
const module = await Test.createTestingModule({
controllers: [NatsController],
}).compile();
server = express();
app = module.createNestApplication(server);
app.connectMicroservice({
transport: Transport.NATS,
url: 'nats://localhost:4222'
});
await app.startAllMicroservicesAsync();
await app.init();
});
it(`/POST`, () => {
return request(server)
.post('/?command=sum')
.send([1, 2, 3, 4, 5])
.expect(200, '15');
});
it(`/POST (Promise/async)`, () => {
return request(server)
.post('/?command=asyncSum')
.send([1, 2, 3, 4, 5])
.expect(200)
.expect(200, '15');
});
it(`/POST (Observable stream)`, () => {
return request(server)
.post('/?command=streamSum')
.send([1, 2, 3, 4, 5])
.expect(200, '15');
});
it(`/POST (streaming)`, () => {
return request(server)
.post('/stream')
.send([1, 2, 3, 4, 5])
.expect(200, '15');
});
afterEach(async () => {
await app.close();
});
});

View File

@@ -0,0 +1,71 @@
import * as express from 'express';
import * as request from 'supertest';
import { Test } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import { Transport } from '@nestjs/microservices';
import { RedisController } from '../src/redis/redis.controller';
describe('REDIS transport', () => {
let server;
let app: INestApplication;
beforeEach(async () => {
const module = await Test.createTestingModule({
controllers: [RedisController],
}).compile();
server = express();
app = module.createNestApplication(server);
app.connectMicroservice({
transport: Transport.REDIS,
});
await app.startAllMicroservicesAsync();
await app.init();
});
it(`/POST`, () => {
return request(server)
.post('/?command=sum')
.send([1, 2, 3, 4, 5])
.expect(200, '15');
});
it(`/POST (Promise/async)`, () => {
return request(server)
.post('/?command=asyncSum')
.send([1, 2, 3, 4, 5])
.expect(200)
.expect(200, '15');
});
it(`/POST (Observable stream)`, () => {
return request(server)
.post('/?command=streamSum')
.send([1, 2, 3, 4, 5])
.expect(200, '15');
});
it(`/POST (concurrent)`, () => {
return request(server)
.post('/concurrent')
.send([
[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10],
[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20],
[21, 22, 23, 24, 25],
])
.expect(200, 'true');
});
it(`/POST (streaming)`, () => {
return request(server)
.post('/stream')
.send([1, 2, 3, 4, 5])
.expect(200, '15');
});
afterEach(async () => {
await app.close();
});
});

View File

@@ -0,0 +1,77 @@
import * as express from 'express';
import * as request from 'supertest';
import { Test } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import { ApplicationModule } from './../src/app.module';
import { Transport } from '@nestjs/microservices';
describe('RPC transport', () => {
let server;
let app: INestApplication;
beforeEach(async () => {
const module = await Test.createTestingModule({
imports: [ApplicationModule],
}).compile();
server = express();
app = module.createNestApplication(server);
app.connectMicroservice({
transport: Transport.TCP,
});
await app.startAllMicroservicesAsync();
await app.init();
});
it(`/POST`, () => {
return request(server)
.post('/?command=sum')
.send([1, 2, 3, 4, 5])
.expect(200, '15');
});
it(`/POST (Promise/async)`, () => {
return request(server)
.post('/?command=asyncSum')
.send([1, 2, 3, 4, 5])
.expect(200)
.expect(200, '15');
});
it(`/POST (Observable stream)`, () => {
return request(server)
.post('/?command=streamSum')
.send([1, 2, 3, 4, 5])
.expect(200, '15');
});
it(`/POST (concurrent)`, () => {
return request(server)
.post('/concurrent')
.send([
[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10],
[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20],
[21, 22, 23, 24, 25],
])
.expect(200, 'true');
});
it(`/POST (streaming)`, () => {
return request(server)
.post('/stream')
.send([1, 2, 3, 4, 5])
.expect(200, '15');
});
it(`/POST (pattern not found)`, () => {
return request(server)
.post('/?command=test')
.expect(500);
});
afterEach(async () => {
await app.close();
});
});

View File

@@ -0,0 +1,59 @@
/*import * as express from 'express';
import * as request from 'supertest';
import { Test } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import { Transport } from '@nestjs/microservices';
import { NatsController } from '../src/nats/nats.controller';
describe('STAN transport', () => {
let server;
let app: INestApplication;
beforeEach(async () => {
const module = await Test.createTestingModule({
controllers: [NatsController],
}).compile();
server = express();
app = module.createNestApplication(server);
app.connectMicroservice({
transport: Transport.STAN,
});
await app.startAllMicroservicesAsync();
await app.init();
});
it(`/POST`, () => {
return request(server)
.post('/?command=sum')
.send([1, 2, 3, 4, 5])
.expect(200, '15');
});
it(`/POST (Promise/async)`, () => {
return request(server)
.post('/?command=asyncSum')
.send([1, 2, 3, 4, 5])
.expect(200)
.expect(200, '15');
});
it(`/POST (Observable stream)`, () => {
return request(server)
.post('/?command=streamSum')
.send([1, 2, 3, 4, 5])
.expect(200, '15');
});
it(`/POST (streaming)`, () => {
return request(server)
.post('/stream')
.send([1, 2, 3, 4, 5])
.expect(200, '15');
});
afterEach(async () => {
await app.close();
});
});
*/

View File

@@ -0,0 +1,27 @@
{
"name": "nest-typescript-starter",
"version": "1.0.0",
"description": "Nest TypeScript starter repository",
"license": "MIT",
"scripts": {
"start": "ts-node src/main"
},
"dependencies": {
"@nestjs/common": "^4.3.0",
"@nestjs/core": "^4.3.0",
"@nestjs/microservices": "^4.3.0",
"@nestjs/testing": "^4.3.0",
"@nestjs/websockets": "^4.3.0",
"class-transformer": "^0.1.7",
"class-validator": "^0.7.2",
"redis": "^2.7.1",
"reflect-metadata": "^0.1.10",
"rxjs": "^5.4.3",
"typescript": "^2.4.2"
},
"devDependencies": {
"@types/node": "^7.0.41",
"supertest": "^3.0.0",
"ts-node": "^3.3.0"
}
}

View File

@@ -0,0 +1,68 @@
import { Controller, Get, Post, Body, Query, HttpCode } from '@nestjs/common';
import {
Client,
MessagePattern,
ClientProxy,
Transport,
} from '@nestjs/microservices';
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import { from } from 'rxjs/observable/from';
import { scan } from 'rxjs/operators';
@Controller()
export class AppController {
@Client({ transport: Transport.TCP })
client: ClientProxy;
@Post()
@HttpCode(200)
call(@Query('command') cmd, @Body() data: number[]): Observable<number> {
return this.client.send<number>({ cmd }, data);
}
@Post('stream')
@HttpCode(200)
stream(@Body() data: number[]): Observable<number> {
return this.client.send<number>({ cmd: 'streaming' }, data)
.pipe(
scan((a, b) => a + b),
);
}
@Post('concurrent')
@HttpCode(200)
concurrent(@Body() data: number[][]): Promise<boolean> {
const send = async (tab: number[]) => {
const expected = tab.reduce((a, b) => a + b);
const result = await this.client
.send<number>({ cmd: 'sum' }, tab)
.toPromise();
return result === expected;
};
return data
.map(async tab => await send(tab))
.reduce(async (a, b) => (await a) && (await b));
}
@MessagePattern({ cmd: 'sum' })
sum(data: number[]): number {
return (data || []).reduce((a, b) => a + b);
}
@MessagePattern({ cmd: 'asyncSum' })
async asyncSum(data: number[]): Promise<number> {
return (data || []).reduce((a, b) => a + b);
}
@MessagePattern({ cmd: 'streamSum' })
streamSum(data: number[]): Observable<number> {
return of((data || []).reduce((a, b) => a + b));
}
@MessagePattern({ cmd: 'streaming' })
streaming(data: number[]): Observable<number> {
return from(data);
}
}

View File

@@ -0,0 +1,7 @@
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
@Module({
controllers: [AppController],
})
export class ApplicationModule {}

View File

@@ -0,0 +1,8 @@
import { NestFactory } from '@nestjs/core';
import { ApplicationModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(ApplicationModule);
await app.listen(3000);
}
bootstrap();

View File

@@ -0,0 +1,27 @@
import { Controller, Get } from '@nestjs/common';
import {
Client,
MessagePattern,
ClientProxy,
Transport,
} from '@nestjs/microservices';
import { Observable } from 'rxjs/Observable';
import { scan, take } from 'rxjs/operators';
@Controller()
export class NatsMulticastController {
@Client({ transport: Transport.NATS, url: 'nats://localhost:4222' })
client: ClientProxy;
@Get('multicast')
multicats() {
return this.client
.send<number>({ cmd: 'multicast' }, {})
.pipe(scan((a, b) => a + b), take(2));
}
@MessagePattern({ cmd: 'multicast' })
replyMulticast(): Observable<number> {
return new Observable(observer => observer.next(1));
}
}

View File

@@ -0,0 +1,67 @@
import { Controller, Get, Post, Body, Query, HttpCode } from '@nestjs/common';
import {
Client,
MessagePattern,
ClientProxy,
Transport,
} from '@nestjs/microservices';
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import { from } from 'rxjs/observable/from';
import { scan } from 'rxjs/operators';
@Controller()
export class NatsController {
@Client({ transport: Transport.NATS, url: 'nats://localhost:4222' })
client: ClientProxy;
@Post()
@HttpCode(200)
call(@Query('command') cmd, @Body() data: number[]): Observable<number> {
return this.client.send<number>({ cmd }, data);
}
@Post('stream')
@HttpCode(200)
stream(@Body() data: number[]): Observable<number> {
return this.client
.send<number>({ cmd: 'streaming' }, data)
.pipe(scan((a, b) => a + b));
}
@Post('concurrent')
@HttpCode(200)
concurrent(@Body() data: number[][]): Promise<boolean> {
const send = async (tab: number[]) => {
const expected = tab.reduce((a, b) => a + b);
const result = await this.client
.send<number>({ cmd: 'sum' }, tab)
.toPromise();
return result === expected;
};
return data
.map(async tab => await send(tab))
.reduce(async (a, b) => (await a) && (await b));
}
@MessagePattern({ cmd: 'sum' })
sum(data: number[]): number {
return (data || []).reduce((a, b) => a + b);
}
@MessagePattern({ cmd: 'asyncSum' })
async asyncSum(data: number[]): Promise<number> {
return (data || []).reduce((a, b) => a + b);
}
@MessagePattern({ cmd: 'streamSum' })
streamSum(data: number[]): Observable<number> {
return of((data || []).reduce((a, b) => a + b));
}
@MessagePattern({ cmd: 'streaming' })
streaming(data: number[]): Observable<number> {
return from(data);
}
}

View File

@@ -0,0 +1,29 @@
import { Controller, Get } from '@nestjs/common';
import {
Client,
MessagePattern,
ClientProxy,
Transport,
} from '@nestjs/microservices';
import { Observable } from 'rxjs/Observable';
import { scan, take } from 'rxjs/operators';
@Controller()
export class RedisMulticastController {
@Client({ transport: Transport.REDIS })
client: ClientProxy;
@Get('multicast')
multicats() {
return this.client.send<number>({ cmd: 'multicast' }, {})
.pipe(
scan((a, b) => a + b),
take(2),
);
}
@MessagePattern({ cmd: 'multicast' })
replyMulticast(): Observable<number> {
return new Observable((observer) => observer.next(1));
}
}

View File

@@ -0,0 +1,68 @@
import { Controller, Get, Post, Body, Query, HttpCode } from '@nestjs/common';
import {
Client,
MessagePattern,
ClientProxy,
Transport,
} from '@nestjs/microservices';
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import { from } from 'rxjs/observable/from';
import { scan } from 'rxjs/operators';
@Controller()
export class RedisController {
@Client({ transport: Transport.REDIS })
client: ClientProxy;
@Post()
@HttpCode(200)
call(@Query('command') cmd, @Body() data: number[]): Observable<number> {
return this.client.send<number>({ cmd }, data);
}
@Post('stream')
@HttpCode(200)
stream(@Body() data: number[]): Observable<number> {
return this.client.send<number>({ cmd: 'streaming' }, data)
.pipe(
scan((a, b) => a + b),
);
}
@Post('concurrent')
@HttpCode(200)
concurrent(@Body() data: number[][]): Promise<boolean> {
const send = async (tab: number[]) => {
const expected = tab.reduce((a, b) => a + b);
const result = await this.client
.send<number>({ cmd: 'sum' }, tab)
.toPromise();
return result === expected;
};
return data
.map(async tab => await send(tab))
.reduce(async (a, b) => (await a) && (await b));
}
@MessagePattern({ cmd: 'sum' })
sum(data: number[]): number {
return (data || []).reduce((a, b) => a + b);
}
@MessagePattern({ cmd: 'asyncSum' })
async asyncSum(data: number[]): Promise<number> {
return (data || []).reduce((a, b) => a + b);
}
@MessagePattern({ cmd: 'streamSum' })
streamSum(data: number[]): Observable<number> {
return of((data || []).reduce((a, b) => a + b));
}
@MessagePattern({ cmd: 'streaming' })
streaming(data: number[]): Observable<number> {
return from(data);
}
}

View File

@@ -0,0 +1,68 @@
import { Controller, Get, Post, Body, Query, HttpCode } from '@nestjs/common';
import {
Client,
MessagePattern,
ClientProxy,
Transport,
} from '@nestjs/microservices';
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import { from } from 'rxjs/observable/from';
import { scan } from 'rxjs/operators';
@Controller()
export class NatsController {
@Client({ transport: Transport.STAN })
client: ClientProxy;
@Post()
@HttpCode(200)
call(@Query('command') cmd, @Body() data: number[]): Observable<number> {
return this.client.send<number>({ cmd }, data);
}
@Post('stream')
@HttpCode(200)
stream(@Body() data: number[]): Observable<number> {
return this.client.send<number>({ cmd: 'streaming' }, data)
.pipe(
scan((a, b) => a + b),
);
}
@Post('concurrent')
@HttpCode(200)
concurrent(@Body() data: number[][]): Promise<boolean> {
const send = async (tab: number[]) => {
const expected = tab.reduce((a, b) => a + b);
const result = await this.client
.send<number>({ cmd: 'sum' }, tab)
.toPromise();
return result === expected;
};
return data
.map(async tab => await send(tab))
.reduce(async (a, b) => (await a) && (await b));
}
@MessagePattern({ cmd: 'sum' })
sum(data: number[]): number {
return (data || []).reduce((a, b) => a + b);
}
@MessagePattern({ cmd: 'asyncSum' })
async asyncSum(data: number[]): Promise<number> {
return (data || []).reduce((a, b) => a + b);
}
@MessagePattern({ cmd: 'streamSum' })
streamSum(data: number[]): Observable<number> {
return of((data || []).reduce((a, b) => a + b));
}
@MessagePattern({ cmd: 'streaming' })
streaming(data: number[]): Observable<number> {
return from(data);
}
}

View File

@@ -0,0 +1,22 @@
{
"compilerOptions": {
"module": "commonjs",
"declaration": false,
"noImplicitAny": false,
"removeComments": true,
"noLib": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es6",
"sourceMap": true,
"allowJs": true,
"outDir": "./dist"
},
"include": [
"src/**/*",
"e2e/**/*"
],
"exclude": [
"node_modules",
]
}

View File

@@ -0,0 +1,53 @@
{
"defaultSeverity": "error",
"extends": [
"tslint:recommended"
],
"jsRules": {
"no-unused-expression": true
},
"rules": {
"eofline": false,
"quotemark": [
true,
"single"
],
"ordered-imports": [
false
],
"max-line-length": [
150
],
"member-ordering": [
false
],
"curly": false,
"interface-name": [
false
],
"array-type": [
false
],
"member-access": [
false
],
"no-empty-interface": false,
"no-empty": false,
"arrow-parens": false,
"object-literal-sort-keys": false,
"no-unused-expression": false,
"max-classes-per-file": [
false
],
"variable-name": [
false
],
"one-line": [
false
],
"one-variable-per-declaration": [
false
]
},
"rulesDirectory": []
}