getConditionalUserProperties();
+}
diff --git a/firebase-dynamic-links/src/test/java/com/google/firebase/dynamiclinks/internal/FakeAnalyticsConnector.java b/firebase-dynamic-links/src/test/java/com/google/firebase/dynamiclinks/internal/FakeAnalyticsConnector.java
new file mode 100644
index 00000000000..3e78d27cab8
--- /dev/null
+++ b/firebase-dynamic-links/src/test/java/com/google/firebase/dynamiclinks/internal/FakeAnalyticsConnector.java
@@ -0,0 +1,132 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.firebase.dynamiclinks.internal;
+
+import android.os.Bundle;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.firebase.analytics.connector.AnalyticsConnector;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * A fast, deterministic, fake implementation of AnalyticsConnector to be used for unit testing.
+ *
+ * It provides support for logging events, setting/getting user properties, and setting/getting
+ * conditional user properties.
+ */
+public class FakeAnalyticsConnector implements AnalyticsConnector, AnalyticsValidator {
+
+ private static final String CAMPAIGN_INFO_SOURCE = "_cis";
+ private static final String FCM_CONNECTOR_CAMPAIGN = "fcm_integration";
+ private final List events = new ArrayList<>();
+ private final Map userProperties = new HashMap<>();
+ private final List conditionalUserProperties = new ArrayList<>();
+
+ @Override
+ public AnalyticsConnectorHandle registerAnalyticsConnectorListener(
+ String origin, AnalyticsConnectorListener listener) {
+ return null;
+ }
+
+ @Override
+ public void logEvent(String origin, String name, Bundle params) {
+ if (origin.equals("fcm")) {
+ params.putString(CAMPAIGN_INFO_SOURCE, FCM_CONNECTOR_CAMPAIGN);
+ }
+ events.add(AnalyticsValidator.LoggedEvent.create(origin, name, params));
+ }
+
+ @Override
+ public void setUserProperty(String origin, String name, Object value) {
+ userProperties.put(name, value);
+ }
+
+ @Override
+ public Map getUserProperties(boolean includeInternal) {
+ ImmutableMap.Builder filteredProperties = ImmutableMap.builder();
+ for (Entry property : userProperties.entrySet()) {
+ if (includeInternal || !property.getKey().startsWith("_")) {
+ filteredProperties.put(property);
+ }
+ }
+ return filteredProperties.build();
+ }
+
+ @Override
+ public void setConditionalUserProperty(ConditionalUserProperty conditionalUserProperty) {
+ conditionalUserProperties.add(conditionalUserProperty);
+ }
+
+ @Override
+ public void clearConditionalUserProperty(
+ String userPropertyName, String clearEventName, Bundle clearEventParams) {
+ for (Iterator iterator = conditionalUserProperties.iterator();
+ iterator.hasNext(); ) {
+ ConditionalUserProperty conditionalUserProperty = iterator.next();
+ if (conditionalUserProperty.name.equals(userPropertyName)) {
+ iterator.remove();
+ logEvent(conditionalUserProperty.origin, clearEventName, clearEventParams);
+ }
+ }
+ }
+
+ @Override
+ public int getMaxUserProperties(String origin) {
+ return 25;
+ }
+
+ @Override
+ public List getConditionalUserProperties(
+ String origin, String propertyNamePrefix) {
+ ImmutableList.Builder filteredProperties = ImmutableList.builder();
+ for (ConditionalUserProperty property : conditionalUserProperties) {
+ if (property.origin.equals(origin) && property.name.startsWith(propertyNamePrefix)) {
+ filteredProperties.add(property);
+ }
+ }
+ return filteredProperties.build();
+ }
+
+ @Override
+ public List getConditionalUserProperties() {
+ return conditionalUserProperties;
+ }
+
+ @Override
+ public ImmutableList getLoggedEvents() {
+ return ImmutableList.copyOf(events);
+ }
+
+ @Override
+ public ImmutableList getLoggedEventNames() {
+ ImmutableList.Builder names = ImmutableList.builder();
+ for (AnalyticsValidator.LoggedEvent event : events) {
+ names.add(event.getName());
+ }
+ return names.build();
+ }
+
+ @Override
+ public void reset() {
+ events.clear();
+ userProperties.clear();
+ conditionalUserProperties.clear();
+ }
+}
diff --git a/firebase-dynamic-links/src/test/java/com/google/firebase/dynamiclinks/internal/FakeConnectorComponent.java b/firebase-dynamic-links/src/test/java/com/google/firebase/dynamiclinks/internal/FakeConnectorComponent.java
new file mode 100644
index 00000000000..e9ce91f14e7
--- /dev/null
+++ b/firebase-dynamic-links/src/test/java/com/google/firebase/dynamiclinks/internal/FakeConnectorComponent.java
@@ -0,0 +1,53 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.firebase.dynamiclinks.internal;
+
+import com.google.firebase.analytics.connector.AnalyticsConnector;
+import com.google.firebase.components.Component;
+import com.google.firebase.components.ComponentRegistrar;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A component that injects a FakeAnalyticsConnector.
+ *
+ * The FakeAnalyticsConnector should be used in open source testing to validate interactions with
+ * the AnalyticsConnector. Use getAnalyticsValidator() for validating.
+ */
+public final class FakeConnectorComponent implements ComponentRegistrar {
+
+ private static final FakeAnalyticsConnector analyticsConnector = new FakeAnalyticsConnector();
+
+ @Override
+ public List> getComponents() {
+ Component connector =
+ Component.builder(AnalyticsConnector.class)
+ .factory(container -> analyticsConnector)
+ .build();
+ return Arrays.asList(connector);
+ }
+
+ /**
+ * Returns an AnalyticsValidator that can be used to validate interactions with the
+ * FakeAnalyticsConnector.
+ */
+ public static AnalyticsValidator getAnalyticsValidator() {
+ return analyticsConnector;
+ }
+
+ /** Provides access to an instance of AnalyticsConnector. */
+ public static AnalyticsConnector getAnalyticsConnector() {
+ return analyticsConnector;
+ }
+}
diff --git a/firebase-dynamic-links/src/test/java/com/google/firebase/dynamiclinks/internal/FirebaseDynamicLinksImplTest.java b/firebase-dynamic-links/src/test/java/com/google/firebase/dynamiclinks/internal/FirebaseDynamicLinksImplTest.java
index 561cddad904..dabb358e9a8 100644
--- a/firebase-dynamic-links/src/test/java/com/google/firebase/dynamiclinks/internal/FirebaseDynamicLinksImplTest.java
+++ b/firebase-dynamic-links/src/test/java/com/google/firebase/dynamiclinks/internal/FirebaseDynamicLinksImplTest.java
@@ -40,6 +40,7 @@
import com.google.firebase.dynamiclinks.PendingDynamicLinkData;
import com.google.firebase.dynamiclinks.ShortDynamicLink;
import com.google.firebase.dynamiclinks.internal.FirebaseDynamicLinksImpl.CreateShortDynamicLinkImpl;
+import com.google.firebase.inject.Provider;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -72,7 +73,11 @@ public class FirebaseDynamicLinksImplTest {
private static final String ANALYTICS_FDL_ORIGIN = "fdl";
- @Mock private AnalyticsConnector mockAnalytics;
+ private final AnalyticsValidator fakeAppMeasurement =
+ FakeConnectorComponent.getAnalyticsValidator();
+ private final Provider mockAnalytics =
+ FakeConnectorComponent::getAnalyticsConnector;
+
@Mock private DynamicLinksApi mockGoogleApi;
@Mock private TaskCompletionSource mockCompletionSource;
@Mock private TaskCompletionSource mockShortFDLCompletionSource;
@@ -90,6 +95,7 @@ private static Bundle createDynamicLinkBundle() {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ fakeAppMeasurement.reset();
FirebaseApp.clearInstancesForTest();
FirebaseOptions.Builder firebaseOptionsBuilder =
new FirebaseOptions.Builder().setApplicationId("application_id").setApiKey("api_key");
@@ -102,7 +108,7 @@ public void setUp() throws Exception {
.buildUpon()
.appendQueryParameter("url", "http://example.google.com")
.build();
- api = new FirebaseDynamicLinksImpl(mockGoogleApi, mockAnalytics);
+ api = new FirebaseDynamicLinksImpl(mockGoogleApi, firebaseApp, mockAnalytics);
}
@Test
@@ -195,6 +201,10 @@ public void testDynamicLinkCallbacks_onGetDynamicLink() {
DynamicLinkData data = genDynamicLinkData(scionParams);
callbacks.onGetDynamicLink(Status.RESULT_SUCCESS, data);
verify(mockCompletionSource).setResult(any(PendingDynamicLinkData.class));
+ AnalyticsValidator.LoggedEvent event = fakeAppMeasurement.getLoggedEvents().get(0);
+ assertEquals(ANALYTICS_FDL_ORIGIN, event.getOrigin());
+ assertEquals(SCION_EVENT_NAME, event.getName());
+ assertEquals(scionParams, event.getParams());
}
@Test
@@ -202,7 +212,7 @@ public void testDynamicLinkCallbacks_onGetDynamicLink_missingAnalytics() {
// Make sure that a result is returned even if scion is not linked.
FirebaseDynamicLinksImpl.DynamicLinkCallbacks callbacks =
new FirebaseDynamicLinksImpl.DynamicLinkCallbacks(
- /* analytics= */ null, mockCompletionSource);
+ /* analytics= */ () -> null, mockCompletionSource);
DynamicLinkData data = genDynamicLinkData(new Bundle());
callbacks.onGetDynamicLink(Status.RESULT_SUCCESS, data);
verify(mockCompletionSource).setResult(any(PendingDynamicLinkData.class));