//////////////////////////////////////////////////////////////////////////////// // (c) Copyright, Ubisoft Entertainment Inc. || Created by Harbour // //////////////////////////////////////////////////////////////////////////////// #include "tests/config.h" #include "tests/common/restStatusCode.h" #include "tests/mock/mockLogDevice.h" #include "tests/fixture/authenticationFixture.h" #include "tests/fixture/loginMockFixture.h" // for BuildList #include "tests/fixture/memoryCheckFixture.h" #include "testsUnit/mock/mockWebsocketStreamImpl.h" #include "testsUnit/mock/mockSocket.h" #include "testsUnit/mock/mockWebsocketClient.h" #include #include #include #include #include #include #include namespace US_NS {; US_DEFINE_TEST(TestConnection); #if !defined(US_DLL) typedef LeakChecker UNIT_CONNECTION; typedef LeakCheckerNoInit UNIT_CONNECTION_NOINIT; typedef LeakCheckerNoScheduler UNIT_CONNECTION_NOENGINES; typedef LoginMockFixture UNIT_CONNECTION_MOCK_NOLOGIN; namespace ConnectionInfoPrivate { bool extractData(const Json& source, ConnectionInfo& target); bool extractData(const Json& source) { ConnectionInfo dummy; return extractData(source, dummy); } } namespace OwnConnectionInfoPrivate { bool extractData(const Json& source, ConnectionInfoOwn& target); bool extractData(const Json& source) { ConnectionInfoOwn dummy; return extractData(source, dummy); } } namespace FieldNames { const char* const CONNECTION_TYPE = "notificationType"; const char* const CONNECTION_ID = "connectionId"; const char* const CONTACT_URL = "contactUrl"; const char* const CONTENT = "content"; const char* const DATE_POSTED = "datePosted"; } namespace FieldValues { const char* const CONNECTION_TYPE = "US_CONNECTION_ESTABLISHED"; const char* const CONNECTION_ID = "3a685713-e022-4e03-bcf7-9d7ba70e2066"; const char* const CONTACT_URL = "http://uat-im-ubiservices.ubi.com/not01/8180/channels/39389/message"; const char* const DATE_POSTED = "2014-07-22T17:17:18.725Z"; } namespace TestConnectionStructures_BF { Json getConnectionInfoMissingInfo() { JsonWriter writer; //writer[CONNECTION_ID] = "11112222-3333-4444-5555-666677778888"; writer["profileId"] = "aaaabbbb-cccc-dddd-eeee-ffffaaaabbbb"; writer["applicationId"] = "1111aaaa-2222-bbbb-3333-cccc4444dddd"; writer[FieldNames::CONTACT_URL] = "https://contact.url.com"; writer["contactProtocol"] = "https"; writer["createdDate"] = "2014-08-01T00:00:00Z"; writer["lastModifiedDate"] = "2014-08-01T00:00:00Z"; writer["messageTypes"] = Vector({"type1", "type2"}); { JsonWriter obj; obj["field"] = "value"; writer["obj"] = obj.getJson(); } return writer.getJson(); } Json getValidConnectionInfo() { const Json json = getConnectionInfoMissingInfo(); JsonWriter writer(json); writer[FieldNames::CONNECTION_ID] = "11112222-3333-4444-5555-666677778888"; return writer.getJson(); } Json getValidConnectionInfoExtraField() { const Json json = getValidConnectionInfo(); JsonWriter writer(json); writer["field"] = "value"; return writer.getJson(); } int32 createMockUbiServicesErrorResponse(char* data, uint32 maxSize) { const String response = "HTTP/1.1 404 Not Found\r\n" "Connection: close\r\n" "X-WebSocket-Reject-Reason: Error message: The resource was not found\r\n" "Content-Type: application/json\r\n" "Content-Length: 297\r\n" "\r\n" "{\"errorCode\":1003,\"errorContext\":\"Events\",\"httpCode\":404,\"message\":\"Error message : The resource was not found\"," "\"moreInfo\":\"A link to more information will be coming soon.Please contact UbiServices for more support.\",\"stackTrace\":\"\"," "\"transactionId\":\"\",\"transactionTime\":\"2015-03-05T21:39:44.248Z\"}"; EXPECT_LE(response.getLength(), maxSize); memcpy(data, response.getUtf8(), response.getLength()); return static_cast(response.getLength()); } } TEST_F(UNIT_CONNECTION_NOENGINES, LOCAL_ConnectionInfoValid) { SAVE_ALLOC_COUNT(count1); const Json info = TestConnectionStructures_BF::getValidConnectionInfo(); EXPECT_ALLOC_COUNT_PC_EQ(62u, count1); EXPECT_TRUE(ConnectionInfoPrivate::extractData(info)); EXPECT_ALLOC_COUNT_PC_EQ(43u, count1); } TEST_F(UNIT_CONNECTION, LOCAL_ConnectionInfoValidExtraField) { const Json info = TestConnectionStructures_BF::getValidConnectionInfo(); JsonWriter writer(info); writer["field"] = "value"; const Json reader = writer.getJson(); EXPECT_TRUE(ConnectionInfoPrivate::extractData(reader)); } TEST_F(UNIT_CONNECTION, LOCAL_ConnectionInfoMissingInfo) { const Json info = TestConnectionStructures_BF::getConnectionInfoMissingInfo(); EXPECT_FALSE(ConnectionInfoPrivate::extractData(info)); } TEST_F(UNIT_CONNECTION, LOCAL_OwnConnectionInfoJson) { const ConnectionId connectionId(FieldValues::CONNECTION_ID); const StringUrl url = FieldValues::CONTACT_URL; const String stringDateTime = FieldValues::DATE_POSTED; const DateTime dateTime = DateTimeHelper::parseDateISO8601(stringDateTime); JsonWriter writer; { JsonWriter child; child[FieldNames::CONNECTION_ID] = connectionId; child[FieldNames::CONTACT_URL] = url; writer[FieldNames::CONTENT] = child.getJson(); } writer[FieldNames::CONNECTION_TYPE] = FieldValues::CONNECTION_TYPE; writer[FieldNames::DATE_POSTED] = stringDateTime; ConnectionInfoOwn connectionInfo; EXPECT_TRUE(OwnConnectionInfoPrivate::extractData(writer.getJson(), connectionInfo)); EXPECT_EQ(connectionId, connectionInfo.m_connectionId); EXPECT_EQ(url, connectionInfo.m_contactUrl); EXPECT_EQ(dateTime, connectionInfo.m_createdTime); } TEST_F(UNIT_CONNECTION_NOINIT, LOCAL_OwnConnectionInfoJson) { SAVE_ALLOC_COUNT(count1); initializeSdk(); { const ConnectionId connectionId(FieldValues::CONNECTION_ID); const StringUrl url = FieldValues::CONTACT_URL; const String dateTime = FieldValues::DATE_POSTED; JsonWriter writer; { JsonWriter child; child[FieldNames::CONNECTION_ID] = connectionId; child[FieldNames::CONTACT_URL] = url; writer[FieldNames::CONTENT] = child.getJson(); } writer[FieldNames::CONNECTION_TYPE] = FieldValues::CONNECTION_TYPE; writer[FieldNames::DATE_POSTED] = dateTime; EXPECT_ALLOC_COUNT_PC_X1_EQ(46u, 46u, count1); { US_PERF_TASK_FORMAT("Instanciating ConnectionInfoOwn", NULL); ConnectionInfoOwn connectionInfo; EXPECT_ALLOC_COUNT_PC_X1_EQ(35u, 38u, count1); { US_PERF_TASK_FORMAT("Populating ConnectionInfo from JSON", NULL); EXPECT_TRUE(OwnConnectionInfoPrivate::extractData(writer.getJson(), connectionInfo)); } EXPECT_ALLOC_COUNT_PC_X1_EQ(53u, 65u, count1); EXPECT_EQ(connectionId, connectionInfo.m_connectionId); EXPECT_EQ(url, connectionInfo.m_contactUrl); EXPECT_EQ(DateTimeHelper::parseDateISO8601(dateTime), connectionInfo.m_createdTime); } EXPECT_ALLOC_COUNT_PC_X1_EQ(7u, 7u, count1); } EXPECT_EQ(UninitializeResult::Complete, uninitializeSdk()); } TEST_F(UNIT_CONNECTION, LOCAL_OwnConnectionInfoJsonExtraParam) { JsonWriter writer; { JsonWriter child; child[FieldNames::CONNECTION_ID] = FieldValues::CONNECTION_ID; child[FieldNames::CONTACT_URL] = FieldValues::CONTACT_URL; writer[FieldNames::CONTENT] = child.getJson(); } writer[FieldNames::CONNECTION_TYPE] = FieldValues::CONNECTION_TYPE; writer[FieldNames::DATE_POSTED] = FieldValues::DATE_POSTED; writer["ExtraParam"] = "ExtraValue"; EXPECT_TRUE(OwnConnectionInfoPrivate::extractData(writer.getJson())); } TEST_F(UNIT_CONNECTION, LOCAL_OwnConnectionInfoJsonMissingParam) { { JsonWriter writer; writer[FieldNames::CONTACT_URL] = FieldValues::CONTACT_URL; writer[FieldNames::CONNECTION_TYPE] = FieldValues::CONNECTION_TYPE; writer[FieldNames::DATE_POSTED] = FieldValues::DATE_POSTED; EXPECT_FALSE(OwnConnectionInfoPrivate::extractData(writer.getJson())); } { JsonWriter writer; writer[FieldNames::CONNECTION_ID] = FieldValues::CONNECTION_ID; writer[FieldNames::CONNECTION_TYPE] = FieldValues::CONNECTION_TYPE; writer[FieldNames::DATE_POSTED] = FieldValues::DATE_POSTED; EXPECT_FALSE(OwnConnectionInfoPrivate::extractData(writer.getJson())); } { JsonWriter writer; writer[FieldNames::CONNECTION_ID] = FieldValues::CONNECTION_ID; writer[FieldNames::CONTACT_URL] = FieldValues::CONTACT_URL; writer[FieldNames::CONNECTION_TYPE] = FieldValues::CONNECTION_TYPE; EXPECT_FALSE(OwnConnectionInfoPrivate::extractData(writer.getJson())); } } #if !defined(US_TARGET_XONE) && !defined(US_TARGET_UWP) && !defined(US_TARGET_MANJARO) ///@test Verifies that the client manages the REST response from the service. /// It also validates that we don't retry the connection on a service unavailable error. TEST_F(UNIT_CONNECTION_MOCK_NOLOGIN, USNOT_ServicesUnavailable) { PrepareLoggingMock([](US_TEST_NS::MockLogDevice& device) { US_EXPECT_LOG("Not Found", LogLevel::Error, Times(3)); }); MockWebSocketEngine* engine = US_NEW(MockWebSocketEngine); InstancesManager::getInstance()->replaceWebSocketEngine(engine); MockWebSocketStreamImpl* mockStream = US_NEW(MockWebSocketStreamImpl, StringUrl(), InstancesManager::getInstance()->getSSLPinningKeys(), HttpObfuscatorHelper::getObfuscator()); { //m_url = {Text="https://api-ubiservices.ubi.com/v2/profiles/sessions"} US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_POST, "/profiles/sessions", getMockedLoginResponseNoUbiAccount()); US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "/parameters") .Times(2) .WillOnce(testing::Return(getMockedParametersApplication())) .WillOnce(testing::Return(getMockedParametersSpace())); { US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "/mock-config-events") .Times(testing::AnyNumber()) .WillOnce(testing::Return(getMockedLoginResponseEventConfig())); } { US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, String::formatText("/%s/mock-spaces-primarystoremapping", "12121212-3434-5656-7878-909090909090")) .Times(testing::AnyNumber()) .WillOnce(testing::Return(getMockedSecondaryPrimaryStoreMapping())); } { US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_POST, "/mock-profiles-inventory-primarystore") .Times(testing::AnyNumber()) .WillRepeatedly(testing::Return(getMockedNotifyPrimaryStoreUpdate())); } { const String jsonBody = "{" "\"populations\": [" "]" "}"; MockAsyncResult resultPopulations("MockPopulations"); resultPopulations.setResult(HttpResponse(RestStatusCode::OK, HttpHeader(), jsonBody)); resultPopulations.setToComplete(US_NS::ErrorDetails(Errors::SUCCESS, "MockPopulationsSuccess")); US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "profiles/me/mock-populations") .Times(testing::AnyNumber()) .WillRepeatedly(testing::Return(resultPopulations)); US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_PUT, "profiles/me/mock-populations/data") .Times(testing::AnyNumber()) .WillRepeatedly(testing::Return(resultPopulations)); } MockSocket* socket = reinterpret_cast(mockStream->getSocket()); using namespace testing; EXPECT_CALL(*engine, createStream(_,_,_)).WillOnce(Return(mockStream)); EXPECT_CALL(*engine, openConnectionImpl(_, _, _, _, _, _, _)) .WillOnce(Invoke(engine, &MockWebSocketEngine::invokeOpenConnectionImpl)); EXPECT_CALL(*socket, Connect(_, _)); EXPECT_CALL(*socket, SetSendBufSize(_)).Times(1); EXPECT_CALL(*socket, Select(_, _, _)).Times(1); EXPECT_CALL(*socket, GetPendingDataCount()).Times(1); EXPECT_CALL(*mockStream, writeStream(_)).WillOnce(Return(Errors::SUCCESS)); EXPECT_CALL(*mockStream, readStream(_)).WillOnce(Invoke(mockStream, &MockWebSocketStreamImpl::DelegateReadStream)); EXPECT_CALL(*socket, Receive(_, _)).WillOnce(Invoke(TestConnectionStructures_BF::createMockUbiServicesErrorResponse)); EXPECT_CALL(*socket, Close()); } { ASSERT_TRUE(AsyncHelper::waitSuccess(getFacade().createSession(getPlayerCredentials(), {}, {}))); ASSERT_FALSE(TestHelpers_BF::waitForPropertyValue(getFacade().getNotificationClient(), &NotificationClient::isConnectionActive, true, "NotificationClient::isConnectionActive", 1000)); } } #endif //!defined(US_TARGET_XONE) && !defined(US_TARGET_UWP) && !defined(US_TARGET_MANJARO) #endif //!defined(US_DLL) };