RequestTests.swift 23.3 KB
Newer Older
M
Mattt Thompson 已提交
1 2
// RequestTests.swift
//
3
// Copyright (c) 2014-2015 Alamofire Software Foundation (http://alamofire.org)
M
Mattt Thompson 已提交
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

23
import Alamofire
24
import Foundation
M
Mattt Thompson 已提交
25 26
import XCTest

27
class RequestInitializationTestCase: BaseTestCase {
28
    func testRequestClassMethodWithMethodAndURL() {
29
        // Given
30
        let URLString = "https://httpbin.org/"
31 32

        // When
33
        let request = Alamofire.request(.GET, URLString)
M
Mattt Thompson 已提交
34

35
        // Then
36
        XCTAssertNotNil(request.request, "request URL request should not be nil")
37 38
        XCTAssertEqual(request.request?.HTTPMethod ?? "", "GET", "request HTTP method should match expected value")
        XCTAssertEqual(request.request?.URLString ?? "", URLString, "request URL string should be equal")
39
        XCTAssertNil(request.response, "request response should be nil")
40
    }
M
Mattt Thompson 已提交
41

42
    func testRequestClassMethodWithMethodAndURLAndParameters() {
43
        // Given
44
        let URLString = "https://httpbin.org/get"
45 46

        // When
47
        let request = Alamofire.request(.GET, URLString, parameters: ["foo": "bar"])
M
Mattt Thompson 已提交
48

49
        // Then
50
        XCTAssertNotNil(request.request, "request URL request should not be nil")
51 52
        XCTAssertEqual(request.request?.HTTPMethod ?? "", "GET", "request HTTP method should match expected value")
        XCTAssertNotEqual(request.request?.URLString ?? "", URLString, "request URL string should be equal")
53 54
        XCTAssertEqual(request.request?.URL?.query ?? "", "foo=bar", "query is incorrect")
        XCTAssertNil(request.response, "request response should be nil")
55
    }
56 57 58

    func testRequestClassMethodWithMethodURLParametersAndHeaders() {
        // Given
59
        let URLString = "https://httpbin.org/get"
60
        let headers = ["Authorization": "123456"]
61 62

        // When
63
        let request = Alamofire.request(.GET, URLString, parameters: ["foo": "bar"], headers: headers)
64 65 66

        // Then
        XCTAssertNotNil(request.request, "request should not be nil")
67 68 69
        XCTAssertEqual(request.request?.HTTPMethod ?? "", "GET", "request HTTP method should match expected value")
        XCTAssertNotEqual(request.request?.URLString ?? "", URLString, "request URL string should be equal")
        XCTAssertEqual(request.request?.URL?.query ?? "", "foo=bar", "query is incorrect")
70

71
        let authorizationHeader = request.request?.valueForHTTPHeaderField("Authorization") ?? ""
72 73 74 75
        XCTAssertEqual(authorizationHeader, "123456", "Authorization header is incorrect")

        XCTAssertNil(request.response, "response should be nil")
    }
76
}
M
Mattt Thompson 已提交
77

78 79 80
// MARK: -

class RequestResponseTestCase: BaseTestCase {
81
    func testRequestResponse() {
82
        // Given
83
        let URLString = "https://httpbin.org/get"
M
Mattt Thompson 已提交
84

85
        let expectation = expectationWithDescription("GET request should succeed: \(URLString)")
M
Mattt Thompson 已提交
86

87 88
        var request: NSURLRequest?
        var response: NSHTTPURLResponse?
89
        var data: NSData?
90
        var error: NSError?
91 92

        // When
93
        Alamofire.request(.GET, URLString, parameters: ["foo": "bar"])
94
            .response { responseRequest, responseResponse, responseData, responseError in
95 96
                request = responseRequest
                response = responseResponse
97
                data = responseData
98
                error = responseError
99

100
                expectation.fulfill()
101
            }
M
Mattt Thompson 已提交
102

103
        waitForExpectationsWithTimeout(defaultTimeout, handler: nil)
104 105 106 107

        // Then
        XCTAssertNotNil(request, "request should not be nil")
        XCTAssertNotNil(response, "response should not be nil")
108
        XCTAssertNotNil(data, "data should not be nil")
109
        XCTAssertNil(error, "error should be nil")
M
Mattt Thompson 已提交
110
    }
111 112 113 114

