Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-implement Unified Emulator Settings #1802

Merged
merged 21 commits into from
Jul 27, 2020
Merged
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/ktx/firestore.md
Original file line number Diff line number Diff line change
@@ -85,7 +85,7 @@ firestore.setFirestoreSettings(settings)
**Kotlin + KTX**
```kotlin
firestore.firestoreSettings = firestoreSettings {
host = "http://10.0.0.2:8080"
host = "http://10.0.2.2:8080"
isSslEnabled = false
isPersistenceEnabled = false
}
Original file line number Diff line number Diff line change
@@ -45,9 +45,6 @@
import com.google.firebase.components.TestComponentOne;
import com.google.firebase.components.TestComponentTwo;
import com.google.firebase.components.TestUserAgentDependentComponent;
import com.google.firebase.emulators.EmulatedServiceSettings;
import com.google.firebase.emulators.EmulatorSettings;
import com.google.firebase.emulators.FirebaseEmulator;
import com.google.firebase.platforminfo.UserAgentPublisher;
import com.google.firebase.testing.FirebaseAppRule;
import java.lang.reflect.InvocationTargetException;
@@ -420,43 +417,6 @@ public void testDirectBoot_shouldPreserveDataCollectionAfterUnlock() {
assertTrue(firebaseApp.isDataCollectionDefaultEnabled());
}

@Test
public void testEnableEmulators_shouldAllowDoubleSetBeforeAccess() {
Context mockContext = createForwardingMockContext();
FirebaseApp firebaseApp = FirebaseApp.initializeApp(mockContext);

// A developer would call FirebaseDatabase.EMULATOR but we can't introduce that
// dependency for this test.
FirebaseEmulator emulator = FirebaseEmulator.forName("database");

EmulatedServiceSettings databaseSettings = new EmulatedServiceSettings("10.0.2.2", 9000);
EmulatorSettings emulatorSettings =
new EmulatorSettings.Builder().addEmulatedService(emulator, databaseSettings).build();

// Set twice
firebaseApp.enableEmulators(emulatorSettings);
firebaseApp.enableEmulators(emulatorSettings);
}

@Test
public void testEnableEmulators_shouldThrowIfSetAfterAccess() {
Context mockContext = createForwardingMockContext();
FirebaseApp firebaseApp = FirebaseApp.initializeApp(mockContext);

FirebaseEmulator emulator = FirebaseEmulator.forName("database");

EmulatedServiceSettings databaseSettings = new EmulatedServiceSettings("10.0.2.2", 9000);
EmulatorSettings emulatorSettings =
new EmulatorSettings.Builder().addEmulatedService(emulator, databaseSettings).build();
firebaseApp.enableEmulators(emulatorSettings);

// Access (as if from the Database SDK)
firebaseApp.getEmulatorSettings().getServiceSettings(emulator);

// Try to set again
assertThrows(IllegalStateException.class, () -> firebaseApp.enableEmulators(emulatorSettings));
}

/** Returns mock context that forwards calls to targetContext and localBroadcastManager. */
private Context createForwardingMockContext() {
final UserManager spyUserManager = spy(targetContext.getSystemService(UserManager.class));
40 changes: 2 additions & 38 deletions firebase-common/src/main/java/com/google/firebase/FirebaseApp.java
Original file line number Diff line number Diff line change
@@ -111,9 +111,6 @@ public class FirebaseApp {
private final FirebaseOptions options;
private final ComponentRuntime componentRuntime;

private final AtomicBoolean emulatorSettingsFrozen = new AtomicBoolean(false);
private EmulatorSettings emulatorSettings = EmulatorSettings.DEFAULT;

// Default disabled. We released Firebase publicly without this feature, so making it default
// enabled is a backwards incompatible change.
private final AtomicBoolean automaticResourceManagementEnabled = new AtomicBoolean(false);
@@ -146,20 +143,6 @@ public FirebaseOptions getOptions() {
return options;
}

/**
* Returns the specified {@link EmulatorSettings} or a default.
*
* <p>TODO(samstern): Un-hide this once Firestore, Database, and Functions are implemented
*
* @hide
*/
@NonNull
public EmulatorSettings getEmulatorSettings() {
checkNotDeleted();
emulatorSettingsFrozen.set(true);
return emulatorSettings;
}

@Override
public boolean equals(Object o) {
if (!(o instanceof FirebaseApp)) {
@@ -323,26 +306,6 @@ public static FirebaseApp initializeApp(
return firebaseApp;
}

/**
* Specify which services should access local emulators for this FirebaseApp instance.
*
* <p>For example, if the {@link EmulatorSettings} contain {@link
* com.google.firebase.emulators.EmulatedServiceSettings} for {@link FirebaseDatabase#EMULATOR},
* then calls to Cloud Firestore will communicate with the emulator rather than production.
*
* <p>TODO(samstern): Un-hide this once Firestore, Database, and Functions are implemented
*
* @param emulatorSettings the emulator settings for all services.
* @hide
*/
public void enableEmulators(@NonNull EmulatorSettings emulatorSettings) {
checkNotDeleted();
Preconditions.checkState(
!this.emulatorSettingsFrozen.get(),
"Cannot enable emulators after Firebase SDKs have already been used.");
this.emulatorSettings = emulatorSettings;
}

/**
* Deletes the {@link FirebaseApp} and all its data. All calls to this {@link FirebaseApp}
* instance will throw once it has been called.
@@ -468,7 +431,8 @@ protected FirebaseApp(Context applicationContext, String name, FirebaseOptions o
LibraryVersionComponent.create(FIREBASE_COMMON, BuildConfig.VERSION_NAME),
kotlinVersion != null ? LibraryVersionComponent.create(KOTLIN, kotlinVersion) : null,
DefaultUserAgentPublisher.component(),
DefaultHeartBeatInfo.component());
DefaultHeartBeatInfo.component(),
EmulatorSettings.component());

dataCollectionConfigStorage =
new Lazy<>(
Original file line number Diff line number Diff line change
@@ -19,9 +19,6 @@
/**
* Settings to connect a single Firebase service to a local emulator.
*
* <p>TODO(samstern): Un-hide this once Firestore, Database, and Functions are implemented
*
* @see EmulatorSettings
* @hide
*/
public final class EmulatedServiceSettings {
Original file line number Diff line number Diff line change
@@ -16,72 +16,40 @@

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.firebase.components.Preconditions;
import java.util.Collections;
import com.google.firebase.FirebaseApp;
import com.google.firebase.components.Component;
import com.google.firebase.components.Dependency;
import java.util.HashMap;
import java.util.Map;

/**
* Settings that control which Firebase services should access a local emulator, rather than
* production.
*
* <p>TODO(samstern): Un-hide this once Firestore, Database, and Functions are implemented
*
* @see com.google.firebase.FirebaseApp#enableEmulators(EmulatorSettings)
* @hide
*/
public final class EmulatorSettings {
/** @hide */
public class EmulatorSettings {

/** Empty emulator settings to be used as an internal default */
public static final EmulatorSettings DEFAULT = new EmulatorSettings.Builder().build();

public static final class Builder {

private final Map<FirebaseEmulator, EmulatedServiceSettings> settingsMap = new HashMap<>();

/** Constructs an empty builder. */
public Builder() {}

/**
* Specify the emulator settings for a single service.
*
* @param emulator the emulated service.
* @param settings the emulator settings.
* @return the builder, for chaining.
*/
@NonNull
public Builder addEmulatedService(
@NonNull FirebaseEmulator emulator, @NonNull EmulatedServiceSettings settings) {
Preconditions.checkState(
!settingsMap.containsKey(emulator),
"Cannot call addEmulatedService twice for " + emulator.toString());
this.settingsMap.put(emulator, settings);
return this;
}

@NonNull
public EmulatorSettings build() {
return new EmulatorSettings(new HashMap<>(settingsMap));
}
@NonNull
public static Component<EmulatorSettings> component() {
return Component.builder(EmulatorSettings.class)
.add(Dependency.required(FirebaseApp.class))
.factory(c -> new EmulatorSettings(c.get(FirebaseApp.class)))
.build();
}

private final Map<FirebaseEmulator, EmulatedServiceSettings> settingsMap;
private final Map<String, EmulatedServiceSettings> settings = new HashMap<>();
private final FirebaseApp app;

private EmulatorSettings(@NonNull Map<FirebaseEmulator, EmulatedServiceSettings> settingsMap) {
this.settingsMap = Collections.unmodifiableMap(settingsMap);
EmulatorSettings(@NonNull FirebaseApp app) {
this.app = app;
}

/**
* Fetch the emulation settings for a single Firebase service.
*
* @hide
*/
@Nullable
public EmulatedServiceSettings getServiceSettings(@NonNull FirebaseEmulator emulator) {
if (settingsMap.containsKey(emulator)) {
return settingsMap.get(emulator);
}
public EmulatedServiceSettings get(@NonNull String name) {
return settings.get(getKeyFor(name));
}

public void set(@NonNull String name, @Nullable EmulatedServiceSettings serviceSettings) {
settings.put(getKeyFor(name), serviceSettings);
}

return null;
private String getKeyFor(@NonNull String name) {
return this.app.getName() + '-' + name;
samtstern marked this conversation as resolved.
Show resolved Hide resolved
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -30,8 +30,6 @@
import com.google.firebase.database.core.persistence.MockPersistenceStorageEngine;
import com.google.firebase.database.core.persistence.PersistenceManager;
import com.google.firebase.database.future.WriteFuture;
import com.google.firebase.emulators.EmulatedServiceSettings;
import com.google.firebase.emulators.EmulatorSettings;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -71,21 +69,34 @@ public void getInstanceForAppWithEmulator() {
FirebaseApp app =
appForDatabaseUrl(IntegrationTestValues.getAltNamespace(), "getInstanceForAppWithEmulator");

EmulatedServiceSettings serviceSettings = new EmulatedServiceSettings("10.0.2.2", 9000);
EmulatorSettings emulatorSettings =
new EmulatorSettings.Builder()
.addEmulatedService(FirebaseDatabase.EMULATOR, serviceSettings)
.build();
app.enableEmulators(emulatorSettings);

FirebaseDatabase db = FirebaseDatabase.getInstance(app);
db.useEmulator("10.0.2.2", 9000);

DatabaseReference rootRef = db.getReference();
assertEquals(rootRef.toString(), "http://10.0.2.2:9000");

DatabaseReference urlReference = db.getReferenceFromUrl("https://otherns.firebaseio.com");
assertEquals(urlReference.toString(), "http://10.0.2.2:9000");
}

@Test
public void getInstanceForAppWithEmulator_throwsIfSetLate() {
FirebaseApp app =
appForDatabaseUrl(
IntegrationTestValues.getAltNamespace(),
"getInstanceForAppWithEmulator_throwsIfSetLate");

FirebaseDatabase db = FirebaseDatabase.getInstance(app);
DatabaseReference rootRef = db.getReference();

try {
db.useEmulator("10.0.2.2", 9000);
fail("Expected to throw");
} catch (IllegalStateException e) {
// Expected to throw
}
}

@Test
public void getInstanceForAppWithUrl() {
FirebaseApp app =
Loading