Skip to content

Commit

Permalink
Merge pull request #142 from krze/updating-network-speed-tracker
Browse files Browse the repository at this point in the history
Updating network speed tracker
  • Loading branch information
Pearapps authored Dec 21, 2017
2 parents 60c4773 + d3405a2 commit 8695fd6
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 25 deletions.
15 changes: 15 additions & 0 deletions Classes/Networking/TMNetworkSpeedTracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,25 @@

@interface TMNetworkSpeedTracker : NSObject

/**
* Add a tracked network event to the pool of network speed samples
*
* - param track: NSDate for the start of the network request
* - param endDate: NSDate for the end of the request, after the response is received
* - param bytes: Size of the request in bytes
*/
- (void)track:(NSDate *)start endDate:(NSDate *)end bytes:(long long)bytes;


/// Raw kilobytes per second representing the network speed
+ (double)kbps;

/**
* Generalized quality of the network speed. If an unknown network speed quality
* is returned, the sample size is too small to provide an adequate judge of
* network speed.
*/
+ (TMNetworkSpeedQuality)quality;

@end

50 changes: 25 additions & 25 deletions Classes/Networking/TMNetworkSpeedTracker.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#import "os/lock.h"

os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;
short samples = 0;
const short targetSampleSize = 10;

@implementation TMNetworkSpeedTracker

Expand All @@ -29,53 +29,44 @@ - (void)track:(NSDate *)start endDate:(NSDate *)end bytes:(long long)bytes {

if (timeDifference > 0) {
const double bytesPerSecond = bytes / timeDifference;
const NSNumber *kbps = @(bytesPerSecond * 0.008);

NSNumber * const kbps = @(bytesPerSecond * 0.008);
const id class = [self class];

os_unfair_lock_lock(&lock);

NSMutableArray *numbers = [class sharedArray];

if (numbers.count > 10) {
numbers[0] = kbps;
}
else {
[numbers addObject:kbps];
}

samples++;

[class addTrackedSpeed:kbps toSpeeds:[class sharedArray]];
os_unfair_lock_unlock(&lock);
}
}
}

