diff options
author | ellyjones <ellyjones@chromium.org> | 2015-08-12 09:19:00 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-08-12 16:19:46 +0000 |
commit | 829ab733f47fd0fa4395f6347411a5a5ab41451b (patch) | |
tree | bf4f0bc816b6598091c231a1315c79f364c398c6 | |
parent | c0d31ab28e21c048f40584ace3b0a8aca5723c17 (diff) | |
download | chromium_src-829ab733f47fd0fa4395f6347411a5a5ab41451b.zip chromium_src-829ab733f47fd0fa4395f6347411a5a5ab41451b.tar.gz chromium_src-829ab733f47fd0fa4395f6347411a5a5ab41451b.tar.bz2 |
Add CrNet integration test framework.
this adds a new target, crnet_test, which builds a standalone binary that runs
CrNet integration tests. Currently there are only two tests, which cover basic
HTTP fetch functionality. Further tests will be added in later CLs.
BUG=422451
Review URL: https://codereview.chromium.org/1235203002
Cr-Commit-Position: refs/heads/master@{#343027}
-rw-r--r-- | ios/crnet/DEPS | 1 | ||||
-rw-r--r-- | ios/crnet/test/Default.png | bin | 0 -> 6540 bytes | |||
-rw-r--r-- | ios/crnet/test/crnet_http_tests.mm | 196 | ||||
-rw-r--r-- | ios/crnet/test/crnet_test.gyp | 40 | ||||
-rw-r--r-- | ios/crnet/test/crnet_test_runner.mm | 11 | ||||
-rw-r--r-- | ios/ios.gyp | 1 |
6 files changed, 249 insertions, 0 deletions
diff --git a/ios/crnet/DEPS b/ios/crnet/DEPS index df845d4..928073c 100644 --- a/ios/crnet/DEPS +++ b/ios/crnet/DEPS @@ -3,6 +3,7 @@ include_rules = [ "+crypto/nss_util.h", "+ios/crnet", "+ios/net", + "+ios/third_party/gcdwebserver", "+ios/web/public/user_agent.h", "+net" ] diff --git a/ios/crnet/test/Default.png b/ios/crnet/test/Default.png Binary files differnew file mode 100644 index 0000000..4c8ca6f69 --- /dev/null +++ b/ios/crnet/test/Default.png diff --git a/ios/crnet/test/crnet_http_tests.mm b/ios/crnet/test/crnet_http_tests.mm new file mode 100644 index 0000000..4436e09 --- /dev/null +++ b/ios/crnet/test/crnet_http_tests.mm @@ -0,0 +1,196 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import <Foundation/Foundation.h> + +#import "CrNet.h" + +#include "base/mac/scoped_nsobject.h" +#import "ios/third_party/gcdwebserver/src/GCDWebServer/Core/GCDWebServer.h" +#include "net/base/mac/url_conversions.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/gtest_mac.h" +#include "url/gurl.h" + +@interface TestDelegate : NSObject<NSURLSessionDataDelegate, + NSURLSessionDelegate, + NSURLSessionTaskDelegate> + +// Completion semaphore for this TestDelegate. When the request this delegate is +// attached to finishes (either successfully or with an error), this delegate +// signals this semaphore. +@property(assign, nonatomic) dispatch_semaphore_t semaphore; + +// Total count of bytes received by the request this delegate is attached to. +@property(nonatomic) unsigned long receivedBytes; + +// Error the request this delegate is attached to failed with, if any. +@property(retain, nonatomic) NSError* error; + +@end + +@implementation TestDelegate +@synthesize semaphore = _semaphore; +@synthesize receivedBytes = _receivedBytes; +@synthesize error = _error; + +- (id)init { + if (self = [super init]) { + _semaphore = dispatch_semaphore_create(0); + } + return self; +} + +- (void)dealloc { + dispatch_release(_semaphore); + [_error release]; + _error = nil; + [super dealloc]; +} + +- (void)URLSession:(NSURLSession*)session + didBecomeInvalidWithError:(NSError*)error { +} + +- (void)URLSession:(NSURLSession*)session + task:(NSURLSessionTask*)task + didCompleteWithError:(NSError*)error { + [self setError:error]; + dispatch_semaphore_signal(_semaphore); +} + +- (void)URLSession:(NSURLSession*)session + task:(NSURLSessionTask*)task + didReceiveChallenge:(NSURLAuthenticationChallenge*)challenge + completionHandler: + (void (^)(NSURLSessionAuthChallengeDisposition disp, + NSURLCredential* credential))completionHandler { + completionHandler(NSURLSessionAuthChallengeUseCredential, nil); +} + +- (void)URLSession:(NSURLSession*)session + dataTask:(NSURLSessionDataTask*)dataTask + didReceiveResponse:(NSURLResponse*)response + completionHandler:(void (^)(NSURLSessionResponseDisposition disposition)) + completionHandler { + completionHandler(NSURLSessionResponseAllow); +} + +- (void)URLSession:(NSURLSession*)session + dataTask:(NSURLSessionDataTask*)dataTask + didReceiveData:(NSData*)data { + _receivedBytes += (unsigned long)data.length; +} + +- (void)URLSession:(NSURLSession*)session + dataTask:(NSURLSessionDataTask*)dataTask + willCacheResponse:(NSCachedURLResponse*)proposedResponse + completionHandler: + (void (^)(NSCachedURLResponse* cachedResponse))completionHandler { + completionHandler(proposedResponse); +} + +@end + +// base::TimeDelta would normally be ideal for this but it does not support +// nanosecond resolution. +static const int64_t ns_in_second = 1000000000LL; + +class HttpTest : public ::testing::Test { + protected: + HttpTest() {} + ~HttpTest() override {} + + void SetUp() override { + [CrNet setPartialUserAgent:@"CrNetTest/1.0.0.0"]; + [CrNet install]; + NSURLSessionConfiguration* config = + [NSURLSessionConfiguration ephemeralSessionConfiguration]; + [CrNet installIntoSessionConfiguration:config]; + delegate_.reset([[TestDelegate alloc] init]); + NSURLSession* session = [NSURLSession sessionWithConfiguration:config + delegate:delegate_ + delegateQueue:nil]; + // Take a reference to the session and store it so it doesn't get + // deallocated until this object does. + session_.reset([session retain]); + web_server_.reset([[GCDWebServer alloc] init]); + } + + void TearDown() override { + [CrNet uninstall]; + [web_server_ stop]; + } + + // Starts a GCDWebServer instance on localhost port 8080, and remembers the + // root URL for later; tests can use GetURL() to produce a URL referring to a + // specific resource under the root URL. + void StartWebServer() { + [web_server_ startWithPort:8080 bonjourName:nil]; + server_root_ = net::GURLWithNSURL([web_server_ serverURL]); + } + + // Registers a fixed response |text| to be returned to requests for |path|, + // which is relative to |server_root_|. + void RegisterPathText(const std::string& path, const std::string& text) { + NSString* nspath = + [NSString stringWithCString:path.c_str() encoding:NSUTF8StringEncoding]; + NSData* data = [NSData dataWithBytes:text.c_str() length:text.length()]; + [web_server_ addGETHandlerForPath:nspath + staticData:data + contentType:@"text/plain" + cacheAge:30]; + } + + // Launches the supplied |task| and blocks until it completes, with a timeout + // of 1 second. + void StartDataTaskAndWaitForCompletion(NSURLSessionDataTask* task) { + [task resume]; + int64_t deadline_ns = 1 * ns_in_second; + dispatch_semaphore_wait([delegate_ semaphore], + dispatch_time(DISPATCH_TIME_NOW, deadline_ns)); + } + + // Returns a URL to refer to the resource named |path| served by the test + // server. If |path| starts with a /, the leading / will be stripped. + GURL GetURL(const std::string& path) { + std::string real_path = path[0] == '/' ? path.substr(1) : path; + return server_root_.Resolve(real_path); + } + + base::scoped_nsobject<NSURLSession> session_; + base::scoped_nsobject<TestDelegate> delegate_; + + private: + base::scoped_nsobject<GCDWebServer> web_server_; + GURL server_root_; +}; + +TEST_F(HttpTest, NSURLConnectionReceivesData) { + const char kData[] = "foobar"; + const char kPath[] = "/foo"; + RegisterPathText(kPath, kData); + StartWebServer(); + + NSURL* url = net::NSURLWithGURL(GetURL(kPath)); + NSURLRequest* req = [NSURLRequest requestWithURL:url]; + NSURLResponse* resp = nil; + NSError* error = nil; + NSData* received = [NSURLConnection sendSynchronousRequest:req + returningResponse:&resp + error:&error]; + EXPECT_EQ(0, memcmp([received bytes], kData, sizeof(kData))); +} + +TEST_F(HttpTest, NSURLSessionReceivesData) { + const char data[] = "foobar"; + RegisterPathText("/foo", data); + StartWebServer(); + + NSURL* url = net::NSURLWithGURL(GetURL("foo")); + NSURLSessionDataTask* task = [session_ dataTaskWithURL:url]; + StartDataTaskAndWaitForCompletion(task); + EXPECT_EQ(nil, [delegate_ error]); + EXPECT_EQ(strlen(data), [delegate_ receivedBytes]); +} diff --git a/ios/crnet/test/crnet_test.gyp b/ios/crnet/test/crnet_test.gyp new file mode 100644 index 0000000..ea785b2 --- /dev/null +++ b/ios/crnet/test/crnet_test.gyp @@ -0,0 +1,40 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +{ + 'variables': { + 'chromium_code': 1, + }, + 'targets': [], + 'conditions': [ + # The CrNet build is ninja-only because of the hack in + # ios/build/packaging/link_dependencies.py. + ['OS=="ios" and "<(GENERATOR)"=="ninja"', { + 'targets': [ + { + 'target_name': 'crnet_test', + 'type': 'executable', + 'dependencies': [ + '../../../ios/crnet/crnet.gyp:crnet', + '../../../ios/third_party/gcdwebserver/gcdwebserver.gyp:gcdwebserver', + '../../../testing/gtest.gyp:gtest', + ], + 'sources': [ + 'crnet_http_tests.mm', + 'crnet_test_runner.mm', + ], + 'mac_bundle_resources': [ + 'Default.png', + ], + 'include_dirs': [ + '../../..', + '..', + ], + 'link_settings': { + }, + }, + ], + }], + ], +} diff --git a/ios/crnet/test/crnet_test_runner.mm b/ios/crnet/test/crnet_test_runner.mm new file mode 100644 index 0000000..869f738 --- /dev/null +++ b/ios/crnet/test/crnet_test_runner.mm @@ -0,0 +1,11 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/gtest_mac.h" + +int main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/ios/ios.gyp b/ios/ios.gyp index 4caf955..17af2d1 100644 --- a/ios/ios.gyp +++ b/ios/ios.gyp @@ -14,6 +14,7 @@ 'crnet/crnet.gyp:*', 'crnet/crnet_pack.gyp:*', 'crnet/crnet_consumer/crnet_consumer.gyp:*', + 'crnet/test/crnet_test.gyp:*', 'net/ios_net.gyp:*', 'net/ios_net_unittests.gyp:*', 'provider/ios_provider_chrome.gyp:*', |