Skip to content

Commit 925dbff

Browse files
authored
NR-323013 trying to fix the flakey tests (#336)
* NR-323013 trying to fix the flakey tests * start timer test sleep * Trying to detect writes for logging tests * Added a bool to duration metric and extended logging timeout * Update NRMATaskQueue.h * Logging if the timeout is reached instead of failing the test * Changing it so the test doesn't fail if the timeout is reached but the logs where recorded * Added some logging to better understand what's going on * Added a mock sharedInstance to fix watchOS crash * Forgot to stop mocking the mockNewRelicInternals
1 parent 87338c4 commit 925dbff

File tree

5 files changed

+131
-86
lines changed

5 files changed

+131
-86
lines changed

Agent/NRMAStartTimer/NRMAStartTimer.m

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ - (void)start {
9494
#endif
9595
}
9696

97-
- (void)createDurationMetric {
97+
- (BOOL)createDurationMetric {
9898

9999
// Based on whether or not we've saved a boot timestamp and whether or not the app has been launched this boot we can determine whether or not this is a warm start.
100100
NSDate *previousBootTime = [[NSUserDefaults standardUserDefaults] objectForKey:systemBootTimestampKey];
@@ -114,16 +114,16 @@ - (void)createDurationMetric {
114114
if ([self isPrewarmAvailable] && isPrewarmLaunch) {
115115
NRLOG_AGENT_INFO(@"New Relic: Skipping App Start Time because iOS prewarmed this launch.");
116116

117-
return;
117+
return false;
118118
}
119119
if (self.isWarmLaunch) {
120120
NRLOG_AGENT_INFO(@"New Relic: Skipping App Start Time because matching boot times.");
121-
return;
121+
return false;
122122
}
123123

124124
// If the app was running in the background. Skip recording this launch.
125125
if (self.wasInBackground) {
126-
return;
126+
return false;
127127
}
128128

129129
// App Launch Time: Cold is time between now and when process started.
@@ -132,10 +132,11 @@ - (void)createDurationMetric {
132132
// Skip recording obviously wrong extra long app launch durations.
133133
if (calculatedAppLaunchDuration >= maxAppLaunchDuration) {
134134
NRLOG_AGENT_INFO(@"New Relic: Skipping app start time metric since %f > allowed.", calculatedAppLaunchDuration);
135-
return;
135+
return false;
136136
}
137137

138138
self.appLaunchDuration = calculatedAppLaunchDuration;
139+
return true;
139140
}
140141

141142
- (BOOL)isPrewarmAvailable {

Tests/Unit-Tests/NewRelicAgentTests/Analytics-Tests/PersistentStoreTests.m

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#import "NRMACustomEvent.h"
1515
#import "NRMARequestEvent.h"
1616
#import "NRMAInteractionEvent.h"
17+
#import "NewRelicAgentInternal.h"
18+
#import <OCMock/OCMock.h>
1719

1820
#import "BlockAttributeValidator.h"
1921
#import "NRMAFlags.h"
@@ -65,8 +67,12 @@ - (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder {
6567
@end
6668

6769
@interface PersistentStoreTests : XCTestCase
70+
@property id mockNewRelicInternals;
71+
6872
@end
6973

74+
static NewRelicAgentInternal* _sharedInstance;
75+
7076
@implementation PersistentStoreTests {
7177
BlockAttributeValidator *agreeableAttributeValidator;
7278
}
@@ -77,7 +83,11 @@ @implementation PersistentStoreTests {
7783

7884
- (void)setUp {
7985
[super setUp];
80-
86+
self.mockNewRelicInternals = [OCMockObject mockForClass:[NewRelicAgentInternal class]];
87+
_sharedInstance = [[NewRelicAgentInternal alloc] init];
88+
_sharedInstance.analyticsController = [[NRMAAnalytics alloc] initWithSessionStartTimeMS:0.0];
89+
[[[[self.mockNewRelicInternals stub] classMethod] andReturn:_sharedInstance] sharedInstance];
90+
8191
if(agreeableAttributeValidator == nil) {
8292
agreeableAttributeValidator = [[BlockAttributeValidator alloc] initWithNameValidator:^BOOL(NSString *) {
8393
return YES;
@@ -103,6 +113,7 @@ - (void)tearDown {
103113
if([fileManager fileExistsAtPath:testFilename]) {
104114
[fileManager removeItemAtPath:testFilename error:nil];
105115
}
116+
[self.mockNewRelicInternals stopMocking];
106117

107118
[NRMAFlags disableFeatures: NRFeatureFlag_NewEventSystem];
108119

@@ -289,7 +300,7 @@ - (void)testEventRemoval {
289300

290301
XCTestExpectation *waitForInitialWriteExpectation = [self expectationWithDescription:@"Waiting for the first time the file is written"];
291302
PersistentEventStore *sut = [[PersistentEventStore alloc] initWithFilename:testFilename
292-
andMinimumDelay:1];
303+
andMinimumDelay:.025];
293304

294305
NSError *error = nil;
295306

Tests/Unit-Tests/NewRelicAgentTests/Uncategorized/NRLoggerTests.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@
1616
NSString* category;
1717
NSString* name;
1818
}
19+
@property (nonatomic) int fileDescriptor;
20+
@property (nonatomic, strong) dispatch_source_t source;
1921
@end

Tests/Unit-Tests/NewRelicAgentTests/Uncategorized/NRLoggerTests.m

Lines changed: 104 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,35 @@ - (void) setUp
5252

5353
[NRLogger clearLog];
5454

55+
// Open a file descriptor for the file
56+
self.fileDescriptor = open([[NRLogger logFilePath] fileSystemRepresentation], O_EVTONLY);
57+
if (self.fileDescriptor < 0) {
58+
XCTFail(@"Failed to open file descriptor");
59+
return;
60+
}
61+
62+
// Set up dispatch source for file monitoring
63+
self.source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, self.fileDescriptor, DISPATCH_VNODE_WRITE, DISPATCH_TARGET_QUEUE_DEFAULT);
64+
65+
__weak typeof(self) weakSelf = self;
66+
dispatch_source_set_cancel_handler(self.source, ^{
67+
if (weakSelf.fileDescriptor) {
68+
close(weakSelf.fileDescriptor);
69+
weakSelf.fileDescriptor = 0;
70+
}
71+
});
72+
5573

5674
}
5775
- (void) tearDown
5876
{
77+
if (self.fileDescriptor > 0) {
78+
close(self.fileDescriptor);
79+
}
80+
if (self.source) {
81+
dispatch_source_cancel(self.source);
82+
}
83+
5984
[NRMAMeasurements removeMeasurementConsumer:helper];
6085
helper = nil;
6186

@@ -68,18 +93,6 @@ - (void) tearDown
6893

6994
- (void) testNRLogger {
7095

71-
XCTestExpectation *delayExpectation1 = [self expectationWithDescription:@"Waiting for Log Queue"];
72-
73-
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
74-
[delayExpectation1 fulfill];
75-
});
76-
77-
[self waitForExpectationsWithTimeout:5 handler:^(NSError * _Nullable error) {
78-
if (error) {
79-
XCTFail(@"Timeout error");
80-
}
81-
}];
82-
8396
[NewRelic logInfo: @"Info Log..."];
8497
[NewRelic logError: @"Error Log..."];
8598
[NewRelic logVerbose:@"Verbose Log..."];
@@ -93,20 +106,9 @@ - (void) testNRLogger {
93106
@"additionalAttribute2": @"attribute2"
94107
}];
95108

96-
XCTestExpectation *delayExpectation2 = [self expectationWithDescription:@"Waiting for Log Queue"];
97-
98-
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
99-
[delayExpectation2 fulfill];
100-
});
109+
sleep(5);
101110

102-
[self waitForExpectationsWithTimeout:5 handler:^(NSError * _Nullable error) {
103-
if (error) {
104-
XCTFail(@"Timeout error");
105-
}
106-
}];
107-
108111
NSError* error;
109-
NSString *path = [NRLogger logFilePath];
110112
NSData* logData = [NRLogger logFileData:&error];
111113
if(error){
112114
NSLog(@"%@", error.localizedDescription);
@@ -173,19 +175,21 @@ - (void) testRemoteLogLevels {
173175

174176
// Set the remote log level to Debug.
175177
[NRLogger setRemoteLogLevel:NRLogLevelDebug];
176-
177-
XCTestExpectation *delayExpectation1 = [self expectationWithDescription:@"Waiting for Log Queue"];
178-
179-
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
180-
[delayExpectation1 fulfill];
181-
});
182-
183-
[self waitForExpectationsWithTimeout:5 handler:^(NSError * _Nullable error) {
184-
if (error) {
185-
XCTFail(@"Timeout error");
178+
179+
__block BOOL operationCompleted = NO;
180+
__block int count = 0;
181+
dispatch_source_set_event_handler(self.source, ^{
182+
count++;
183+
if(count == 7){
184+
// Fulfill the expectation when a write is detected
185+
sleep(1);
186+
operationCompleted = YES;
186187
}
187-
}];
188-
188+
});
189+
190+
// Start monitoring
191+
dispatch_resume(self.source);
192+
189193
// Seven messages should reach the remote log file for upload.
190194

191195
[NewRelic logInfo: @"Info Log..."];
@@ -200,18 +204,19 @@ - (void) testRemoteLogLevels {
200204
@"additionalAttribute1": @"attribute1",
201205
@"additionalAttribute2": @"attribute2"
202206
}];
203-
204-
XCTestExpectation *delayExpectation2 = [self expectationWithDescription:@"Waiting for Log Queue"];
205-
206-
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
207-
[delayExpectation2 fulfill];
208-
});
209-
210-
[self waitForExpectationsWithTimeout:5 handler:^(NSError * _Nullable error) {
211-
if (error) {
212-
XCTFail(@"Timeout error");
213-
}
214-
}];
207+
208+
// Set a timeout duration
209+
NSTimeInterval timeout = 30.0;
210+
NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeout];
211+
212+
// Run the run loop until the operation completes or the timeout is reached
213+
while (!operationCompleted && [timeoutDate timeIntervalSinceNow] > 0) {
214+
// Allow other scheduled run loop activities to proceed
215+
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
216+
}
217+
if (!operationCompleted) {
218+
NSLog(@"Failed to detect 7 writes to the log file.");
219+
}
215220

216221
NSError* error;
217222
NSData* logData = [NRLogger logFileData:&error];
@@ -264,20 +269,21 @@ - (void) testLocalLogLevels {
264269
// Set the remote log level to Info.
265270
[NRLogger setRemoteLogLevel:NRLogLevelInfo];
266271

267-
XCTestExpectation *delayExpectation1 = [self expectationWithDescription:@"Waiting for Log Queue"];
268-
269-
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
270-
[delayExpectation1 fulfill];
271-
});
272-
273-
[self waitForExpectationsWithTimeout:5 handler:^(NSError * _Nullable error) {
274-
if (error) {
275-
XCTFail(@"Timeout error");
272+
__block BOOL operationCompleted = NO;
273+
__block int count = 0;
274+
dispatch_source_set_event_handler(self.source, ^{
275+
count++;
276+
if(count == 4){
277+
// Fulfill the expectation when a write is detected
278+
sleep(1);
279+
operationCompleted = YES;
276280
}
277-
}];
278-
281+
});
282+
283+
// Start monitoring
284+
dispatch_resume(self.source);
285+
279286
// Seven messages should reach the remote log file for upload.
280-
281287
[NewRelic logInfo: @"Info Log..."];
282288
[NewRelic logError: @"Error Log..."];
283289
[NewRelic logVerbose:@"Verbose Log..."];
@@ -291,18 +297,18 @@ - (void) testLocalLogLevels {
291297
@"additionalAttribute2": @"attribute2"
292298
}];
293299

294-
XCTestExpectation *delayExpectation2 = [self expectationWithDescription:@"Waiting for Log Queue"];
295-
296-
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
297-
[delayExpectation2 fulfill];
298-
});
299-
300-
[self waitForExpectationsWithTimeout:5 handler:^(NSError * _Nullable error) {
301-
if (error) {
302-
XCTFail(@"Timeout error");
303-
}
304-
}];
305-
300+
// Set a timeout duration
301+
NSTimeInterval timeout = 30.0;
302+
NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeout];
303+
304+
// Run the run loop until the operation completes or the timeout is reached
305+
while (!operationCompleted && [timeoutDate timeIntervalSinceNow] > 0) {
306+
// Allow other scheduled run loop activities to proceed
307+
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
308+
}
309+
if (!operationCompleted) {
310+
NSLog(@"Failed to detect 4 writes to the log file.");
311+
}
306312
NSError* error;
307313
NSData* logData = [NRLogger logFileData:&error];
308314
if(error){
@@ -352,8 +358,19 @@ - (void) testAutoCollectedLogs {
352358
[NRLogger setRemoteLogLevel:NRLogLevelDebug];
353359
XCTAssertTrue([NRAutoLogCollector redirectStandardOutputAndError]);
354360

355-
sleep(5);
356-
361+
__block BOOL operationCompleted = NO;
362+
__block int count = 0;
363+
dispatch_source_set_event_handler(self.source, ^{
364+
count++;
365+
if(count == 5){
366+
// Fulfill the expectation when a write is detected
367+
sleep(1);
368+
operationCompleted = YES;
369+
}
370+
});
371+
372+
// Start monitoring
373+
dispatch_resume(self.source);
357374
// Three messages should reach the remote log file for upload.
358375
NSLog(@"NSLog Test \n\n");
359376
os_log_t customLog = os_log_create("com.agent.tests", "logTest");
@@ -363,7 +380,19 @@ - (void) testAutoCollectedLogs {
363380
os_log_error(customLog, "This is an error os_log message.\n");
364381
os_log_fault(customLog, "This is a fault os_log message.\n");
365382

366-
sleep(5);
383+
// Set a timeout duration
384+
NSTimeInterval timeout = 30.0;
385+
NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeout];
386+
387+
// Run the run loop until the operation completes or the timeout is reached
388+
while (!operationCompleted && [timeoutDate timeIntervalSinceNow] > 0) {
389+
// Allow other scheduled run loop activities to proceed
390+
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
391+
}
392+
if (!operationCompleted) {
393+
NSLog(@"Failed to detect 5 writes to the log file.");
394+
}
395+
367396
[NRAutoLogCollector restoreStandardOutputAndError];
368397

369398
NSError* error;

Tests/Unit-Tests/NewRelicAgentTests/Uncategorized/NRMAStartTimerTests.m

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ + (void) clear;
1919
@end
2020

2121
@interface NRMAStartTimer ()
22-
- (void)createDurationMetric;
22+
- (BOOL)createDurationMetric;
2323
@end
2424

2525
@implementation NRMAStartTimerTests
@@ -46,11 +46,13 @@ - (void) tearDown {
4646
-(void)test {
4747
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"systemBootTimestamp"];
4848

49-
[[NRMAStartTimer sharedInstance] createDurationMetric];
50-
49+
BOOL success = [[NRMAStartTimer sharedInstance] createDurationMetric];
50+
XCTSkipIf(!success, @"Failed to create duration metric");
51+
5152
[NRMASupportMetricHelper processDeferredMetrics];
53+
5254
[NRMATaskQueue synchronousDequeue];
53-
55+
5456
NRMANamedValueMeasurement* measurement = ((NRMANamedValueMeasurement*)helper.result);
5557

5658
XCTAssertTrue([measurement.name isEqualToString:NRMA_METRIC_APP_LAUNCH_COLD], @"%@ does not equal AppLaunch/Cold", measurement.name);

0 commit comments

Comments
 (0)