Skip to content

Implement NSSecureCoding protocol for GDLLogEvent #2191

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 55 additions & 1 deletion GoogleDataLogger/GoogleDataLogger/Classes/GDLLogEvent.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
* limitations under the License.
*/

#import "GDLLogEvent.h"
#import <GoogleDataLogger/GDLLogEvent.h>

#import "GDLLogEvent_Private.h"

@implementation GDLLogEvent

Expand All @@ -29,4 +31,56 @@ - (instancetype)initWithLogMapID:(NSString *)logMapID logTarget:(NSInteger)logTa
return self;
}

#pragma mark - NSSecureCoding and NSCoding Protocols

/** NSCoding key for logMapID property. */
static NSString *logMapIDKey = @"_logMapID";

/** NSCoding key for logTarget property. */
static NSString *logTargetKey = @"_logTarget";

/** NSCoding key for extensionBytes property. */
static NSString *extensionBytesKey = @"_extensionBytes";

/** NSCoding key for qosTier property. */
static NSString *qosTierKey = @"_qosTier";

/** NSCoding key for clockSnapshot.timeMillis property. */
static NSString *clockSnapshotTimeMillisKey = @"_clockSnapshotTimeMillis";

/** NSCoding key for clockSnapshot.uptimeMillis property. */
static NSString *clockSnapshotUpTimeMillis = @"_clockSnapshotUpTimeMillis";

/** NSCoding key for clockSnapshot.timezoneOffsetMillis property. */
static NSString *clockSnapshotTimezoneOffsetMillis = @"_clockSnapshotTimezoneOffsetMillis";

+ (BOOL)supportsSecureCoding {
return YES;
}

- (id)initWithCoder:(NSCoder *)aDecoder {
NSString *logMapID = [aDecoder decodeObjectOfClass:[NSObject class] forKey:logMapIDKey];
NSInteger logTarget = [aDecoder decodeIntegerForKey:logTargetKey];
self = [self initWithLogMapID:logMapID logTarget:logTarget];
if (self) {
_extensionBytes = [aDecoder decodeObjectOfClass:[NSData class] forKey:extensionBytesKey];
_qosTier = [aDecoder decodeIntegerForKey:qosTierKey];
_clockSnapshot.timeMillis = [aDecoder decodeInt64ForKey:clockSnapshotTimeMillisKey];
_clockSnapshot.uptimeMillis = [aDecoder decodeInt64ForKey:clockSnapshotUpTimeMillis];
_clockSnapshot.timezoneOffsetMillis =
[aDecoder decodeInt64ForKey:clockSnapshotTimezoneOffsetMillis];
}
return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:_logMapID forKey:logMapIDKey];
[aCoder encodeInteger:_logTarget forKey:logTargetKey];
[aCoder encodeObject:_extensionBytes forKey:extensionBytesKey];
[aCoder encodeInteger:_qosTier forKey:qosTierKey];
[aCoder encodeInt64:_clockSnapshot.timeMillis forKey:clockSnapshotTimeMillisKey];
[aCoder encodeInt64:_clockSnapshot.uptimeMillis forKey:clockSnapshotUpTimeMillis];
[aCoder encodeInt64:_clockSnapshot.timezoneOffsetMillis forKey:clockSnapshotTimezoneOffsetMillis];
}

@end
12 changes: 12 additions & 0 deletions GoogleDataLogger/GoogleDataLogger/Classes/GDLLogWriter.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#import <GoogleDataLogger/GDLLogTransformer.h>

#import "GDLConsoleLogger.h"
#import "GDLLogEvent_Private.h"
#import "GDLLogStorage.h"

@implementation GDLLogWriter
Expand Down Expand Up @@ -60,6 +61,17 @@ - (void)writeLog:(GDLLogEvent *)log
return;
}
}

// Convert the extension to bytes after transforming.
NSAssert([log.extension respondsToSelector:@selector(protoBytes)],
@"The log event's extension must respond to -protoBytes.");
if ([log.extension respondsToSelector:@selector(protoBytes)]) {
log.extensionBytes = [log.extension protoBytes];
log.extension = nil;
} else {
GDLLogWarning(GDLMCWExtensionMissingBytesImpl, @"%@",
@"The log event's extension must respond to -protoBytes.");
}
// TODO(mikehaney24): [[GDLLogStorage sharedInstance] storeLog:transformedLog];
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright 2018 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 "GDLLogEvent.h"

#import "GDLLogClock.h"

NS_ASSUME_NONNULL_BEGIN

@interface GDLLogEvent ()

/** The serialized bytes of the log object. */
@property(nonatomic) NSData *extensionBytes;

/** The quality of service tier this log belongs to. */
@property(nonatomic) GDLLogQoS qosTier;

/** The clock snapshot at the time of logging. */
@property(nonatomic) GDLLogClockSnapshot clockSnapshot;

@end

NS_ASSUME_NONNULL_END
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

#import <Foundation/Foundation.h>

#import "GDLLogClock.h"
#import "GDLLogProto.h"

NS_ASSUME_NONNULL_BEGIN
Expand All @@ -39,7 +38,7 @@ typedef NS_ENUM(NSInteger, GDLLogQoS) {
GDLLogQoSFast = 4
};