+ (TMNetworkSpeedQuality)quality {
const double kbps = [self kbps];
const short bad = 150;
const short moderate = 550;

const float low = 150;
const float medium = 550;
const float high = 2000;

if (kbps <= low) {
if (kbps <= 0) {
return TMNetworkSpeedQualityUnkown;
}
else if (kbps <= bad) {
return TMNetworkSpeedQualityBad;
}
else if (kbps <= medium) {
else if (kbps <= moderate) {
return TMNetworkSpeedQualityModerate;
}
else if (kbps <= high) {
else {
return TMNetworkSpeedQualityGood;
}

return TMNetworkSpeedQualityUnkown;
}

+ (double)kbps {
os_unfair_lock_lock(&lock);

// Make a copy of this so we can iterate through it outside the lock
NSArray *copy = [[[self class] sharedArray] copy];

if (copy.count < targetSampleSize) {
os_unfair_lock_unlock(&lock);
return -1;
}
os_unfair_lock_unlock(&lock);

double total = 0;
Expand All @@ -86,4 +77,13 @@ + (double)kbps {
return total / copy.count;
}

+ (void)addTrackedSpeed:(NSNumber *)kbps toSpeeds:(NSMutableArray *)speeds {
[speeds addObject:kbps];
// Keeps the sample size capped to monitor the most recent samples taken
if (speeds.count > targetSampleSize) {
[speeds removeObjectAtIndex:0];
}
}

@end

4 changes: 4 additions & 0 deletions ExampleiOS/ExampleiOS.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
2DEC2FF21EBA336B00A1BDEA /* TMMockSession.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DEC2FF11EBA336B00A1BDEA /* TMMockSession.m */; };
2DEC2FF51EBA3FEC00A1BDEA /* TMSynchronousMockURLSessionTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DEC2FF41EBA3FEC00A1BDEA /* TMSynchronousMockURLSessionTask.m */; };
2DEC2FFF1EBBA1AD00A1BDEA /* TMAuthTokenRequestGeneratorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DEC2FFE1EBBA1AC00A1BDEA /* TMAuthTokenRequestGeneratorTests.m */; };
4EF02C761FE9BC8600DECADB /* TMNetworkSpeedTrackerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4EF02C751FE9BC8600DECADB /* TMNetworkSpeedTrackerTests.m */; };
4F1262741ECB51BC0039DD2F /* json_dictionary.json in Resources */ = {isa = PBXBuildFile; fileRef = 4F1262731ECB51BC0039DD2F /* json_dictionary.json */; };
4F1262761ECB542E0039DD2F /* json_data in Resources */ = {isa = PBXBuildFile; fileRef = 4F1262751ECB52FD0039DD2F /* json_data */; };
4F42407C1E7870440025D05A /* TMRequestBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F42407B1E7870440025D05A /* TMRequestBodyTests.swift */; };
Expand Down Expand Up @@ -85,6 +86,7 @@
2DEC2FF41EBA3FEC00A1BDEA /* TMSynchronousMockURLSessionTask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TMSynchronousMockURLSessionTask.m; sourceTree = "<group>"; };
2DEC2FFE1EBBA1AC00A1BDEA /* TMAuthTokenRequestGeneratorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TMAuthTokenRequestGeneratorTests.m; sourceTree = "<group>"; };
2E30B1AA52F4A5DF6989226C /* Pods-ExampleiOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ExampleiOSTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-ExampleiOSTests/Pods-ExampleiOSTests.release.xcconfig"; sourceTree = "<group>"; };
4EF02C751FE9BC8600DECADB /* TMNetworkSpeedTrackerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TMNetworkSpeedTrackerTests.m; sourceTree = "<group>"; };
4F1262731ECB51BC0039DD2F /* json_dictionary.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = json_dictionary.json; sourceTree = "<group>"; };
4F1262751ECB52FD0039DD2F /* json_data */ = {isa = PBXFileReference; lastKnownFileType = file; path = json_data; sourceTree = "<group>"; };
4F42407B1E7870440025D05A /* TMRequestBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TMRequestBodyTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -280,6 +282,7 @@
4F42407B1E7870440025D05A /* TMRequestBodyTests.swift */,
2DEC2FFE1EBBA1AC00A1BDEA /* TMAuthTokenRequestGeneratorTests.m */,
2D8396631EE0767C0003A80F /* TMBasicBaseURLDeterminerTests.m */,
4EF02C751FE9BC8600DECADB /* TMNetworkSpeedTrackerTests.m */,
);
path = ExampleiOSTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -560,6 +563,7 @@
2DEC2FF21EBA336B00A1BDEA /* TMMockSession.m in Sources */,
2DEC2FFF1EBBA1AD00A1BDEA /* TMAuthTokenRequestGeneratorTests.m in Sources */,
2DBBAF3F1E9EC5E40029437A /* TMOAuthAuthenticatorTests.m in Sources */,
4EF02C761FE9BC8600DECADB /* TMNetworkSpeedTrackerTests.m in Sources */,
B9BA14391D10DB5E00D90A89 /* TMURLEncodingTests.m in Sources */,
B9E6BCD31D0B402F0049C88E /* TMSDKUserAgentTests.m in Sources */,
B9415D701D13763000F80E01 /* TMAllSystemTests.m in Sources */,
Expand Down
137 changes: 137 additions & 0 deletions ExampleiOS/ExampleiOSTests/TMNetworkSpeedTrackerTests.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
//
// TMNetworkSpeedTrackerTests.m
// Tests
//
// Created by Ken Krzeminski on 12/19/17.
// Copyright © 2017 Tumblr. All rights reserved.
//

#import <XCTest/XCTest.h>
#import <TMTumblrSDK/TMNetworkSpeedTracker.h>

// Testable tracker for receiving multiple events
@interface TestableTMNetworkSpeedTracker : TMNetworkSpeedTracker

@end

@implementation TestableTMNetworkSpeedTracker

+ (NSMutableArray *)sharedArray {
static dispatch_once_t once;
static NSMutableArray *sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[NSMutableArray alloc] init];
});
return sharedInstance;
}

@end

// Testable tracker for testing the state before 10 events are reached
@interface TestableEmptyTMNetworkSpeedTracker : TMNetworkSpeedTracker

@end

@implementation TestableEmptyTMNetworkSpeedTracker