    func testRequestResponseWithProgress() {
        // Given
        let randomBytes = 4 * 1024 * 1024
115
        let URLString = "https://httpbin.org/bytes/\(randomBytes)"
116 117 118 119 120 121 122

        let expectation = expectationWithDescription("Bytes download progress should be reported: \(URLString)")

        var byteValues: [(bytes: Int64, totalBytes: Int64, totalBytesExpected: Int64)] = []
        var progressValues: [(completedUnitCount: Int64, totalUnitCount: Int64)] = []
        var responseRequest: NSURLRequest?
        var responseResponse: NSHTTPURLResponse?
123
        var responseData: NSData?
124
        var responseError: ErrorType?
125 126 127 128 129 130 131

        // When
        let request = Alamofire.request(.GET, URLString)
        request.progress { bytesRead, totalBytesRead, totalBytesExpectedToRead in
            let bytes = (bytes: bytesRead, totalBytes: totalBytesRead, totalBytesExpected: totalBytesExpectedToRead)
            byteValues.append(bytes)

132 133 134 135
            let progress = (
                completedUnitCount: request.progress.completedUnitCount,
                totalUnitCount: request.progress.totalUnitCount
            )
136 137 138 139 140 141 142 143 144 145 146
            progressValues.append(progress)
        }
        request.response { request, response, data, error in
            responseRequest = request
            responseResponse = response
            responseData = data
            responseError = error

            expectation.fulfill()
        }

147
        waitForExpectationsWithTimeout(defaultTimeout, handler: nil)
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162

        // Then
        XCTAssertNotNil(responseRequest, "response request should not be nil")
        XCTAssertNotNil(responseResponse, "response response should not be nil")
        XCTAssertNotNil(responseData, "response data should not be nil")
        XCTAssertNil(responseError, "response error should be nil")

        XCTAssertEqual(byteValues.count, progressValues.count, "byteValues count should equal progressValues count")

        if byteValues.count == progressValues.count {
            for index in 0..<byteValues.count {
                let byteValue = byteValues[index]
                let progressValue = progressValues[index]

                XCTAssertGreaterThan(byteValue.bytes, 0, "reported bytes should always be greater than 0")
163 164 165 166 167 168 169 170 171 172
                XCTAssertEqual(
                    byteValue.totalBytes,
                    progressValue.completedUnitCount,
                    "total bytes should be equal to completed unit count"
                )
                XCTAssertEqual(
                    byteValue.totalBytesExpected,
                    progressValue.totalUnitCount,
                    "total bytes expected should be equal to total unit count"
                )
173 174 175
            }
        }

176 177
        if let
            lastByteValue = byteValues.last,
178 179 180 181 182 183 184 185 186 187 188
            lastProgressValue = progressValues.last
        {
            let byteValueFractionalCompletion = Double(lastByteValue.totalBytes) / Double(lastByteValue.totalBytesExpected)
            let progressValueFractionalCompletion = Double(lastProgressValue.0) / Double(lastProgressValue.1)

            XCTAssertEqual(byteValueFractionalCompletion, 1.0, "byte value fractional completion should equal 1.0")
            XCTAssertEqual(progressValueFractionalCompletion, 1.0, "progress value fractional completion should equal 1.0")
        } else {
            XCTFail("last item in bytesValues and progressValues should not be nil")
        }
    }
189 190 191 192

