From edfef058ae346bea8370763485e075f70985d980 Mon Sep 17 00:00:00 2001 From: Andrew McKnight Date: Thu, 17 Aug 2023 15:28:17 -0800 Subject: [PATCH 1/7] feat: add more db info on span data --- Sources/Sentry/SentryCoreDataTracker.m | 69 ++++++++++++++------------ 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/Sources/Sentry/SentryCoreDataTracker.m b/Sources/Sentry/SentryCoreDataTracker.m index df75fd8c8c1..fea6e6fbd95 100644 --- a/Sources/Sentry/SentryCoreDataTracker.m +++ b/Sources/Sentry/SentryCoreDataTracker.m @@ -44,23 +44,18 @@ - (NSArray *)managedObjectContext:(NSManagedObjectContext *)context }]; if (fetchSpan) { - [SentryLog - logWithMessage:[NSString stringWithFormat: - @"SentryCoreDataTracker automatically " - @"started a new span with description: %@, operation: %@", - fetchSpan.description, SENTRY_COREDATA_FETCH_OPERATION] - andLevel:kSentryLevelDebug]; + SENTRY_LOG_DEBUG(@"SentryCoreDataTracker automatically started a new span with " + @"description: %@, operation: %@", + fetchSpan.description, fetchSpan.operation); } else { - [SentryLog - logWithMessage: - @"managedObjectContext:executeFetchRequest:error:originalImp: fetchSpan is nil." - andLevel:kSentryLevelError]; + SENTRY_LOG_ERROR( + @"managedObjectContext:executeFetchRequest:error:originalImp: fetchSpan is nil."); } NSArray *result = original(request, error); if (fetchSpan) { - [self mainThreadExtraInfo:fetchSpan]; + [self addExtraInfoToSpan:fetchSpan withContext:context]; [fetchSpan setDataValue:[NSNumber numberWithInteger:result.count] forKey:@"read_count"]; [fetchSpan @@ -78,35 +73,34 @@ - (BOOL)managedObjectContext:(NSManagedObjectContext *)context originalImp:(BOOL(NS_NOESCAPE ^)(NSError **))original { - __block id fetchSpan = nil; + __block id saveSpan = nil; if (context.hasChanges) { __block NSDictionary *operations = [self groupEntitiesOperations:context]; [SentrySDK.currentHub.scope useSpan:^(id _Nullable span) { - fetchSpan = [span startChildWithOperation:SENTRY_COREDATA_SAVE_OPERATION - description:[self descriptionForOperations:operations - inContext:context]]; - fetchSpan.origin = SentryTraceOriginAutoDBCoreData; - if (fetchSpan) { - [SentryLog - logWithMessage:[NSString - stringWithFormat:@"SentryCoreDataTracker automatically " - @"started a new span with description: %@, " - @"operation: %@", - fetchSpan.description, SENTRY_COREDATA_FETCH_OPERATION] - andLevel:kSentryLevelDebug]; - - [fetchSpan setDataValue:operations forKey:@"operations"]; - } + saveSpan = [span startChildWithOperation:SENTRY_COREDATA_SAVE_OPERATION + description:[self descriptionForOperations:operations + inContext:context]]; + saveSpan.origin = SentryTraceOriginAutoDBCoreData; }]; + + if (saveSpan) { + SENTRY_LOG_DEBUG(@"SentryCoreDataTracker automatically started a new span with " + @"description: %@, operation: %@", + saveSpan.description, saveSpan.operation); + + [saveSpan setDataValue:operations forKey:@"operations"]; + } else { + SENTRY_LOG_ERROR(@"managedObjectContext:save:originalImp: saveSpan is nil"); + } } BOOL result = original(error); - if (fetchSpan) { - [self mainThreadExtraInfo:fetchSpan]; - [fetchSpan finishWithStatus:result ? kSentrySpanStatusOk : kSentrySpanStatusInternalError]; + if (saveSpan) { + [self addExtraInfoToSpan:saveSpan withContext:context]; + [saveSpan finishWithStatus:result ? kSentrySpanStatusOk : kSentrySpanStatusInternalError]; SENTRY_LOG_DEBUG(@"SentryCoreDataTracker automatically finished span with status: %@", result ? @"ok" : @"error"); @@ -115,11 +109,24 @@ - (BOOL)managedObjectContext:(NSManagedObjectContext *)context return result; } -- (void)mainThreadExtraInfo:(SentrySpan *)span +- (void)addExtraInfoToSpan:(SentrySpan *)span withContext:(NSManagedObjectContext *)context { BOOL isMainThread = [NSThread isMainThread]; [span setDataValue:@(isMainThread) forKey:BLOCKED_MAIN_THREAD]; + NSMutableArray *systems = [NSMutableArray array]; + NSMutableArray *names = [NSMutableArray array]; + [context.persistentStoreCoordinator.persistentStores enumerateObjectsUsingBlock:^( + __kindof NSPersistentStore *_Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) { + [systems addObject:obj.type]; + if (obj.URL != nil) { + [names addObject:obj.URL.path]; + } else { + [names addObject:@"(null)"]; + } + }]; + [span setDataValue:[systems componentsJoinedByString:@";"] forKey:@"db.system"]; + [span setDataValue:[names componentsJoinedByString:@";"] forKey:@"db.name"]; if (!isMainThread) { return; From 43fb9d01c86b7ccf77c586e3bd0d2809f4f07ded Mon Sep 17 00:00:00 2001 From: Andrew McKnight Date: Thu, 17 Aug 2023 15:38:35 -0800 Subject: [PATCH 2/7] changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1de993546ca..11a120bd9db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ ### Features +### Features + +- Report database backing store information for Core Data (#3231) + ## 8.10.0 ### Features From 87fed6ca65b0738f234770622989001e7f281c33 Mon Sep 17 00:00:00 2001 From: Andrew McKnight Date: Thu, 17 Aug 2023 16:08:49 -0800 Subject: [PATCH 3/7] tests --- .../CoreData/SentryCoreDataTrackerTest.swift | 173 ++++++++---------- .../CoreData/TestCoreDataStack.swift | 50 ++++- 2 files changed, 120 insertions(+), 103 deletions(-) diff --git a/Tests/SentryTests/Integrations/Performance/CoreData/SentryCoreDataTrackerTest.swift b/Tests/SentryTests/Integrations/Performance/CoreData/SentryCoreDataTrackerTest.swift index 803c813d747..ec17c57ffdf 100644 --- a/Tests/SentryTests/Integrations/Performance/CoreData/SentryCoreDataTrackerTest.swift +++ b/Tests/SentryTests/Integrations/Performance/CoreData/SentryCoreDataTrackerTest.swift @@ -5,7 +5,10 @@ import XCTest class SentryCoreDataTrackerTests: XCTestCase { private class Fixture { - let context = TestNSManagedObjectContext() + let coreDataStack = TestCoreDataStack() + lazy var context: TestNSManagedObjectContext = { + coreDataStack.managedObjectContext + }() let threadInspector = TestThreadInspector.instance let imageProvider = TestDebugImageProvider() @@ -51,121 +54,121 @@ class SentryCoreDataTrackerTests: XCTestCase { XCTAssertEqual(SENTRY_COREDATA_SAVE_OPERATION, "db.sql.transaction") } - func testFetchRequest() { + func testFetchRequest() throws { let fetch = NSFetchRequest(entityName: "TestEntity") - assertRequest(fetch, expectedDescription: "SELECT 'TestEntity'") + try assertRequest(fetch, expectedDescription: "SELECT 'TestEntity'") } func testFetchRequestBackgroundThread() { let expect = expectation(description: "Operation in background thread") DispatchQueue.global(qos: .default).async { let fetch = NSFetchRequest(entityName: "TestEntity") - self.assertRequest(fetch, expectedDescription: "SELECT 'TestEntity'", mainThread: false) + try? self.assertRequest(fetch, expectedDescription: "SELECT 'TestEntity'", mainThread: false) expect.fulfill() } wait(for: [expect], timeout: 1.0) } - func test_FetchRequest_WithPredicate() { + func test_FetchRequest_WithPredicate() throws { let fetch = NSFetchRequest(entityName: "TestEntity") fetch.predicate = NSPredicate(format: "field1 = %@ and field2 = %@", argumentArray: ["First Argument", 2]) - assertRequest(fetch, expectedDescription: "SELECT 'TestEntity' WHERE field1 == %@ AND field2 == %@") + try assertRequest(fetch, expectedDescription: "SELECT 'TestEntity' WHERE field1 == %@ AND field2 == %@") } - func test_FetchRequest_WithSortAscending() { + func test_FetchRequest_WithSortAscending() throws { let fetch = NSFetchRequest(entityName: "TestEntity") fetch.sortDescriptors = [NSSortDescriptor(key: "field1", ascending: true)] - assertRequest(fetch, expectedDescription: "SELECT 'TestEntity' SORT BY field1") + try assertRequest(fetch, expectedDescription: "SELECT 'TestEntity' SORT BY field1") } - func test_FetchRequest_WithSortDescending() { + func test_FetchRequest_WithSortDescending() throws { let fetch = NSFetchRequest(entityName: "TestEntity") fetch.sortDescriptors = [NSSortDescriptor(key: "field1", ascending: false)] - assertRequest(fetch, expectedDescription: "SELECT 'TestEntity' SORT BY field1 DESCENDING") + try assertRequest(fetch, expectedDescription: "SELECT 'TestEntity' SORT BY field1 DESCENDING") } - func test_FetchRequest_WithSortTwoFields() { + func test_FetchRequest_WithSortTwoFields() throws { let fetch = NSFetchRequest(entityName: "TestEntity") fetch.sortDescriptors = [NSSortDescriptor(key: "field1", ascending: false), NSSortDescriptor(key: "field2", ascending: true)] - assertRequest(fetch, expectedDescription: "SELECT 'TestEntity' SORT BY field1 DESCENDING, field2") + try assertRequest(fetch, expectedDescription: "SELECT 'TestEntity' SORT BY field1 DESCENDING, field2") } - func test_FetchRequest_WithPredicateAndSort() { + func test_FetchRequest_WithPredicateAndSort() throws { let fetch = NSFetchRequest(entityName: "TestEntity") fetch.predicate = NSPredicate(format: "field1 = %@", argumentArray: ["First Argument"]) fetch.sortDescriptors = [NSSortDescriptor(key: "field1", ascending: false)] - assertRequest(fetch, expectedDescription: "SELECT 'TestEntity' WHERE field1 == %@ SORT BY field1 DESCENDING") + try assertRequest(fetch, expectedDescription: "SELECT 'TestEntity' WHERE field1 == %@ SORT BY field1 DESCENDING") } - func test_Save_1Insert_1Entity() { + func test_Save_1Insert_1Entity() throws { fixture.context.inserted = [fixture.testEntity()] - assertSave("INSERTED 1 'TestEntity'") + try assertSave("INSERTED 1 'TestEntity'") } func testSaveBackgroundThread() { let expect = expectation(description: "Operation in background thread") DispatchQueue.global(qos: .default).async { self.fixture.context.inserted = [self.fixture.testEntity()] - self.assertSave("INSERTED 1 'TestEntity'", mainThread: false) + try? self.assertSave("INSERTED 1 'TestEntity'", mainThread: false) expect.fulfill() } wait(for: [expect], timeout: 1.0) } - func test_Save_2Insert_1Entity() { + func test_Save_2Insert_1Entity() throws { fixture.context.inserted = [fixture.testEntity(), fixture.testEntity()] - assertSave("INSERTED 2 'TestEntity'") + try assertSave("INSERTED 2 'TestEntity'") } - func test_Save_2Insert_2Entity() { + func test_Save_2Insert_2Entity() throws { fixture.context.inserted = [fixture.testEntity(), fixture.secondTestEntity()] - assertSave("INSERTED 2 items") + try assertSave("INSERTED 2 items") } - func test_Save_1Update_1Entity() { + func test_Save_1Update_1Entity() throws { fixture.context.updated = [fixture.testEntity()] - assertSave("UPDATED 1 'TestEntity'") + try assertSave("UPDATED 1 'TestEntity'") } - func test_Save_2Update_1Entity() { + func test_Save_2Update_1Entity() throws { fixture.context.updated = [fixture.testEntity(), fixture.testEntity()] - assertSave("UPDATED 2 'TestEntity'") + try assertSave("UPDATED 2 'TestEntity'") } - func test_Save_2Update_2Entity() { + func test_Save_2Update_2Entity() throws { fixture.context.updated = [fixture.testEntity(), fixture.secondTestEntity()] - assertSave("UPDATED 2 items") + try assertSave("UPDATED 2 items") } - func test_Save_1Delete_1Entity() { + func test_Save_1Delete_1Entity() throws { fixture.context.deleted = [fixture.testEntity()] - assertSave("DELETED 1 'TestEntity'") + try assertSave("DELETED 1 'TestEntity'") } - func test_Save_2Delete_1Entity() { + func test_Save_2Delete_1Entity() throws { fixture.context.deleted = [fixture.testEntity(), fixture.testEntity()] - assertSave("DELETED 2 'TestEntity'") + try assertSave("DELETED 2 'TestEntity'") } - func test_Save_2Delete_2Entity() { + func test_Save_2Delete_2Entity() throws { fixture.context.deleted = [fixture.testEntity(), fixture.secondTestEntity()] - assertSave("DELETED 2 items") + try assertSave("DELETED 2 items") } - func test_Save_Insert_Update_Delete_1Entity() { + func test_Save_Insert_Update_Delete_1Entity() throws { fixture.context.inserted = [fixture.testEntity()] fixture.context.updated = [fixture.testEntity()] fixture.context.deleted = [fixture.testEntity()] - assertSave("INSERTED 1 'TestEntity', UPDATED 1 'TestEntity', DELETED 1 'TestEntity'") + try assertSave("INSERTED 1 'TestEntity', UPDATED 1 'TestEntity', DELETED 1 'TestEntity'") } - func test_Save_Insert_Update_Delete_2Entity() { + func test_Save_Insert_Update_Delete_2Entity() throws { fixture.context.inserted = [fixture.testEntity(), fixture.secondTestEntity()] fixture.context.updated = [fixture.testEntity(), fixture.secondTestEntity()] fixture.context.deleted = [fixture.testEntity(), fixture.secondTestEntity()] - assertSave("INSERTED 2 items, UPDATED 2 items, DELETED 2 items") + try assertSave("INSERTED 2 items, UPDATED 2 items, DELETED 2 items") } func test_Operation_InData() { @@ -288,8 +291,12 @@ class SentryCoreDataTrackerTests: XCTestCase { XCTAssertEqual(transaction.children.count, 0) } - - func assertSave(_ expectedDescription: String, mainThread: Bool = true) { + +} + +private extension SentryCoreDataTrackerTests { + + func assertSave(_ expectedDescription: String, mainThread: Bool = true) throws { let sut = fixture.getSut() let transaction = startTransaction() @@ -298,26 +305,12 @@ class SentryCoreDataTrackerTests: XCTestCase { return true }) - guard let dbSpan = try? XCTUnwrap(transaction.children.first) else { - XCTFail("Span for DB operation don't exist.") - return - } - - XCTAssertEqual(dbSpan.operation, SENTRY_COREDATA_SAVE_OPERATION) - XCTAssertEqual(dbSpan.spanDescription, expectedDescription) - XCTAssertEqual(dbSpan.data["blocked_main_thread"] as? Bool ?? false, mainThread) - - if mainThread { - guard let frames = (dbSpan as? SentrySpan)?.frames else { - XCTFail("File IO Span in the main thread has no frames") - return - } - XCTAssertEqual(frames.first, TestData.mainFrame) - XCTAssertEqual(frames.last, TestData.testFrame) - } + let dbSpan = try XCTUnwrap(transaction.children.first) + + assertDataAndFrames(dbSpan: dbSpan, expectedOperation: SENTRY_COREDATA_SAVE_OPERATION, expectedDescription: expectedDescription, mainThread: mainThread) } - func assertRequest(_ fetch: NSFetchRequest, expectedDescription: String, mainThread: Bool = true) { + func assertRequest(_ fetch: NSFetchRequest, expectedDescription: String, mainThread: Bool = true) throws { let transaction = startTransaction() let sut = fixture.getSut() @@ -325,21 +318,23 @@ class SentryCoreDataTrackerTests: XCTestCase { let someEntity = fixture.testEntity() - let result = try? sut.fetchManagedObjectContext(context, request: fetch) { _, _ in + let result = try? sut.fetchManagedObjectContext(context, request: fetch) { _, _ in return [someEntity] } - guard let dbSpan = try? XCTUnwrap(transaction.children.first) else { - XCTFail("Span for DB operation don't exist.") - return - } + let dbSpan = try XCTUnwrap(transaction.children.first) XCTAssertEqual(result?.count, 1) - XCTAssertEqual(dbSpan.operation, SENTRY_COREDATA_FETCH_OPERATION) - XCTAssertEqual(dbSpan.origin, "auto.db.core_data") + + assertDataAndFrames(dbSpan: dbSpan, expectedOperation: SENTRY_COREDATA_FETCH_OPERATION, expectedDescription: expectedDescription, mainThread: mainThread) + } + + func assertDataAndFrames(dbSpan: Span, expectedOperation: String, expectedDescription: String, mainThread: Bool) { + XCTAssertEqual(dbSpan.operation, expectedOperation) XCTAssertEqual(dbSpan.spanDescription, expectedDescription) - XCTAssertEqual(dbSpan.data["read_count"] as? Int, 1) XCTAssertEqual(dbSpan.data["blocked_main_thread"] as? Bool ?? false, mainThread) + XCTAssertEqual(try XCTUnwrap(dbSpan.data["db.system"] as? String), "SQLite") + XCTAssert(try XCTUnwrap(dbSpan.data["db.name"] as? NSString).contains(TestCoreDataStack.databaseFilename)) if mainThread { guard let frames = (dbSpan as? SentrySpan)?.frames else { @@ -359,35 +354,19 @@ class SentryCoreDataTrackerTests: XCTestCase { } -class TestNSManagedObjectContext: NSManagedObjectContext { - - var inserted: Set? - var updated: Set? - var deleted: Set? - - override var insertedObjects: Set { - inserted ?? [] - } - - override var updatedObjects: Set { - updated ?? [] - } - - override var deletedObjects: Set { - deleted ?? [] - } - - init() { - super.init(concurrencyType: .mainQueueConcurrencyType) - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - } - - override var hasChanges: Bool { - return ((inserted?.count ?? 0) > 0) || - ((deleted?.count ?? 0) > 0) || - ((updated?.count ?? 0) > 0) - } -} +//class TestCoreDataStack { +// lazy var managedObjectModel = TestNSManagedObjectModel() +// lazy var persistentStoreCoordinator = TestNSPersistentStoreCoordinator(managedObjectModel: managedObjectModel) +// lazy var managedObjectContext = TestNSManagedObjectContext() +//} +// +//class TestNSManagedObjectModel: NSManagedObjectModel { +// +//} +// +//class TestNSPersistentStoreCoordinator: NSPersistentStoreCoordinator { +// override init(managedObjectModel model: NSManagedObjectModel) { +// super.init(managedObjectModel: model) +// try! addPersistentStore(ofType: NSInMemoryStoreType, configurationName: nil, at: nil) +// } +//} diff --git a/Tests/SentryTests/Integrations/Performance/CoreData/TestCoreDataStack.swift b/Tests/SentryTests/Integrations/Performance/CoreData/TestCoreDataStack.swift index b01e8ec9b8e..8a33f7bca70 100644 --- a/Tests/SentryTests/Integrations/Performance/CoreData/TestCoreDataStack.swift +++ b/Tests/SentryTests/Integrations/Performance/CoreData/TestCoreDataStack.swift @@ -56,9 +56,10 @@ class TestCoreDataStack { return model }() - + + static let databaseFilename = "SingleViewCoreData.sqlite" + lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = { - guard let tempDir = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first else { return nil } if !FileManager.default.fileExists(atPath: tempDir.path) { @@ -66,22 +67,22 @@ class TestCoreDataStack { } let coordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel) - let url = tempDir.appendingPathComponent("SingleViewCoreData.sqlite") + let url = tempDir.appendingPathComponent(TestCoreDataStack.databaseFilename) let _ = try? coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: nil) return coordinator }() - lazy var managedObjectContext: NSManagedObjectContext = { - var managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType) + lazy var managedObjectContext: TestNSManagedObjectContext = { + var managedObjectContext = TestNSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType) managedObjectContext.persistentStoreCoordinator = self.persistentStoreCoordinator return managedObjectContext }() func reset() { guard let tempDir = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first else { return } - let url = tempDir.appendingPathComponent("SingleViewCoreData.sqlite") + let url = tempDir.appendingPathComponent(TestCoreDataStack.databaseFilename) try? FileManager.default.removeItem(at: url) } @@ -99,3 +100,40 @@ class TestCoreDataStack { } } } + +class TestNSManagedObjectContext: NSManagedObjectContext { + + var inserted: Set? + var updated: Set? + var deleted: Set? + + override var insertedObjects: Set { + inserted ?? [] + } + + override var updatedObjects: Set { + updated ?? [] + } + + override var deletedObjects: Set { + deleted ?? [] + } + + init() { + super.init(concurrencyType: .mainQueueConcurrencyType) + } + + override init(concurrencyType ct: NSManagedObjectContextConcurrencyType) { + super.init(concurrencyType: ct) + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + } + + override var hasChanges: Bool { + return ((inserted?.count ?? 0) > 0) || + ((deleted?.count ?? 0) > 0) || + ((updated?.count ?? 0) > 0) + } +} From 1f31a08fb59c28ff82d91011426d4ae2c0a400d2 Mon Sep 17 00:00:00 2001 From: Andrew McKnight Date: Thu, 17 Aug 2023 16:14:05 -0800 Subject: [PATCH 4/7] fix test --- .../CoreData/SentryCoreDataTrackerTest.swift | 17 ----------------- .../CoreData/TestCoreDataStack.swift | 4 ++-- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/Tests/SentryTests/Integrations/Performance/CoreData/SentryCoreDataTrackerTest.swift b/Tests/SentryTests/Integrations/Performance/CoreData/SentryCoreDataTrackerTest.swift index ec17c57ffdf..e3c374dc4bb 100644 --- a/Tests/SentryTests/Integrations/Performance/CoreData/SentryCoreDataTrackerTest.swift +++ b/Tests/SentryTests/Integrations/Performance/CoreData/SentryCoreDataTrackerTest.swift @@ -353,20 +353,3 @@ private extension SentryCoreDataTrackerTests { } } - -//class TestCoreDataStack { -// lazy var managedObjectModel = TestNSManagedObjectModel() -// lazy var persistentStoreCoordinator = TestNSPersistentStoreCoordinator(managedObjectModel: managedObjectModel) -// lazy var managedObjectContext = TestNSManagedObjectContext() -//} -// -//class TestNSManagedObjectModel: NSManagedObjectModel { -// -//} -// -//class TestNSPersistentStoreCoordinator: NSPersistentStoreCoordinator { -// override init(managedObjectModel model: NSManagedObjectModel) { -// super.init(managedObjectModel: model) -// try! addPersistentStore(ofType: NSInMemoryStoreType, configurationName: nil, at: nil) -// } -//} diff --git a/Tests/SentryTests/Integrations/Performance/CoreData/TestCoreDataStack.swift b/Tests/SentryTests/Integrations/Performance/CoreData/TestCoreDataStack.swift index 8a33f7bca70..ed62e2862a5 100644 --- a/Tests/SentryTests/Integrations/Performance/CoreData/TestCoreDataStack.swift +++ b/Tests/SentryTests/Integrations/Performance/CoreData/TestCoreDataStack.swift @@ -132,8 +132,8 @@ class TestNSManagedObjectContext: NSManagedObjectContext { } override var hasChanges: Bool { - return ((inserted?.count ?? 0) > 0) || + return ((inserted?.count ?? 0) > 0) || ((deleted?.count ?? 0) > 0) || - ((updated?.count ?? 0) > 0) + ((updated?.count ?? 0) > 0) || super.hasChanges } } From 9fd258d2b774f6577b1ceb0680f24a710db402cf Mon Sep 17 00:00:00 2001 From: Andrew McKnight Date: Tue, 29 Aug 2023 14:25:45 -0400 Subject: [PATCH 5/7] wip adding back accidentally removed assertions --- .../Performance/CoreData/SentryCoreDataTrackerTest.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tests/SentryTests/Integrations/Performance/CoreData/SentryCoreDataTrackerTest.swift b/Tests/SentryTests/Integrations/Performance/CoreData/SentryCoreDataTrackerTest.swift index e3c374dc4bb..af2bbe633a3 100644 --- a/Tests/SentryTests/Integrations/Performance/CoreData/SentryCoreDataTrackerTest.swift +++ b/Tests/SentryTests/Integrations/Performance/CoreData/SentryCoreDataTrackerTest.swift @@ -331,6 +331,8 @@ private extension SentryCoreDataTrackerTests { func assertDataAndFrames(dbSpan: Span, expectedOperation: String, expectedDescription: String, mainThread: Bool) { XCTAssertEqual(dbSpan.operation, expectedOperation) + XCTAssertEqual(dbSpan.origin, "auto.db.core_data") + XCTAssertEqual(dbSpan.data["read_count"] as? Int, 1) XCTAssertEqual(dbSpan.spanDescription, expectedDescription) XCTAssertEqual(dbSpan.data["blocked_main_thread"] as? Bool ?? false, mainThread) XCTAssertEqual(try XCTUnwrap(dbSpan.data["db.system"] as? String), "SQLite") From 8251982018bc798ac229cc653fe8fffa10fbd908 Mon Sep 17 00:00:00 2001 From: Andrew McKnight Date: Tue, 29 Aug 2023 14:53:41 -0400 Subject: [PATCH 6/7] put assert back in right spot --- .../Performance/CoreData/SentryCoreDataTrackerTest.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/SentryTests/Integrations/Performance/CoreData/SentryCoreDataTrackerTest.swift b/Tests/SentryTests/Integrations/Performance/CoreData/SentryCoreDataTrackerTest.swift index af2bbe633a3..3b517cc9f25 100644 --- a/Tests/SentryTests/Integrations/Performance/CoreData/SentryCoreDataTrackerTest.swift +++ b/Tests/SentryTests/Integrations/Performance/CoreData/SentryCoreDataTrackerTest.swift @@ -322,17 +322,17 @@ private extension SentryCoreDataTrackerTests { return [someEntity] } - let dbSpan = try XCTUnwrap(transaction.children.first) - XCTAssertEqual(result?.count, 1) + let dbSpan = try XCTUnwrap(transaction.children.first) + XCTAssertEqual(dbSpan.data["read_count"] as? Int, 1) + assertDataAndFrames(dbSpan: dbSpan, expectedOperation: SENTRY_COREDATA_FETCH_OPERATION, expectedDescription: expectedDescription, mainThread: mainThread) } func assertDataAndFrames(dbSpan: Span, expectedOperation: String, expectedDescription: String, mainThread: Bool) { XCTAssertEqual(dbSpan.operation, expectedOperation) XCTAssertEqual(dbSpan.origin, "auto.db.core_data") - XCTAssertEqual(dbSpan.data["read_count"] as? Int, 1) XCTAssertEqual(dbSpan.spanDescription, expectedDescription) XCTAssertEqual(dbSpan.data["blocked_main_thread"] as? Bool ?? false, mainThread) XCTAssertEqual(try XCTUnwrap(dbSpan.data["db.system"] as? String), "SQLite") From bc5e3935c74596bdb0a10577e6376719016363bd Mon Sep 17 00:00:00 2001 From: Andrew McKnight Date: Tue, 29 Aug 2023 15:32:49 -0400 Subject: [PATCH 7/7] fix changelog --- CHANGELOG.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11a120bd9db..05ce7d88c74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,6 @@ ### Features -### Features - - Report database backing store information for Core Data (#3231) ## 8.10.0