Files
Jeremy JiangandPaul Beusterien ec193d0150 Add Performance Support for Swift Package Manager (#8412)
* Create NanoPb code generation scripts (#8336)

* Create NanoPb code generation scripts

* Fix style and add README

* Fix copyright

* Update proto_generator.py

* Update README.md

* Create nanopb options file. (#8371)

* Create NanoPb code generation scripts

* Fix style and add README

* Fix copyright

* Update perf_metrics.options

* Update options with map

* Add generated proto files.

* Update imports.

* Convert Objective-C Classes to Nanopb (#8387)

* Convert all traces to nanopb

* Refactor for loop.

* Add set has_application_info to true.

* Incorporated comments.

* Fix style

* Create NanoPb code generation scripts (#8336)

* Create NanoPb code generation scripts

* Fix style and add README

* Fix copyright

* Update proto_generator.py

* Update README.md

* Create nanopb options file. (#8371)

* Create NanoPb code generation scripts

* Fix style and add README

* Fix copyright

* Update perf_metrics.options

* Update options with map

* Add generated proto files.

* Update imports.

* Convert Objective-C Classes to Nanopb (#8387)

* Convert all traces to nanopb

* Refactor for loop.

* Add set has_application_info to true.

* Incorporated comments.

* Fix style

* Fix style

* Convert nanopb struct to GDTCOREventDataObject and update the source code to use nanopb struct. (#8439)

* Convert all traces to nanopb

* Refactor for loop.

* WIP: nanopb conversion in FPRClient and FPREvent

* Update FPRClientTest.m

* Update FPRClient.m

* Update FPRClientTest.m

* Add set has_application_info to true.

* Remove proto imports.

* Set has_fields to be true in FPRTestUtils.m

* Completed GDTEvent conversion.

* Fix sampler tests.

* Fix style

* Refactor nanopb struct setter

* Fix style

* Fix pod-lib-lint failures.

* Update FPRClient with decoded string

* Set some "_has" fields to true.

* Add prefix to extern methods.

* Fix style.

* Update FPRClient to use trace.name without FPRDecodeString

* Fix style

* Incorporate comments.

* Integrate Performance with SPM (#8476)

* Convert all traces to nanopb

* Refactor for loop.

* WIP: nanopb conversion in FPRClient and FPREvent

* Update FPRClientTest.m

* Update FPRClient.m

* Update FPRClientTest.m

* Add set has_application_info to true.

* Remove proto imports.

* Set has_fields to be true in FPRTestUtils.m

* Completed GDTEvent conversion.

* Fix sampler tests.

* Fix style

* Refactor nanopb struct setter

* Fix style

* Fix pod-lib-lint failures.

* Update FPRClient with decoded string

* Set some "_has" fields to true.

* Add prefix to extern methods.

* Fix style.

* Update FPRClient to use trace.name without FPRDecodeString

* Fix style

* Update Package.swift

* Update Package.swift

* Update Package.swift

* Made SDK and unit tests buildable.

* Made all unit tests passing.

* Update keyWindow style.

* Add Performance to workflow.

* Update FPRUIViewControllerInstrument.h

* Incorporate comments.

* Add Performance to SwiftPMTests.

* Update style.

* Fix Unit tests and update workflow.

* Add FirebasePerformance wrapper

* Update import statement.

* Update style.

* Update performance.yml

* Create PerformanceUnit.xcscheme

* Update objc-module.m

* Update objc-module.m

* Updae objc-header.m

* Update objc-header.m

* Incorporate feedback.

* Update objc-header.m

* Organize folder structure to fix the spm tests.

* Update public import path

* Delete xcodebuild.log

* Update workflow files

* Fix failing swift-test for Perf SPM (#8507)

* Fix UIKit import

* Update FPRNetworkTraceTest.m

* Exclude TARGET_OS_MACCATALYST from objc header test

* Update main.swift

* Update main.swift

Co-authored-by: Paul Beusterien <paulbeusterien@google.com>

* Remove Protobuf dependency  (#8511)

* Remove protobuf dependency

* Update FirebasePerformance.podspec

* Incorporate comments.

* Update UIKit import

Co-authored-by: Paul Beusterien <paulbeusterien@google.com>
2021-08-10 13:41:18 -04:00

275 lines
13 KiB
Objective-C

// Copyright 2020 Google LLC
//
// 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 <XCTest/XCTest.h>
#import "FirebasePerformance/Sources/Loggers/FPRGDTLogSampler+Private.h"
#import "FirebasePerformance/Sources/Loggers/FPRGDTLogSampler.h"
#import "FirebasePerformance/Sources/Configurations/FPRConfigurations+Private.h"
#import "FirebasePerformance/Sources/FPRNanoPbUtils.h"
#import "FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace+Private.h"
#import "FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace.h"
#import "FirebasePerformance/Sources/Loggers/FPRGDTEvent.h"
#import "FirebasePerformance/Sources/Public/FirebasePerformance/FIRTrace.h"
#import "FirebasePerformance/Sources/Timer/FIRTrace+Internal.h"
#import "FirebasePerformance/Sources/Timer/FIRTrace+Private.h"
#import "FirebasePerformance/Tests/Unit/FPRTestCase.h"
#import "FirebasePerformance/Tests/Unit/FPRTestUtils.h"
#import "FirebasePerformance/Tests/Unit/Fakes/FPRFakeConfigurations.h"
#import <GoogleDataTransport/GoogleDataTransport.h>
#import <OCMock/OCMock.h>
@interface FPRGDTLogSamplerTest : FPRTestCase
/** The log sampler object. */
@property(nonatomic) FPRGDTLogSampler *logSampler;
/** Transport object which generates initial GDTCOREvent. */
@property(nonatomic) GDTCORTransport *gdtfllTransport;
/** GDTCOREvent which contains trace event for testing. */
@property(nonatomic) GDTCOREvent *transportTraceEvent;
/** GDTCOREvent which contains network trace event for testing. */
@property(nonatomic) GDTCOREvent *transportNetworkEvent;
/** Fake configurations flags used for overriding configs. */
@property(nonatomic) FPRFakeConfigurations *fakeConfigs;
@end
@implementation FPRGDTLogSamplerTest
- (void)setUp {
[super setUp];
self.appFake.fakeIsDataCollectionDefaultEnabled = YES;
// Mocks log sampling configuration to allow event dispatch.
self.fakeConfigs =
[[FPRFakeConfigurations alloc] initWithSources:FPRConfigurationSourceRemoteConfig];
self.logSampler = [[FPRGDTLogSampler alloc] initWithFlags:self.fakeConfigs
samplingThreshold:0.66];
[self.fakeConfigs setTraceSamplingRate:1.0];
[self.fakeConfigs setNetworkSamplingRate:1.0];
// Defines transport logger for generating log events.
self.gdtfllTransport = [[GDTCORTransport alloc] initWithMappingID:@"462"
transformers:nil
target:kGDTCORTargetFLL];
// Generates sample trace metric.
firebase_perf_v1_PerfMetric tracePerfMetric = [FPRTestUtils createRandomPerfMetric:@"Random"];
self.transportTraceEvent = [self.gdtfllTransport eventForTransport];
self.transportTraceEvent.qosTier = GDTCOREventQosDefault;
self.transportTraceEvent.dataObject = [FPRGDTEvent gdtEventForPerfMetric:tracePerfMetric];
// Generates sample network trace metric.
NSString *randomAppID = @"RandomID";
firebase_perf_v1_PerfMetric networkTraceMetric = FPRGetPerfMetricMessage(randomAppID);
NSURL *URL = [NSURL URLWithString:@"https://abc.xyz"];
NSURLRequest *URLRequest = [NSURLRequest requestWithURL:URL];
FPRNetworkTrace *networkTrace = [[FPRNetworkTrace alloc] initWithURLRequest:URLRequest];
[networkTrace start];
[networkTrace checkpointState:FPRNetworkTraceCheckpointStateInitiated];
[networkTrace checkpointState:FPRNetworkTraceCheckpointStateResponseReceived];
NSDictionary<NSString *, NSString *> *headerFields = @{@"Content-Type" : @"text/json"};
NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:URL
statusCode:200
HTTPVersion:@"HTTP/1.1"
headerFields:headerFields];
[networkTrace didReceiveData:[NSData data]];
[networkTrace didCompleteRequestWithResponse:response error:nil];
// Make sure there are no sessions as they will not be sampled.
networkTrace.activeSessions = [NSMutableArray array];
FPRSetNetworkRequestMetric(&networkTraceMetric, FPRGetNetworkRequestMetric(networkTrace));
self.transportNetworkEvent = [self.gdtfllTransport eventForTransport];
self.transportNetworkEvent.qosTier = GDTCOREventQosDefault;
self.transportNetworkEvent.dataObject = [FPRGDTEvent gdtEventForPerfMetric:networkTraceMetric];
}
/** Validates if the object creation is successful. */
- (void)testObjectCreation {
XCTAssertNotNil([[FPRGDTLogSampler alloc] init]);
}
/** Validates if sampling works for valid values of configs. */
- (void)testLogSamplingWithBucketIdentifier {
[self.fakeConfigs setTraceSamplingRate:0.05];
[self.fakeConfigs setNetworkSamplingRate:0.05];
XCTAssertNil([self.logSampler transformGDTEvent:self.transportTraceEvent]);
XCTAssertNil([self.logSampler transformGDTEvent:self.transportNetworkEvent]);
[self.fakeConfigs setTraceSamplingRate:0.65];
[self.fakeConfigs setNetworkSamplingRate:0.65];
XCTAssertNil([self.logSampler transformGDTEvent:self.transportTraceEvent]);
XCTAssertNil([self.logSampler transformGDTEvent:self.transportNetworkEvent]);
[self.fakeConfigs setTraceSamplingRate:0.66];
[self.fakeConfigs setNetworkSamplingRate:0.66];
XCTAssertEqual([self.logSampler transformGDTEvent:self.transportTraceEvent],
self.transportTraceEvent);
XCTAssertEqual([self.logSampler transformGDTEvent:self.transportNetworkEvent],
self.transportNetworkEvent);
[self.fakeConfigs setTraceSamplingRate:0.67];
[self.fakeConfigs setNetworkSamplingRate:0.67];
XCTAssertEqual([self.logSampler transformGDTEvent:self.transportTraceEvent],
self.transportTraceEvent);
XCTAssertEqual([self.logSampler transformGDTEvent:self.transportNetworkEvent],
self.transportNetworkEvent);
[self.fakeConfigs setTraceSamplingRate:1.0];
[self.fakeConfigs setNetworkSamplingRate:1.0];
XCTAssertEqual([self.logSampler transformGDTEvent:self.transportTraceEvent],
self.transportTraceEvent);
XCTAssertEqual([self.logSampler transformGDTEvent:self.transportNetworkEvent],
self.transportNetworkEvent);
}
/** Validates if the trace and network trace event honor different sampling rates. */
- (void)testSamplingWhenTracesAndNetworkSamplingRatesAreDifferent {
[self.fakeConfigs setTraceSamplingRate:0.65];
[self.fakeConfigs setNetworkSamplingRate:0.67];
XCTAssertNil([self.logSampler transformGDTEvent:self.transportTraceEvent]);
XCTAssertEqual([self.logSampler transformGDTEvent:self.transportNetworkEvent],
self.transportNetworkEvent);
[self.fakeConfigs setTraceSamplingRate:0.67];
[self.fakeConfigs setNetworkSamplingRate:0.65];
XCTAssertEqual([self.logSampler transformGDTEvent:self.transportTraceEvent],
self.transportTraceEvent);
XCTAssertNil([self.logSampler transformGDTEvent:self.transportNetworkEvent]);
}
/** Validates if sampling works when trace sampling rate is greater than 1. */
- (void)testTraceSamplingWithInvalidNumerator {
[self.fakeConfigs setTraceSamplingRate:2.0];
XCTAssertEqual([self.logSampler transformGDTEvent:self.transportTraceEvent],
self.transportTraceEvent);
}
/** Validates if sampling works with trace sampling rate of Zero. */
- (void)testTraceSamplingWithZeroNumerator {
[self.fakeConfigs setTraceSamplingRate:0.0];
XCTAssertNil([self.logSampler transformGDTEvent:self.transportTraceEvent]);
}
/** Validates if sampling works when network sampling rate is greater than 1. */
- (void)testNetworkSamplingWithInvalidNumerator {
[self.fakeConfigs setNetworkSamplingRate:2.0];
XCTAssertEqual([self.logSampler transformGDTEvent:self.transportNetworkEvent],
self.transportNetworkEvent);
}
/** Validates if sampling works with network sampling rate of Zero. */
- (void)testNetworkSamplingWithZeroNumerator {
[self.fakeConfigs setNetworkSamplingRate:0.0];
XCTAssertNil([self.logSampler transformGDTEvent:self.transportNetworkEvent]);
}
/** Validates if the trace event is not dropped if the session is verbose. */
- (void)testTraceSamplingWhenSessionIsVerbose {
[self.fakeConfigs setTraceSamplingRate:0.0];
// Trace is verbose.
firebase_perf_v1_PerfMetric traceMetric = [FPRTestUtils createVerboseRandomPerfMetric:@"Random"];
GDTCOREvent *traceEvent = [self.gdtfllTransport eventForTransport];
traceEvent.qosTier = GDTCOREventQosDefault;
traceEvent.dataObject = [FPRGDTEvent gdtEventForPerfMetric:traceMetric];
// Trace event will not be dropped.
XCTAssertEqual([self.logSampler transformGDTEvent:traceEvent], traceEvent);
}
/** Validates if the trace event is sampled if the session is not verbose. */
- (void)testTraceSamplingWhenSessionIsNotVerbose {
[self.fakeConfigs setTraceSamplingRate:0.0];
// Trace is non-verbose.
firebase_perf_v1_PerfMetric tracePerfMetric = [FPRTestUtils createRandomPerfMetric:@"random"];
GDTCOREvent *traceEvent = [self.gdtfllTransport eventForTransport];
traceEvent.qosTier = GDTCOREventQosDefault;
traceEvent.dataObject = [FPRGDTEvent gdtEventForPerfMetric:tracePerfMetric];
// Trace event is dropped because of sampling.
XCTAssertNil([self.logSampler transformGDTEvent:traceEvent]);
}
/** Validates if the network trace event is not sampled if the session is verbose. */
- (void)testNetworkTraceSamplingWhenSessionIsVerbose {
self.appFake.fakeIsDataCollectionDefaultEnabled = YES;
[self.fakeConfigs setNetworkSamplingRate:0.0];
// Network request is verbose.
firebase_perf_v1_PerfMetric networkMetric = FPRGetPerfMetricMessage(@"RandomID");
NSURL *URL = [NSURL URLWithString:@"https://abc.com"];
NSURLRequest *testURLRequest = [NSURLRequest requestWithURL:URL];
FPRNetworkTrace *networkTrace = [[FPRNetworkTrace alloc] initWithURLRequest:testURLRequest];
[networkTrace start];
NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:testURLRequest.URL
statusCode:200
HTTPVersion:@"HTTP/1.1"
headerFields:nil];
[networkTrace didCompleteRequestWithResponse:response error:nil];
FPRSessionDetails *details =
[[FPRSessionDetails alloc] initWithSessionId:@"random" options:FPRSessionOptionsGauges];
networkTrace.activeSessions = [[NSMutableArray alloc] initWithObjects:details, nil];
FPRSetNetworkRequestMetric(&networkMetric, FPRGetNetworkRequestMetric(networkTrace));
GDTCOREvent *networkEvent = [self.gdtfllTransport eventForTransport];
networkEvent.qosTier = GDTCOREventQosDefault;
networkEvent.dataObject = [FPRGDTEvent gdtEventForPerfMetric:networkMetric];
// Network event will not be dropped.
XCTAssertEqual([self.logSampler transformGDTEvent:networkEvent], networkEvent);
}
/** Validates if the network trace event is sampled if the session is not verbose. */
- (void)testNetworkTraceSamplingWhenSessionIsNotVerbose {
[self.fakeConfigs setNetworkSamplingRate:0.0];
// Network request is not verbose.
firebase_perf_v1_PerfMetric networkMetric = FPRGetPerfMetricMessage(@"RandomID");
NSURL *URL = [NSURL URLWithString:@"https://abc.com"];
NSURLRequest *testURLRequest = [NSURLRequest requestWithURL:URL];
FPRNetworkTrace *networkTrace = [[FPRNetworkTrace alloc] initWithURLRequest:testURLRequest];
[networkTrace start];
NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:testURLRequest.URL
statusCode:200
HTTPVersion:@"HTTP/1.1"
headerFields:nil];
[networkTrace didCompleteRequestWithResponse:response error:nil];
// Make sure the session information is empty.
networkTrace.activeSessions = [NSMutableArray array];
FPRSetNetworkRequestMetric(&networkMetric, FPRGetNetworkRequestMetric(networkTrace));
GDTCOREvent *networkEvent = [self.gdtfllTransport eventForTransport];
networkEvent.qosTier = GDTCOREventQosDefault;
networkEvent.dataObject = [FPRGDTEvent gdtEventForPerfMetric:networkMetric];
// Network event is dropped because of sampling.
XCTAssertNil([self.logSampler transformGDTEvent:networkEvent]);
}
@end