Files
firebase-ios-sdk/Example/Database/Tests/Helpers/FMockStorageEngine.m
T

178 lines
6.5 KiB
Objective-C
Raw Normal View History

2017-05-15 12:27:07 -07:00
/*
* Copyright 2017 Google
*
* 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 "FMockStorageEngine.h"
#import "FCompoundWrite.h"
#import "FEmptyNode.h"
2019-08-05 13:27:47 -07:00
#import "FNode.h"
2017-05-15 12:27:07 -07:00
#import "FPruneForest.h"
2019-08-05 13:27:47 -07:00
#import "FTrackedQuery.h"
#import "FWriteRecord.h"
2017-05-15 12:27:07 -07:00
@interface FMockStorageEngine ()
2019-08-05 13:27:47 -07:00
@property(nonatomic) BOOL closed;
@property(nonatomic, strong) NSMutableDictionary *userWritesDict;
@property(nonatomic, strong) FCompoundWrite *serverCache;
@property(nonatomic, strong) NSMutableDictionary *trackedQueries;
@property(nonatomic, strong) NSMutableDictionary *trackedQueryKeys;
2017-05-15 12:27:07 -07:00
@end
@implementation FMockStorageEngine
- (id)init {
2019-08-05 13:27:47 -07:00
self = [super init];
if (self != nil) {
self->_userWritesDict = [NSMutableDictionary dictionary];
self->_serverCache = [FCompoundWrite emptyWrite];
self->_trackedQueries = [NSMutableDictionary dictionary];
self->_trackedQueryKeys = [NSMutableDictionary dictionary];
}
return self;
2017-05-15 12:27:07 -07:00
}
- (void)close {
2019-08-05 13:27:47 -07:00
self.closed = YES;
2017-05-15 12:27:07 -07:00
}
- (void)saveUserOverwrite:(id<FNode>)node atPath:(FPath *)path writeId:(NSUInteger)writeId {
2019-08-05 13:27:47 -07:00
FWriteRecord *writeRecord = [[FWriteRecord alloc] initWithPath:path
overwrite:node
writeId:writeId
visible:YES];
self.userWritesDict[@(writeId)] = writeRecord;
2017-05-15 12:27:07 -07:00
}
- (void)saveUserMerge:(FCompoundWrite *)merge atPath:(FPath *)path writeId:(NSUInteger)writeId {
2019-08-05 13:27:47 -07:00
FWriteRecord *writeRecord = [[FWriteRecord alloc] initWithPath:path merge:merge writeId:writeId];
self.userWritesDict[@(writeId)] = writeRecord;
2017-05-15 12:27:07 -07:00
}
- (void)removeUserWrite:(NSUInteger)writeId {
2019-08-05 13:27:47 -07:00
[self.userWritesDict removeObjectForKey:@(writeId)];
2017-05-15 12:27:07 -07:00
}
- (void)removeAllUserWrites {
2019-08-05 13:27:47 -07:00
[self.userWritesDict removeAllObjects];
2017-05-15 12:27:07 -07:00
}
- (NSArray *)userWrites {
2019-08-05 13:27:47 -07:00
return [[self.userWritesDict allValues]
sortedArrayUsingComparator:^NSComparisonResult(FWriteRecord *obj1, FWriteRecord *obj2) {
2017-05-15 12:27:07 -07:00
if (obj1.writeId < obj2.writeId) {
2019-08-05 13:27:47 -07:00
return NSOrderedAscending;
2017-05-15 12:27:07 -07:00
} else if (obj1.writeId > obj2.writeId) {
2019-08-05 13:27:47 -07:00
return NSOrderedDescending;
2017-05-15 12:27:07 -07:00
} else {
2019-08-05 13:27:47 -07:00
return NSOrderedSame;
2017-05-15 12:27:07 -07:00
}
2019-08-05 13:27:47 -07:00
}];
2017-05-15 12:27:07 -07:00
}
- (id<FNode>)serverCacheAtPath:(FPath *)path {
2019-08-05 13:27:47 -07:00
return [[self.serverCache childCompoundWriteAtPath:path] applyToNode:[FEmptyNode emptyNode]];
2017-05-15 12:27:07 -07:00
}
- (id<FNode>)serverCacheForKeys:(NSSet *)keys atPath:(FPath *)path {
2019-08-05 13:27:47 -07:00
__block id<FNode> children = [FEmptyNode emptyNode];
id<FNode> fullNode =
[[self.serverCache childCompoundWriteAtPath:path] applyToNode:[FEmptyNode emptyNode]];
[keys enumerateObjectsUsingBlock:^(NSString *key, BOOL *stop) {
children = [children updateImmediateChild:key withNewChild:[fullNode getImmediateChild:key]];
}];
return children;
2017-05-15 12:27:07 -07:00
}
- (void)updateServerCache:(id<FNode>)node atPath:(FPath *)path merge:(BOOL)merge {
2019-08-05 13:27:47 -07:00
if (merge) {
[node enumerateChildrenUsingBlock:^(NSString *key, id<FNode> childNode, BOOL *stop) {
self.serverCache = [self.serverCache addWrite:childNode atPath:[path childFromString:key]];
}];
} else {
self.serverCache = [self.serverCache addWrite:node atPath:path];
}
2017-05-15 12:27:07 -07:00
}
- (void)updateServerCacheWithMerge:(FCompoundWrite *)merge atPath:(FPath *)path {
2019-08-05 13:27:47 -07:00
self.serverCache = [self.serverCache addCompoundWrite:merge atPath:path];
2017-05-15 12:27:07 -07:00
}
- (NSUInteger)serverCacheEstimatedSizeInBytes {
2019-08-05 13:27:47 -07:00
id data = [[self.serverCache applyToNode:[FEmptyNode emptyNode]] valForExport:YES];
return [NSJSONSerialization dataWithJSONObject:data options:0 error:nil].length;
2017-05-15 12:27:07 -07:00
}
- (void)pruneCache:(FPruneForest *)pruneForest atPath:(FPath *)prunePath {
2019-08-05 13:27:47 -07:00
[self.serverCache enumerateWrites:^(FPath *absolutePath, id<FNode> node, BOOL *stop) {
NSAssert([prunePath isEqual:absolutePath] || ![absolutePath contains:prunePath],
@"Pruning at %@ but we found data higher up!", prunePath);
if ([prunePath contains:absolutePath]) {
FPath *relativePath = [FPath relativePathFrom:prunePath to:absolutePath];
if ([pruneForest shouldPruneUnkeptDescendantsAtPath:relativePath]) {
__block FCompoundWrite *newCache = [FCompoundWrite emptyWrite];
[[pruneForest childAtPath:relativePath] enumarateKeptNodesUsingBlock:^(FPath *keepPath) {
newCache = [newCache addWrite:[node getChild:keepPath] atPath:keepPath];
}];
self.serverCache =
[[self.serverCache removeWriteAtPath:absolutePath] addCompoundWrite:newCache
atPath:absolutePath];
} else {
// NOTE: This is technically a valid scenario (e.g. you ask to prune at / but only want to
// prune 'foo' and 'bar' and ignore everything else). But currently our pruning will
// explicitly prune or keep everything we know about, so if we hit this it means our tracked
// queries and the server cache are out of sync.
NSAssert([pruneForest shouldKeepPath:relativePath],
@"We have data at %@ that is neither pruned nor kept.", relativePath);
}
}
}];
2017-05-15 12:27:07 -07:00
}
- (NSArray *)loadTrackedQueries {
2019-08-05 13:27:47 -07:00
return self.trackedQueries.allValues;
2017-05-15 12:27:07 -07:00
}
- (void)removeTrackedQuery:(NSUInteger)queryId {
2019-08-05 13:27:47 -07:00
[self.trackedQueries removeObjectForKey:@(queryId)];
[self.trackedQueryKeys removeObjectForKey:@(queryId)];
2017-05-15 12:27:07 -07:00
}
- (void)saveTrackedQuery:(FTrackedQuery *)query {
2019-08-05 13:27:47 -07:00
self.trackedQueries[@(query.queryId)] = query;
2017-05-15 12:27:07 -07:00
}
- (void)setTrackedQueryKeys:(NSSet *)keys forQueryId:(NSUInteger)queryId {
2019-08-05 13:27:47 -07:00
self.trackedQueryKeys[@(queryId)] = keys;
2017-05-15 12:27:07 -07:00
}
2019-08-05 13:27:47 -07:00
- (void)updateTrackedQueryKeysWithAddedKeys:(NSSet *)added
removedKeys:(NSSet *)removed
forQueryId:(NSUInteger)queryId {
NSSet *oldKeys = [self trackedQueryKeysForQuery:queryId];
NSMutableSet *newKeys = [NSMutableSet setWithSet:oldKeys];
[newKeys minusSet:removed];
[newKeys unionSet:added];
self.trackedQueryKeys[@(queryId)] = newKeys;
2017-05-15 12:27:07 -07:00
}
- (NSSet *)trackedQueryKeysForQuery:(NSUInteger)queryId {
2019-08-05 13:27:47 -07:00
NSSet *keys = self.trackedQueryKeys[@(queryId)];
return keys != nil ? keys : [NSSet set];
2017-05-15 12:27:07 -07:00
}
@end