Skip to content

Commit 2278ffa

Browse files
authored
Merge 7bfbec9 into 45d4274
2 parents 45d4274 + 7bfbec9 commit 2278ffa

File tree

6 files changed

+73
-13
lines changed

6 files changed

+73
-13
lines changed

.changeset/forty-bags-arrive.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
'@firebase/database-compat': patch
3+
'@firebase/database': patch
4+
'firebase': patch
5+
---
6+
7+
Fixed: invoking `connectDatabaseEmulator` multiple times with the same parameters will no longer
8+
cause an error. Fixes [GitHub Issue #6824](https://github.com/firebase/firebase-js-sdk/issues/6824).

packages/database-compat/test/database.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,9 @@ describe('Database Tests', () => {
301301

302302
expect(() => {
303303
db.useEmulator('localhost', 1234);
304-
}).to.throw(/Cannot call useEmulator/);
304+
}).to.throw(
305+
'FIREBASE FATAL ERROR: connectDatabaseEmulator() cannot initialize or alter the emulator configuration after the database instance has started.'
306+
);
305307
});
306308

307309
it('refFromURL returns an emulated ref with useEmulator', () => {

packages/database/src/api/Database.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { Provider } from '@firebase/component';
2727
import {
2828
getModularInstance,
2929
createMockUserToken,
30+
deepEqual,
3031
EmulatorMockTokenOptions,
3132
getDefaultEmulatorHostnameAndPort
3233
} from '@firebase/util';
@@ -38,7 +39,7 @@ import {
3839
FirebaseAuthTokenProvider
3940
} from '../core/AuthTokenProvider';
4041
import { Repo, repoInterrupt, repoResume, repoStart } from '../core/Repo';
41-
import { RepoInfo } from '../core/RepoInfo';
42+
import { RepoInfo, RepoInfoEmulatorOptions } from '../core/RepoInfo';
4243
import { parseRepoInfo } from '../core/util/libs/parser';
4344
import { newEmptyPath, pathIsEmpty } from '../core/util/Path';
4445
import {
@@ -84,19 +85,20 @@ let useRestClient = false;
8485
*/
8586
function repoManagerApplyEmulatorSettings(
8687
repo: Repo,
87-
host: string,
88-
port: number,
88+
hostAndPort: string,
89+
emulatorOptions: RepoInfoEmulatorOptions,
8990
tokenProvider?: AuthTokenProvider
9091
): void {
9192
repo.repoInfo_ = new RepoInfo(
92-
`${host}:${port}`,
93+
hostAndPort,
9394
/* secure= */ false,
9495
repo.repoInfo_.namespace,
9596
repo.repoInfo_.webSocketOnly,
9697
repo.repoInfo_.nodeAdmin,
9798
repo.repoInfo_.persistenceKey,
9899
repo.repoInfo_.includeNamespaceInQueryParams,
99-
/*isUsingEmulator=*/ true
100+
/*isUsingEmulator=*/ true,
101+
emulatorOptions
100102
);
101103

102104
if (tokenProvider) {
@@ -350,13 +352,22 @@ export function connectDatabaseEmulator(
350352
): void {
351353
db = getModularInstance(db);
352354
db._checkNotDeleted('useEmulator');
355+
const hostAndPort = `${host}:${port}`;
356+
const repo = db._repoInternal;
353357
if (db._instanceStarted) {
358+
// If the instance has already been started, then silenty fail if this function is called again
359+
// with the same parameters. If the parameters differ then assert.
360+
if (
361+
hostAndPort === db._repoInternal.repoInfo_.host &&
362+
deepEqual(options, repo.repoInfo_.emulatorOptions)
363+
) {
364+
return;
365+
}
354366
fatal(
355-
'Cannot call useEmulator() after instance has already been initialized.'
367+
'connectDatabaseEmulator() cannot initialize or alter the emulator configuration after the database instance has started.'
356368
);
357369
}
358370

359-
const repo = db._repoInternal;
360371
let tokenProvider: EmulatorTokenProvider | undefined = undefined;
361372
if (repo.repoInfo_.nodeAdmin) {
362373
if (options.mockUserToken) {
@@ -374,7 +385,7 @@ export function connectDatabaseEmulator(
374385
}
375386

376387
// Modify the repo to apply emulator settings
377-
repoManagerApplyEmulatorSettings(repo, host, port, tokenProvider);
388+
repoManagerApplyEmulatorSettings(repo, hostAndPort, options, tokenProvider);
378389
}
379390

380391
/**

packages/database/src/core/RepoInfo.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,17 @@
1515
* limitations under the License.
1616
*/
1717

18-
import { assert } from '@firebase/util';
18+
import { assert, EmulatorMockTokenOptions } from '@firebase/util';
1919

2020
import { LONG_POLLING, WEBSOCKET } from '../realtime/Constants';
2121

2222
import { PersistentStorage } from './storage/storage';
2323
import { each } from './util/util';
2424

25+
export interface RepoInfoEmulatorOptions {
26+
mockUserToken?: string | EmulatorMockTokenOptions;
27+
}
28+
2529
/**
2630
* A class that holds metadata about a Repo object
2731
*/
@@ -46,7 +50,8 @@ export class RepoInfo {
4650
public readonly nodeAdmin: boolean = false,
4751
public readonly persistenceKey: string = '',
4852
public readonly includeNamespaceInQueryParams: boolean = false,
49-
public readonly isUsingEmulator: boolean = false
53+
public readonly isUsingEmulator: boolean = false,
54+
public readonly emulatorOptions: RepoInfoEmulatorOptions | null = null
5055
) {
5156
this._host = host.toLowerCase();
5257
this._domain = this._host.substr(this._host.indexOf('.') + 1);

packages/database/test/exp/integration.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import {
3535
orderByKey
3636
} from '../../src/api/Reference_impl';
3737
import {
38+
connectDatabaseEmulator,
3839
getDatabase,
3940
goOffline,
4041
goOnline,
@@ -46,8 +47,10 @@ import { EventAccumulatorFactory } from '../helpers/EventAccumulator';
4647
import {
4748
DATABASE_ADDRESS,
4849
DATABASE_URL,
50+
EMULATOR_PORT,
4951
getFreshRepo,
5052
getRWRefs,
53+
USE_EMULATOR,
5154
waitFor,
5255
waitUntil,
5356
writeAndValidate
@@ -138,6 +141,37 @@ describe('Database@exp Tests', () => {
138141
unsubscribe();
139142
});
140143

144+
if (USE_EMULATOR) {
145+
it('can connect to emulator', async () => {
146+
const db = getDatabase(defaultApp);
147+
connectDatabaseEmulator(db, 'localhost', parseInt(EMULATOR_PORT, 10));
148+
await get(refFromURL(db, `${DATABASE_ADDRESS}/foo/bar`));
149+
});
150+
it('can change emulator config before network operations', async () => {
151+
const db = getDatabase(defaultApp);
152+
const port = parseInt(EMULATOR_PORT, 10);
153+
connectDatabaseEmulator(db, 'localhost', port + 1);
154+
connectDatabaseEmulator(db, 'localhost', port);
155+
await get(refFromURL(db, `${DATABASE_ADDRESS}/foo/bar`));
156+
});
157+
it('can connect to emulator after network operations with same parameters', async () => {
158+
const db = getDatabase(defaultApp);
159+
const port = parseInt(EMULATOR_PORT, 10);
160+
connectDatabaseEmulator(db, 'localhost', port);
161+
await get(refFromURL(db, `${DATABASE_ADDRESS}/foo/bar`));
162+
connectDatabaseEmulator(db, 'localhost', port);
163+
});
164+
it('cannot connect to emulator after network operations with different parameters', async () => {
165+
const db = getDatabase(defaultApp);
166+
const port = parseInt(EMULATOR_PORT, 10);
167+
connectDatabaseEmulator(db, 'localhost', port);
168+
await get(refFromURL(db, `${DATABASE_ADDRESS}/foo/bar`));
169+
expect(() => {
170+
connectDatabaseEmulator(db, 'localhost', 9001);
171+
}).to.throw();
172+
});
173+
}
174+
141175
it('can properly handle unknown deep merges', async () => {
142176
// Note: This test requires `testIndex` to be added as an index.
143177
// Please run `yarn test:setup` to ensure that this gets added.

packages/database/test/helpers/util.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ import { EventAccumulator } from './EventAccumulator';
3333

3434
// eslint-disable-next-line @typescript-eslint/no-require-imports
3535
export const TEST_PROJECT = require('../../../../config/project.json');
36-
const EMULATOR_PORT = process.env.RTDB_EMULATOR_PORT;
36+
export const EMULATOR_PORT = process.env.RTDB_EMULATOR_PORT;
3737
const EMULATOR_NAMESPACE = process.env.RTDB_EMULATOR_NAMESPACE;
38-
const USE_EMULATOR = !!EMULATOR_PORT;
38+
export const USE_EMULATOR = !!EMULATOR_PORT;
3939

4040
let freshRepoId = 0;
4141
const activeFreshApps: FirebaseApp[] = [];

0 commit comments

Comments
 (0)