//////////////////////////////////////////////////////////////////////////////// // (c) Copyright, Ubisoft Entertainment Inc. || Created by Harbour // //////////////////////////////////////////////////////////////////////////////// #include "tests/config.h" #include "tests/common/helpers.h" #include "tests/common/restStatusCode.h" #include "tests/fixture/memoryCheckFixture.h" #include "testsUnit/http/msApi/mockXmlHttpRequest.h" #include "testsUnit/mock/mockHttpRequest.h" #include #include #include #include #include #include #include #include #include #include #if defined(US_TARGET_XONE) # include #endif namespace US_NS {; US_DEFINE_TEST(TestHttpEngineXHR); typedef LeakChecker HTTP_ENGINE_XBOX_ONE_MOCK; #if !defined(US_DLL) // Validate request creation when IXMLHTTPRequest2::Open succeed TEST_F(HTTP_ENGINE_XBOX_ONE_MOCK, LOCAL_CreateRequestSuccess) { using namespace testing; using namespace Microsoft::WRL; HttpRequestContext requestContext = MockHttpRequest_BF::createDummyContext(); MockHttpRequestXHRFactory* factory = US_NEW(MockHttpRequestXHRFactory); ComPtr mockXmlRequest = US_NEW(MockXmlHttpRequest); ComPtr httpCallback; ASSERT_EQ(S_OK, Details::MakeAndInitialize(&httpCallback)); HttpRequestXHR* xhrRequest = US_NEW(HttpRequestXHR, requestContext, mockXmlRequest, httpCallback); HttpEngineXHR engineXHR(factory); EXPECT_CALL(*factory, createHttpRequest(_)).WillOnce(Return(xhrRequest)); EXPECT_CALL(*mockXmlRequest.Get(), Open(_, _, _, _, _, _, _)).WillOnce(Return(S_OK)); EXPECT_TRUE(engineXHR.initialize(HttpEngineConfig())); HttpRequestInternal* internalRequest = engineXHR.createRequest(requestContext); // Make sure that the created request is the one from the factory EXPECT_EQ(xhrRequest, internalRequest); // Request is not delete automatically by the engine implementation but by HttpEngine components engineXHR.releaseRequest(internalRequest); } // Validate request creation when request factory fail TEST_F(HTTP_ENGINE_XBOX_ONE_MOCK, LOCAL_CreateRequestError) { using namespace testing; using namespace Microsoft::WRL; HttpRequestContext requestContext = MockHttpRequest_BF::createDummyContext(); MockHttpRequestXHRFactory* factory = US_NEW(MockHttpRequestXHRFactory); HttpEngineXHR engineXHR(factory); EXPECT_CALL(*factory, createHttpRequest(_)).WillOnce(ReturnNull()); EXPECT_TRUE(engineXHR.initialize(HttpEngineConfig())); HttpRequestInternal* internalRequest = engineXHR.createRequest(requestContext); // Make sure that the created request is the one from the factory EXPECT_EQ(nullptr, internalRequest); } // Validate request creation when request IXMLHTTPRequest2::Open fail TEST_F(HTTP_ENGINE_XBOX_ONE_MOCK, LOCAL_CreateRequestOpenError) { using namespace testing; using namespace Microsoft::WRL; HttpRequestContext requestContext = MockHttpRequest_BF::createDummyContext(); MockHttpRequestXHRFactory* factory = US_NEW(MockHttpRequestXHRFactory); ComPtr mockXmlRequest = US_NEW(MockXmlHttpRequest); ComPtr httpCallback; ASSERT_EQ(S_OK, Details::MakeAndInitialize(&httpCallback)); HttpRequestXHR* xhrRequest = US_NEW(HttpRequestXHR, requestContext, mockXmlRequest, httpCallback); HttpEngineXHR engineXHR(factory); EXPECT_CALL(*factory, createHttpRequest(_)).WillOnce(Return(xhrRequest)); EXPECT_CALL(*mockXmlRequest.Get(), Open(_, _, _, _, _, _, _)).WillOnce(Return(E_FAIL)); EXPECT_TRUE(engineXHR.initialize(HttpEngineConfig())); HttpRequestInternal* internalRequest = engineXHR.createRequest(requestContext); // Make sure that the request has not been created EXPECT_EQ(nullptr, internalRequest); } // Validate that the headers are set when creating a request TEST_F(HTTP_ENGINE_XBOX_ONE_MOCK, LOCAL_CreateRequestSetHeaders) { using namespace testing; using namespace Microsoft::WRL; HttpHeader requestHeader; { requestHeader["X-H"] = "XbOne"; requestHeader["X-H2"] = "X360"; } HttpRequestContext requestContext = MockHttpRequest_BF::createDummyContext(0, requestHeader); MockHttpRequestXHRFactory* factory = US_NEW(MockHttpRequestXHRFactory); ComPtr mockXmlRequest = US_NEW(MockXmlHttpRequest); ComPtr httpCallback; ASSERT_EQ(S_OK, Details::MakeAndInitialize(&httpCallback)); HttpRequestXHR* xhrRequest = US_NEW(HttpRequestXHR, requestContext, mockXmlRequest, httpCallback); HttpEngineXHR engineXHR(factory); EXPECT_CALL(*factory, createHttpRequest(_)).WillOnce(Return(xhrRequest)); EXPECT_CALL(*mockXmlRequest.Get(), Open(_, _, _, _, _, _, _)).WillOnce(Return(S_OK)); EXPECT_CALL(*mockXmlRequest.Get(), SetRequestHeader(_, _)).WillRepeatedly(Return(S_OK)); // Others headers (ex: User-Agent) EXPECT_CALL(*mockXmlRequest.Get(), SetRequestHeader(StrEq(L"X-H"), StrEq(L"XbOne"))).WillOnce(Return(S_OK)); EXPECT_CALL(*mockXmlRequest.Get(), SetRequestHeader(StrEq(L"X-H2"), StrEq(L"X360"))).WillOnce(Return(S_OK)); EXPECT_TRUE(engineXHR.initialize(HttpEngineConfig())); HttpRequestInternal* internalRequest = engineXHR.createRequest(requestContext); // Make sure that the created request is the one from the factory EXPECT_EQ(xhrRequest, internalRequest); // Request is not delete automatically by the engine implementation but by HttpEngine components engineXHR.releaseRequest(internalRequest); } // Validate request user-agent TEST_F(HTTP_ENGINE_XBOX_ONE_MOCK, LOCAL_CreateRequestSetUserAgent) { using namespace testing; using namespace Microsoft::WRL; HttpEngineConfig engineConfig; engineConfig.setUserAgent("John Doe"); HttpRequestContext requestContext = MockHttpRequest_BF::createDummyContext(); MockHttpRequestXHRFactory* factory = US_NEW(MockHttpRequestXHRFactory); ComPtr mockXmlRequest = US_NEW(MockXmlHttpRequest); ComPtr httpCallback; ASSERT_EQ(S_OK, Details::MakeAndInitialize(&httpCallback)); HttpRequestXHR* xhrRequest = US_NEW(HttpRequestXHR, requestContext, mockXmlRequest, httpCallback); HttpEngineXHR engineXHR(factory); EXPECT_CALL(*factory, createHttpRequest(_)).WillOnce(Return(xhrRequest)); EXPECT_CALL(*mockXmlRequest.Get(), Open(_, _, _, _, _, _, _)).WillOnce(Return(S_OK)); #if defined(US_TARGET_UWP) EXPECT_CALL(*mockXmlRequest.Get(), SetRequestHeader(StrEq(L"If-Modified-Since"), StrEq(L"Mon, 27 Mar 1972 00:00:00 GMT"))); #endif EXPECT_CALL(*mockXmlRequest.Get(), SetRequestHeader(StrEq(L"User-Agent"), StrEq(engineConfig.getUserAgent().getUtf16().c_str()))) .WillOnce(Return(S_OK)); EXPECT_TRUE(engineXHR.initialize(engineConfig)); HttpRequestInternal* internalRequest = engineXHR.createRequest(requestContext); // Make sure that the created request is the one from the factory EXPECT_EQ(xhrRequest, internalRequest); // Request is not delete automatically by the engine implementation but by HttpEngine components engineXHR.releaseRequest(internalRequest);; } // Mock a complete GET request that succeed TEST_F(HTTP_ENGINE_XBOX_ONE_MOCK, LOCAL_XHREngineRequestGet) { using namespace testing; using namespace Microsoft::WRL; const RestStatusCode::Enum STATUS_CODE = RestStatusCode::OK; const String expectStatusCodeStr = "200"; const String responseBody = "The best activities for your health are pumping and humping."; const wchar* URL_TEXT = L"http://DummyUrl/"; HttpHeader expectHeader; expectHeader.addHeaderLine(String::formatText("Content-Length: %i", responseBody.getLength() + 1)); const String expectHeaderStr = expectHeader.convertToString(); MockHttpRequestXHRFactory* factory = US_NEW(MockHttpRequestXHRFactory); ComPtr mockXmlRequest = US_NEW(MockXmlHttpRequest); ComPtr httpCallback; ASSERT_EQ(S_OK, Details::MakeAndInitialize(&httpCallback)); ComPtr mockSequentialStream = US_NEW(MockSequentialStream); HttpEngine httpEngine(US_NEW(HttpEngineXHR, factory)); EXPECT_CALL(*factory, createHttpRequest(_)).WillOnce(MockXmlHttpRequest_BF::CreateRequestXHR(mockXmlRequest, httpCallback)); // IXMLHttpRequest expectations const StringW expectHeaderStrW = expectHeaderStr.getUtf16(); EXPECT_CALL(*mockXmlRequest.Get(), Open(StrEq(L"GET"), StrEq(URL_TEXT), _, _, _, _, _)).WillOnce(Return(S_OK)); EXPECT_CALL(*mockXmlRequest.Get(), Send(IsNull(), Eq(0))).WillOnce(Return(S_OK)); EXPECT_CALL(*mockXmlRequest.Get(), GetAllResponseHeaders(_)).WillOnce(DoAll( MockXmlHttpRequest_BF::SetAllHeaders(expectHeaderStrW.c_str()), Return(S_OK))); // Sequential stream expectations EXPECT_CALL(*mockSequentialStream.Get(), Read(_, _, _)).WillOnce(DoAll( MockXmlHttpRequest_BF::DoSequentialStreamRead(responseBody), Return(S_OK))); // Test execution EXPECT_TRUE(httpEngine.initialize(HttpConfig())); HttpRequestContext requestContext = httpEngine.createRequest(HttpGet(URL_TEXT), HttpRetryHandler(HttpRetryConfig(0u))); US_EXPECT_PROPERTY_WAIT(requestContext, HttpRequestContext::isProcessing, true, 1000); const StringW expectStatusCodeStrW = expectStatusCodeStr.getUtf16(); httpCallback->OnHeadersAvailable(mockXmlRequest.Get(), STATUS_CODE, expectStatusCodeStrW.c_str()); httpCallback->OnDataAvailable(mockXmlRequest.Get(), mockSequentialStream.Get()); httpCallback->OnResponseReceived(mockXmlRequest.Get(), mockSequentialStream.Get()); US_EXPECT_PROPERTY_WAIT(requestContext, HttpRequestContext::isComplete, true, 1000); EXPECT_TRUE(requestContext.hasSucceeded()); const HttpRequestContext::ResponseData& responseData = requestContext.getResponseData(); EXPECT_EQ(STATUS_CODE, responseData.m_statusCode); EXPECT_EQ(expectHeader, responseData.m_header); EXPECT_STREQ(responseBody.getUtf8(), HttpEntityReader::readAllAsString(responseData.m_entity).getUtf8()); httpEngine.shutdown(); } /// @test Mocks a GET request failing because of IXMLHTTPRequest2::Send TEST_F(HTTP_ENGINE_XBOX_ONE_MOCK, LOCAL_XHREngineRequestGetSendError) { using namespace testing; using namespace Microsoft::WRL; const wchar* URL_TEXT = L"http://DummyUrl/"; MockHttpRequestXHRFactory* factory = US_NEW(MockHttpRequestXHRFactory); ComPtr mockXmlRequest = US_NEW(MockXmlHttpRequest); ComPtr httpCallback; ASSERT_EQ(S_OK, Details::MakeAndInitialize(&httpCallback)); HttpEngine httpEngine(US_NEW(HttpEngineXHR, factory)); EXPECT_CALL(*factory, createHttpRequest(_)).WillOnce(MockXmlHttpRequest_BF::CreateRequestXHR(mockXmlRequest, httpCallback)); // IXMLHttpRequest expectations EXPECT_CALL(*mockXmlRequest.Get(), Open(StrEq(L"GET"), StrEq(URL_TEXT), _, _, _, _, _)).WillOnce(Return(S_OK)); EXPECT_CALL(*mockXmlRequest.Get(), Send(IsNull(), Eq(0))).WillOnce(Return(E_FAIL)); EXPECT_CALL(*mockXmlRequest.Get(), Abort()).WillOnce(Return(S_OK)); // Test execution ASSERT_TRUE(httpEngine.initialize(HttpConfig())); HttpRequestContext requestContext = httpEngine.createRequest(HttpGet(URL_TEXT), HttpRetryHandler(HttpRetryConfig(0))); // Disable retry US_EXPECT_PROPERTY_WAIT(requestContext, HttpRequestContext::hasFailed, true, 1000); US_EXPECT_PROPERTY_WAIT(requestContext, HttpRequestContext::isComplete, true, 1000); EXPECT_EQ(Errors::HTTP_REQUEST_TRANSFER_FAILURE, requestContext.getError().m_code); httpEngine.shutdown(); } // Mock a complete GET request without a Content-Length header TEST_F(HTTP_ENGINE_XBOX_ONE_MOCK, LOCAL_XHREngineRequestGetNoContentLength) { using namespace testing; using namespace Microsoft::WRL; const RestStatusCode::Enum STATUS_CODE = RestStatusCode::OK; const String expectStatusCodeStr = "200"; const String responseBody = "The best activities for your health are pumping and humping."; const wchar* URL_TEXT = L"http://DummyUrl/"; MockHttpRequestXHRFactory* factory = US_NEW(MockHttpRequestXHRFactory); ComPtr mockXmlRequest = US_NEW(MockXmlHttpRequest); ComPtr httpCallback; ASSERT_EQ(S_OK, Details::MakeAndInitialize(&httpCallback)); ComPtr mockSequentialStream = US_NEW(MockSequentialStream); HttpEngine httpEngine(US_NEW(HttpEngineXHR, factory)); EXPECT_CALL(*factory, createHttpRequest(_)).WillOnce(MockXmlHttpRequest_BF::CreateRequestXHR(mockXmlRequest, httpCallback)); // IXMLHttpRequest expectations EXPECT_CALL(*mockXmlRequest.Get(), Open(StrEq(L"GET"), StrEq(URL_TEXT), _, _, _, _, _)).WillOnce(Return(S_OK)); EXPECT_CALL(*mockXmlRequest.Get(), Send(IsNull(), Eq(0))).WillOnce(Return(S_OK)); EXPECT_CALL(*mockXmlRequest.Get(), GetAllResponseHeaders(_)).WillOnce(DoAll( SetArgPointee<0>(nullptr), Return(S_OK) )); // Sequential stream expectations EXPECT_CALL(*mockSequentialStream.Get(), Read(_, _, _)).WillOnce(DoAll( MockXmlHttpRequest_BF::DoSequentialStreamRead(responseBody), Return(S_OK))).WillRepeatedly(Return(S_OK)); // Test execution EXPECT_TRUE(httpEngine.initialize(HttpConfig())); HttpRequestContext requestContext = httpEngine.createRequest(HttpGet(URL_TEXT), HttpRetryHandler(HttpRetryConfig(0u))); US_EXPECT_PROPERTY_WAIT(requestContext, HttpRequestContext::isProcessing, true, 1000); const StringW expectStatusCodeStrW = expectStatusCodeStr.getUtf16(); httpCallback->OnHeadersAvailable(mockXmlRequest.Get(), STATUS_CODE, expectStatusCodeStrW.c_str()); httpCallback->OnDataAvailable(mockXmlRequest.Get(), mockSequentialStream.Get()); httpCallback->OnResponseReceived(mockXmlRequest.Get(), mockSequentialStream.Get()); US_EXPECT_PROPERTY_WAIT(requestContext, HttpRequestContext::isComplete, true, 1000); EXPECT_TRUE(requestContext.hasSucceeded()); const HttpRequestContext::ResponseData& responseData = requestContext.getResponseData(); EXPECT_EQ(STATUS_CODE, responseData.m_statusCode); EXPECT_STREQ(responseBody.getUtf8(), HttpEntityReader::readAllAsString(responseData.m_entity).getUtf8()); httpEngine.shutdown(); } // Validate when ISequentialStream::Read returns S_FALSE, the request is still ok // (S_FALSE means that all data has been transfered, but the buffer passed to retrieve data couldn't be filled completely) TEST_F(HTTP_ENGINE_XBOX_ONE_MOCK, LOCAL_XHREngineRequestGetReadFalse) { using namespace testing; using namespace Microsoft::WRL; const RestStatusCode::Enum STATUS_CODE = RestStatusCode::OK; const String expectStatusCodeStr = "200"; const String responseBody = "The best activity for your health is hunting honey badgers in Far Cry."; const wchar* URL_TEXT = L"http://DummyUrl/"; HttpHeader expectHeader; expectHeader.addHeaderLine(String::formatText("Content-Length: %i", responseBody.getLength() + 1)); const String expectHeaderStr = expectHeader.convertToString(); MockHttpRequestXHRFactory* factory = US_NEW(MockHttpRequestXHRFactory); ComPtr mockXmlRequest = US_NEW(MockXmlHttpRequest); ComPtr httpCallback; ASSERT_EQ(S_OK, Details::MakeAndInitialize(&httpCallback)); ComPtr mockSequentialStream = US_NEW(MockSequentialStream); HttpEngine httpEngine(US_NEW(HttpEngineXHR, factory)); EXPECT_CALL(*factory, createHttpRequest(_)).WillOnce(MockXmlHttpRequest_BF::CreateRequestXHR(mockXmlRequest, httpCallback)); // IXMLHttpRequest expectations const StringW expectHeaderStrW = expectHeaderStr.getUtf16(); EXPECT_CALL(*mockXmlRequest.Get(), Open(StrEq(L"GET"), StrEq(URL_TEXT), _, _, _, _, _)).WillOnce(Return(S_OK)); EXPECT_CALL(*mockXmlRequest.Get(), Send(IsNull(), Eq(0))).WillOnce(Return(S_OK)); EXPECT_CALL(*mockXmlRequest.Get(), GetAllResponseHeaders(_)).WillOnce(DoAll( MockXmlHttpRequest_BF::SetAllHeaders(expectHeaderStrW.c_str()), Return(S_OK))); // Sequential stream expectations EXPECT_CALL(*mockSequentialStream.Get(), Read(_, _, _)).WillOnce(DoAll( MockXmlHttpRequest_BF::DoSequentialStreamRead(responseBody), Return(S_FALSE))); // Test execution EXPECT_TRUE(httpEngine.initialize(HttpConfig())); HttpRequestContext requestContext = httpEngine.createRequest(HttpGet(URL_TEXT), HttpRetryHandler(HttpRetryConfig(0u))); US_EXPECT_PROPERTY_WAIT(requestContext, HttpRequestContext::isProcessing, true, 1000); const StringW expectStatusCodeStrW = expectStatusCodeStr.getUtf16(); httpCallback->OnHeadersAvailable(mockXmlRequest.Get(), STATUS_CODE, expectStatusCodeStrW.c_str()); httpCallback->OnDataAvailable(mockXmlRequest.Get(), mockSequentialStream.Get()); httpCallback->OnResponseReceived(mockXmlRequest.Get(), mockSequentialStream.Get()); US_EXPECT_PROPERTY_WAIT(requestContext, HttpRequestContext::isComplete, true, 1000); EXPECT_TRUE(requestContext.hasSucceeded()); const HttpRequestContext::ResponseData& responseData = requestContext.getResponseData(); EXPECT_EQ(STATUS_CODE, responseData.m_statusCode); EXPECT_EQ(expectHeader, responseData.m_header); EXPECT_STREQ(responseBody.getUtf8(), HttpEntityReader::readAllAsString(responseData.m_entity).getUtf8()); httpEngine.shutdown(); } // Validate when ISequentialStream::Read returns an error (STG_E_ACCESSDENIED chosen arbitrarily in this case) // the request is stopped and returns an error TEST_F(HTTP_ENGINE_XBOX_ONE_MOCK, LOCAL_XHREngineRequestGetReadError) { using namespace testing; using namespace Microsoft::WRL; const RestStatusCode::Enum STATUS_CODE = RestStatusCode::OK; const String expectStatusCodeStr = "200"; const String responseBody = "The best activities for your health are pumping and humping."; const wchar* URL_TEXT = L"http://DummyUrl/"; HttpHeader expectHeader; expectHeader.addHeaderLine(String::formatText("Content-Length: %i", responseBody.getLength() + 1)); const String expectHeaderStr = expectHeader.convertToString(); MockHttpRequestXHRFactory* factory = US_NEW(MockHttpRequestXHRFactory); ComPtr mockXmlRequest = US_NEW(MockXmlHttpRequest); ComPtr httpCallback; ASSERT_EQ(S_OK, Details::MakeAndInitialize(&httpCallback)); ComPtr mockSequentialStream = US_NEW(MockSequentialStream); HttpEngine httpEngine(US_NEW(HttpEngineXHR, factory)); EXPECT_CALL(*factory, createHttpRequest(_)).WillOnce(MockXmlHttpRequest_BF::CreateRequestXHR(mockXmlRequest, httpCallback)); // IXMLHttpRequest expectations const StringW expectHeaderStrW = expectHeaderStr.getUtf16(); EXPECT_CALL(*mockXmlRequest.Get(), Open(StrEq(L"GET"), StrEq(URL_TEXT), _, _, _, _, _)).WillOnce(Return(S_OK)); EXPECT_CALL(*mockXmlRequest.Get(), Send(IsNull(), Eq(0))).WillOnce(Return(S_OK)); EXPECT_CALL(*mockXmlRequest.Get(), GetAllResponseHeaders(_)).WillOnce(DoAll( MockXmlHttpRequest_BF::SetAllHeaders(expectHeaderStrW.c_str()), Return(S_OK))); EXPECT_CALL(*mockXmlRequest.Get(), Abort()).WillOnce(Return(S_OK)); // Sequential stream expectations EXPECT_CALL(*mockSequentialStream.Get(), Read(_, _, _)).WillOnce(DoAll( MockXmlHttpRequest_BF::DoSequentialStreamRead(responseBody), Return(STG_E_ACCESSDENIED))); // Test execution EXPECT_TRUE(httpEngine.initialize(HttpConfig())); HttpRequestContext requestContext = httpEngine.createRequest(HttpGet(URL_TEXT), HttpRetryHandler(HttpRetryConfig(0u))); US_EXPECT_PROPERTY_WAIT(requestContext, HttpRequestContext::isProcessing, true, 1000); const StringW expectStatusCodeStrW = expectStatusCodeStr.getUtf16(); httpCallback->OnHeadersAvailable(mockXmlRequest.Get(), STATUS_CODE, expectStatusCodeStrW.c_str()); httpCallback->OnResponseReceived(mockXmlRequest.Get(), mockSequentialStream.Get()); US_EXPECT_PROPERTY_WAIT(requestContext, HttpRequestContext::isComplete, true, 1000); EXPECT_TRUE(requestContext.hasFailed()); EXPECT_EQ(Errors::HTTP_REQUEST_TRANSFER_FAILURE, requestContext.getError().m_code); httpEngine.shutdown(); } #endif // US_DLL };