Velhotes/Vinyl

Network Timeout

RLovelett opened this issue · 5 comments

Is there anyway to simulate a network timeout with Vinyl?

I've been playing around with this and I'm not sure that there is a way to simulate a network timeout or other types of network issues currently with Vinyl.

So I'm interested in feedback on adding a slight variation of the Vinyl fixture format. One that handles a good response and one that handles a bad response.

The format would largely be the same as before except that the "response" JSON property could now have an "error" property which would be mapped into an NSError. This NSError would then be provided during Vinyl playback.

[
    {
        "request": {
            "url": "http://api.test.com"
        },
        "response": {
            "error": {
                "code": -1006,
                "domain": "NSURLErrorDomain",
                "userInfo": {
                    "NSErrorFailingURLKey": "http://api.test.com",
                    "NSErrorFailingURLStringKey": "http://api.test.com",
                    "NSLocalizedDescription": "A server with the specified hostname could not be found."
                }
            },
            "url": "http://api.test.com"
        }
    }
]

Thoughts?

You can simulate a network timeout by creating a vinyl programmatically and provide the expected NSError using this specific API.

For this kind of tests I think creating a vinyl programmatically is more appropriate since you can use constants instead of hard-coded strings that should map without guarantees to a NSError.

That seems fair and I kind of like that too. Though it does feel disjointed that some of my test fixtures will be in files and some of my test fixtures will be inline. Cannot say it matters too much. Just thought I'd point that out.

Of course, the major problem is that it does not work properly, at least not yet.

func testNotMocked() {
    let expectation = self.expectationWithDescription(#function)
    defer { self.waitForExpectationsWithTimeout(50.0, handler: nil) }

    let url = NSURL(string: "http://dfsdfhttpbin.org/hidden-basic-auth/:user/:passwd")!
    let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())

    session.dataTaskWithURL(url) { (data, response, error) in
        XCTAssertNil(data)
        XCTAssertNil(response)
        XCTAssertNotNil(error)
        print(error)
        expectation.fulfill()
    }.resume()
}

func testMocked() {
    let expectation = self.expectationWithDescription(#function)
    defer { self.waitForExpectationsWithTimeout(50.0, handler: nil) }

    let url = NSURL(string: "http://dfsdfhttpbin.org/hidden-basic-auth/:user/:passwd")!
    let error = NSError(domain: NSURLErrorDomain, code: NSURLErrorDNSLookupFailed, userInfo: nil)
    let track = [TrackFactory.createBadTrack(url, statusCode: 400, error: error)]
    let vinyl = Vinyl(tracks: track)
    let turntable = Turntable(vinyl: vinyl)

    turntable.dataTaskWithURL(url) { (data, response, error) in
        XCTAssertNil(data)
        XCTAssertNil(response)
        XCTAssertNotNil(error)
        print(error)
        expectation.fulfill()
    }.resume()
}

The testNotMocked one comes through without a problem. The testMocked on the other-hand does not. The second one's response is not nil and fails the assertion.

It would seem to me that Response needs to be refactored to have an NSHTTPURLResponse? instead of NSHTTPURLResponse. Agree?

Well spotted, yes it need to be optional since we may not have one, when there's an error. This can be confirmed in NSURLSession's methods like this one.

I'm currently on vacation so I'm not able to work on this until the weekend but PRs are welcome ✨

@dmcrodrigues there is a pull for this at #62.