| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import <Foundation/Foundation.h> | 5 #import <Foundation/Foundation.h> |
| 6 #include <stdint.h> | 6 #include <stdint.h> |
| 7 | 7 |
| 8 #import <CrNet/CrNet.h> | 8 #import "components/cronet/ios/Cronet.h" |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/mac/scoped_nsobject.h" | 11 #include "base/mac/scoped_nsobject.h" |
| 12 #include "base/strings/sys_string_conversions.h" | 12 #include "base/strings/sys_string_conversions.h" |
| 13 #import "ios/third_party/gcdwebserver/src/GCDWebServer/Core/GCDWebServer.h" | 13 #include "components/cronet/ios/test/quic_test_server.h" |
| 14 #import "ios/third_party/gcdwebserver/src/GCDWebServer/Responses/GCDWebServerDat
aResponse.h" | |
| 15 #include "net/base/mac/url_conversions.h" | 14 #include "net/base/mac/url_conversions.h" |
| 15 #include "net/base/net_errors.h" |
| 16 #include "net/cert/mock_cert_verifier.h" |
| 16 #include "testing/gtest/include/gtest/gtest.h" | 17 #include "testing/gtest/include/gtest/gtest.h" |
| 17 #include "testing/gtest_mac.h" | 18 #include "testing/gtest_mac.h" |
| 19 |
| 18 #include "url/gurl.h" | 20 #include "url/gurl.h" |
| 19 | 21 |
| 20 @interface TestDelegate : NSObject<NSURLSessionDataDelegate, | 22 @interface TestDelegate : NSObject<NSURLSessionDataDelegate, |
| 21 NSURLSessionDelegate, | 23 NSURLSessionDelegate, |
| 22 NSURLSessionTaskDelegate> | 24 NSURLSessionTaskDelegate> |
| 23 | 25 |
| 24 // Completion semaphore for this TestDelegate. When the request this delegate is | 26 // Completion semaphore for this TestDelegate. When the request this delegate is |
| 25 // attached to finishes (either successfully or with an error), this delegate | 27 // attached to finishes (either successfully or with an error), this delegate |
| 26 // signals this semaphore. | 28 // signals this semaphore. |
| 27 @property(assign, nonatomic) dispatch_semaphore_t semaphore; | 29 @property(assign, nonatomic) dispatch_semaphore_t semaphore; |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 - (void)URLSession:(NSURLSession*)session | 92 - (void)URLSession:(NSURLSession*)session |
| 91 dataTask:(NSURLSessionDataTask*)dataTask | 93 dataTask:(NSURLSessionDataTask*)dataTask |
| 92 willCacheResponse:(NSCachedURLResponse*)proposedResponse | 94 willCacheResponse:(NSCachedURLResponse*)proposedResponse |
| 93 completionHandler: | 95 completionHandler: |
| 94 (void (^)(NSCachedURLResponse* cachedResponse))completionHandler { | 96 (void (^)(NSCachedURLResponse* cachedResponse))completionHandler { |
| 95 completionHandler(proposedResponse); | 97 completionHandler(proposedResponse); |
| 96 } | 98 } |
| 97 | 99 |
| 98 @end | 100 @end |
| 99 | 101 |
| 102 namespace cronet { |
| 100 // base::TimeDelta would normally be ideal for this but it does not support | 103 // base::TimeDelta would normally be ideal for this but it does not support |
| 101 // nanosecond resolution. | 104 // nanosecond resolution. |
| 102 static const int64_t ns_in_second = 1000000000LL; | 105 static const int64_t ns_in_second = 1000000000LL; |
| 103 const char kUserAgent[] = "CrNetTest/1.0.0.0"; | 106 const char kUserAgent[] = "CronetTest/1.0.0.0"; |
| 107 |
| 108 // TODO(mef): Create common header file to declare this. |
| 109 void StartCronetIfNecessary(); |
| 104 | 110 |
| 105 class HttpTest : public ::testing::Test { | 111 class HttpTest : public ::testing::Test { |
| 106 protected: | 112 protected: |
| 107 HttpTest() {} | 113 HttpTest() {} |
| 108 ~HttpTest() override {} | 114 ~HttpTest() override {} |
| 109 | 115 |
| 110 void SetUp() override { | 116 void SetUp() override { |
| 111 [CrNet setUserAgent:base::SysUTF8ToNSString(kUserAgent) partial:NO]; | 117 StartCronetIfNecessary(); |
| 112 [CrNet install]; | |
| 113 NSURLSessionConfiguration* config = | 118 NSURLSessionConfiguration* config = |
| 114 [NSURLSessionConfiguration ephemeralSessionConfiguration]; | 119 [NSURLSessionConfiguration ephemeralSessionConfiguration]; |
| 115 [CrNet installIntoSessionConfiguration:config]; | 120 [Cronet installIntoSessionConfiguration:config]; |
| 116 delegate_.reset([[TestDelegate alloc] init]); | 121 delegate_.reset([[TestDelegate alloc] init]); |
| 117 NSURLSession* session = [NSURLSession sessionWithConfiguration:config | 122 NSURLSession* session = [NSURLSession sessionWithConfiguration:config |
| 118 delegate:delegate_ | 123 delegate:delegate_ |
| 119 delegateQueue:nil]; | 124 delegateQueue:nil]; |
| 120 // Take a reference to the session and store it so it doesn't get | 125 // Take a reference to the session and store it so it doesn't get |
| 121 // deallocated until this object does. | 126 // deallocated until this object does. |
| 122 session_.reset([session retain]); | 127 session_.reset([session retain]); |
| 123 web_server_.reset([[GCDWebServer alloc] init]); | 128 StartQuicTestServer(); |
| 124 } | 129 } |
| 125 | 130 |
| 126 void TearDown() override { | 131 void TearDown() override { ShutdownQuicTestServer(); } |
| 127 [CrNet uninstall]; | |
| 128 [web_server_ stop]; | |
| 129 } | |
| 130 | |
| 131 // Starts a GCDWebServer instance on localhost port 8080, and remembers the | |
| 132 // root URL for later; tests can use GetURL() to produce a URL referring to a | |
| 133 // specific resource under the root URL. | |
| 134 void StartWebServer() { | |
| 135 [web_server_ startWithPort:8080 bonjourName:nil]; | |
| 136 server_root_ = net::GURLWithNSURL([web_server_ serverURL]); | |
| 137 } | |
| 138 | |
| 139 // Registers a fixed response |text| to be returned to requests for |path|, | |
| 140 // which is relative to |server_root_|. | |
| 141 void RegisterPathText(const std::string& path, const std::string& text) { | |
| 142 NSString* nspath = base::SysUTF8ToNSString(path); | |
| 143 NSData* data = [NSData dataWithBytes:text.c_str() length:text.length()]; | |
| 144 [web_server_ addGETHandlerForPath:nspath | |
| 145 staticData:data | |
| 146 contentType:@"text/plain" | |
| 147 cacheAge:30]; | |
| 148 } | |
| 149 | |
| 150 void RegisterPathHandler(const std::string& path, | |
| 151 GCDWebServerProcessBlock handler) { | |
| 152 NSString* nspath = base::SysUTF8ToNSString(path); | |
| 153 [web_server_ addHandlerForMethod:@"GET" | |
| 154 path:nspath | |
| 155 requestClass:NSClassFromString(@"GCDWebServerRequest") | |
| 156 processBlock:handler]; | |
| 157 } | |
| 158 | 132 |
| 159 // Launches the supplied |task| and blocks until it completes, with a timeout | 133 // Launches the supplied |task| and blocks until it completes, with a timeout |
| 160 // of 1 second. | 134 // of 1 second. |
| 161 void StartDataTaskAndWaitForCompletion(NSURLSessionDataTask* task) { | 135 void StartDataTaskAndWaitForCompletion(NSURLSessionDataTask* task) { |
| 162 [task resume]; | 136 [task resume]; |
| 163 int64_t deadline_ns = 1 * ns_in_second; | 137 int64_t deadline_ns = 1 * ns_in_second; |
| 164 dispatch_semaphore_wait([delegate_ semaphore], | 138 dispatch_semaphore_wait([delegate_ semaphore], |
| 165 dispatch_time(DISPATCH_TIME_NOW, deadline_ns)); | 139 dispatch_time(DISPATCH_TIME_NOW, deadline_ns)); |
| 166 } | 140 } |
| 167 | 141 |
| 168 // Returns a URL to refer to the resource named |path| served by the test | |
| 169 // server. If |path| starts with a /, the leading / will be stripped. | |
| 170 GURL GetURL(const std::string& path) { | |
| 171 std::string real_path = path[0] == '/' ? path.substr(1) : path; | |
| 172 return server_root_.Resolve(real_path); | |
| 173 } | |
| 174 | |
| 175 // Some convenience functions for working with GCDWebServerRequest and | |
| 176 // GCDWebServerResponse. | |
| 177 | |
| 178 // Returns true if the value for the request header |header| is not nil and | |
| 179 // contains the string |target|. | |
| 180 bool HeaderValueContains(GCDWebServerRequest* request, | |
| 181 const std::string& header, | |
| 182 const std::string& target) { | |
| 183 NSString* key = base::SysUTF8ToNSString(header); | |
| 184 NSString* needle = base::SysUTF8ToNSString(target); | |
| 185 NSString* haystack = request.headers[key]; | |
| 186 if (!haystack) | |
| 187 return false; | |
| 188 return [haystack rangeOfString:needle].location != NSNotFound; | |
| 189 } | |
| 190 | |
| 191 base::scoped_nsobject<NSURLSession> session_; | 142 base::scoped_nsobject<NSURLSession> session_; |
| 192 base::scoped_nsobject<TestDelegate> delegate_; | 143 base::scoped_nsobject<TestDelegate> delegate_; |
| 193 | |
| 194 private: | |
| 195 base::scoped_nsobject<GCDWebServer> web_server_; | |
| 196 GURL server_root_; | |
| 197 }; | 144 }; |
| 198 | 145 |
| 199 TEST_F(HttpTest, NSURLSessionReceivesData) { | 146 TEST_F(HttpTest, NSURLSessionReceivesData) { |
| 200 const char kPath[] = "/foo"; | 147 NSURL* url = net::NSURLWithGURL(GURL(kTestServerUrl)); |
| 201 const char kData[] = "foobar"; | |
| 202 RegisterPathText(kPath, kData); | |
| 203 StartWebServer(); | |
| 204 | |
| 205 NSURL* url = net::NSURLWithGURL(GetURL(kPath)); | |
| 206 NSURLSessionDataTask* task = [session_ dataTaskWithURL:url]; | 148 NSURLSessionDataTask* task = [session_ dataTaskWithURL:url]; |
| 207 StartDataTaskAndWaitForCompletion(task); | 149 StartDataTaskAndWaitForCompletion(task); |
| 208 EXPECT_EQ(nil, [delegate_ error]); | 150 EXPECT_EQ(nil, [delegate_ error]); |
| 209 EXPECT_EQ(strlen(kData), [delegate_ receivedBytes]); | 151 EXPECT_EQ(strlen(kHelloBodyValue), [delegate_ receivedBytes]); |
| 210 } | 152 } |
| 211 | 153 |
| 212 TEST_F(HttpTest, SdchDisabledByDefault) { | 154 TEST_F(HttpTest, GetGlobalMetricsDeltas) { |
| 213 const char kPath[] = "/sdchtest"; | 155 NSData* delta1 = [Cronet getGlobalMetricsDeltas]; |
| 214 RegisterPathHandler(kPath, | 156 |
| 215 ^GCDWebServerResponse* (GCDWebServerRequest* req) { | 157 NSURL* url = net::NSURLWithGURL(GURL(kTestServerUrl)); |
| 216 EXPECT_FALSE(HeaderValueContains(req, "Accept-Encoding", "sdch")); | |
| 217 return [GCDWebServerDataResponse responseWithText:@"woot!"]; | |
| 218 }); | |
| 219 StartWebServer(); | |
| 220 NSURL* url = net::NSURLWithGURL(GetURL(kPath)); | |
| 221 NSURLSessionDataTask* task = [session_ dataTaskWithURL:url]; | 158 NSURLSessionDataTask* task = [session_ dataTaskWithURL:url]; |
| 222 StartDataTaskAndWaitForCompletion(task); | 159 StartDataTaskAndWaitForCompletion(task); |
| 223 EXPECT_EQ(nil, [delegate_ error]); | 160 EXPECT_EQ(nil, [delegate_ error]); |
| 224 EXPECT_TRUE([delegate_ receivedBytes]); | 161 EXPECT_EQ(strlen(kHelloBodyValue), [delegate_ receivedBytes]); |
| 162 |
| 163 NSData* delta2 = [Cronet getGlobalMetricsDeltas]; |
| 164 EXPECT_FALSE([delta2 isEqualToData:delta1]); |
| 225 } | 165 } |
| 226 | 166 |
| 227 TEST_F(HttpTest, SetUserAgentIsExact) { | 167 TEST_F(HttpTest, NSURLSessionReceivesData2) { |
| 228 const char kPath[] = "/uatest"; | 168 NSURL* url = net::NSURLWithGURL(GURL(GetTestServerURL("/"))); |
| 229 RegisterPathHandler(kPath, ^GCDWebServerResponse*(GCDWebServerRequest* req) { | |
| 230 EXPECT_STREQ(kUserAgent, | |
| 231 [[req.headers valueForKey:@"User-Agent"] UTF8String]); | |
| 232 return [GCDWebServerDataResponse responseWithText:@"yay!"]; | |
| 233 }); | |
| 234 StartWebServer(); | |
| 235 NSURL* url = net::NSURLWithGURL(GetURL(kPath)); | |
| 236 NSURLSessionDataTask* task = [session_ dataTaskWithURL:url]; | 169 NSURLSessionDataTask* task = [session_ dataTaskWithURL:url]; |
| 237 StartDataTaskAndWaitForCompletion(task); | 170 StartDataTaskAndWaitForCompletion(task); |
| 238 EXPECT_EQ(nil, [delegate_ error]); | 171 EXPECT_EQ(nil, [delegate_ error]); |
| 239 EXPECT_TRUE([delegate_ receivedBytes]); | 172 EXPECT_EQ(strlen(kUserAgent), [delegate_ receivedBytes]); |
| 240 } | 173 } |
| 241 | 174 |
| 242 // TODO(ellyjones): There needs to be a test that enabling SDCH works, but | 175 } // namespace cronet |
| 243 // because CrNet is static and 'uninstall' only disables it, there is no way to | |
| 244 // have an individual test enable or disable SDCH. | |
| 245 // Probably there is a way to get gtest tests to run in a separate process, but | |
| 246 // I'm not sure what it is. | |
| OLD | NEW |