mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-01-12 17:43:34 +08:00
567 lines
34 KiB
Objective-C
567 lines
34 KiB
Objective-C
//
|
|
// RKManagedObjectStoreTest.m
|
|
// RestKit
|
|
//
|
|
// Created by Blake Watters on 7/2/11.
|
|
// Copyright (c) 2009-2012 RestKit. All rights reserved.
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
#import "RKTestEnvironment.h"
|
|
#import "RKHuman.h"
|
|
#import "RKPathUtilities.h"
|
|
#import "RKSearchIndexer.h"
|
|
|
|
// TODO: Does this become `RKManagedObjectStore managedObjectModelWithName:version:inBundle:` ??? URLForManagedObjectModel
|
|
static NSURL *RKURLForManagedObjectModelWithNameAtVersion(NSString *modelName, NSUInteger version)
|
|
{
|
|
NSString *modelNameAndVersion = (version == 1) ? modelName : [NSString stringWithFormat:@"%@ %ld", modelName, (unsigned long) version];
|
|
return [[RKTestFixture fixtureBundle] URLForResource:[NSString stringWithFormat:@"%@.momd/%@", modelName, modelNameAndVersion] withExtension:@"mom"];
|
|
}
|
|
|
|
static NSManagedObjectModel *RKManagedObjectModelWithNameAtVersion(NSString *modelName, NSUInteger version)
|
|
{
|
|
NSURL *URL = RKURLForManagedObjectModelWithNameAtVersion(modelName, version);
|
|
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:URL];
|
|
return model;
|
|
}
|
|
|
|
@interface RKManagedObjectStoreTest : RKTestCase
|
|
|
|
@end
|
|
|
|
@implementation RKManagedObjectStoreTest
|
|
|
|
- (void)setUp
|
|
{
|
|
[RKTestFactory setUp];
|
|
|
|
// Delete any sqlite files in the app data directory
|
|
NSError *error;
|
|
NSArray *paths = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:RKApplicationDataDirectory() error:&error];
|
|
for (NSString *path in paths) {
|
|
if ([[path pathExtension] isEqualToString:@"sqlite"]) {
|
|
NSString *fullPath = [RKApplicationDataDirectory() stringByAppendingPathComponent:path];
|
|
BOOL success = [[NSFileManager defaultManager] removeItemAtPath:fullPath error:&error];
|
|
NSAssert(success, @"Failed to remove SQLite file at path: %@", fullPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)tearDown
|
|
{
|
|
[RKTestFactory tearDown];
|
|
}
|
|
|
|
- (void)testAdditionOfSQLiteStoreRetainsPathOfSeedDatabase
|
|
{
|
|
// Create a store with a SQLite database to use as our store
|
|
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"Data Model" withExtension:@"mom"];
|
|
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
|
|
RKManagedObjectStore *seedStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model];
|
|
NSString *seedPath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"Seed.sqlite"];
|
|
NSError *error;
|
|
NSPersistentStore *persistentStore = [seedStore addSQLitePersistentStoreAtPath:seedPath fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
|
|
expect(persistentStore).notTo.beNil();
|
|
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:seedPath];
|
|
expect(fileExists).to.beTruthy();
|
|
|
|
// Create a secondary store using the seed
|
|
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model];
|
|
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"Test.sqlite"];
|
|
persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:seedPath withConfiguration:nil options:nil error:&error];
|
|
expect(persistentStore).notTo.beNil();
|
|
|
|
fileExists = [[NSFileManager defaultManager] fileExistsAtPath:storePath];
|
|
expect(fileExists).to.beTruthy();
|
|
|
|
// Check that the store has a reference to the seed file option
|
|
NSString *seedDatabasePath = [[persistentStore options] valueForKey:RKSQLitePersistentStoreSeedDatabasePathOption];
|
|
expect(seedDatabasePath).to.equal(seedPath);
|
|
}
|
|
|
|
- (void)testAddingPersistentSQLiteStoreFromSeedDatabase
|
|
{
|
|
// Create a store with an object to serve as our seed database
|
|
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"Data Model" withExtension:@"mom"];
|
|
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
|
|
RKManagedObjectStore *seedStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model];
|
|
NSError *error;
|
|
NSString *seedPath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"Seed.sqlite"];
|
|
NSPersistentStore *seedPersistentStore = [seedStore addSQLitePersistentStoreAtPath:seedPath fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
|
|
assertThat(seedPersistentStore, is(notNilValue()));
|
|
[seedStore createManagedObjectContexts];
|
|
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:seedStore.persistentStoreManagedObjectContext];
|
|
human.name = @"Blake";
|
|
BOOL success = [seedStore.mainQueueManagedObjectContext saveToPersistentStore:&error];
|
|
assertThatBool(success, is(equalToBool(YES)));
|
|
NSManagedObjectID *seedObjectID = human.objectID;
|
|
|
|
// Create a secondary store using the first store as the seed
|
|
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"SeededStore.sqlite"];
|
|
RKManagedObjectStore *seededStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model];
|
|
NSPersistentStore *persistentStore = [seededStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:seedPath withConfiguration:nil options:nil error:&error];
|
|
assertThat(persistentStore, is(notNilValue()));
|
|
[seededStore createManagedObjectContexts];
|
|
|
|
// Get back the seeded object
|
|
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Human"];
|
|
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"name = %@", @"Blake"];
|
|
NSArray *array = [seededStore.persistentStoreManagedObjectContext executeFetchRequest:fetchRequest error:&error];
|
|
assertThat(array, isNot(empty()));
|
|
RKHuman *seededHuman = [array objectAtIndex:0];
|
|
assertThat([[seededHuman.objectID URIRepresentation] URLByDeletingLastPathComponent], is(equalTo([[seedObjectID URIRepresentation] URLByDeletingLastPathComponent])));
|
|
}
|
|
|
|
- (void)testResetPersistentStoresRecreatesInMemoryStoreThusDeletingAllManagedObjects
|
|
{
|
|
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"Data Model" withExtension:@"mom"];
|
|
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
|
|
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model];
|
|
NSError *error;
|
|
NSPersistentStore *persistentStore = [managedObjectStore addInMemoryPersistentStore:&error];
|
|
assertThat(persistentStore, is(notNilValue()));
|
|
[managedObjectStore createManagedObjectContexts];
|
|
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
|
|
human.name = @"Blake";
|
|
BOOL success = [managedObjectStore.mainQueueManagedObjectContext saveToPersistentStore:&error];
|
|
assertThatBool(success, is(equalToBool(YES)));
|
|
|
|
// Spin the run loop to allow the did save notifications to propogate
|
|
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]];
|
|
|
|
success = [managedObjectStore resetPersistentStores:&error];
|
|
assertThatBool(success, is(equalToBool(YES)));
|
|
|
|
// Check that the persistent store has changed
|
|
NSPersistentStore *newPersistentStore = [managedObjectStore.persistentStoreCoordinator.persistentStores objectAtIndex:0];
|
|
assertThat(newPersistentStore, isNot(equalTo(persistentStore)));
|
|
|
|
// Check that the object is gone
|
|
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Human"];
|
|
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"name = %@", @"Blake"];
|
|
NSArray *array = [managedObjectStore.mainQueueManagedObjectContext executeFetchRequest:fetchRequest error:&error];
|
|
assertThat(array, is(empty()));
|
|
}
|
|
|
|
- (void)testResetPersistentStoresRecreatesSQLiteStoreThusDeletingAllManagedObjects
|
|
{
|
|
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"Data Model" withExtension:@"mom"];
|
|
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
|
|
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model];
|
|
NSError *error;
|
|
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"Test.sqlite"];
|
|
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
|
|
assertThat(persistentStore, is(notNilValue()));
|
|
[managedObjectStore createManagedObjectContexts];
|
|
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
|
|
human.name = @"Blake";
|
|
BOOL success = [managedObjectStore.mainQueueManagedObjectContext saveToPersistentStore:&error];
|
|
assertThatBool(success, is(equalToBool(YES)));
|
|
|
|
// Spin the run loop to allow the did save notifications to propogate
|
|
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]];
|
|
|
|
success = [managedObjectStore resetPersistentStores:&error];
|
|
assertThatBool(success, is(equalToBool(YES)));
|
|
|
|
// Check that the object is gone
|
|
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Human"];
|
|
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"name = %@", @"Blake"];
|
|
NSArray *array = [managedObjectStore.mainQueueManagedObjectContext executeFetchRequest:fetchRequest error:&error];
|
|
assertThat(array, is(empty()));
|
|
}
|
|
|
|
|
|
- (void)testResetPersistentStoreRecreatesSQLiteStoreThusRecreatingTheStoreFileOnDisk
|
|
{
|
|
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"Data Model" withExtension:@"mom"];
|
|
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
|
|
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model];
|
|
NSError *error;
|
|
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"Test.sqlite"];
|
|
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
|
|
assertThat(persistentStore, is(notNilValue()));
|
|
[managedObjectStore createManagedObjectContexts];
|
|
|
|
NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:storePath error:&error];
|
|
assertThat(attributes, is(notNilValue()));
|
|
NSDate *modificationDate = [attributes objectForKey:NSFileModificationDate];
|
|
|
|
BOOL success = [managedObjectStore resetPersistentStores:&error];
|
|
assertThatBool(success, is(equalToBool(YES)));
|
|
|
|
// Check that the persistent store has changed
|
|
NSPersistentStore *newPersistentStore = [managedObjectStore.persistentStoreCoordinator.persistentStores objectAtIndex:0];
|
|
assertThat(newPersistentStore, isNot(equalTo(persistentStore)));
|
|
|
|
attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:storePath error:&error];
|
|
assertThat(attributes, is(notNilValue()));
|
|
NSDate *newModificationDate = [attributes objectForKey:NSFileModificationDate];
|
|
|
|
NSDate *laterDate = [modificationDate laterDate:newModificationDate];
|
|
assertThat(laterDate, is(equalTo(newModificationDate)));
|
|
}
|
|
|
|
- (void)testResetPersistentStoreForSQLiteStoreSeededWithDatabaseReclonesTheSeedDatabaseToTheStoreLocation
|
|
{
|
|
// Create a store with an object to serve as our seed database
|
|
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"Data Model" withExtension:@"mom"];
|
|
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
|
|
RKManagedObjectStore *seedStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model];
|
|
NSError *error;
|
|
NSString *seedPath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"Seed.sqlite"];
|
|
NSPersistentStore *seedPersistentStore = [seedStore addSQLitePersistentStoreAtPath:seedPath fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
|
|
assertThat(seedPersistentStore, is(notNilValue()));
|
|
[seedStore createManagedObjectContexts];
|
|
RKHuman *human = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:seedStore.persistentStoreManagedObjectContext];
|
|
human.name = @"Blake";
|
|
BOOL success = [seedStore.mainQueueManagedObjectContext saveToPersistentStore:&error];
|
|
assertThatBool(success, is(equalToBool(YES)));
|
|
NSManagedObjectID *seedObjectID = human.objectID;
|
|
|
|
// Create a secondary store using the first store as the seed
|
|
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"SeededStore.sqlite"];
|
|
RKManagedObjectStore *seededStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model];
|
|
NSPersistentStore *persistentStore = [seededStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:seedPath withConfiguration:nil options:nil error:&error];
|
|
assertThat(persistentStore, is(notNilValue()));
|
|
[seededStore createManagedObjectContexts];
|
|
|
|
// Create a second object in the seeded store
|
|
RKHuman *human2 = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:seedStore.persistentStoreManagedObjectContext];
|
|
human2.name = @"Sarah";
|
|
success = [seededStore.mainQueueManagedObjectContext saveToPersistentStore:&error];
|
|
assertThatBool(success, is(equalToBool(YES)));
|
|
|
|
// Reset the persistent stores, causing the seed database to be recopied and orphaning the second object
|
|
success = [seededStore resetPersistentStores:&error];
|
|
assertThatBool(success, is(equalToBool(YES)));
|
|
|
|
// Get back the seeded object and check against the seeded object ID
|
|
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Human"];
|
|
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"name = %@", @"Blake"];
|
|
NSArray *array = [seededStore.persistentStoreManagedObjectContext executeFetchRequest:fetchRequest error:&error];
|
|
assertThat(array, isNot(empty()));
|
|
RKHuman *seededHuman = [array objectAtIndex:0];
|
|
assertThat([[seededHuman.objectID URIRepresentation] URLByDeletingLastPathComponent], is(equalTo([[seedObjectID URIRepresentation] URLByDeletingLastPathComponent])));
|
|
|
|
// Check that the secondary object does not exist
|
|
fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Human"];
|
|
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"name = %@", @"Sarah"];
|
|
array = [seededStore.persistentStoreManagedObjectContext executeFetchRequest:fetchRequest error:&error];
|
|
assertThat(array, is(empty()));
|
|
}
|
|
|
|
#if __IPHONE_OS_VERSION_MIN_REQUIRED
|
|
- (void)testThatAddingASQLiteStoreExcludesThePathFromiCloudBackups
|
|
{
|
|
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"Data Model" withExtension:@"mom"];
|
|
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
|
|
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model];
|
|
NSError *error;
|
|
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"TestBackupExclusion.sqlite"];
|
|
[managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
|
|
NSURL *storeURL = [NSURL fileURLWithPath:storePath];
|
|
id resourceValue = nil;
|
|
BOOL success = [storeURL getResourceValue:&resourceValue forKey:NSURLIsExcludedFromBackupKey error:&error];
|
|
expect(success).to.beTruthy();
|
|
expect(resourceValue).to.equal(@(YES));
|
|
}
|
|
#endif
|
|
|
|
- (void)testResetPersistentStoresDoesNotTriggerDeadlock
|
|
{
|
|
RKManagedObjectStore *managedObjectStore = [RKTestFactory managedObjectStore];
|
|
NSManagedObject *managedObject1 = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext];
|
|
NSManagedObject *managedObject2 = [NSEntityDescription insertNewObjectForEntityForName:@"Human" inManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
|
|
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Human"];
|
|
[fetchRequest setSortDescriptors:@[ [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES] ]];
|
|
NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectStore.mainQueueManagedObjectContext sectionNameKeyPath:nil cacheName:nil];
|
|
NSError *error = nil;
|
|
[fetchedResultsController performFetch:&error];
|
|
BOOL success = [managedObjectStore resetPersistentStores:&error];
|
|
expect(success).to.equal(YES);
|
|
expect(error).to.beNil();
|
|
[fetchedResultsController performFetch:&error];
|
|
[managedObject1 setValue:@"Blake" forKey:@"name"];
|
|
[managedObject2.managedObjectContext performBlockAndWait:^{
|
|
[managedObject2 setValue:@"Blake" forKey:@"name"];
|
|
}];
|
|
}
|
|
|
|
- (void)testCleanupOfExternalStorageDirectoryOnReset
|
|
{
|
|
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"Data Model" withExtension:@"mom"];
|
|
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
|
|
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model];
|
|
NSEntityDescription *humanEntity = [managedObjectStore.managedObjectModel entitiesByName][@"Human"];
|
|
NSAttributeDescription *photoAttribute = [[NSAttributeDescription alloc] init];
|
|
[photoAttribute setName:@"photo"];
|
|
[photoAttribute setAttributeType:NSTransformableAttributeType];
|
|
[photoAttribute setAllowsExternalBinaryDataStorage:YES];
|
|
NSArray *newProperties = [[humanEntity properties] arrayByAddingObject:photoAttribute];
|
|
[humanEntity setProperties:newProperties];
|
|
NSError *error = nil;
|
|
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"RKTestsStore.sqlite"];
|
|
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
|
|
assertThat(persistentStore, is(notNilValue()));
|
|
[managedObjectStore createManagedObjectContexts];
|
|
|
|
// Check that there is a support directory
|
|
NSString *supportDirectoryName = [NSString stringWithFormat:@".%@_SUPPORT", [[persistentStore.URL lastPathComponent] stringByDeletingPathExtension]];
|
|
NSURL *supportDirectoryFileURL = [NSURL URLWithString:supportDirectoryName relativeToURL:[persistentStore.URL URLByDeletingLastPathComponent]];
|
|
|
|
BOOL isDirectory = NO;
|
|
BOOL supportDirectoryExists = [[NSFileManager defaultManager] fileExistsAtPath:[supportDirectoryFileURL path] isDirectory:&isDirectory];
|
|
expect(supportDirectoryExists).to.equal(YES);
|
|
expect(isDirectory).to.equal(YES);
|
|
NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[supportDirectoryFileURL path] error:&error];
|
|
NSDate *creationDate = attributes[NSFileCreationDate];
|
|
|
|
BOOL success = [managedObjectStore resetPersistentStores:&error];
|
|
expect(success).to.equal(YES);
|
|
|
|
attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[supportDirectoryFileURL path] error:&error];
|
|
NSDate *newCreationDate = attributes[NSFileCreationDate];
|
|
|
|
expect([creationDate laterDate:newCreationDate]).to.equal(newCreationDate);
|
|
}
|
|
|
|
- (void)testThatPersistentStoreWithLongNameHasExternalStorageResetCorrectly
|
|
{
|
|
// Create a store with an object to serve as our seed database
|
|
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"Data Model" withExtension:@"mom"];
|
|
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
|
|
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model];
|
|
NSError *error = nil;
|
|
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"This is the Store.sqlite"];
|
|
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
|
|
assertThat(persistentStore, is(notNilValue()));
|
|
[managedObjectStore createManagedObjectContexts];
|
|
|
|
// Check that there is a support directory
|
|
NSString *supportDirectoryName = [NSString stringWithFormat:@".%@_SUPPORT", [[persistentStore.URL lastPathComponent] stringByDeletingPathExtension]];
|
|
NSString *supportDirectoryPath = [[[[persistentStore URL] path] stringByDeletingLastPathComponent] stringByAppendingPathComponent:supportDirectoryName];
|
|
|
|
BOOL isDirectory = NO;
|
|
BOOL supportDirectoryExists = [[NSFileManager defaultManager] fileExistsAtPath:supportDirectoryPath isDirectory:&isDirectory];
|
|
expect(supportDirectoryExists).to.equal(YES);
|
|
expect(isDirectory).to.equal(YES);
|
|
NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:supportDirectoryPath error:&error];
|
|
NSDate *creationDate = attributes[NSFileCreationDate];
|
|
|
|
BOOL success = [managedObjectStore resetPersistentStores:&error];
|
|
expect(success).to.equal(YES);
|
|
|
|
attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:supportDirectoryPath error:&error];
|
|
NSDate *newCreationDate = attributes[NSFileCreationDate];
|
|
|
|
expect([creationDate laterDate:newCreationDate]).to.equal(newCreationDate);
|
|
}
|
|
|
|
#pragma mark - Versioning Tests
|
|
|
|
- (void)testThatAttemptToMigrateStoreAtNonExistantFileURLReturnsError
|
|
{
|
|
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"NonExistantStore.sqlite"];
|
|
NSURL *storeURL = [NSURL fileURLWithPath:storePath];
|
|
NSError *error = nil;
|
|
NSURL *modelURL = RKURLForManagedObjectModelWithNameAtVersion(@"VersionedModel", 1);
|
|
BOOL success = [RKManagedObjectStore migratePersistentStoreOfType:NSSQLiteStoreType atURL:storeURL toModelAtURL:modelURL error:&error configuringModelsWithBlock:nil];
|
|
expect(success).to.equal(NO);
|
|
expect(error.code).to.equal(0);
|
|
}
|
|
|
|
- (void)testThatAttemptingToMigrateToANonVersionedModelReturnsError
|
|
{
|
|
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"Data Model" withExtension:@"mom"];
|
|
NSManagedObjectModel *model_v1 = RKManagedObjectModelWithNameAtVersion(@"VersionedModel", 1);
|
|
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model_v1];
|
|
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"TestStore.sqlite"];
|
|
NSError *error = nil;
|
|
NSDictionary *options = @{ NSMigratePersistentStoresAutomaticallyOption: @(NO), NSInferMappingModelAutomaticallyOption: @(NO) };
|
|
[managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:options error:&error];
|
|
[managedObjectStore createManagedObjectContexts];
|
|
managedObjectStore = nil;
|
|
|
|
// Attempting to update to `modelURL` will fail because this is an unversioned model
|
|
NSURL *storeURL = [NSURL fileURLWithPath:storePath];
|
|
BOOL success = [RKManagedObjectStore migratePersistentStoreOfType:NSSQLiteStoreType atURL:storeURL toModelAtURL:modelURL error:&error configuringModelsWithBlock:nil];
|
|
expect(success).to.equal(NO);
|
|
expect(error).notTo.beNil();
|
|
expect(error.code).to.equal(NSMigrationError);
|
|
assertThat([error localizedDescription], startsWith(@"Migration failed: Migrations can only be performed to versioned destination models contained in a .momd package. Incompatible destination model given at path"));
|
|
}
|
|
|
|
- (void)testThatAttemptingToMigrateFromAnUnidentifiableSourceModelReturnsError
|
|
{
|
|
NSManagedObjectModel *model_v1 = RKManagedObjectModelWithNameAtVersion(@"VersionedModel", 1);
|
|
NSEntityDescription *extraEntity = [NSEntityDescription new];
|
|
[extraEntity setName:@"Extra"];
|
|
[model_v1 setEntities:[[model_v1 entities] arrayByAddingObject:extraEntity]];
|
|
|
|
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model_v1];
|
|
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"TestStore.sqlite"];
|
|
NSError *error = nil;
|
|
NSDictionary *options = @{ NSMigratePersistentStoresAutomaticallyOption: @(NO), NSInferMappingModelAutomaticallyOption: @(NO) };
|
|
[managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:options error:&error];
|
|
[managedObjectStore createManagedObjectContexts];
|
|
managedObjectStore = nil;
|
|
|
|
// Attempting to upgrade to v2 returns NO, because it can't find the source model (due to the added entity)
|
|
NSURL *storeURL = [NSURL fileURLWithPath:storePath];
|
|
NSURL *modelURL = RKURLForManagedObjectModelWithNameAtVersion(@"VersionedModel", 2);
|
|
BOOL success = [RKManagedObjectStore migratePersistentStoreOfType:NSSQLiteStoreType atURL:storeURL toModelAtURL:modelURL error:&error configuringModelsWithBlock:nil];
|
|
expect(success).to.equal(NO);
|
|
expect(error).notTo.beNil();
|
|
expect(error.code).to.equal(NSMigrationMissingSourceModelError);
|
|
assertThat([error localizedDescription], startsWith(@"Migration failed: Unable to find the source managed object model used to create the SQLite store at path"));
|
|
}
|
|
|
|
- (void)testMigrationToCompatibleVersionReturnsYes
|
|
{
|
|
NSManagedObjectModel *model_v1 = RKManagedObjectModelWithNameAtVersion(@"VersionedModel", 1);
|
|
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model_v1];
|
|
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"TestStore.sqlite"];
|
|
NSError *error = nil;
|
|
NSDictionary *options = @{ NSMigratePersistentStoresAutomaticallyOption: @(NO), NSInferMappingModelAutomaticallyOption: @(NO) };
|
|
[managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:options error:&error];
|
|
[managedObjectStore createManagedObjectContexts];
|
|
managedObjectStore = nil;
|
|
|
|
// Attempting to upgrade to v1 returns YES, because its already compatible
|
|
NSURL *storeURL = [NSURL fileURLWithPath:storePath];
|
|
NSURL *modelURL = RKURLForManagedObjectModelWithNameAtVersion(@"VersionedModel", 1);
|
|
BOOL success = [RKManagedObjectStore migratePersistentStoreOfType:NSSQLiteStoreType atURL:storeURL toModelAtURL:modelURL error:&error configuringModelsWithBlock:nil];
|
|
expect(success).to.equal(YES);
|
|
expect(error).to.beNil();
|
|
}
|
|
|
|
- (void)testUpgradingFromVersionedModelAt1_0to2_0
|
|
{
|
|
// Create a v1 Store
|
|
NSManagedObjectModel *model_v1 = RKManagedObjectModelWithNameAtVersion(@"VersionedModel", 1);
|
|
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model_v1];
|
|
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"TestStore.sqlite"];
|
|
NSError *error = nil;
|
|
NSDictionary *options = @{ NSMigratePersistentStoresAutomaticallyOption: @(NO), NSInferMappingModelAutomaticallyOption: @(NO) };
|
|
[managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:options error:&error];
|
|
[managedObjectStore createManagedObjectContexts];
|
|
managedObjectStore = nil;
|
|
|
|
// Now upgrade it to v2
|
|
NSURL *storeURL = [NSURL fileURLWithPath:storePath];
|
|
NSURL *modelURL = RKURLForManagedObjectModelWithNameAtVersion(@"VersionedModel", 2);
|
|
BOOL success = [RKManagedObjectStore migratePersistentStoreOfType:NSSQLiteStoreType atURL:storeURL toModelAtURL:modelURL error:&error configuringModelsWithBlock:nil];
|
|
expect(success).to.equal(YES);
|
|
expect(error).to.beNil();
|
|
}
|
|
|
|
- (void)testUpgradingFromVersionedModelAt1_0to_4_0
|
|
{
|
|
// Create a v1 Store
|
|
NSManagedObjectModel *model_v1 = RKManagedObjectModelWithNameAtVersion(@"VersionedModel", 1);
|
|
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model_v1];
|
|
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"TestStore.sqlite"];
|
|
NSError *error = nil;
|
|
NSDictionary *options = @{ NSMigratePersistentStoresAutomaticallyOption: @(NO), NSInferMappingModelAutomaticallyOption: @(NO) };
|
|
[managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:options error:&error];
|
|
[managedObjectStore createManagedObjectContexts];
|
|
managedObjectStore = nil;
|
|
|
|
// Now upgrade it to v4
|
|
NSURL *storeURL = [NSURL fileURLWithPath:storePath];
|
|
NSURL *modelURL = RKURLForManagedObjectModelWithNameAtVersion(@"VersionedModel", 4);
|
|
BOOL success = [RKManagedObjectStore migratePersistentStoreOfType:NSSQLiteStoreType atURL:storeURL toModelAtURL:modelURL error:&error configuringModelsWithBlock:nil];
|
|
expect(success).to.equal(YES);
|
|
expect(error).to.beNil();
|
|
}
|
|
|
|
- (void)testUpgradingFromVersionedModelWithSearchAttributesAt2_0to_3_0
|
|
{
|
|
// Create a v2 Store
|
|
NSManagedObjectModel *model_v2 = RKManagedObjectModelWithNameAtVersion(@"VersionedModel", 2);
|
|
|
|
// Add search indexing on the title attribute
|
|
NSEntityDescription *articleEntity = [[model_v2 entitiesByName] objectForKey:@"Article"];
|
|
[RKSearchIndexer addSearchIndexingToEntity:articleEntity onAttributes:@[ @"title" ]];
|
|
|
|
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model_v2];
|
|
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"TestStore.sqlite"];
|
|
NSError *error = nil;
|
|
NSDictionary *options = @{ NSMigratePersistentStoresAutomaticallyOption: @(NO), NSInferMappingModelAutomaticallyOption: @(NO) };
|
|
[managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:options error:&error];
|
|
[managedObjectStore createManagedObjectContexts];
|
|
managedObjectStore = nil;
|
|
|
|
// Now upgrade it to v3
|
|
NSURL *storeURL = [NSURL fileURLWithPath:storePath];
|
|
NSURL *modelURL = RKURLForManagedObjectModelWithNameAtVersion(@"VersionedModel", 4);
|
|
BOOL success = [RKManagedObjectStore migratePersistentStoreOfType:NSSQLiteStoreType atURL:storeURL toModelAtURL:modelURL error:&error configuringModelsWithBlock:^(NSManagedObjectModel *model, NSURL *sourceURL) {
|
|
if ([[model versionIdentifiers] isEqualToSet:[NSSet setWithObject:@"2.0"]]) {
|
|
NSEntityDescription *articleEntity = [[model entitiesByName] objectForKey:@"Article"];
|
|
[RKSearchIndexer addSearchIndexingToEntity:articleEntity onAttributes:@[ @"title" ]];
|
|
}
|
|
}];
|
|
expect(success).to.equal(YES);
|
|
expect(error).to.beNil();
|
|
}
|
|
|
|
- (void)testUpgradingFromVersionedModelWithSearchAttributesAt_1_0toLatest
|
|
{
|
|
// Create a v1 Store
|
|
NSManagedObjectModel *model_v1 = RKManagedObjectModelWithNameAtVersion(@"VersionedModel", 1);
|
|
|
|
// Add search indexing on the title attribute
|
|
NSEntityDescription *articleEntity = [[model_v1 entitiesByName] objectForKey:@"Article"];
|
|
NSEntityDescription *tagEntity = [[model_v1 entitiesByName] objectForKey:@"Tag"];
|
|
[RKSearchIndexer addSearchIndexingToEntity:articleEntity onAttributes:@[ @"title" ]];
|
|
[RKSearchIndexer addSearchIndexingToEntity:tagEntity onAttributes:@[ @"name" ]];
|
|
|
|
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:model_v1];
|
|
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"TestStore.sqlite"];
|
|
NSError *error = nil;
|
|
NSDictionary *options = @{ NSMigratePersistentStoresAutomaticallyOption: @(NO), NSInferMappingModelAutomaticallyOption: @(NO) };
|
|
[managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:options error:&error];
|
|
[managedObjectStore createManagedObjectContexts];
|
|
managedObjectStore = nil;
|
|
|
|
// Now upgrade it to the latest version
|
|
NSURL *storeURL = [NSURL fileURLWithPath:storePath];
|
|
NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"VersionedModel" withExtension:@"momd"];
|
|
BOOL success = [RKManagedObjectStore migratePersistentStoreOfType:NSSQLiteStoreType atURL:storeURL toModelAtURL:modelURL error:&error configuringModelsWithBlock:^(NSManagedObjectModel *model, NSURL *sourceURL) {
|
|
if ([[model versionIdentifiers] isEqualToSet:[NSSet setWithObject:@"1.0"]]) {
|
|
NSEntityDescription *articleEntity = [[model entitiesByName] objectForKey:@"Article"];
|
|
NSEntityDescription *tagEntity = [[model entitiesByName] objectForKey:@"Tag"];
|
|
[RKSearchIndexer addSearchIndexingToEntity:articleEntity onAttributes:@[ @"title" ]];
|
|
[RKSearchIndexer addSearchIndexingToEntity:tagEntity onAttributes:@[ @"name" ]];
|
|
} else if ([[model versionIdentifiers] isEqualToSet:[NSSet setWithObject:@"2.0"]]) {
|
|
NSEntityDescription *articleEntity = [[model entitiesByName] objectForKey:@"Article"];
|
|
NSEntityDescription *tagEntity = [[model entitiesByName] objectForKey:@"Tag"];
|
|
[RKSearchIndexer addSearchIndexingToEntity:articleEntity onAttributes:@[ @"title", @"body" ]];
|
|
[RKSearchIndexer addSearchIndexingToEntity:tagEntity onAttributes:@[ @"name" ]];
|
|
} else if ([[model versionIdentifiers] containsObject:@"3.0"] || [[model versionIdentifiers] containsObject:@"4.0"]) {
|
|
// We index the same attributes on v3 and v4
|
|
NSEntityDescription *articleEntity = [[model entitiesByName] objectForKey:@"Article"];
|
|
NSEntityDescription *tagEntity = [[model entitiesByName] objectForKey:@"Tag"];
|
|
[RKSearchIndexer addSearchIndexingToEntity:articleEntity onAttributes:@[ @"title", @"body", @"authorName" ]];
|
|
[RKSearchIndexer addSearchIndexingToEntity:tagEntity onAttributes:@[ @"name" ]];
|
|
}
|
|
}];
|
|
expect(success).to.equal(YES);
|
|
expect(error).to.beNil();
|
|
}
|
|
|
|
@end
|