    func testRequestResponseWithStream() {
        // Given
        let randomBytes = 4 * 1024 * 1024
193
        let URLString = "https://httpbin.org/bytes/\(randomBytes)"
194 195 196 197 198

        let expectation = expectationWithDescription("Bytes download progress should be reported: \(URLString)")

        var byteValues: [(bytes: Int64, totalBytes: Int64, totalBytesExpected: Int64)] = []
        var progressValues: [(completedUnitCount: Int64, totalUnitCount: Int64)] = []
199 200
        var accumulatedData = [NSData]()

201 202
        var responseRequest: NSURLRequest?
        var responseResponse: NSHTTPURLResponse?
203
        var responseData: NSData?
204
        var responseError: ErrorType?
205 206 207 208 209 210 211

        // When
        let request = Alamofire.request(.GET, URLString)
        request.progress { bytesRead, totalBytesRead, totalBytesExpectedToRead in
            let bytes = (bytes: bytesRead, totalBytes: totalBytesRead, totalBytesExpected: totalBytesExpectedToRead)
            byteValues.append(bytes)

212 213 214 215
            let progress = (
                completedUnitCount: request.progress.completedUnitCount,
                totalUnitCount: request.progress.totalUnitCount
            )
216 217
            progressValues.append(progress)
        }
218
        request.stream { accumulatedData.append($0) }
219 220 221 222 223 224 225 226 227
        request.response { request, response, data, error in
            responseRequest = request
            responseResponse = response
            responseData = data
            responseError = error

            expectation.fulfill()
        }

228
        waitForExpectationsWithTimeout(defaultTimeout, handler: nil)
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244

        // Then
        XCTAssertNotNil(responseRequest, "response request should not be nil")
        XCTAssertNotNil(responseResponse, "response response should not be nil")
        XCTAssertNil(responseData, "response data should be nil")
        XCTAssertNil(responseError, "response error should be nil")
        XCTAssertGreaterThanOrEqual(accumulatedData.count, 1, "accumulated data should have one or more parts")

        XCTAssertEqual(byteValues.count, progressValues.count, "byteValues count should equal progressValues count")

        if byteValues.count == progressValues.count {
            for index in 0..<byteValues.count {
                let byteValue = byteValues[index]
                let progressValue = progressValues[index]

                XCTAssertGreaterThan(byteValue.bytes, 0, "reported bytes should always be greater than 0")
245 246 247 248 249 250 251 252 253 254
                XCTAssertEqual(
                    byteValue.totalBytes,
                    progressValue.completedUnitCount,
                    "total bytes should be equal to completed unit count"
                )
                XCTAssertEqual(
                    byteValue.totalBytesExpected,
                    progressValue.totalUnitCount,
                    "total bytes expected should be equal to total unit count"
                )
255 256 257
            }
        }

258 259
        if let
            lastByteValue = byteValues.last,
260 261 262 263 264 265
            lastProgressValue = progressValues.last
        {
            let byteValueFractionalCompletion = Double(lastByteValue.totalBytes) / Double(lastByteValue.totalBytesExpected)
            let progressValueFractionalCompletion = Double(lastProgressValue.0) / Double(lastProgressValue.1)

            XCTAssertEqual(byteValueFractionalCompletion, 1.0, "byte value fractional completion should equal 1.0")
266 267 268 269 270 271
            XCTAssertEqual(
                progressValueFractionalCompletion,
                1.0,
                "progress value fractional completion should equal 1.0"
            )
            XCTAssertEqual(
272
                accumulatedData.reduce(Int64(0)) { $0 + $1.length },
273 274 275
                lastByteValue.totalBytes,
                "accumulated data length should match byte count"
            )
276 277 278 279
        } else {
            XCTFail("last item in bytesValues and progressValues should not be nil")
        }
    }
280

281
    func testPOSTRequestWithUnicodeParameters() {
282 283 284 285 286 287 288 289 290 291 292
        // Given
        let URLString = "https://httpbin.org/post"
        let parameters = [
            "french": "français",
            "japanese": "日本語",
            "arabic": "العربية",
            "emoji": "😃"
        ]

        let expectation = expectationWithDescription("request should succeed")

293
        var response: Response<AnyObject, NSError>?
294 295 296

        // When
        Alamofire.request(.POST, URLString, parameters: parameters)
297 298
            .responseJSON { closureResponse in
                response = closureResponse
299 300 301 302 303 304
                expectation.fulfill()
            }

        waitForExpectationsWithTimeout(defaultTimeout, handler: nil)

        // Then
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
        if let response = response {
            XCTAssertNotNil(response.request, "request should not be nil")
            XCTAssertNotNil(response.response, "response should not be nil")
            XCTAssertNotNil(response.data, "data should not be nil")

            if let
                JSON = response.result.value as? [String: AnyObject],
                form = JSON["form"] as? [String: String]
            {
                XCTAssertEqual(form["french"], parameters["french"], "french parameter value should match form value")
                XCTAssertEqual(form["japanese"], parameters["japanese"], "japanese parameter value should match form value")
                XCTAssertEqual(form["arabic"], parameters["arabic"], "arabic parameter value should match form value")
                XCTAssertEqual(form["emoji"], parameters["emoji"], "emoji parameter value should match form value")
            } else {
                XCTFail("form parameter in JSON should not be nil")
            }
321
        } else {
322
            XCTFail("response should not be nil")
323 324
        }
    }
325 326 327 328 329 330

