Skip to content

Commit 039195e

Browse files
authored
Merge branch 'main' into daymon-add-clean-command
2 parents 2e122e4 + 91a74cc commit 039195e

File tree

15 files changed

+457
-86
lines changed

15 files changed

+457
-86
lines changed

firebase-crashlytics/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Unreleased
2-
2+
* [feature] Added an overload for `recordException` that allows logging additional custom
3+
keys to the non fatal event [#3551]
34

45
# 19.3.0
56
* [fixed] Fixed inefficiency in the Kotlin `FirebaseCrashlytics.setCustomKeys` extension.

firebase-crashlytics/api.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@ package com.google.firebase.crashlytics {
2020
method public void deleteUnsentReports();
2121
method public boolean didCrashOnPreviousExecution();
2222
method @NonNull public static com.google.firebase.crashlytics.FirebaseCrashlytics getInstance();
23+
method public boolean isCrashlyticsCollectionEnabled();
2324
method public void log(@NonNull String);
2425
method public void recordException(@NonNull Throwable);
26+
method public void recordException(@NonNull Throwable, @NonNull com.google.firebase.crashlytics.CustomKeysAndValues);
2527
method public void sendUnsentReports();
26-
method public boolean isCrashlyticsCollectionEnabled();
2728
method public void setCrashlyticsCollectionEnabled(boolean);
2829
method public void setCrashlyticsCollectionEnabled(@Nullable Boolean);
2930
method public void setCustomKey(@NonNull String, boolean);
@@ -38,11 +39,12 @@ package com.google.firebase.crashlytics {
3839

3940
public final class FirebaseCrashlyticsKt {
4041
method @NonNull public static com.google.firebase.crashlytics.FirebaseCrashlytics getCrashlytics(@NonNull com.google.firebase.Firebase);
42+
method public static void recordException(@NonNull com.google.firebase.crashlytics.FirebaseCrashlytics, @NonNull Throwable throwable, @NonNull kotlin.jvm.functions.Function1<? super com.google.firebase.crashlytics.KeyValueBuilder,kotlin.Unit> init);
4143
method public static void setCustomKeys(@NonNull com.google.firebase.crashlytics.FirebaseCrashlytics, @NonNull kotlin.jvm.functions.Function1<? super com.google.firebase.crashlytics.KeyValueBuilder,kotlin.Unit> init);
4244
}
4345

4446
public final class KeyValueBuilder {
45-
ctor public KeyValueBuilder(@NonNull com.google.firebase.crashlytics.FirebaseCrashlytics crashlytics);
47+
ctor @Deprecated public KeyValueBuilder(@NonNull com.google.firebase.crashlytics.FirebaseCrashlytics crashlytics);
4648
method public void key(@NonNull String key, boolean value);
4749
method public void key(@NonNull String key, double value);
4850
method public void key(@NonNull String key, float value);

firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/CrashlyticsTests.kt

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,21 +62,36 @@ class CrashlyticsTests {
6262
@Test
6363
fun keyValueBuilder() {
6464
val keyValueBuilder = KeyValueBuilder()
65-
keyValueBuilder.key("hello", "world")
66-
keyValueBuilder.key("hello2", 23)
67-
keyValueBuilder.key("hello3", 0.1)
65+
keyValueBuilder.key("string", "world")
66+
keyValueBuilder.key("int", Int.MAX_VALUE)
67+
keyValueBuilder.key("float", Float.MAX_VALUE)
68+
keyValueBuilder.key("boolean", true)
69+
keyValueBuilder.key("double", Double.MAX_VALUE)
70+
keyValueBuilder.key("long", Long.MAX_VALUE)
6871

6972
val result: Map<String, String> = keyValueBuilder.build().keysAndValues
7073

71-
assertThat(result).containsExactly("hello", "world", "hello2", "23", "hello3", "0.1")
74+
val expectedKeys =
75+
mapOf(
76+
"string" to "world",
77+
"int" to "${Int.MAX_VALUE}",
78+
"float" to "${Float.MAX_VALUE}",
79+
"boolean" to "${true}",
80+
"double" to "${Double.MAX_VALUE}",
81+
"long" to "${Long.MAX_VALUE}"
82+
)
83+
assertThat(result).isEqualTo(expectedKeys)
7284
}
7385

7486
@Test
7587
fun keyValueBuilder_withCrashlyticsInstance() {
7688
@Suppress("DEPRECATION") val keyValueBuilder = KeyValueBuilder(Firebase.crashlytics)
77-
keyValueBuilder.key("hello", "world")
78-
keyValueBuilder.key("hello2", 23)
79-
keyValueBuilder.key("hello3", 0.1)
89+
keyValueBuilder.key("string", "world")
90+
keyValueBuilder.key("int", Int.MAX_VALUE)
91+
keyValueBuilder.key("float", Float.MAX_VALUE)
92+
keyValueBuilder.key("boolean", true)
93+
keyValueBuilder.key("double", Double.MAX_VALUE)
94+
keyValueBuilder.key("long", Long.MAX_VALUE)
8095

8196
val result: Map<String, String> = keyValueBuilder.build().keysAndValues
8297

firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsControllerTest.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import com.google.firebase.crashlytics.internal.NativeSessionFileProvider;
4545
import com.google.firebase.crashlytics.internal.analytics.AnalyticsEventLogger;
4646
import com.google.firebase.crashlytics.internal.concurrency.CrashlyticsWorkers;
47+
import com.google.firebase.crashlytics.internal.metadata.EventMetadata;
4748
import com.google.firebase.crashlytics.internal.metadata.LogFileManager;
4849
import com.google.firebase.crashlytics.internal.metadata.UserMetadata;
4950
import com.google.firebase.crashlytics.internal.model.CrashlyticsReport;
@@ -57,6 +58,7 @@
5758
import java.util.Arrays;
5859
import java.util.Collections;
5960
import java.util.List;
61+
import java.util.Map;
6062
import java.util.TreeSet;
6163
import java.util.concurrent.Executor;
6264
import java.util.concurrent.TimeUnit;
@@ -216,14 +218,14 @@ public void testWriteNonFatal_callsSessionReportingCoordinatorPersistNonFatal()
216218
when(mockSessionReportingCoordinator.listSortedOpenSessionIds())
217219
.thenReturn(new TreeSet<>(Collections.singleton(sessionId)));
218220

219-
controller.writeNonFatalException(thread, nonFatal);
221+
controller.writeNonFatalException(thread, nonFatal, Map.of());
220222
crashlyticsWorkers.common.submit(() -> controller.doCloseSessions(testSettingsProvider));
221223

222224
crashlyticsWorkers.common.await();
223225
crashlyticsWorkers.diskWrite.await();
224226

225227
verify(mockSessionReportingCoordinator)
226-
.persistNonFatalEvent(eq(nonFatal), eq(thread), eq(sessionId), anyLong());
228+
.persistNonFatalEvent(eq(nonFatal), eq(thread), any(EventMetadata.class));
227229
}
228230

229231
@SdkSuppress(minSdkVersion = 30) // ApplicationExitInfo
@@ -377,7 +379,7 @@ public void testLoggedExceptionsAfterCrashOk() {
377379
testSettingsProvider, Thread.currentThread(), new RuntimeException());
378380

379381
// This should not throw.
380-
controller.writeNonFatalException(Thread.currentThread(), new RuntimeException());
382+
controller.writeNonFatalException(Thread.currentThread(), new RuntimeException(), Map.of());
381383
}
382384

383385
/**

firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsCoreTest.java

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,143 @@ public void testCustomAttributes() throws Exception {
159159
assertEquals(longValue, metadata.getCustomKeys().get(key1));
160160
}
161161

162+
@Test
163+
public void testCustomAttributes_retrievedWithEmptyEventKeys() throws Exception {
164+
UserMetadata metadata = crashlyticsCore.getController().getUserMetadata();
165+
166+
assertTrue(metadata.getCustomKeys(Map.of()).isEmpty());
167+
168+
final String id = "id012345";
169+
crashlyticsCore.setUserId(id);
170+
crashlyticsWorkers.common.await();
171+
assertEquals(id, metadata.getUserId());
172+
173+
final StringBuffer idBuffer = new StringBuffer(id);
174+
while (idBuffer.length() < UserMetadata.MAX_ATTRIBUTE_SIZE) {
175+
idBuffer.append("0");
176+
}
177+
final String longId = idBuffer.toString();
178+
final String superLongId = longId + "more chars";
179+
180+
crashlyticsCore.setUserId(superLongId);
181+
crashlyticsWorkers.common.await();
182+
assertEquals(longId, metadata.getUserId());
183+
184+
final String key1 = "key1";
185+
final String value1 = "value1";
186+
crashlyticsCore.setCustomKey(key1, value1);
187+
crashlyticsWorkers.common.await();
188+
assertEquals(value1, metadata.getCustomKeys(Map.of()).get(key1));
189+
190+
// Adding an existing key with the same value should return false
191+
assertFalse(metadata.setCustomKey(key1, value1));
192+
assertTrue(metadata.setCustomKey(key1, "someOtherValue"));
193+
assertTrue(metadata.setCustomKey(key1, value1));
194+
assertFalse(metadata.setCustomKey(key1, value1));
195+
196+
final String longValue = longId.replaceAll("0", "x");
197+
final String superLongValue = longValue + "some more chars";
198+
199+
// test truncation of custom keys and attributes
200+
crashlyticsCore.setCustomKey(superLongId, superLongValue);
201+
crashlyticsWorkers.common.await();
202+
assertNull(metadata.getCustomKeys(Map.of()).get(superLongId));
203+
assertEquals(longValue, metadata.getCustomKeys().get(longId));
204+
205+
// test the max number of attributes. We've already set 2.
206+
for (int i = 2; i < UserMetadata.MAX_ATTRIBUTES; ++i) {
207+
final String key = "key" + i;
208+
final String value = "value" + i;
209+
crashlyticsCore.setCustomKey(key, value);
210+
crashlyticsWorkers.common.await();
211+
assertEquals(value, metadata.getCustomKeys(Map.of()).get(key));
212+
}
213+
// should be full now, extra key, value pairs will be dropped.
214+
final String key = "new key";
215+
crashlyticsCore.setCustomKey(key, "some value");
216+
crashlyticsWorkers.common.await();
217+
assertFalse(metadata.getCustomKeys(Map.of()).containsKey(key));
218+
219+
// should be able to update existing keys
220+
crashlyticsCore.setCustomKey(key1, longValue);
221+
crashlyticsWorkers.common.await();
222+
assertEquals(longValue, metadata.getCustomKeys(Map.of()).get(key1));
223+
224+
// when we set a key to null, it should still exist with an empty value
225+
crashlyticsCore.setCustomKey(key1, null);
226+
crashlyticsWorkers.common.await();
227+
assertEquals("", metadata.getCustomKeys(Map.of()).get(key1));
228+
229+
// keys and values are trimmed.
230+
crashlyticsCore.setCustomKey(" " + key1 + " ", " " + longValue + " ");
231+
crashlyticsWorkers.common.await();
232+
assertTrue(metadata.getCustomKeys(Map.of()).containsKey(key1));
233+
assertEquals(longValue, metadata.getCustomKeys(Map.of()).get(key1));
234+
}
235+
236+
@Test
237+
public void testCustomKeysMergedWithEventKeys() throws Exception {
238+
UserMetadata metadata = crashlyticsCore.getController().getUserMetadata();
239+
240+
Map<String, String> keysAndValues = new HashMap<>();
241+
keysAndValues.put("customKey1", "value");
242+
keysAndValues.put("customKey2", "value");
243+
keysAndValues.put("customKey3", "value");
244+
245+
crashlyticsCore.setCustomKeys(keysAndValues);
246+
crashlyticsWorkers.common.await();
247+
248+
Map<String, String> eventKeysAndValues = new HashMap<>();
249+
eventKeysAndValues.put("eventKey1", "eventValue");
250+
eventKeysAndValues.put("eventKey2", "eventValue");
251+
252+
// Tests reading custom keys with event keys.
253+
assertEquals(keysAndValues.size(), metadata.getCustomKeys().size());
254+
assertEquals(keysAndValues.size(), metadata.getCustomKeys(Map.of()).size());
255+
assertEquals(
256+
keysAndValues.size() + eventKeysAndValues.size(),
257+
metadata.getCustomKeys(eventKeysAndValues).size());
258+
259+
// Tests event keys don't add to custom keys in future reads.
260+
assertEquals(keysAndValues.size(), metadata.getCustomKeys().size());
261+
assertEquals(keysAndValues.size(), metadata.getCustomKeys(Map.of()).size());
262+
263+
// Tests additional event keys.
264+
eventKeysAndValues.put("eventKey3", "eventValue");
265+
eventKeysAndValues.put("eventKey4", "eventValue");
266+
assertEquals(
267+
keysAndValues.size() + eventKeysAndValues.size(),
268+
metadata.getCustomKeys(eventKeysAndValues).size());
269+
270+
// Tests overriding custom key with event keys.
271+
keysAndValues.put("eventKey1", "value");
272+
crashlyticsCore.setCustomKeys(keysAndValues);
273+
crashlyticsWorkers.common.await();
274+
275+
assertEquals("value", metadata.getCustomKeys().get("eventKey1"));
276+
assertEquals("value", metadata.getCustomKeys(Map.of()).get("eventKey1"));
277+
assertEquals("eventValue", metadata.getCustomKeys(eventKeysAndValues).get("eventKey1"));
278+
279+
// Test the event key behavior when the count of custom keys is max.
280+
for (int i = keysAndValues.size(); i < UserMetadata.MAX_ATTRIBUTES; ++i) {
281+
final String key = "key" + i;
282+
final String value = "value" + i;
283+
crashlyticsCore.setCustomKey(key, value);
284+
crashlyticsWorkers.common.await();
285+
assertEquals(value, metadata.getCustomKeys().get(key));
286+
}
287+
288+
assertEquals(UserMetadata.MAX_ATTRIBUTES, metadata.getCustomKeys().size());
289+
290+
// Tests event keys override global custom keys when the key exists.
291+
assertEquals("value", metadata.getCustomKeys().get("eventKey1"));
292+
assertEquals("value", metadata.getCustomKeys(Map.of()).get("eventKey1"));
293+
assertEquals("eventValue", metadata.getCustomKeys(eventKeysAndValues).get("eventKey1"));
294+
295+
// Test when event keys *don't* override global custom keys.
296+
assertNull(metadata.getCustomKeys(eventKeysAndValues).get("eventKey2"));
297+
}
298+
162299
@Test
163300
public void testBulkCustomKeys() throws Exception {
164301
final double DELTA = 1e-15;

0 commit comments

Comments
 (0)