+ (NSMutableArray *)sharedArray {
static dispatch_once_t once;
static NSMutableArray *sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[NSMutableArray alloc] init];
});
return sharedInstance;
}

@end


@interface TMNetworkSpeedTrackerTests : XCTestCase


@end

// Test constants

// Number of bytes transferred in a mock response
const short tinyPayload = 10;
const short oneKBPayload = 1024;
const short badStatePayload = 18750;
const int moderateStatePayload = 68750;
const int goodStatePayload = 68751;

// Time interval for transfers
const float timeInterval = 1.0;

@implementation TMNetworkSpeedTrackerTests

- (void)testUnknownQualityState {
TMNetworkSpeedTracker *testEmptyTracker = [[TestableEmptyTMNetworkSpeedTracker alloc] init];
NSDate* start = [NSDate date];
NSDate* endDate = [NSDate dateWithTimeInterval:timeInterval sinceDate:start];

XCTAssertEqual([TestableEmptyTMNetworkSpeedTracker quality], TMNetworkSpeedQualityUnkown,
"Received a network quality other than 'unknown' with no tracked network speed rates.");

for (int i = 0; i < 20; i++) {
[testEmptyTracker track:start endDate:endDate bytes:tinyPayload];
}
XCTAssertEqual([TestableEmptyTMNetworkSpeedTracker quality], TMNetworkSpeedQualityUnkown,
"Quality was tracked when a series of requests smaller than the trackable payload size were received.");

[testEmptyTracker track:start endDate:endDate bytes:oneKBPayload];
XCTAssertEqual([TestableEmptyTMNetworkSpeedTracker quality], TMNetworkSpeedQualityUnkown,
"Received a network quality other than 'unknown' with only one tracked network speed rate.");

// The tracker should only send back a state other than "Unknown" when it receives 10 requests.
for (int i = 0; i < 8; i++) {
[testEmptyTracker track:start endDate:endDate bytes:oneKBPayload];
}
XCTAssertEqual([TestableEmptyTMNetworkSpeedTracker quality], TMNetworkSpeedQualityUnkown,
"After receiving at 9 requests that are 1 KB in size, the tracker sending back a quality other than 'Unknown'.");

[testEmptyTracker track:start endDate:endDate bytes:oneKBPayload];
XCTAssertNotEqual([TestableEmptyTMNetworkSpeedTracker quality], TMNetworkSpeedQualityUnkown,
"After receiving at 10 requests that are 1 KB in size, the tracker sending back an 'Unknown' network quality.");
}

- (void)testBadQualityState {
TMNetworkSpeedTracker *testTracker = [[TestableTMNetworkSpeedTracker alloc] init];
NSDate* start = [NSDate date];
NSDate* endDate = [NSDate dateWithTimeInterval:timeInterval sinceDate:start];

for (int i = 0; i < 10; i++) {
[testTracker track:start endDate:endDate bytes:badStatePayload];
}

XCTAssertEqual([TestableTMNetworkSpeedTracker quality], TMNetworkSpeedQualityBad,
"150 kbps was not rated as 'Bad'.");
}

- (void)testModerateQualityState {
TMNetworkSpeedTracker *testTracker = [[TestableTMNetworkSpeedTracker alloc] init];
NSDate* start = [NSDate date];
NSDate* endDate = [NSDate dateWithTimeInterval:timeInterval sinceDate:start];

for (int i = 0; i < 10; i++) {
[testTracker track:start endDate:endDate bytes:moderateStatePayload];
}

XCTAssertEqual([TestableTMNetworkSpeedTracker quality], TMNetworkSpeedQualityModerate,
"550 kbps was not rated as 'Moderate'.");
}

- (void)testGoodQualityState {
TMNetworkSpeedTracker *testTracker = [[TestableTMNetworkSpeedTracker alloc] init];
NSDate* start = [NSDate date];
NSDate* endDate = [NSDate dateWithTimeInterval:timeInterval sinceDate:start];

for (int i = 0; i < 10; i++) {
[testTracker track:start endDate:endDate bytes:goodStatePayload];
}

XCTAssertEqual([TestableTMNetworkSpeedTracker quality], TMNetworkSpeedQualityGood,
"> 550 kbps was not rated as 'Good'.");
}

@end

0 comments on commit 8695fd6

Please sign in to comment.