    func testPOSTRequestWithBase64EncodedImages() {
        // Given
        let URLString = "https://httpbin.org/post"

        let pngBase64EncodedString: String = {
331
            let URL = URLForResource("unicorn", withExtension: "png")
332 333
            let data = NSData(contentsOfURL: URL)!

334
            return data.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
335 336 337 338 339 340
        }()

        let jpegBase64EncodedString: String = {
            let URL = URLForResource("rainbow", withExtension: "jpg")
            let data = NSData(contentsOfURL: URL)!

341
            return data.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
342 343 344 345 346 347 348 349 350 351
        }()

        let parameters = [
            "email": "user@alamofire.org",
            "png_image": pngBase64EncodedString,
            "jpeg_image": jpegBase64EncodedString
        ]

        let expectation = expectationWithDescription("request should succeed")

352
        var response: Response<AnyObject, NSError>?
353 354 355

        // When
        Alamofire.request(.POST, URLString, parameters: parameters)
356 357
            .responseJSON { closureResponse in
                response = closureResponse
358
                expectation.fulfill()
359
            }
360 361 362 363

        waitForExpectationsWithTimeout(defaultTimeout, handler: nil)

        // Then
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
        if let response = response {
            XCTAssertNotNil(response.request, "request should not be nil")
            XCTAssertNotNil(response.response, "response should not be nil")
            XCTAssertNotNil(response.data, "data should not be nil")
            XCTAssertTrue(response.result.isSuccess, "result should be success")

            if let
                JSON = response.result.value as? [String: AnyObject],
                form = JSON["form"] as? [String: String]
            {
                XCTAssertEqual(form["email"], parameters["email"], "email parameter value should match form value")
                XCTAssertEqual(form["png_image"], parameters["png_image"], "png_image parameter value should match form value")
                XCTAssertEqual(form["jpeg_image"], parameters["jpeg_image"], "jpeg_image parameter value should match form value")
            } else {
                XCTFail("form parameter in JSON should not be nil")
            }
380
        } else {
381
            XCTFail("response should not be nil")
382 383
        }
    }
M
Mattt Thompson 已提交
384
}
385

386 387
// MARK: -

388 389
extension Request {
    private func preValidate(operation: Void -> Void) -> Self {
390
        delegate.queue.addOperationWithBlock {
391 392 393 394 395 396 397
            operation()
        }

        return self
    }

