FBDiagnostic conforms to FBJSONDeserializable
Summary: This will allow wiring of diagnostics to a remote machine. By using the read-into-memory method on the builder it makes it possible to distinguish between json encodings of a local file, or a payload that can be transmitted to a remote machine. Reviewed By: marekcirkos Differential Revision: D3047137 fb-gh-sync-id: f4b8e559291b88dd266a8157c0fce4039f4d8d6e shipit-source-id: f4b8e559291b88dd266a8157c0fce4039f4d8d6e
This commit is contained in:
Родитель
927669d664
Коммит
5f126df855
|
@ -16,7 +16,7 @@
|
|||
Defines the content & metadata of a log.
|
||||
Lazily converts between the backing store data formats.
|
||||
*/
|
||||
@interface FBDiagnostic : NSObject <NSCopying, NSCoding, FBJSONSerializable, FBDebugDescribeable>
|
||||
@interface FBDiagnostic : NSObject <NSCopying, NSCoding, FBJSONSerializable, FBJSONDeserializable, FBDebugDescribeable>
|
||||
|
||||
/**
|
||||
The name of the Log for uniquely identifying the log.
|
||||
|
@ -182,14 +182,13 @@
|
|||
- (instancetype)updatePath:(NSString *)path;
|
||||
|
||||
/**
|
||||
Updates the underlying `FBDiagnostic` with JSON Encoded String.
|
||||
Updates the underlying `FBDiagnostic` with the provided Native JSON Object.
|
||||
Will replace any data, string or path associated with the log.
|
||||
|
||||
@param jsonSerializable Can be either an FBJSONSerializable
|
||||
or an object that meets the requirements of NSJSONSerialization.
|
||||
@param json Can be either an FBJSONSerializable or an object that meets the requirements of NSJSONSerialization.
|
||||
@return the reciever, for chaining.
|
||||
*/
|
||||
- (instancetype)updateJSONSerializable:(id)jsonSerializable;
|
||||
- (instancetype)updateJSON:(id)json;
|
||||
|
||||
/**
|
||||
Returns a File Path suitable for writing data into.
|
||||
|
@ -217,6 +216,13 @@
|
|||
Updates the underlying `FBDiagnostic` by reading it into memory, if it is backed by a file.
|
||||
This means that the created FBDiagnostic is effectively immutable since the content cannot change.
|
||||
|
||||
File-backed Diagnostics are beneficial as they allow for the work of reading, transforming or writing a diagnostic
|
||||
to be deferred to a later date. Once a Diagnostic is read into memory the backing file can change and will not
|
||||
affect the diagnostic object.
|
||||
|
||||
If you wish to transfer a diagnostic to a remote machine, reading it into memory will also mean that it can be encoded
|
||||
into a JSON representation and reconstructed as a file on the remote machine.
|
||||
|
||||
@return the reciever, for chaining.
|
||||
*/
|
||||
- (instancetype)readIntoMemory;
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#import "FBCollectionInformation.h"
|
||||
#import "FBControlCoreError.h"
|
||||
|
||||
@interface FBDiagnostic ()
|
||||
|
||||
@property (nonatomic, copy, readwrite) NSString *shortName;
|
||||
|
@ -31,6 +34,8 @@
|
|||
*/
|
||||
@interface FBDiagnostic_Data : FBDiagnostic
|
||||
|
||||
+ (NSData *)dataFromJSON:(NSDictionary *)json error:(NSError **)error;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
|
@ -38,6 +43,8 @@
|
|||
*/
|
||||
@interface FBDiagnostic_String : FBDiagnostic
|
||||
|
||||
+ (NSString *)stringFromJSON:(NSDictionary *)json error:(NSError **)error;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
|
@ -45,6 +52,8 @@
|
|||
*/
|
||||
@interface FBDiagnostic_Path : FBDiagnostic
|
||||
|
||||
+ (NSString *)pathFromJSON:(NSDictionary *)json error:(NSError **)error;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
|
@ -52,6 +61,8 @@
|
|||
*/
|
||||
@interface FBDiagnostic_JSON : FBDiagnostic
|
||||
|
||||
+ (id)objectFromJSON:(NSDictionary *)json error:(NSError **)error;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
|
@ -172,7 +183,42 @@
|
|||
return [storageDirectory stringByAppendingPathComponent:filename];
|
||||
}
|
||||
|
||||
#pragma mark FBJSONSerializable
|
||||
#pragma mark JSON
|
||||
|
||||
+ (instancetype)inflateFromJSON:(NSDictionary *)json error:(NSError **)error
|
||||
{
|
||||
if (![FBCollectionInformation isArrayHeterogeneous:json.allKeys withClass:NSString.class]) {
|
||||
return [[FBControlCoreError describeFormat:@"%@ does not have string keys", json] fail:error];
|
||||
}
|
||||
NSString *shortName = json[@"short_name"];
|
||||
if (!shortName) {
|
||||
return [[FBControlCoreError describeFormat:@"%@ should exist for for 'short_name'", shortName] fail:error];
|
||||
}
|
||||
NSString *humanReadableName = json[@"human_name"];
|
||||
NSString *fileType = json[@"file_type"];
|
||||
FBDiagnosticBuilder *builder = [[[[FBDiagnosticBuilder builder]
|
||||
updateShortName:shortName]
|
||||
updateHumanReadableName:humanReadableName]
|
||||
updateFileType:fileType];
|
||||
|
||||
NSData *data = [FBDiagnostic_Data dataFromJSON:json error:nil];
|
||||
if (data) {
|
||||
return [[builder updateData:data] build];
|
||||
}
|
||||
NSString *string = [FBDiagnostic_String stringFromJSON:json error:nil];
|
||||
if (string) {
|
||||
return [[builder updateString:string] build];
|
||||
}
|
||||
NSString *path = [FBDiagnostic_Path pathFromJSON:json error:nil];
|
||||
if (path) {
|
||||
return [[builder updatePath:path] build];
|
||||
}
|
||||
id object = [FBDiagnostic_JSON objectFromJSON:json error:nil];
|
||||
if (object) {
|
||||
return [[builder updateJSON:object] build];
|
||||
}
|
||||
return [builder build];
|
||||
}
|
||||
|
||||
- (NSDictionary *)jsonSerializableRepresentation
|
||||
{
|
||||
|
@ -311,7 +357,20 @@
|
|||
return [self.backingData writeToFile:path options:0 error:error];
|
||||
}
|
||||
|
||||
#pragma mark FBJSONSerializable
|
||||
#pragma mark JSON
|
||||
|
||||
+ (NSData *)dataFromJSON:(NSDictionary *)json error:(NSError **)error
|
||||
{
|
||||
NSString *base64String = json[@"data"];
|
||||
if (![base64String isKindOfClass:NSString.class]) {
|
||||
return [[FBControlCoreError describeFormat:@"%@ is not a string for 'data'", base64String] fail:error];
|
||||
}
|
||||
NSData *data = [[NSData alloc] initWithBase64EncodedString:base64String options:0];
|
||||
if (!data) {
|
||||
return [[FBControlCoreError describe:@"base64 encoded string could not be decoded"] fail:error];
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
- (NSDictionary *)jsonSerializableRepresentation
|
||||
{
|
||||
|
@ -441,7 +500,16 @@
|
|||
return [self.backingString writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:error];
|
||||
}
|
||||
|
||||
#pragma mark FBJSONSerializable
|
||||
#pragma mark JSON
|
||||
|
||||
+ (NSString *)stringFromJSON:(NSDictionary *)json error:(NSError **)error
|
||||
{
|
||||
NSString *string = json[@"contents"];
|
||||
if (![string isKindOfClass:NSString.class]) {
|
||||
return [[FBControlCoreError describeFormat:@"%@ is not a string for 'contents'", string] fail:error];
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
- (NSDictionary *)jsonSerializableRepresentation
|
||||
{
|
||||
|
@ -553,7 +621,16 @@
|
|||
return [NSFileManager.defaultManager copyItemAtPath:self.backingFilePath toPath:path error:error];
|
||||
}
|
||||
|
||||
#pragma mark FBJSONSerializable
|
||||
#pragma mark JSON
|
||||
|
||||
+ (NSString *)pathFromJSON:(NSDictionary *)json error:(NSError **)error
|
||||
{
|
||||
NSString *path = json[@"location"];
|
||||
if (![path isKindOfClass:NSString.class]) {
|
||||
return [[FBControlCoreError describeFormat:@"%@ is not a string for 'path'", path] fail:error];
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
- (NSDictionary *)jsonSerializableRepresentation
|
||||
{
|
||||
|
@ -683,7 +760,16 @@
|
|||
return bytesWritten > 0;
|
||||
}
|
||||
|
||||
#pragma mark FBJSONSerializable
|
||||
#pragma mark JSON
|
||||
|
||||
+ (id)objectFromJSON:(NSDictionary *)json error:(NSError **)error
|
||||
{
|
||||
id object = json[@"object"];
|
||||
if (!object) {
|
||||
return [[FBControlCoreError describe:@"'object' does not exist"] fail:error];
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
- (NSDictionary *)jsonSerializableRepresentation
|
||||
{
|
||||
|
@ -758,16 +844,37 @@
|
|||
|
||||
@implementation FBDiagnosticBuilder : NSObject
|
||||
|
||||
#pragma mark Initializers
|
||||
|
||||
+ (instancetype)builder
|
||||
{
|
||||
return [self builderWithDiagnostic:nil];
|
||||
return [[FBDiagnosticBuilder alloc] initWithDiagnostic:nil];
|
||||
}
|
||||
|
||||
+ (instancetype)builderWithDiagnostic:(FBDiagnostic *)diagnostic
|
||||
{
|
||||
return [[FBDiagnosticBuilder new] updateDiagnostic:[diagnostic copy] ?: [FBDiagnostic_Empty new]];
|
||||
return [[FBDiagnosticBuilder alloc] initWithDiagnostic:diagnostic];
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
return [self initWithDiagnostic:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithDiagnostic:(FBDiagnostic *)diagnostic
|
||||
{
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
_diagnostic = [diagnostic copy] ?: FBDiagnostic_Empty.new;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark Updates
|
||||
|
||||
- (instancetype)updateDiagnostic:(FBDiagnostic *)diagnostic
|
||||
{
|
||||
if (!diagnostic) {
|
||||
|
@ -851,11 +958,9 @@
|
|||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)updateJSONSerializable:(id)jsonSerializable
|
||||
- (instancetype)updateJSON:(id)json
|
||||
{
|
||||
id json = [jsonSerializable conformsToProtocol:@protocol(FBJSONSerializable)]
|
||||
? [jsonSerializable jsonSerializableRepresentation]
|
||||
: jsonSerializable;
|
||||
json = [json conformsToProtocol:@protocol(FBJSONSerializable)] ? [json jsonSerializableRepresentation] : json;
|
||||
if (!json) {
|
||||
return self;
|
||||
}
|
||||
|
|
|
@ -29,8 +29,9 @@
|
|||
{
|
||||
NSArray *values = @[self.photoDiagnostic, self.simulatorSystemLog, self.treeJSONDiagnostic];
|
||||
[self assertEqualityOfCopy:values];
|
||||
[self assertJSONSerialization:values];
|
||||
[self assertUnarchiving:values];
|
||||
[self assertJSONSerialization:values];
|
||||
[self assertJSONDeserialization:values];
|
||||
}
|
||||
|
||||
- (void)assertWritesOutToFile:(FBDiagnostic *)diagnostic
|
||||
|
@ -224,7 +225,7 @@
|
|||
};
|
||||
FBDiagnostic *diagnostic = [[[[FBDiagnosticBuilder builder]
|
||||
updateShortName:@"somelog"]
|
||||
updateJSONSerializable:json]
|
||||
updateJSON:json]
|
||||
build];
|
||||
|
||||
XCTAssertNotNil(diagnostic.asPath);
|
||||
|
@ -278,7 +279,7 @@
|
|||
{
|
||||
FBDiagnostic *diagnostic = [[[[FBDiagnosticBuilder builder]
|
||||
updateShortName:@"process_info"]
|
||||
updateJSONSerializable:self.launchCtlProcess]
|
||||
updateJSON:self.launchCtlProcess]
|
||||
build];
|
||||
|
||||
XCTAssertNotNil(diagnostic.asPath);
|
||||
|
@ -290,4 +291,21 @@
|
|||
[self assertWritesOutToFile:diagnostic];
|
||||
}
|
||||
|
||||
- (void)testJSONFileWiring
|
||||
{
|
||||
FBDiagnostic *localFile = self.treeJSONDiagnostic;
|
||||
FBDiagnostic *wireDiagnostic = [[[FBDiagnosticBuilder
|
||||
builderWithDiagnostic:localFile]
|
||||
readIntoMemory]
|
||||
build];
|
||||
|
||||
id json = [wireDiagnostic jsonSerializableRepresentation];
|
||||
NSError *error = nil;
|
||||
FBDiagnostic *remoteDiagnostic = [FBDiagnostic inflateFromJSON:json error:&error];
|
||||
XCTAssertNil(error);
|
||||
XCTAssertNotNil(remoteDiagnostic);
|
||||
XCTAssertEqualObjects(localFile.shortName , remoteDiagnostic.shortName);
|
||||
XCTAssertEqualObjects(localFile.asString, remoteDiagnostic.asString);
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
Загрузка…
Ссылка в новой задаче