Skip to content

Commit 1c88f68

Browse files
author
Clément Le Provost
committed
[test] Test reachability usage for online requests
NOTE: This requires to mock `NetworkReachability` during the tests.
1 parent e62f91c commit 1c88f68

File tree

5 files changed

+95
-5
lines changed

5 files changed

+95
-5
lines changed

AlgoliaSearch.xcodeproj/project.pbxproj

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@
148148
BCDA73791CA546800082B197 /* NetworkTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCDA73771CA546800082B197 /* NetworkTests.swift */; };
149149
BCDA737E1CA555070082B197 /* MockURLSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCDA737D1CA555070082B197 /* MockURLSession.swift */; };
150150
BCDA737F1CA555070082B197 /* MockURLSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCDA737D1CA555070082B197 /* MockURLSession.swift */; };
151+
BCE2E9851E23949D00F189F3 /* MockNetworkReachability.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCE2E9841E23949D00F189F3 /* MockNetworkReachability.swift */; };
152+
BCE2E9861E23949D00F189F3 /* MockNetworkReachability.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCE2E9841E23949D00F189F3 /* MockNetworkReachability.swift */; };
153+
BCE2E9871E23949D00F189F3 /* MockNetworkReachability.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCE2E9841E23949D00F189F3 /* MockNetworkReachability.swift */; };
154+
BCE2E9881E23949D00F189F3 /* MockNetworkReachability.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCE2E9841E23949D00F189F3 /* MockNetworkReachability.swift */; };
151155
BCEE36811E0830810091D113 /* settings.json in Resources */ = {isa = PBXBuildFile; fileRef = BCEE36801E0830810091D113 /* settings.json */; };
152156
BCEE36831E08309F0091D113 /* objects.json in Resources */ = {isa = PBXBuildFile; fileRef = BCEE36821E08309F0091D113 /* objects.json */; };
153157
BCFC281C1D92660C00BFE0A0 /* MirroredIndexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCFC281B1D92660C00BFE0A0 /* MirroredIndexTests.swift */; };
@@ -242,6 +246,7 @@
242246
BCD57D3B1D89B1EA00C5DE68 /* OfflineTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OfflineTestCase.swift; sourceTree = "<group>"; };
243247
BCDA73771CA546800082B197 /* NetworkTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkTests.swift; sourceTree = "<group>"; };
244248
BCDA737D1CA555070082B197 /* MockURLSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockURLSession.swift; sourceTree = "<group>"; };
249+
BCE2E9841E23949D00F189F3 /* MockNetworkReachability.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockNetworkReachability.swift; sourceTree = "<group>"; };
245250
BCEE36801E0830810091D113 /* settings.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = settings.json; sourceTree = "<group>"; };
246251
BCEE36821E08309F0091D113 /* objects.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = objects.json; sourceTree = "<group>"; };
247252
BCFC281B1D92660C00BFE0A0 /* MirroredIndexTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MirroredIndexTests.swift; sourceTree = "<group>"; };
@@ -399,6 +404,7 @@
399404
5D8FFA371AAB08830078869E /* ClientTests.swift */,
400405
5D44D0261B362648008369AC /* Helpers.swift */,
401406
5D8FFA391AAB0AB80078869E /* IndexTests.swift */,
407+
BCE2E9841E23949D00F189F3 /* MockNetworkReachability.swift */,
402408
BCDA737D1CA555070082B197 /* MockURLSession.swift */,
403409
BCDA73771CA546800082B197 /* NetworkTests.swift */,
404410
BC72244C1D9C137B00B56908 /* OnlineTestCase.swift */,
@@ -920,6 +926,7 @@
920926
BCDA737E1CA555070082B197 /* MockURLSession.swift in Sources */,
921927
BC4DDF131DD13423004D9A6E /* PlacesQueryTests.swift in Sources */,
922928
BC4A7F3C1CB5373E00AF1DCB /* CancelTests.swift in Sources */,
929+
BCE2E9851E23949D00F189F3 /* MockNetworkReachability.swift in Sources */,
923930
5D44D0271B362648008369AC /* Helpers.swift in Sources */,
924931
5D8FFA3A1AAB0AB80078869E /* IndexTests.swift in Sources */,
925932
BC85EA701D82C8C3009E9E7D /* ObjectiveCBridging.m in Sources */,
@@ -964,6 +971,7 @@
964971
BCDA737F1CA555070082B197 /* MockURLSession.swift in Sources */,
965972
BC4DDF141DD13423004D9A6E /* PlacesQueryTests.swift in Sources */,
966973
BC4A7F3D1CB5373E00AF1DCB /* CancelTests.swift in Sources */,
974+
BCE2E9861E23949D00F189F3 /* MockNetworkReachability.swift in Sources */,
967975
5D44D0281B362648008369AC /* Helpers.swift in Sources */,
968976
5DB2515D1AAD9F3B00945339 /* IndexTests.swift in Sources */,
969977
BC582C5D1D82B453007B815A /* ObjectiveCBridging.m in Sources */,
@@ -1063,6 +1071,7 @@
10631071
BCD1F5741CC61DB80006E227 /* QueryTests.swift in Sources */,
10641072
BC4DDF151DD13423004D9A6E /* PlacesQueryTests.swift in Sources */,
10651073
BCD1F5711CC61DB80006E227 /* IndexTests.swift in Sources */,
1074+
BCE2E9871E23949D00F189F3 /* MockNetworkReachability.swift in Sources */,
10661075
BCD1F56E1CC61DB80006E227 /* CancelTests.swift in Sources */,
10671076
BCD1F5701CC61DB80006E227 /* Helpers.swift in Sources */,
10681077
BC85EA711D82C8C4009E9E7D /* ObjectiveCBridging.m in Sources */,
@@ -1076,6 +1085,7 @@
10761085
files = (
10771086
BCD57D3D1D89B1EA00C5DE68 /* OfflineIndexTests.swift in Sources */,
10781087
BCFC281D1D92670100BFE0A0 /* Helpers.swift in Sources */,
1088+
BCE2E9881E23949D00F189F3 /* MockNetworkReachability.swift in Sources */,
10791089
BCD57D3E1D89B1EA00C5DE68 /* OfflineTestCase.swift in Sources */,
10801090
BCFC281C1D92660C00BFE0A0 /* MirroredIndexTests.swift in Sources */,
10811091
BCD57D3C1D89B1EA00C5DE68 /* OfflineClientTests.swift in Sources */,

Source/AbstractClient.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,9 @@ internal struct HostStatus {
187187

188188
#if !os(watchOS)
189189

190-
/// Network reachability tester.
191-
internal let reachability = NetworkReachability()
190+
/// Network reachability detecter.
191+
internal var reachability: NetworkReachability = SystemNetworkReachability()
192+
// ^ NOTE: Not constant only for the sake of mocking during unit tests.
192193

193194
/// Whether to use network reachability to decide if online requests should be attempted.
194195
///

Source/NetworkReachability.swift

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,21 @@ import Foundation
2727
import SystemConfiguration
2828

2929

30-
/// Tests network reachability.
30+
/// Detects network reachability.
3131
///
32-
class NetworkReachability {
32+
protocol NetworkReachability {
33+
// MARK: Properties
34+
35+
/// Test if network connectivity is currently available.
36+
///
37+
/// - returns: true if network connectivity is available, false otherwise.
38+
///
39+
func isReachable() -> Bool
40+
}
41+
42+
/// Detects network reachability using the system's built-in mechanism.
43+
///
44+
class SystemNetworkReachability: NetworkReachability {
3345
// MARK: Properties
3446

3547
/// Reachability handle used to test connectivity.
@@ -39,7 +51,7 @@ class NetworkReachability {
3951

4052
init() {
4153
// Create reachability handle to an all-zeroes address.
42-
var zeroAddress = NetworkReachability.zeroAddress
54+
var zeroAddress = SystemNetworkReachability.zeroAddress
4355
reachability = withUnsafePointer(to: &zeroAddress) {
4456
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
4557
SCNetworkReachabilityCreateWithAddress(nil, $0)

Tests/ClientTests.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,4 +456,35 @@ class ClientTests: OnlineTestCase {
456456
})
457457
self.waitForExpectations(timeout: expectationTimeout, handler: nil)
458458
}
459+
460+
/// Test that we take reachability into account when making requests, unless `useReachability` is set to false.
461+
///
462+
func testUseReachability() {
463+
let expectation = self.expectation(description: #function)
464+
465+
// Pretend that we are offline.
466+
let reachability = MockNetworkReachability()
467+
client.reachability = reachability
468+
reachability.reachable = false
469+
470+
// Check that requests fail right away.
471+
let startTime = Date()
472+
client.listIndexes { (content, error) in
473+
let stopTime = Date()
474+
let duration = stopTime.timeIntervalSince(startTime)
475+
guard let error = error as? NSError else { XCTFail("Request should have failed"); expectation.fulfill(); return }
476+
XCTAssertEqual(NSURLErrorDomain, error.domain)
477+
XCTAssertEqual(NSURLErrorNotConnectedToInternet, error.code)
478+
XCTAssert(duration < min(self.client.searchTimeout, self.client.timeout)) // check that we failed without waiting for the timeout
479+
480+
// Choose to ignore reachability now, and check that requests are performed, although network is supposedly down.
481+
self.client.useReachability = false
482+
self.client.listIndexes { (content, error) in
483+
// The request should work, since we are actually connected (fake reachability)!
484+
XCTAssertNil(error)
485+
expectation.fulfill()
486+
}
487+
}
488+
self.waitForExpectations(timeout: expectationTimeout, handler: nil)
489+
}
459490
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//
2+
// Copyright (c) 2016 Algolia
3+
// http://www.algolia.com/
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included in
13+
// all copies or substantial portions of the Software.
14+
//
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
// THE SOFTWARE.
22+
//
23+
24+
@testable import AlgoliaSearch
25+
import Foundation
26+
27+
28+
/// A simple mock of `NetworkReachability` that just returns a stored state.
29+
///
30+
public class MockNetworkReachability: AlgoliaSearch.NetworkReachability {
31+
public var reachable: Bool = true
32+
33+
public func isReachable() -> Bool {
34+
return reachable
35+
}
36+
}

0 commit comments

Comments
 (0)