    private func postValidate(operation: Void -> Void) -> Self {
398
        delegate.queue.addOperationWithBlock {
399 400 401 402 403 404 405 406 407 408 409 410
            operation()
        }

        return self
    }
}

// MARK: -

class RequestExtensionTestCase: BaseTestCase {
    func testThatRequestExtensionHasAccessToTaskDelegateQueue() {
        // Given
411
        let URLString = "https://httpbin.org/get"
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
        let expectation = expectationWithDescription("GET request should succeed: \(URLString)")

        var responses: [String] = []

        // When
        Alamofire.request(.GET, URLString)
            .preValidate {
                responses.append("preValidate")
            }
            .validate()
            .postValidate {
                responses.append("postValidate")
            }
            .response { _, _, _, _ in
                responses.append("response")
                expectation.fulfill()
        }

430
        waitForExpectationsWithTimeout(defaultTimeout, handler: nil)
431 432 433 434 435 436 437 438 439 440 441 442 443 444

        // Then
        if responses.count == 3 {
            XCTAssertEqual(responses[0], "preValidate", "response at index 0 should be preValidate")
            XCTAssertEqual(responses[1], "postValidate", "response at index 1 should be postValidate")
            XCTAssertEqual(responses[2], "response", "response at index 2 should be response")
        } else {
            XCTFail("responses count should be equal to 3")
        }
    }
}

// MARK: -

445
class RequestDescriptionTestCase: BaseTestCase {
446
    func testRequestDescription() {
447
        // Given
448
        let URLString = "https://httpbin.org/get"
449
        let request = Alamofire.request(.GET, URLString)
450
        let initialRequestDescription = request.description
451

452
        let expectation = expectationWithDescription("Request description should update: \(URLString)")
453

454 455 456 457 458 459 460
        var finalRequestDescription: String?
        var response: NSHTTPURLResponse?

        // When
        request.response { _, responseResponse, _, _ in
            finalRequestDescription = request.description
            response = responseResponse
461 462

            expectation.fulfill()
463 464
        }

465
        waitForExpectationsWithTimeout(defaultTimeout, handler: nil)
466 467

        // Then
468
        XCTAssertEqual(initialRequestDescription, "GET https://httpbin.org/get", "incorrect request description")
469 470 471 472 473
        XCTAssertEqual(
            finalRequestDescription ?? "",
            "GET https://httpbin.org/get (\(response?.statusCode ?? -1))",
            "incorrect request description"
        )
474 475 476
    }
}

477 478 479 480 481
// MARK: -

