forked from mozilla-mobile/firefox-ios
-
Notifications
You must be signed in to change notification settings - Fork 0
/
TestLocking.swift
158 lines (139 loc) · 6.26 KB
/
TestLocking.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import UIKit
import XCTest
class TestLocking: XCTestCase {
// Test creating a read lock while a read lock is already active
func testReadLock() {
let lock = Lock(name: "MyLock")
var reading = false
var passed = false
let expectation = expectationWithDescription("main thread")
lock.withReadLock { () -> Void in
reading = true
let queue = dispatch_queue_create("Test", nil)
dispatch_async(queue) { () -> Void in
lock.withReadLock() {
passed = reading
XCTAssertTrue(reading, "Can get two read locks at once")
}
expectation.fulfill()
}
// If we're reading, we'll wait for the inner read lock to pass before finishing
self.waitForExpectationsWithTimeout(10, handler: nil)
reading = false;
}
XCTAssertFalse(reading, "Reading is done")
XCTAssertTrue(passed, "Multiple read locks were allowed")
}
// Test creating a write lock while a read lock is already active
func testWriteLock() {
let lock = Lock(name: "MyLock")
var reading = false
var writing = false
var started = false
let expectation = expectationWithDescription("main thread")
let queue = dispatch_queue_create("Test", nil)
lock.withReadLock {
reading = true
dispatch_async(queue) { () -> Void in
started = true
lock.withWriteLock { () -> Void in
writing = true
XCTAssertTrue(writing, "Writer is running")
XCTAssertFalse(reading, "Reader is finished")
writing = false
expectation.fulfill()
}
started = false
}
// Give the write thread some time to start (and block on the write lock)
sleep(1)
XCTAssertTrue(reading, "Reading thread is working")
XCTAssertTrue(started, "Write thread is started")
XCTAssertFalse(writing, "Write task is blocked")
reading = false
}
waitForExpectationsWithTimeout(10, handler: nil)
XCTAssertFalse(reading, "Reader is done")
XCTAssertFalse(started, "Writer is done")
XCTAssertFalse(writing, "Write task is done")
}
// Test two threads accessing the read Protector at the same time
func testProtectorReading() {
let p = Protector(name: "testProtector", item: [1,2,3]);
var reading = false
var passed = false
let queue = dispatch_queue_create("Test", nil)
let expectation = expectationWithDescription("main thread")
dispatch_async(queue) { () -> Void in
p.withReadLock { protected -> Void in
XCTAssertEqual(protected[0], 1, "Item zero is correct")
XCTAssertEqual(protected[1], 2, "Item one is correct")
XCTAssertEqual(protected[2], 3, "Item two is correct")
// protected[0] = 4 // This array is immuatable, so this won't build. Need a better way to test.
passed = reading
XCTAssertTrue(reading, "Can get two read protectors at once")
}
expectation.fulfill()
}
p.withReadLock { protected -> Void in
reading = true
// If we're reading, we'll wait for the inner read protectors to pass
self.waitForExpectationsWithTimeout(10, handler: nil)
XCTAssertEqual(protected[0], 1, "Item zero is correct")
XCTAssertEqual(protected[1], 2, "Item one is correct")
XCTAssertEqual(protected[2], 3, "Item two is correct")
reading = false;
}
XCTAssertFalse(reading, "Reading is done")
XCTAssertTrue(passed, "Multiple read locks were allowed")
}
// Test a writer accessing the protector at the same time a reader is active
func testProtectorWriting() {
let lock = Protector(name: "MyLock", item: [1,2,3])
var reading = false
var writing = false
var started = false
let expectation = expectationWithDescription("main thread")
let queue = dispatch_queue_create("Test", nil)
lock.withReadLock { protected -> Void in
reading = true
dispatch_async(queue) { () -> Void in
started = true
lock.withWriteLock { protected -> Void in
writing = true
XCTAssertEqual(protected[0], 1, "Item zero is correct")
XCTAssertEqual(protected[1], 2, "Item one is correct")
XCTAssertEqual(protected[2], 3, "Item two is correct")
protected[0] = 4
XCTAssertEqual(protected[0], 4, "Item zero modified")
XCTAssertTrue(writing, "Writer is running")
XCTAssertFalse(reading, "Reader is finished")
writing = false
expectation.fulfill()
}
started = false
}
// Give the write thread some time to start
sleep(1)
XCTAssertEqual(protected[0], 1, "Item zero is correct");
XCTAssertEqual(protected[1], 2, "Item one is correct");
XCTAssertEqual(protected[2], 3, "Item two is correct");
XCTAssertTrue(reading, "Reading thread is working")
XCTAssertTrue(started, "Write thread is started")
XCTAssertFalse(writing, "Write task is blocked")
reading = false
}
self.waitForExpectationsWithTimeout(10, handler: nil)
XCTAssertFalse(reading, "Reader is done")
XCTAssertFalse(started, "Writer is done")
XCTAssertFalse(writing, "Write task is done")
lock.withReadLock { protected -> Void in
XCTAssertEqual(protected[0], 4, "Item zero was modified")
XCTAssertEqual(protected[1], 2, "Item one is correct")
XCTAssertEqual(protected[2], 3, "Item two is correct")
}
}
}