Skip to content

[Remote Config] add useEmulator to Remote Config SDK #3806

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

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions firebase-config/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ package com.google.firebase.remoteconfig {
method @NonNull public com.google.android.gms.tasks.Task<java.lang.Void> setConfigSettingsAsync(@NonNull com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings);
method @NonNull public com.google.android.gms.tasks.Task<java.lang.Void> setDefaultsAsync(@NonNull java.util.Map<java.lang.String,java.lang.Object>);
method @NonNull public com.google.android.gms.tasks.Task<java.lang.Void> setDefaultsAsync(@XmlRes int);
method public void useEmulator(@NonNull String, int);
field public static final boolean DEFAULT_VALUE_FOR_BOOLEAN = false;
field public static final byte[] DEFAULT_VALUE_FOR_BYTE_ARRAY;
field public static final double DEFAULT_VALUE_FOR_DOUBLE = 0.0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.google.firebase.abt.AbtException;
import com.google.firebase.abt.FirebaseABTesting;
import com.google.firebase.concurrent.FirebaseExecutors;
import com.google.firebase.emulators.EmulatedServiceSettings;
import com.google.firebase.installations.FirebaseInstallationsApi;
import com.google.firebase.installations.InstallationTokenResult;
import com.google.firebase.remoteconfig.internal.ConfigCacheClient;
Expand Down Expand Up @@ -571,6 +572,24 @@ public ConfigUpdateListenerRegistration addOnConfigUpdateListener(
return configRealtimeHandler.addRealtimeConfigUpdateListener(configUpdateListener);
}

/**
* Modifies this FirebaseRemoteConfig instance to communicate with the Firebase Remote Config
* emulator.
*
* <p>Note: Call this method before using the instance to do any Remote Config operations.
*
* @param host the emulator host (for example, 10.0.2.2)
* @param port the emulator port (for example, 9299)
* @exception FirebaseRemoteConfigClientException Thrown when useEmulator is called after a fetch.
*/
public void useEmulator(@NonNull String host, int port) {
if (this.frcMetadata.getInfo().getLastFetchStatus() != LAST_FETCH_STATUS_NO_FETCH_YET) {
throw new IllegalStateException(
"Cannot connect to emulator after a fetch has been made.");
}
fetchHandler.setEmulatedServiceSettings(new EmulatedServiceSettings(host, port));
}

/**
* Loads all the configs from disk by calling {@link ConfigCacheClient#get} on each cache client.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.Tasks;
import com.google.firebase.analytics.connector.AnalyticsConnector;
import com.google.firebase.emulators.EmulatedServiceSettings;
import com.google.firebase.inject.Provider;
import com.google.firebase.installations.FirebaseInstallationsApi;
import com.google.firebase.installations.InstallationTokenResult;
Expand Down Expand Up @@ -223,6 +224,10 @@ public Task<FetchResponse> fetchNowWithTypeAndAttemptNumber(
copyOfCustomHttpHeaders));
}

public void setEmulatedServiceSettings(EmulatedServiceSettings emulatedServiceSettings) {
frcBackendApiClient.setEmulatedServiceSettings(emulatedServiceSettings);
}

/**
* Fetches from the backend if the fetched configs cache has expired and the client is not
* currently throttled.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,12 @@
import android.os.Build;
import android.util.Log;
import androidx.annotation.Keep;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.core.content.pm.PackageInfoCompat;
import com.google.android.gms.common.util.AndroidUtilsLight;
import com.google.android.gms.common.util.Hex;
import com.google.firebase.emulators.EmulatedServiceSettings;
import com.google.firebase.remoteconfig.BuildConfig;
import com.google.firebase.remoteconfig.FirebaseRemoteConfigClientException;
import com.google.firebase.remoteconfig.FirebaseRemoteConfigException;
Expand Down Expand Up @@ -94,6 +96,7 @@ public class ConfigFetchHttpClient {
private final String namespace;
private final long connectTimeoutInSeconds;
private final long readTimeoutInSeconds;
@Nullable private EmulatedServiceSettings emulatedServiceSettings;

/** ISO-8601 UTC timestamp format. */
private static final String ISO_DATE_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
Expand Down Expand Up @@ -127,6 +130,10 @@ public long getReadTimeoutInSeconds() {
return readTimeoutInSeconds;
}

void setEmulatedServiceSettings(EmulatedServiceSettings emulatedServiceSettings) {
this.emulatedServiceSettings = emulatedServiceSettings;
}

/**
* A regular expression for the GMP App Id format. The first group (index 1) is the project
* number.
Expand Down Expand Up @@ -243,6 +250,17 @@ private void setUpUrlConnection(
}

private String getFetchUrl(String projectNumber, String namespace) {
if (emulatedServiceSettings != null) {
return "http://"
+ emulatedServiceSettings.getHost()
+ ":"
+ emulatedServiceSettings.getPort()
+ "/v1/projects/"
+ projectNumber
+ "/namespaces/"
+ namespace
+ ":fetch";
}
return String.format(FETCH_REGEX_URL, projectNumber, namespace);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import com.google.android.gms.common.util.MockClock;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableMap;
import com.google.firebase.emulators.EmulatedServiceSettings;
import com.google.firebase.remoteconfig.BuildConfig;
import com.google.firebase.remoteconfig.FirebaseRemoteConfigClientException;
import com.google.firebase.remoteconfig.FirebaseRemoteConfigException;
Expand Down Expand Up @@ -85,6 +86,8 @@ public class ConfigFetchHttpClientTest {
"etag-" + PROJECT_NUMBER + "-" + DEFAULT_NAMESPACE + "-fetch-%d";
private static final String FIRST_ETAG = String.format(ETAG_FORMAT, 1);
private static final String SECOND_ETAG = String.format(ETAG_FORMAT, 2);
private static final String FETCH_EMULATOR_REGEX_URL =
"http://10.0.2.2:9299/v1/projects/%s/namespaces/%s:fetch";

private Context context;
private ConfigFetchHttpClient configFetchHttpClient;
Expand Down Expand Up @@ -144,6 +147,16 @@ public void createHttpURLConnection_returnsHttpURLConnectionWithValidFetchURL()
.isEqualTo(String.format(FETCH_REGEX_URL, PROJECT_NUMBER, DEFAULT_NAMESPACE));
}

@Test
public void createHttpURLConnection_withEmulator() throws Exception {
configFetchHttpClient.setEmulatedServiceSettings(new EmulatedServiceSettings("10.0.2.2", 9299));

HttpURLConnection urlConnection = configFetchHttpClient.createHttpURLConnection();

assertThat(urlConnection.getURL().toString())
.isEqualTo(String.format(FETCH_EMULATOR_REGEX_URL, PROJECT_NUMBER, DEFAULT_NAMESPACE));
}

@Test
public void fetch_newValues_responseSet() throws Exception {
setServerResponseTo(hasChangeResponseBody, SECOND_ETAG);
Expand Down