Skip to content

Commit

Permalink
Merge branch 'master' into kafka-commit-offsets
Browse files Browse the repository at this point in the history
  • Loading branch information
davidschuette committed Mar 14, 2022
2 parents 37d83ee + 0dc4f91 commit 9147851
Show file tree
Hide file tree
Showing 158 changed files with 5,055 additions and 1,533 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ node_modules/
/.idea
/.awcache
/.vscode
/.devcontainer
*.code-workspace

# bundle
Expand Down
6 changes: 4 additions & 2 deletions integration/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ services:
restart: always
mqtt:
container_name: test-mqtt
image: toke/mosquitto
image: eclipse-mosquitto
volumes:
- ./mosquitto.conf:/mosquitto/config/mosquitto.conf
ports:
- "1883:1883"
- "9001:9001"
restart: always
mysql:
image: mysql:8.0.27
image: mysql:8.0.28
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: test
Expand Down
56 changes: 56 additions & 0 deletions integration/injector/e2e/injector.spec.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
import { RuntimeException } from '@nestjs/core/errors/exceptions/runtime.exception';
import { UnknownDependenciesException } from '@nestjs/core/errors/exceptions/unknown-dependencies.exception';
import { UnknownExportException } from '@nestjs/core/errors/exceptions/unknown-export.exception';
import { Test } from '@nestjs/testing';
import { expect } from 'chai';
import * as chai from 'chai';
import * as chaiAsPromised from 'chai-as-promised';
import {
DYNAMIC_TOKEN,
DYNAMIC_VALUE,
NestDynamicModule,
} from '../src/dynamic/dynamic.module';
import { ExportsModule } from '../src/exports/exports.module';
import { InjectModule } from '../src/inject/inject.module';
import { InjectSameNameModule } from '../src/inject/inject-same-name.module';
import {
SelfInjectionProviderModule,
SelfInjectionProviderCustomTokenModule,
SelfInjectionForwardProviderModule,
} from '../src/self-injection/self-injection-provider.module';
chai.use(chaiAsPromised);