class RequestDebugDescriptionTestCase: BaseTestCase {
    // MARK: Properties

482 483
    let manager: Manager = {
        let manager = Manager(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
484
        manager.startRequestsImmediately = false
485 486
        return manager
    }()
487

488
    let managerDisallowingCookies: Manager = {
489 490 491
        let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
        configuration.HTTPShouldSetCookies = false

492
        let manager = Manager(configuration: configuration)
493 494 495 496 497
        manager.startRequestsImmediately = false

        return manager
    }()

498
    // MARK: Tests
499 500

    func testGETRequestDebugDescription() {
501
        // Given
502
        let URLString = "https://httpbin.org/get"
503 504

        // When
505
        let request = manager.request(.GET, URLString)
506 507
        let components = cURLCommandComponents(request)

508 509
        // Then
        XCTAssertEqual(components[0..<3], ["$", "curl", "-i"], "components should be equal")
510
        XCTAssertFalse(components.contains("-X"), "command should not contain explicit -X flag")
511
        XCTAssertEqual(components.last ?? "", "\"\(URLString)\"", "URL component should be equal")
512 513 514
    }

    func testPOSTRequestDebugDescription() {
515
        // Given
516
        let URLString = "https://httpbin.org/post"
517 518

        // When
519
        let request = manager.request(.POST, URLString)
520 521
        let components = cURLCommandComponents(request)

522 523 524
        // Then
        XCTAssertEqual(components[0..<3], ["$", "curl", "-i"], "components should be equal")
        XCTAssertEqual(components[3..<5], ["-X", "POST"], "command should contain explicit -X flag")
525
        XCTAssertEqual(components.last ?? "", "\"\(URLString)\"", "URL component should be equal")
526 527 528
    }

    func testPOSTRequestWithJSONParametersDebugDescription() {
529
        // Given
530
        let URLString = "https://httpbin.org/post"
531 532

        // When
533
        let request = manager.request(.POST, URLString, parameters: ["foo": "bar"], encoding: .JSON)
534 535
        let components = cURLCommandComponents(request)

536 537 538
        // Then
        XCTAssertEqual(components[0..<3], ["$", "curl", "-i"], "components should be equal")
        XCTAssertEqual(components[3..<5], ["-X", "POST"], "command should contain explicit -X flag")
539 540 541 542 543 544 545 546
        XCTAssertTrue(
            request.debugDescription.rangeOfString("-H \"Content-Type: application/json\"") != nil,
            "command should contain 'application/json' Content-Type"
        )
        XCTAssertTrue(
            request.debugDescription.rangeOfString("-d \"{\\\"foo\\\":\\\"bar\\\"}\"") != nil,
            "command data should contain JSON encoded parameters"
        )
547
        XCTAssertEqual(components.last ?? "", "\"\(URLString)\"", "URL component should be equal")
548
    }
549 550

    func testPOSTRequestWithCookieDebugDescription() {
551
        // Given
552
        let URLString = "https://httpbin.org/post"
553 554 555 556 557 558 559

        let properties = [
            NSHTTPCookieDomain: "httpbin.org",
            NSHTTPCookiePath: "/post",
            NSHTTPCookieName: "foo",
            NSHTTPCookieValue: "bar",
        ]
560

561
        let cookie = NSHTTPCookie(properties: properties)!
562
        manager.session.configuration.HTTPCookieStorage?.setCookie(cookie)
563

564
        // When
565
        let request = manager.request(.POST, URLString)
566 567
        let components = cURLCommandComponents(request)

568 569 570
        // Then
        XCTAssertEqual(components[0..<3], ["$", "curl", "-i"], "components should be equal")
        XCTAssertEqual(components[3..<5], ["-X", "POST"], "command should contain explicit -X flag")
571
        XCTAssertEqual(components.last ?? "", "\"\(URLString)\"", "URL component should be equal")
572
        XCTAssertEqual(components[5..<6], ["-b"], "command should contain -b flag")
573
    }
574

575 576
    func testPOSTRequestWithCookiesDisabledDebugDescription() {
        // Given
577
        let URLString = "https://httpbin.org/post"
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597

        let properties = [
            NSHTTPCookieDomain: "httpbin.org",
            NSHTTPCookiePath: "/post",
            NSHTTPCookieName: "foo",
            NSHTTPCookieValue: "bar",
        ]

        let cookie = NSHTTPCookie(properties: properties)!
        managerDisallowingCookies.session.configuration.HTTPCookieStorage?.setCookie(cookie)

        // When
        let request = managerDisallowingCookies.request(.POST, URLString)
        let components = cURLCommandComponents(request)

        // Then
        let cookieComponents = components.filter { $0 == "-b" }
        XCTAssertTrue(cookieComponents.isEmpty, "command should not contain -b flag")
    }

598
    // MARK: Test Helper Methods
599 600

    private func cURLCommandComponents(request: Request) -> [String] {
601 602 603
        let whitespaceCharacterSet = NSCharacterSet.whitespaceAndNewlineCharacterSet()
        return request.debugDescription.componentsSeparatedByCharactersInSet(whitespaceCharacterSet)
                                       .filter { $0 != "" && $0 != "\\" }
604
    }
605
}