@interface GDLLogEvent : NSObject
@interface GDLLogEvent : NSObject <NSSecureCoding>

/** The log map identifier, to allow backends to map the extension property to a proto. */
@property(readonly, nonatomic) NSString *logMapID;
Expand All @@ -49,13 +48,7 @@ typedef NS_ENUM(NSInteger, GDLLogQoS) {

/** The log object itself, encapsulated in the transport of your choice, as long as it implements
* the GDLLogProto protocol. */
@property(nonatomic) id<GDLLogProto> extension;

/** The quality of service tier this log belongs to. */
@property(nonatomic) GDLLogQoS qosTier;

/** The clock snapshot at the time of logging. */
@property(nonatomic) GDLLogClockSnapshot clockSnapshot;
@property(nullable, nonatomic) id<GDLLogProto> extension;

// Please use the designated initializer.
- (instancetype)init NS_UNAVAILABLE;
Expand Down
12 changes: 8 additions & 4 deletions GoogleDataLogger/GoogleDataLogger/Classes/Public/GDLLogger.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,19 @@ NS_ASSUME_NONNULL_BEGIN
logTransformers:(nullable NSArray<id<GDLLogTransformer>> *)logTransformers
logTarget:(NSInteger)logTarget NS_DESIGNATED_INITIALIZER;

/** Logs an internal telemetry event. Logs sent using this API are lower in priority, and sometimes
* won't be sent on their own.
/** Copies and logs an internal telemetry event. Logs sent using this API are lower in priority, and
* sometimes won't be sent on their own.
*
* @note This will convert the log event's extension proto to data and release the original log.
*
* @param logEvent The log event to log.
*/
- (void)logTelemetryEvent:(GDLLogEvent *)logEvent;

/** Logs an SDK service data event. Logs send using this API are higher in priority, and will cause
* a network request at some point in the relative near future.
/** Copies and logs an SDK service data event. Logs send using this API are higher in priority, and
* will cause a network request at some point in the relative near future.
*
* @note This will convert the log event's extension proto to data and release the original log.
*
* @param logEvent The log event to log.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@
* limitations under the License.
*/

#import "GDLLogEvent.h"
#import "GDLLogTransformer.h"
#import "GDLLogger.h"
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ static GULLoggerService kGDLConsoleLogger = @"[GoogleDataLogger]";
typedef NS_ENUM(NSInteger, GDLMessageCode) {

/** For warning messages concerning transform: not being implemented by a log transformer. */
GDLMCWTransformerDoesntImplementTransform = 1
GDLMCWTransformerDoesntImplementTransform = 1,

/** For warning messages concerning protoBytes: not being implemented by a log extension. */
GDLMCWExtensionMissingBytesImpl = 2
};

/** */
Expand Down
30 changes: 29 additions & 1 deletion GoogleDataLogger/Tests/GDLLogEventTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,45 @@

#import <XCTest/XCTest.h>

#import "GDLLogEvent.h"
#import <GoogleDataLogger/GDLLogEvent.h>

#import "GDLLogEvent_Private.h"

@interface GDLLogEventTest : XCTestCase

@end

@implementation GDLLogEventTest

/** Tests the designated initializer. */
- (void)testInit {
XCTAssertNotNil([[GDLLogEvent alloc] initWithLogMapID:@"1" logTarget:1]);
XCTAssertThrows([[GDLLogEvent alloc] initWithLogMapID:@"" logTarget:1]);
}

/** Tests NSKeyedArchiver encoding and decoding. */
- (void)testArchiving {
XCTAssertTrue([GDLLogEvent supportsSecureCoding]);
GDLLogClockSnapshot clockSnapshot = {10, 100, 1000};
GDLLogEvent *logEvent = [[GDLLogEvent alloc] initWithLogMapID:@"testID" logTarget:42];
logEvent.extensionBytes = [@"someData" dataUsingEncoding:NSUTF8StringEncoding];
logEvent.qosTier = GDLLogQoSTelemetry;
logEvent.clockSnapshot = clockSnapshot;

NSData *archiveData = [NSKeyedArchiver archivedDataWithRootObject:logEvent];

// To ensure that all the objects being retained by the original logEvent are dealloc'd.
logEvent = nil;

GDLLogEvent *decodedLogEvent = [NSKeyedUnarchiver unarchiveObjectWithData:archiveData];
XCTAssertEqualObjects(decodedLogEvent.logMapID, @"testID");
XCTAssertEqual(decodedLogEvent.logTarget, 42);
XCTAssertEqualObjects(decodedLogEvent.extensionBytes,
[@"someData" dataUsingEncoding:NSUTF8StringEncoding]);
XCTAssertEqual(decodedLogEvent.qosTier, GDLLogQoSTelemetry);
XCTAssertEqual(decodedLogEvent.clockSnapshot.timeMillis, 10);
XCTAssertEqual(decodedLogEvent.clockSnapshot.uptimeMillis, 100);
XCTAssertEqual(decodedLogEvent.clockSnapshot.timezoneOffsetMillis, 1000);
}

@end
5 changes: 5 additions & 0 deletions GoogleDataLogger/Tests/GDLLogWriterTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#import <GoogleDataLogger/GDLLogTransformer.h>

#import "GDLLogEvent.h"
#import "GDLLogExtensionTesterClasses.h"
#import "GDLLogWriter.h"
#import "GDLLogWriter_Private.h"

Expand Down Expand Up @@ -66,6 +67,7 @@ - (void)testSharedInstance {
- (void)testWriteLogWithoutTransformers {
GDLLogWriter *writer = [GDLLogWriter sharedInstance];
GDLLogEvent *log = [[GDLLogEvent alloc] initWithLogMapID:@"1" logTarget:1];
log.extension = [[GDLLogExtensionTesterSimple alloc] init];
XCTAssertNoThrow([writer writeLog:log afterApplyingTransformers:nil]);
dispatch_sync(writer.logWritingQueue, ^{
// TODO(mikehaney24): Assert that storage contains the log.
Expand All @@ -76,6 +78,7 @@ - (void)testWriteLogWithoutTransformers {
- (void)testWriteLogWithTransformersThatNilTheLog {
GDLLogWriter *writer = [GDLLogWriter sharedInstance];
GDLLogEvent *log = [[GDLLogEvent alloc] initWithLogMapID:@"2" logTarget:1];
log.extension = [[GDLLogExtensionTesterSimple alloc] init];
NSArray<id<GDLLogTransformer>> *transformers =
@[ [[GDLLogWriterTestNilingTransformer alloc] init] ];
XCTAssertNoThrow([writer writeLog:log afterApplyingTransformers:transformers]);
Expand All @@ -88,6 +91,7 @@ - (void)testWriteLogWithTransformersThatNilTheLog {
- (void)testWriteLogWithTransformersThatCreateANewLog {
GDLLogWriter *writer = [GDLLogWriter sharedInstance];
GDLLogEvent *log = [[GDLLogEvent alloc] initWithLogMapID:@"2" logTarget:1];
log.extension = [[GDLLogExtensionTesterSimple alloc] init];
NSArray<id<GDLLogTransformer>> *transformers =
@[ [[GDLLogWriterTestNewLogTransformer alloc] init] ];
XCTAssertNoThrow([writer writeLog:log afterApplyingTransformers:transformers]);
Expand All @@ -100,6 +104,7 @@ - (void)testWriteLogWithTransformersThatCreateANewLog {
- (void)testWriteLogWithBadTransformer {
GDLLogWriter *writer = [GDLLogWriter sharedInstance];
GDLLogEvent *log = [[GDLLogEvent alloc] initWithLogMapID:@"2" logTarget:1];
log.extension = [[GDLLogExtensionTesterSimple alloc] init];
NSArray *transformers = @[ [[NSObject alloc] init] ];
@try {
dispatch_sync(writer.logWritingQueue, ^{
Expand Down
5 changes: 5 additions & 0 deletions GoogleDataLogger/Tests/GDLLoggerTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@

#import <XCTest/XCTest.h>

#import <GoogleDataLogger/GDLLogEvent.h>
#import <GoogleDataLogger/GDLLogger.h>

#import "GDLLogExtensionTesterClasses.h"

@interface GDLLoggerTest : XCTestCase

@end
Expand All @@ -34,13 +37,15 @@ - (void)testInit {
- (void)testLogTelemetryEvent {
GDLLogger *logger = [[GDLLogger alloc] initWithLogMapID:@"1" logTransformers:nil logTarget:1];
GDLLogEvent *event = [logger newEvent];
event.extension = [[GDLLogExtensionTesterSimple alloc] init];
XCTAssertNoThrow([logger logTelemetryEvent:event]);
}

/** Tests logging a data event. */
- (void)testLogDataEvent {
GDLLogger *logger = [[GDLLogger alloc] initWithLogMapID:@"1" logTransformers:nil logTarget:1];
GDLLogEvent *event = [logger newEvent];
event.extension = [[GDLLogExtensionTesterSimple alloc] init];
XCTAssertNoThrow([logger logDataEvent:event]);
}

Expand Down
31 changes: 31 additions & 0 deletions GoogleDataLogger/Tests/Helpers/GDLLogExtensionTesterClasses.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2018 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 <Foundation/Foundation.h>

#import <GoogleDataLogger/GDLLogProto.h>

NS_ASSUME_NONNULL_BEGIN

/** A class to represent a simple log proto. */
@interface GDLLogExtensionTesterSimple : NSObject <GDLLogProto>

/** A string that will be turned into bytes. */
@property(nonatomic) NSString *aString;

@end

NS_ASSUME_NONNULL_END
33 changes: 33 additions & 0 deletions GoogleDataLogger/Tests/Helpers/GDLLogExtensionTesterClasses.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 2018 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 "GDLLogExtensionTesterClasses.h"

@implementation GDLLogExtensionTesterSimple

- (instancetype)init {
self = [super init];
if (self) {
_aString = @"test";
}
return self;
}

- (NSData *)protoBytes {
return [_aString dataUsingEncoding:NSUTF8StringEncoding];
}

@end