describe('Injector', () => {
describe('when "providers" and "exports" properties are inconsistent', () => {
Expand All @@ -24,6 +34,16 @@ describe('Injector', () => {
});
});

describe("When class injects a provider with the same as class's name", () => {
it('should compile with success', async () => {
const builder = Test.createTestingModule({
imports: [InjectSameNameModule],
});

await expect(builder.compile()).to.eventually.be.fulfilled;
});
});

describe('when Nest cannot resolve dependencies', () => {
it(`should fail with "RuntimeException"`, async () => {
try {
Expand All @@ -35,6 +55,42 @@ describe('Injector', () => {
expect(err).to.be.instanceof(RuntimeException);
}
});

describe('due to self-injection providers', () => {
it('should fail with "UnknownDependenciesException" due to self-injection via same class reference', async () => {
const builder = Test.createTestingModule({
imports: [SelfInjectionProviderModule],
});

await expect(
builder.compile(),
).to.eventually.be.rejected.and.be.an.instanceOf(
UnknownDependenciesException,
);
});
it('should fail with "UnknownDependenciesException" due to self-injection via forwardRef to the same class reference', async () => {
const builder = Test.createTestingModule({
imports: [SelfInjectionForwardProviderModule],
});

await expect(
builder.compile(),
).to.eventually.be.rejected.and.be.an.instanceOf(
UnknownDependenciesException,
);
});
it('should fail with "UnknownDependenciesException" due to self-injection via custom provider', async () => {
const builder = Test.createTestingModule({
imports: [SelfInjectionProviderCustomTokenModule],
});

await expect(
builder.compile(),
).to.eventually.be.rejected.and.be.an.instanceOf(
UnknownDependenciesException,
);
});
});
});

describe('when dynamic module', () => {
Expand Down
96 changes: 96 additions & 0 deletions integration/injector/e2e/optional-factory-provider-dep.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { UnknownDependenciesException } from '@nestjs/core/errors/exceptions/unknown-dependencies.exception';
import { Test } from '@nestjs/testing';
import { expect } from 'chai';

describe('Optional factory provider deps', () => {
describe('when dependency is optional', () => {
describe('and it is available', () => {
it('then it should be injected into the factory function', async () => {
const defaultValue = 'DEFAULT_VALUE';
const moduleRef = await Test.createTestingModule({
providers: [
{
provide: 'FACTORY',
useFactory: dep => dep ?? defaultValue,
inject: [{ token: 'MISSING_DEP', optional: true }],
},
{ provide: 'MISSING_DEP', useValue: 'OPTIONAL_DEP_VALUE' },
],
}).compile();

const factoryProvider = moduleRef.get('FACTORY');
expect(factoryProvider).to.equal('OPTIONAL_DEP_VALUE');
});
});
describe('otherwise', () => {
it('"undefined" should be injected into the factory function', async () => {
const defaultValue = 'DEFAULT_VALUE';
const moduleRef = await Test.createTestingModule({
providers: [
{
provide: 'FACTORY',
useFactory: dep => dep ?? defaultValue,
inject: [{ token: 'MISSING_DEP', optional: true }],
},
],
}).compile();

const factoryProvider = moduleRef.get('FACTORY');
expect(factoryProvider).to.equal(defaultValue);
});
});
});
describe('otherwise', () => {
describe('and dependency is not registered', () => {
it('should error out', async () => {
try {
const builder = Test.createTestingModule({
providers: [
{
provide: 'FACTORY',
useFactory: () => 'RETURNED_VALUE',
inject: ['MISSING_DEP'],
},
],
});
await builder.compile();
} catch (err) {
expect(err).to.be.instanceOf(UnknownDependenciesException);
}
});
});
});
describe('and dependency is registered but it cannot be instantiated', () => {
it('should error out', async () => {
try {
const builder = Test.createTestingModule({
providers: [
{
provide: 'POSSIBLY_MISSING_DEP',
useFactory: () => null,
inject: ['MISSING_DEP'],
},
{
provide: 'FACTORY',
useFactory: () => 'RETURNED_VALUE',
inject: [{ token: 'POSSIBLY_MISSING_DEP', optional: false }],
},
],
});
await builder.compile();
} catch (err) {
expect(err).to.be.instanceOf(UnknownDependenciesException);
expect(err.message).to
.equal(`Nest can't resolve dependencies of the POSSIBLY_MISSING_DEP (?). Please make sure that the argument MISSING_DEP at index [0] is available in the RootTestModule context.
Potential solutions:
- If MISSING_DEP is a provider, is it part of the current RootTestModule?
- If MISSING_DEP is exported from a separate @Module, is that module imported within RootTestModule?
@Module({
imports: [ /* the Module containing MISSING_DEP */ ]
})
`);
}
});
});
});
16 changes: 16 additions & 0 deletions integration/injector/src/inject/inject-same-name.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Module, Injectable, Inject } from '@nestjs/common';

@Injectable()
class CoreService {
constructor(@Inject(CoreService.name) private readonly coreService: any) {}
}

@Module({
providers: [
{
provide: CoreService.name,
useValue: 'anything',
},
],
})
export class InjectSameNameModule {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Module, Injectable, Inject, forwardRef } from '@nestjs/common';

@Injectable()
class ServiceInjectingItself {
constructor(private readonly coreService: ServiceInjectingItself) {}
}

@Injectable()
class ServiceInjectingItselfForwared {
constructor(
@Inject(forwardRef(() => ServiceInjectingItself))
private readonly coreService: ServiceInjectingItself,
) {}
}

@Injectable()
class ServiceInjectingItselfViaCustomToken {
constructor(@Inject('AnotherToken') private readonly coreService: any) {}
}

@Module({
providers: [ServiceInjectingItself],
})
export class SelfInjectionProviderModule {}

@Module({
providers: [ServiceInjectingItselfForwared],
})
export class SelfInjectionForwardProviderModule {}

@Module({
providers: [
ServiceInjectingItselfViaCustomToken,
{
provide: 'AnotherToken',
useClass: ServiceInjectingItselfViaCustomToken,
},
],
})
export class SelfInjectionProviderCustomTokenModule {}
38 changes: 38 additions & 0 deletions integration/microservices/e2e/sum-mqtt.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,44 @@ describe('MQTT transport', () => {
.expect(201, '15');
});

it(`/POST (shared wildcard EVENT #)`, done => {
request(server)
.post('/shared-wildcard-event')
.send([1, 2, 3, 4, 5])
.end(() => {
setTimeout(() => {
expect(MqttController.IS_SHARED_WILDCARD_EVENT_RECEIVED).to.be.true;
done();
}, 1000);
});
});

it(`/POST (shared wildcard MESSAGE #)`, () => {
return request(server)
.post('/shared-wildcard-message')
.send([1, 2, 3, 4, 5])
.expect(201, '15');
});

it(`/POST (shared wildcard EVENT +)`, done => {
request(server)
.post('/shared-wildcard-event2')
.send([1, 2, 3, 4, 5])
.end(() => {
setTimeout(() => {
expect(MqttController.IS_SHARED_WILDCARD2_EVENT_RECEIVED).to.be.true;
done();
}, 1000);
});
});

it(`/POST (shared wildcard MESSAGE +)`, () => {
return request(server)
.post('/shared-wildcard-message2')
.send([1, 2, 3, 4, 5])
.expect(201, '15');
});

afterEach(async () => {
await app.close();
});
Expand Down
51 changes: 51 additions & 0 deletions integration/microservices/src/mqtt/mqtt.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export class MqttController {
static IS_NOTIFIED = false;
static IS_WILDCARD_EVENT_RECEIVED = false;
static IS_WILDCARD2_EVENT_RECEIVED = false;
static IS_SHARED_WILDCARD_EVENT_RECEIVED = false;
static IS_SHARED_WILDCARD2_EVENT_RECEIVED = false;

@Client({ transport: Transport.MQTT })
client: ClientProxy;
Expand Down Expand Up @@ -109,6 +111,32 @@ export class MqttController {
};
}

@Post('shared-wildcard-event')
async sendSharedWildcardEvent(): Promise<any> {
return this.client.emit<number>('shared-wildcard-event/test', true);
}

@Post('shared-wildcard-message')
async sendSharedWildcardMessage(
@Body() data: number[],
): Promise<Observable<number>> {
await this.client.connect();
return this.client.send<number>('shared-wildcard-message/test', data);
}

@Post('shared-wildcard-event2')
async sendSharedWildcardEvent2(): Promise<any> {
return this.client.emit<number>('shared-wildcard-event2/test/test', true);
}

@Post('shared-wildcard-message2')
async sendSharedWildcardMessage2(
@Body() data: number[],
): Promise<Observable<number>> {
await this.client.connect();
return this.client.send<number>('shared-wildcard-message2/test/test', data);
}

@MessagePattern('wildcard-message/#')
wildcardMessageHandler(data: number[]): number {
if ((data as any).response) {
Expand Down Expand Up @@ -156,4 +184,27 @@ export class MqttController {
streaming(data: number[]): Observable<number> {
return from(data);
}

@MessagePattern('$share/test-group/shared-wildcard-message/#')
sharedWildcardMessageHandler(data: number[]): number {
if ((data as any).response) {
return;
}
return (data || []).reduce((a, b) => a + b);
}

@EventPattern('$share/test-group/shared-wildcard-event/#')
sharedWildcardEventHandler(data: boolean) {
MqttController.IS_SHARED_WILDCARD_EVENT_RECEIVED = data;
}

@MessagePattern('$share/test-group/shared-wildcard-message2/+/test')
sharedWildcardMessageHandler2(data: number[]): number {
return (data || []).reduce((a, b) => a + b);
}

@EventPattern('$share/test-group/shared-wildcard-event2/+/test')
sharedWildcardEventHandler2(data: boolean) {
MqttController.IS_SHARED_WILDCARD2_EVENT_RECEIVED = data;
}
}

0 comments on commit 9147851

Please sign in to comment.