Skip to content

Commit

Permalink
Merge pull request #378 from Simperium/develop
Browse files Browse the repository at this point in the history
Simperium Mark 0.7.2
  • Loading branch information
jleandroperez committed Oct 21, 2014
2 parents 81acafd + 63355fe commit 326ed9b
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 103 deletions.
2 changes: 1 addition & 1 deletion Simperium.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "Simperium"
s.version = "0.7.1"
s.version = "0.7.2"
s.summary = "Simperium libraries."
s.description = "Simperium is a simple way for developers to move data as it changes, instantly and automatically."
s.homepage = "https://github.com/Simperium/simperium-ios"
Expand Down
84 changes: 7 additions & 77 deletions Simperium/SPCoreDataStorage.m
Original file line number Diff line number Diff line change
Expand Up @@ -88,18 +88,17 @@ - (instancetype)initWithSibling:(SPCoreDataStorage *)aSibling {
// and will also post the changes to the MainQueue
self.mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
self.mainManagedObjectContext.userInfo[SPCoreDataWorkerContext] = @(true);

self.writerManagedObjectContext = aSibling.writerManagedObjectContext;

// Wire the Thread Confined Context, directly to the writer MOC
self.mainManagedObjectContext.parentContext = self.writerManagedObjectContext;
self.mainManagedObjectContext.persistentStoreCoordinator = aSibling.persistentStoreCoordinator;

// Simperium's context always trumps the app's local context (potentially stomping in-memory changes)
[self.mainManagedObjectContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];

// For efficiency
[self.mainManagedObjectContext setUndoManager:nil];

// Keep a reference to the writerContext
self.writerManagedObjectContext = aSibling.writerManagedObjectContext;

// Shared mutex
self.mutex = aSibling.mutex;

Expand All @@ -115,9 +114,9 @@ - (void)dealloc {
}

- (void)setBucketList:(NSDictionary *)dict {
// Associate the bucketList with the writerMOC, so that every NSManagedObject instance can retrieve
// the appropiate SPBucket pointer
objc_setAssociatedObject(self.writerManagedObjectContext, SPCoreDataBucketListKey, dict, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
// Associate the bucketList with the persistentStoreCoordinator:
// Every NSManagedObject instance will be able to retrieve the appropiate SPBucket pointer
objc_setAssociatedObject(self.persistentStoreCoordinator, SPCoreDataBucketListKey, dict, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSArray *)exportSchemas {
Expand Down Expand Up @@ -280,10 +279,6 @@ - (id)insertNewObjectForBucketName:(NSString *)bucketName simperiumKey:(NSString

object.simperiumKey = key ? key : [NSString sp_makeUUID];

// Populate with member data if applicable
// if (memberData)
// [entity loadMemberData: memberData manager: self];

return object;
}

Expand Down Expand Up @@ -508,9 +503,6 @@ - (void)childrenContextDidSave:(NSNotification*)notification {

// Proceed with the regular merge. This should trigger a contextDidChange note
[mainMOC mergeChangesFromContextDidSaveNotification:notification];

// Note: Once the changes have been merged to the mainMOC, let's persist to "disk"!
[self saveWriterContext];
}];
}

Expand Down Expand Up @@ -663,65 +655,3 @@ - (BOOL)migrateStore:(NSURL *)storeURL sourceModel:(NSManagedObjectModel *)srcMo
}

@end


// Unused code for dividing up changes per bucket (ugly)
// // Divvy up according to buckets; this is necessary to avoid each object maintaining a reference back to its bucket, which doesn't
// // work well with multiple Simperium instances
// // On iOS5, bucket references on objects could work via userInfo on NSManagedObjectContext instead
// NSMutableDictionary *bucketLists = [NSMutableDictionary dictionaryWithCapacity:5];
//
// // This code is awful
// for (id<SPDiffable>object in insertedObjects) {
// NSString *bucketName = [self nameForEntityClass:[object class]];
// NSMutableDictionary *objectLists = [bucketLists objectForKey:bucketName];
// if (!objectLists) {
// // Create a dict to hold all inserted, updated and deleted objects for that bucket
// objectLists = [NSMutableDictionary dictionaryWithCapacity:3];
// [bucketLists setObject:objectLists forKey:bucketName];
// }
//
// NSMutableArray *bucketObjects = [objectLists objectForKey:@"insertedObjects"];
// if (!bucketObjects) {
// // Create an array in the dict
// bucketObjects = [NSMutableArray arrayWithCapacity:3];
// [objectLists setObject:bucketObjects forKey:@"insertedObjects"];
// }
// [bucketObjects addObject:object];
// }
//
// for (id<SPDiffable>object in updatedObjects) {
// NSString *bucketName = [self nameForEntityClass:[object class]];
// NSMutableDictionary *objectLists = [bucketLists objectForKey:bucketName];
// if (!objectLists) {
// // Create a dict to hold all inserted, updated and deleted objects for that bucket
// objectLists = [NSMutableDictionary dictionaryWithCapacity:3];
// [bucketLists setObject:objectLists forKey:bucketName];
// }
//
// NSMutableArray *bucketObjects = [objectLists objectForKey:@"updatedObjects"];
// if (!bucketObjects) {
// // Create an array in the dict
// bucketObjects = [NSMutableArray arrayWithCapacity:3];
// [objectLists setObject:bucketObjects forKey:@"updatedObjects"];
// }
// [bucketObjects addObject:object];
// }
//
// for (id<SPDiffable>object in deletedObjects) {
// NSString *bucketName = [self nameForEntityClass:[object class]];
// NSMutableDictionary *objectLists = [bucketLists objectForKey:bucketName];
// if (!objectLists) {
// // Create a dict to hold all inserted, updated and deleted objects for that bucket
// objectLists = [NSMutableDictionary dictionaryWithCapacity:3];
// [bucketLists setObject:objectLists forKey:bucketName];
// }
//
// NSMutableArray *bucketObjects = [objectLists objectForKey:@"deletedObjects"];
// if (!bucketObjects) {
// // Create an array in the dict
// bucketObjects = [NSMutableArray arrayWithCapacity:3];
// [objectLists setObject:bucketObjects forKey:@"deletedObjects"];
// }
// [bucketObjects addObject:object];
// }
2 changes: 1 addition & 1 deletion Simperium/SPEnvironment.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#endif

// TODO: Update this automatically via a script that looks at current git tag
NSString* const SPLibraryVersion = @"0.7.1";
NSString* const SPLibraryVersion = @"0.7.2";

// SSL Certificate Expiration: '2016-09-07 02:36:04 +0000' expressed as seconds since 1970
NSTimeInterval const SPCertificateExpiration = 1473215764;
Expand Down
13 changes: 3 additions & 10 deletions Simperium/SPManagedObject.m
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,9 @@ - (id)simperiumValueForKey:(NSString *)key {

- (void)configureBucket {

// Get the MOC's Grandpa (writerContext)
NSManagedObjectContext *writerManagedObjectContext = self.managedObjectContext;

while (writerManagedObjectContext.parentContext) {
writerManagedObjectContext = writerManagedObjectContext.parentContext;
}

// Check
NSDictionary *bucketList = objc_getAssociatedObject(writerManagedObjectContext, SPCoreDataBucketListKey);
// Load the Bucket List
NSPersistentStoreCoordinator *persistentStoreCoordinator = self.managedObjectContext.persistentStoreCoordinator;
NSDictionary *bucketList = objc_getAssociatedObject(persistentStoreCoordinator, SPCoreDataBucketListKey);

if (!bucketList) {
NSLog(@"Simperium error: bucket list not loaded. Ensure Simperium is started before any objects are fetched.");
Expand All @@ -61,7 +55,6 @@ - (void)awakeFromFetch {
[super awakeFromFetch];
SPGhost *newGhost = [[SPGhost alloc] initFromDictionary: [self.ghostData sp_objectFromJSONString]];
self.ghost = newGhost;
[self.managedObjectContext userInfo];
[self configureBucket];
}

Expand Down
15 changes: 15 additions & 0 deletions SimperiumTests/SPCoreDataStorageTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,21 @@ @interface SPCoreDataStorageTests : XCTestCase

@implementation SPCoreDataStorageTests

- (void)testBucketListMechanism {
MockSimperium* s = [MockSimperium mockSimperium];

NSManagedObjectContext *mainContext = s.managedObjectContext;
NSManagedObjectContext *derivedContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
derivedContext.parentContext = mainContext;

NSString *entityName = NSStringFromClass([Post class]);
Post *mainPost = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:mainContext];
Post *nestedPost = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:derivedContext];

XCTAssertNotNil(mainPost.bucket, @"Missing bucket in main context");
XCTAssertNotNil(nestedPost.bucket, @"Missing bucket in nested context");
}

- (void)testStress {
for (NSInteger i = 0; ++i <= kStressIterations; ) {
NSLog(@"<> Stress Iteration %ld", (long)i);
Expand Down
24 changes: 12 additions & 12 deletions SimperiumTests/SimperiumCoreDataTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ @interface SimperiumCoreDataTests : SimperiumTests

static NSString* const kInsertedKey = @"inserted";
static NSString* const kUpdatedKey = @"updated";
static NSString* const kRefreshedKey = @"refreshed";
static NSString* const kDeletedKey = @"deleted";


Expand Down Expand Up @@ -203,12 +204,10 @@ - (void)testRemoteCRUD {

// Prepare everything we need
NSManagedObjectContext *followerMainMOC = follower.simperium.managedObjectContext;
NSManagedObjectContext *followerWriterMOC = follower.simperium.writerManagedObjectContext;

// Listen to the follower MainMOC changes & WriterMOC save notifications
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(handleContextNote:) name:NSManagedObjectContextObjectsDidChangeNotification object:followerMainMOC];
[nc addObserver:self selector:@selector(handleContextNote:) name:NSManagedObjectContextDidSaveNotification object:followerWriterMOC];


// ====================================================================================
Expand All @@ -232,10 +231,7 @@ - (void)testRemoteCRUD {
[self waitFor:kRemoteTestTimeout];

NSArray *mainInserted = [[self changesForContext:followerMainMOC] objectForKey:kInsertedKey];
NSArray *writerInserted = [[self changesForContext:followerWriterMOC] objectForKey:kInsertedKey];

XCTAssertTrue( (mainInserted.count == kObjectsCount), @"The follower's mainMOC didn't get the new objects");
XCTAssertTrue( (writerInserted.count == kObjectsCount), @"The follower's writerMOC didn't persist the new objects");


// ====================================================================================
Expand All @@ -258,10 +254,10 @@ - (void)testRemoteCRUD {

[self waitFor:kRemoteTestTimeout];

NSArray *mainUpdated = [self changesForContext:followerWriterMOC][kUpdatedKey];
XCTAssertTrue( (mainUpdated.count == objects.count), @"Error Updating Objects" );
NSArray *mainRefreshed = [self changesForContext:followerMainMOC][kRefreshedKey];
XCTAssertTrue( (mainRefreshed.count == objects.count), @"Error Updating Objects" );

for (Config* config in mainUpdated) {
for (Config* config in mainRefreshed) {
XCTAssertTrue([config.warpSpeed isEqual:@(31337)], @"Update Test Failed");
XCTAssertTrue([config.shieldsUp isEqual:@(YES)], @"Update Test Failed");
XCTAssertTrue([config.shieldPercent isEqual:@(100)], @"Update Test Failed");
Expand All @@ -287,10 +283,7 @@ - (void)testRemoteCRUD {
[self waitFor:kRemoteTestTimeout];

NSArray *mainDeleted = [[self changesForContext:followerMainMOC] objectForKey:kDeletedKey];
NSArray *writerDeleted = [[self changesForContext:followerWriterMOC] objectForKey:kDeletedKey];

XCTAssertTrue( (mainDeleted.count == kObjectsCount), @"The follower's mainMOC failed to delete objects");
XCTAssertTrue( (writerDeleted.count == kObjectsCount), @"The follower's writerMOC failed to delete objects");

NSLog(@"%@ end", self.name);
}
Expand All @@ -310,6 +303,7 @@ - (void)handleContextNote:(NSNotification*)note {
changes[kInsertedKey] = [NSMutableArray array];
changes[kUpdatedKey] = [NSMutableArray array];
changes[kDeletedKey] = [NSMutableArray array];
changes[kRefreshedKey] = [NSMutableArray array];
self.changesByContext[wrappedSender] = changes;
}

Expand All @@ -318,7 +312,8 @@ - (void)handleContextNote:(NSNotification*)note {
NSSet* receivedInserts = userInfo[kInsertedKey];
NSSet* receivedUpdates = userInfo[kUpdatedKey];
NSSet* receivedDeletions = userInfo[kDeletedKey];

NSSet* receivedRefreshed = userInfo[kRefreshedKey];

if (receivedInserts) {
NSMutableArray* inserted = changes[kInsertedKey];
[inserted addObjectsFromArray:[receivedInserts allObjects]];
Expand All @@ -333,6 +328,11 @@ - (void)handleContextNote:(NSNotification*)note {
NSMutableArray* deleted = changes[kDeletedKey];
[deleted addObjectsFromArray:[receivedDeletions allObjects]];
}

if (receivedRefreshed) {
NSMutableArray* refreshed = changes[kRefreshedKey];
[refreshed addObjectsFromArray:[receivedRefreshed allObjects]];
}
}

- (NSDictionary*)changesForContext:(NSManagedObjectContext*)context {
Expand Down
3 changes: 1 addition & 2 deletions SimperiumTests/SimperiumOfflineTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -273,8 +273,7 @@ - (void)testOfflineDeletionOfObjectWithSharedKeyAfterInitialSync
[followerBucket deleteObject:followerConfig];
[follower.simperium save];

follower.expectedAdditions = 1;
follower.expectedDeletions = 1;
follower.expectedAcknowledgments = 1;
[follower connect];
XCTAssertTrue([self waitForCompletion:4.0 farmArray:@[ follower ]], @"timed out (adding)");

Expand Down

0 comments on commit 326ed9b

Please sign in to comment.