-
Notifications
You must be signed in to change notification settings - Fork 297
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
17 changed files
with
1,163 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
load("@build_bazel_rules_apple//apple:macos.bzl", "macos_command_line_application") | ||
load("//:helper.bzl", "santa_unit_test") | ||
|
||
package(default_visibility = ["//:santa_package_group"]) | ||
|
||
licenses(["notice"]) # Apache 2.0 | ||
|
||
objc_library( | ||
name = "SNTMetricServiceLib", | ||
srcs = [ | ||
"SNTMetricService.h", | ||
"SNTMetricService.m", | ||
"main.m", | ||
], | ||
deps = [ | ||
"//Source/common:SNTConfigurator", | ||
"//Source/common:SNTLogging", | ||
"//Source/common:SNTMetricSet", | ||
"//Source/common:SNTXPCMetricServiceInterface", | ||
"//Source/santametricservice/Formats:SNTMetricRawJSONFormat", | ||
"//Source/santametricservice/Writers:SNTMetricFileWriter", | ||
"@MOLCodesignChecker", | ||
"@MOLXPCConnection", | ||
], | ||
) | ||
|
||
santa_unit_test( | ||
name = "SNTMetricServiceTest", | ||
srcs = ["SNTMetricServiceTest.m"], | ||
deps = [ | ||
":SNTMetricServiceLib", | ||
"@OCMock", | ||
], | ||
) | ||
|
||
test_suite( | ||
name = "unit_tests", | ||
tests = [ | ||
":SNTMetricServiceTest", | ||
"//Source/santametricservice/Formats:SNTMetricRawJSONFormatTest", | ||
"//Source/santametricservice/Writers:SNTMetricFileWriterTest", | ||
], | ||
) | ||
|
||
macos_command_line_application( | ||
name = "santametricservice", | ||
bundle_id = "com.google.santa.metricservice", | ||
infoplists = ["Info.plist"], | ||
minimum_os_version = "10.15", | ||
version = "//:version", | ||
visibility = ["//:santa_package_group"], | ||
deps = [":SNTMetricServiceLib"], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
load("@build_bazel_rules_apple//apple:macos.bzl", "macos_command_line_application") | ||
load("//:helper.bzl", "santa_unit_test") | ||
|
||
package(default_visibility = ["//:santa_package_group"]) | ||
|
||
licenses(["notice"]) # Apache 2.0 | ||
|
||
objc_library( | ||
name = "SNTMetricFormat", | ||
hdrs = ["SNTMetricFormat.h"], | ||
) | ||
|
||
objc_library( | ||
name = "SNTMetricRawJSONFormat", | ||
srcs = [ | ||
"SNTMetricFormat.h", | ||
"SNTMetricRawJSONFormat.h", | ||
"SNTMetricRawJSONFormat.m", | ||
], | ||
deps = [ | ||
":SNTMetricFormat", | ||
"//Source/common:SNTLogging", | ||
], | ||
) | ||
|
||
santa_unit_test( | ||
name = "SNTMetricRawJSONFormatTest", | ||
srcs = [ | ||
"SNTMetricRawJSONFormatTest.m", | ||
], | ||
structured_resources = glob(["testdata/**"]), | ||
deps = [ | ||
":SNTMetricRawJSONFormat", | ||
"//Source/common:SNTMetricSet", | ||
], | ||
) | ||
|
||
test_suite( | ||
name = "format_tests", | ||
tests = [ | ||
":SNTMetricRawJSONFormatTest", | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/// Copyright 2021 Google Inc. 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 <Foundation/Foundation.h> | ||
|
||
@protocol SNTMetricFormat | ||
- (NSArray<NSData *> *)convert:(NSDictionary *)metrics error:(NSError **)err; | ||
@end |
20 changes: 20 additions & 0 deletions
20
Source/santametricservice/Formats/SNTMetricRawJSONFormat.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/// Copyright 2021 Google Inc. 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 <Foundation/Foundation.h> | ||
|
||
#import "Source/santametricservice/Formats/SNTMetricFormat.h" | ||
|
||
@interface SNTMetricRawJSONFormat : NSObject <SNTMetricFormat> | ||
@end |
101 changes: 101 additions & 0 deletions
101
Source/santametricservice/Formats/SNTMetricRawJSONFormat.m
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
/// Copyright 2021 Google Inc. 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 "Source/common/SNTLogging.h" | ||
|
||
#import "Source/santametricservice/Formats/SNTMetricRawJSONFormat.h" | ||
|
||
@implementation SNTMetricRawJSONFormat { | ||
NSDateFormatter *_dateFormatter; | ||
} | ||
|
||
- (instancetype)init { | ||
self = [super init]; | ||
if (self) { | ||
_dateFormatter = [[NSDateFormatter alloc] init]; | ||
[_dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"]; | ||
} | ||
return self; | ||
} | ||
|
||
- (NSArray *)normalizeArray:(NSArray *)arr { | ||
NSMutableArray *normalized = [NSMutableArray arrayWithArray:arr]; | ||
|
||
[normalized enumerateObjectsUsingBlock:^(id value, NSUInteger index, BOOL *stop) { | ||
if ([value isKindOfClass:[NSDate class]]) { | ||
normalized[index] = [self->_dateFormatter stringFromDate:(NSDate *)value]; | ||
} else if ([value isKindOfClass:[NSArray class]]) { | ||
normalized[index] = [self normalizeArray:(NSArray *)value]; | ||
} else if ([value isKindOfClass:[NSDictionary class]]) { | ||
normalized[index] = [self normalize:(NSDictionary *)value]; | ||
} | ||
}]; | ||
|
||
return normalized; | ||
} | ||
|
||
/** | ||
* Normalizes the metrics dictionary for exporting to JSON | ||
**/ | ||
- (NSDictionary *)normalize:(NSDictionary *)metrics { | ||
// Convert NSDate's to RFC3339 in strings as NSDate's cannot be serialized | ||
// to JSON. | ||
NSMutableDictionary *normalizedMetrics = [NSMutableDictionary dictionaryWithDictionary:metrics]; | ||
|
||
[metrics enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { | ||
if ([value isKindOfClass:[NSDate class]]) { | ||
normalizedMetrics[key] = [self->_dateFormatter stringFromDate:(NSDate *)value]; | ||
} else if ([value isKindOfClass:[NSDictionary class]]) { | ||
normalizedMetrics[key] = [self normalize:(NSDictionary *)value]; | ||
} else if ([value isKindOfClass:[NSArray class]]) { | ||
normalizedMetrics[key] = [self normalizeArray:(NSArray *)value]; | ||
} | ||
}]; | ||
|
||
return (NSDictionary *)normalizedMetrics; | ||
} | ||
|
||
/* | ||
* Convert normalies and converts the metrics dictionary to a single JSON | ||
* object. | ||
* | ||
* @param metrics an NSDictionary exported by the SNTMetricSet | ||
* @param error a pointer to an NSError to allow errors to bubble up. | ||
* | ||
* Returns an NSArray containing one entry of all metrics serialized to JSON or | ||
* nil on error. | ||
*/ | ||
- (NSArray<NSData *> *)convert:(NSDictionary *)metrics error:(NSError **)err { | ||
NSDictionary *normalizedMetrics = [self normalize:metrics]; | ||
|
||
if (![NSJSONSerialization isValidJSONObject:normalizedMetrics]) { | ||
*err = [[NSError alloc] | ||
initWithDomain:@"SNTMetricRawJSONFileWriter" | ||
code:EINVAL | ||
userInfo:@{ | ||
NSLocalizedDescriptionKey : @"unable to convert metrics to JSON: invalid metrics" | ||
}]; | ||
|
||
return nil; | ||
} | ||
|
||
NSData *json = [NSJSONSerialization dataWithJSONObject:normalizedMetrics | ||
options:NSJSONWritingPrettyPrinted | ||
error:err]; | ||
if (json == nil && *err != nil) { | ||
return nil; | ||
} | ||
|
||
return @[ json ]; | ||
} | ||
@end |
153 changes: 153 additions & 0 deletions
153
Source/santametricservice/Formats/SNTMetricRawJSONFormatTest.m
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
#import <XCTest/XCTest.h> | ||
|
||
#import "Source/common/SNTMetricSet.h" | ||
#import "Source/santametricservice/Formats/SNTMetricRawJSONFormat.h" | ||
|
||
NSDictionary *validMetricsDict = nil; | ||
|
||
@interface SNTMetricRawJSONFormatTest : XCTestCase | ||
@end | ||
|
||
@implementation SNTMetricRawJSONFormatTest | ||
|
||
- (void)initializeValidMetricsDict { | ||
NSDateFormatter *formatter = NSDateFormatter.new; | ||
[formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"]; | ||
NSDate *fixedDate = [formatter dateFromString:@"2021-09-16T21:07:34.826Z"]; | ||
|
||
validMetricsDict = @{ | ||
@"root_labels" : @{@"hostname" : @"testHost", @"username" : @"testUser"}, | ||
@"metrics" : @{ | ||
@"/build/label" : @{ | ||
@"type" : [NSNumber numberWithInt:(int)SNTMetricTypeConstantString], | ||
@"fields" : @{ | ||
@"" : @[ @{ | ||
@"value" : @"", | ||
@"created" : fixedDate, | ||
@"last_updated" : fixedDate, | ||
@"data" : @"20210809.0.1" | ||
} ] | ||
} | ||
}, | ||
@"/santa/events" : @{ | ||
@"type" : [NSNumber numberWithInt:(int)SNTMetricTypeCounter], | ||
@"fields" : @{ | ||
@"rule_type" : @[ | ||
@{ | ||
@"value" : @"binary", | ||
@"created" : fixedDate, | ||
@"last_updated" : fixedDate, | ||
@"data" : @1, | ||
}, | ||
@{ | ||
@"value" : @"certificate", | ||
@"created" : fixedDate, | ||
@"last_updated" : fixedDate, | ||
@"data" : @2, | ||
}, | ||
], | ||
}, | ||
}, | ||
@"/santa/rules" : @{ | ||
@"type" : [NSNumber numberWithInt:(int)SNTMetricTypeGaugeInt64], | ||
@"fields" : @{ | ||
@"rule_type" : @[ | ||
@{ | ||
@"value" : @"binary", | ||
@"created" : fixedDate, | ||
@"last_updated" : fixedDate, | ||
@"data" : @1 | ||
}, | ||
@{ | ||
@"value" : @"certificate", | ||
@"created" : fixedDate, | ||
@"last_updated" : fixedDate, | ||
@"data" : @3 | ||
} | ||
] | ||
}, | ||
}, | ||
@"/santa/using_endpoint_security_framework" : @{ | ||
@"type" : [NSNumber numberWithInt:(int)SNTMetricTypeConstantBool], | ||
@"fields" : @{ | ||
@"" : @[ @{ | ||
@"value" : @"", | ||
@"created" : fixedDate, | ||
@"last_updated" : fixedDate, | ||
@"data" : [NSNumber numberWithBool:YES] | ||
} ] | ||
} | ||
}, | ||
@"/proc/birth_timestamp" : @{ | ||
@"type" : [NSNumber numberWithInt:(int)SNTMetricTypeConstantInt64], | ||
@"fields" : @{ | ||
@"" : @[ @{ | ||
@"value" : @"", | ||
@"created" : fixedDate, | ||
@"last_updated" : fixedDate, | ||
@"data" : [NSNumber numberWithLong:1250999830800] | ||
} ] | ||
}, | ||
}, | ||
@"/proc/memory/virtual_size" : @{ | ||
@"type" : [NSNumber numberWithInt:(int)SNTMetricTypeGaugeInt64], | ||
@"fields" : @{ | ||
@"" : @[ @{ | ||
@"value" : @"", | ||
@"created" : fixedDate, | ||
@"last_updated" : fixedDate, | ||
@"data" : [NSNumber numberWithInt:987654321] | ||
} ] | ||
} | ||
}, | ||
@"/proc/memory/resident_size" : @{ | ||
@"type" : [NSNumber numberWithInt:(int)SNTMetricTypeGaugeInt64], | ||
@"fields" : @{ | ||
@"" : @[ @{ | ||
@"value" : @"", | ||
@"created" : fixedDate, | ||
@"last_updated" : fixedDate, | ||
@"data" : [NSNumber numberWithInt:123456789] | ||
} ] | ||
}, | ||
}, | ||
} | ||
}; | ||
} | ||
|
||
- (void)setUp { | ||
[self initializeValidMetricsDict]; | ||
} | ||
|
||
- (void)testMetricsConversionToJSON { | ||
SNTMetricRawJSONFormat *formatter = [[SNTMetricRawJSONFormat alloc] init]; | ||
NSError *err = nil; | ||
NSArray<NSData *> *output = [formatter convert:validMetricsDict error:&err]; | ||
|
||
XCTAssertEqual(1, [output count]); | ||
XCTAssertNotNil(output[0]); | ||
XCTAssertNil(err); | ||
|
||
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:output[0] | ||
options:NSJSONReadingAllowFragments | ||
error:&err]; | ||
XCTAssertNotNil(jsonDict); | ||
|
||
NSString *path = [[NSBundle bundleForClass:[self class]] resourcePath]; | ||
path = [path stringByAppendingPathComponent:@"testdata/json/test.json"]; | ||
|
||
NSFileManager *filemgr = [NSFileManager defaultManager]; | ||
NSData *goldenFileData = [filemgr contentsAtPath:path]; | ||
|
||
XCTAssertNotNil(goldenFileData, @"unable to open / read golden file"); | ||
|
||
NSDictionary *expectedJSONDict = | ||
[NSJSONSerialization JSONObjectWithData:goldenFileData | ||
options:NSJSONReadingAllowFragments | ||
error:&err]; | ||
|
||
XCTAssertNotNil(expectedJSONDict); | ||
XCTAssertEqualObjects(expectedJSONDict, jsonDict, @"generated JSON does not match golden file."); | ||
} | ||
|
||
@end |
Oops, something went wrong.