From 72724b8d25b3c4be6bba5a67efc379d0397b0718 Mon Sep 17 00:00:00 2001 From: Austin Eng Date: Fri, 19 Jul 2019 16:16:58 +0000 Subject: [PATCH] Add wire tests and mocks for the MemoryTransferService This CL tests integration of the MemoryTransferService with buffer mapping. It tests the basic success and error cases for buffer mapping, and it tests mocked failures of each fallible MemoryTransferService method that an embedder could implement. Change-Id: Iece660fb49664cc6a09a0b0b8dbe59e2882a6017 Bug: dawn:156 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/8841 Commit-Queue: Austin Eng Reviewed-by: Kai Ninomiya Reviewed-by: Corentin Wallez --- BUILD.gn | 7 + .../ClientMemoryTransferService_mock.cpp | 86 ++ .../client/ClientMemoryTransferService_mock.h | 87 ++ .../ServerMemoryTransferService_mock.cpp | 82 ++ .../server/ServerMemoryTransferService_mock.h | 93 ++ .../wire/WireMemoryTransferServiceTests.cpp | 1122 +++++++++++++++++ src/tests/unittests/wire/WireTest.cpp | 19 +- src/tests/unittests/wire/WireTest.h | 14 +- 8 files changed, 1504 insertions(+), 6 deletions(-) create mode 100644 src/dawn_wire/client/ClientMemoryTransferService_mock.cpp create mode 100644 src/dawn_wire/client/ClientMemoryTransferService_mock.h create mode 100644 src/dawn_wire/server/ServerMemoryTransferService_mock.cpp create mode 100644 src/dawn_wire/server/ServerMemoryTransferService_mock.h create mode 100644 src/tests/unittests/wire/WireMemoryTransferServiceTests.cpp diff --git a/BUILD.gn b/BUILD.gn index 2f986c7157..ead3c39b52 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -577,6 +577,12 @@ test("dawn_unittests") { configs += [ ":libdawn_native_internal" ] sources = get_target_outputs(":mock_dawn_gen") + sources += [ + "src/dawn_wire/client/ClientMemoryTransferService_mock.cpp", + "src/dawn_wire/client/ClientMemoryTransferService_mock.h", + "src/dawn_wire/server/ServerMemoryTransferService_mock.cpp", + "src/dawn_wire/server/ServerMemoryTransferService_mock.h", + ] sources += [ "src/tests/unittests/BitSetIteratorTests.cpp", "src/tests/unittests/CommandAllocatorTests.cpp", @@ -620,6 +626,7 @@ test("dawn_unittests") { "src/tests/unittests/wire/WireErrorCallbackTests.cpp", "src/tests/unittests/wire/WireFenceTests.cpp", "src/tests/unittests/wire/WireInjectTextureTests.cpp", + "src/tests/unittests/wire/WireMemoryTransferServiceTests.cpp", "src/tests/unittests/wire/WireOptionalTests.cpp", "src/tests/unittests/wire/WireTest.cpp", "src/tests/unittests/wire/WireTest.h", diff --git a/src/dawn_wire/client/ClientMemoryTransferService_mock.cpp b/src/dawn_wire/client/ClientMemoryTransferService_mock.cpp new file mode 100644 index 0000000000..6762265fa7 --- /dev/null +++ b/src/dawn_wire/client/ClientMemoryTransferService_mock.cpp @@ -0,0 +1,86 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "dawn_wire/client/ClientMemoryTransferService_mock.h" + +#include +#include "common/Assert.h" + +namespace dawn_wire { namespace client { + + MockMemoryTransferService::MockReadHandle::MockReadHandle(MockMemoryTransferService* service) + : ReadHandle(), mService(service) { + } + + MockMemoryTransferService::MockReadHandle::~MockReadHandle() { + mService->OnReadHandleDestroy(this); + } + + size_t MockMemoryTransferService::MockReadHandle::SerializeCreate(void* serializePointer) { + return mService->OnReadHandleSerializeCreate(this, serializePointer); + } + + bool MockMemoryTransferService::MockReadHandle::DeserializeInitialData( + const void* deserializePointer, + size_t deserializeSize, + const void** data, + size_t* dataLength) { + ASSERT(deserializeSize % sizeof(uint32_t) == 0); + return mService->OnReadHandleDeserializeInitialData( + this, reinterpret_cast(deserializePointer), deserializeSize, data, + dataLength); + } + + MockMemoryTransferService::MockWriteHandle::MockWriteHandle(MockMemoryTransferService* service) + : WriteHandle(), mService(service) { + } + + MockMemoryTransferService::MockWriteHandle::~MockWriteHandle() { + mService->OnWriteHandleDestroy(this); + } + + size_t MockMemoryTransferService::MockWriteHandle::SerializeCreate(void* serializePointer) { + return mService->OnWriteHandleSerializeCreate(this, serializePointer); + } + + std::pair MockMemoryTransferService::MockWriteHandle::Open() { + return mService->OnWriteHandleOpen(this); + } + + size_t MockMemoryTransferService::MockWriteHandle::SerializeFlush(void* serializePointer) { + return mService->OnWriteHandleSerializeFlush(this, serializePointer); + } + + MockMemoryTransferService::MockMemoryTransferService() = default; + MockMemoryTransferService::~MockMemoryTransferService() = default; + + MockMemoryTransferService::ReadHandle* MockMemoryTransferService::CreateReadHandle( + size_t size) { + return OnCreateReadHandle(size); + } + + MockMemoryTransferService::WriteHandle* MockMemoryTransferService::CreateWriteHandle( + size_t size) { + return OnCreateWriteHandle(size); + } + + MockMemoryTransferService::MockReadHandle* MockMemoryTransferService::NewReadHandle() { + return new MockReadHandle(this); + } + + MockMemoryTransferService::MockWriteHandle* MockMemoryTransferService::NewWriteHandle() { + return new MockWriteHandle(this); + } + +}} // namespace dawn_wire::client diff --git a/src/dawn_wire/client/ClientMemoryTransferService_mock.h b/src/dawn_wire/client/ClientMemoryTransferService_mock.h new file mode 100644 index 0000000000..c54ce2360e --- /dev/null +++ b/src/dawn_wire/client/ClientMemoryTransferService_mock.h @@ -0,0 +1,87 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef DAWNWIRE_CLIENT_CLIENTMEMORYTRANSFERSERVICE_MOCK_H_ +#define DAWNWIRE_CLIENT_CLIENTMEMORYTRANSFERSERVICE_MOCK_H_ + +#include + +#include "dawn_wire/WireClient.h" +#include "dawn_wire/client/Client.h" + +namespace dawn_wire { namespace client { + + class MockMemoryTransferService : public MemoryTransferService { + public: + class MockReadHandle : public ReadHandle { + public: + explicit MockReadHandle(MockMemoryTransferService* service); + ~MockReadHandle() override; + + size_t SerializeCreate(void* serializePointer) override; + bool DeserializeInitialData(const void* deserializePointer, + size_t deserializeSize, + const void** data, + size_t* dataLength) override; + + private: + MockMemoryTransferService* mService; + }; + + class MockWriteHandle : public WriteHandle { + public: + explicit MockWriteHandle(MockMemoryTransferService* service); + ~MockWriteHandle() override; + + size_t SerializeCreate(void* serializePointer) override; + std::pair Open() override; + size_t SerializeFlush(void* serializePointer) override; + + private: + MockMemoryTransferService* mService; + }; + + MockMemoryTransferService(); + ~MockMemoryTransferService() override; + + ReadHandle* CreateReadHandle(size_t) override; + WriteHandle* CreateWriteHandle(size_t) override; + + MockReadHandle* NewReadHandle(); + MockWriteHandle* NewWriteHandle(); + + MOCK_METHOD1(OnCreateReadHandle, ReadHandle*(size_t)); + MOCK_METHOD1(OnCreateWriteHandle, WriteHandle*(size_t)); + + MOCK_METHOD2(OnReadHandleSerializeCreate, + size_t(const ReadHandle*, void* serializePointer)); + MOCK_METHOD5(OnReadHandleDeserializeInitialData, + bool(const ReadHandle*, + const uint32_t* deserializePointer, + size_t deserializeSize, + const void** data, + size_t* dataLength)); + MOCK_METHOD1(OnReadHandleDestroy, void(const ReadHandle*)); + + MOCK_METHOD2(OnWriteHandleSerializeCreate, + size_t(const void* WriteHandle, void* serializePointer)); + MOCK_METHOD1(OnWriteHandleOpen, std::pair(const void* WriteHandle)); + MOCK_METHOD2(OnWriteHandleSerializeFlush, + size_t(const void* WriteHandle, void* serializePointer)); + MOCK_METHOD1(OnWriteHandleDestroy, void(const void* WriteHandle)); + }; + +}} // namespace dawn_wire::client + +#endif // DAWNWIRE_CLIENT_CLIENTMEMORYTRANSFERSERVICE_MOCK_H_ diff --git a/src/dawn_wire/server/ServerMemoryTransferService_mock.cpp b/src/dawn_wire/server/ServerMemoryTransferService_mock.cpp new file mode 100644 index 0000000000..316a991a4e --- /dev/null +++ b/src/dawn_wire/server/ServerMemoryTransferService_mock.cpp @@ -0,0 +1,82 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "dawn_wire/server/ServerMemoryTransferService_mock.h" + +#include "common/Assert.h" + +namespace dawn_wire { namespace server { + + MockMemoryTransferService::MockReadHandle::MockReadHandle(MockMemoryTransferService* service) + : ReadHandle(), mService(service) { + } + + MockMemoryTransferService::MockReadHandle::~MockReadHandle() { + mService->OnReadHandleDestroy(this); + } + + size_t MockMemoryTransferService::MockReadHandle::SerializeInitialData(const void* data, + size_t dataLength, + void* serializePointer) { + return mService->OnReadHandleSerializeInitialData(this, data, dataLength, serializePointer); + } + + MockMemoryTransferService::MockWriteHandle::MockWriteHandle(MockMemoryTransferService* service) + : WriteHandle(), mService(service) { + } + + MockMemoryTransferService::MockWriteHandle::~MockWriteHandle() { + mService->OnWriteHandleDestroy(this); + } + + bool MockMemoryTransferService::MockWriteHandle::DeserializeFlush( + const void* deserializePointer, + size_t deserializeSize) { + ASSERT(deserializeSize % sizeof(uint32_t) == 0); + return mService->OnWriteHandleDeserializeFlush( + this, reinterpret_cast(deserializePointer), deserializeSize); + } + + const uint32_t* MockMemoryTransferService::MockWriteHandle::GetData() const { + return reinterpret_cast(mTargetData); + } + + MockMemoryTransferService::MockMemoryTransferService() = default; + MockMemoryTransferService::~MockMemoryTransferService() = default; + + bool MockMemoryTransferService::DeserializeReadHandle(const void* deserializePointer, + size_t deserializeSize, + ReadHandle** readHandle) { + ASSERT(deserializeSize % sizeof(uint32_t) == 0); + return OnDeserializeReadHandle(reinterpret_cast(deserializePointer), + deserializeSize, readHandle); + } + + bool MockMemoryTransferService::DeserializeWriteHandle(const void* deserializePointer, + size_t deserializeSize, + WriteHandle** writeHandle) { + ASSERT(deserializeSize % sizeof(uint32_t) == 0); + return OnDeserializeWriteHandle(reinterpret_cast(deserializePointer), + deserializeSize, writeHandle); + } + + MockMemoryTransferService::MockReadHandle* MockMemoryTransferService::NewReadHandle() { + return new MockReadHandle(this); + } + + MockMemoryTransferService::MockWriteHandle* MockMemoryTransferService::NewWriteHandle() { + return new MockWriteHandle(this); + } + +}} // namespace dawn_wire::server diff --git a/src/dawn_wire/server/ServerMemoryTransferService_mock.h b/src/dawn_wire/server/ServerMemoryTransferService_mock.h new file mode 100644 index 0000000000..5065264e1e --- /dev/null +++ b/src/dawn_wire/server/ServerMemoryTransferService_mock.h @@ -0,0 +1,93 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef DAWNWIRE_SERVER_SERVERMEMORYTRANSFERSERVICE_MOCK_H_ +#define DAWNWIRE_SERVER_SERVERMEMORYTRANSFERSERVICE_MOCK_H_ + +#include + +#include "dawn_wire/WireServer.h" +#include "dawn_wire/server/Server.h" + +namespace dawn_wire { namespace server { + + class MockMemoryTransferService : public MemoryTransferService { + public: + class MockReadHandle : public ReadHandle { + public: + MockReadHandle(MockMemoryTransferService* service); + ~MockReadHandle() override; + + size_t SerializeInitialData(const void* data, + size_t dataLength, + void* serializePointer) override; + + private: + MockMemoryTransferService* mService; + }; + + class MockWriteHandle : public WriteHandle { + public: + MockWriteHandle(MockMemoryTransferService* service); + ~MockWriteHandle() override; + + bool DeserializeFlush(const void* deserializePointer, size_t deserializeSize) override; + + const uint32_t* GetData() const; + + private: + MockMemoryTransferService* mService; + }; + + MockMemoryTransferService(); + ~MockMemoryTransferService() override; + + bool DeserializeReadHandle(const void* deserializePointer, + size_t deserializeSize, + ReadHandle** readHandle) override; + + bool DeserializeWriteHandle(const void* deserializePointer, + size_t deserializeSize, + WriteHandle** writeHandle) override; + + MockReadHandle* NewReadHandle(); + MockWriteHandle* NewWriteHandle(); + + MOCK_METHOD3(OnDeserializeReadHandle, + bool(const uint32_t* deserializePointer, + size_t deserializeSize, + ReadHandle** readHandle)); + + MOCK_METHOD3(OnDeserializeWriteHandle, + bool(const uint32_t* deserializePointer, + size_t deserializeSize, + WriteHandle** writeHandle)); + + MOCK_METHOD4(OnReadHandleSerializeInitialData, + size_t(const ReadHandle* readHandle, + const void* data, + size_t dataLength, + void* serializePointer)); + MOCK_METHOD1(OnReadHandleDestroy, void(const ReadHandle* readHandle)); + + MOCK_METHOD3(OnWriteHandleDeserializeFlush, + bool(const WriteHandle* writeHandle, + const uint32_t* deserializePointer, + size_t deserializeSize)); + MOCK_METHOD1(OnWriteHandleDestroy, void(const WriteHandle* writeHandle)); + }; + +}} // namespace dawn_wire::server + +#endif // DAWNWIRE_SERVER_SERVERMEMORYTRANSFERSERVICE_MOCK_H_ diff --git a/src/tests/unittests/wire/WireMemoryTransferServiceTests.cpp b/src/tests/unittests/wire/WireMemoryTransferServiceTests.cpp new file mode 100644 index 0000000000..cdd8419f05 --- /dev/null +++ b/src/tests/unittests/wire/WireMemoryTransferServiceTests.cpp @@ -0,0 +1,1122 @@ +// Copyright 2019 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tests/unittests/wire/WireTest.h" + +#include "dawn_wire/client/ClientMemoryTransferService_mock.h" +#include "dawn_wire/server/ServerMemoryTransferService_mock.h" + +using namespace testing; +using namespace dawn_wire; + +namespace { + + // Mock classes to add expectations on the wire calling callbacks + class MockBufferMapReadCallback { + public: + MOCK_METHOD4(Call, + void(DawnBufferMapAsyncStatus status, + const uint32_t* ptr, + uint64_t dataLength, + void* userdata)); + }; + + std::unique_ptr> mockBufferMapReadCallback; + void ToMockBufferMapReadCallback(DawnBufferMapAsyncStatus status, + const void* ptr, + uint64_t dataLength, + void* userdata) { + // Assume the data is uint32_t to make writing matchers easier + mockBufferMapReadCallback->Call(status, static_cast(ptr), dataLength, + userdata); + } + + class MockBufferMapWriteCallback { + public: + MOCK_METHOD4(Call, + void(DawnBufferMapAsyncStatus status, + uint32_t* ptr, + uint64_t dataLength, + void* userdata)); + }; + + std::unique_ptr> mockBufferMapWriteCallback; + void ToMockBufferMapWriteCallback(DawnBufferMapAsyncStatus status, + void* ptr, + uint64_t dataLength, + void* userdata) { + // Assume the data is uint32_t to make writing matchers easier + mockBufferMapWriteCallback->Call(status, static_cast(ptr), dataLength, userdata); + } + + class MockBufferCreateMappedCallback { + public: + MOCK_METHOD5(Call, + void(DawnBufferMapAsyncStatus status, + DawnBuffer buffer, + uint32_t* ptr, + uint64_t dataLength, + void* userdata)); + }; + + std::unique_ptr> mockCreateBufferMappedCallback; + void ToMockCreateBufferMappedCallback(DawnBufferMapAsyncStatus status, + DawnCreateBufferMappedResult result, + void* userdata) { + // Assume the data is uint32_t to make writing matchers easier + mockCreateBufferMappedCallback->Call(status, result.buffer, + static_cast(result.data), result.dataLength, + userdata); + } + +} // anonymous namespace + +// WireMemoryTransferServiceTests test the MemoryTransferService with buffer mapping. +// They test the basic success and error cases for buffer mapping, and they test +// mocked failures of each fallible MemoryTransferService method that an embedder +// could implement. +// The test harness defines multiple helpers for expecting operations on Read/Write handles +// and for mocking failures. The helpers are designed such that for a given run of a test, +// a Serialization expection has a corresponding Deserialization expectation for which the +// serialized data must match. +// There are tests which check for Success for every mapping operation which mock an entire mapping +// operation from map to unmap, and add all MemoryTransferService expectations. +// Tests which check for errors perform the same mapping operations but insert mocked failures for +// various mapping or MemoryTransferService operations. +class WireMemoryTransferServiceTests : public WireTest { + public: + WireMemoryTransferServiceTests() { + } + ~WireMemoryTransferServiceTests() override = default; + + client::MemoryTransferService* GetClientMemoryTransferService() override { + return &clientMemoryTransferService; + } + + server::MemoryTransferService* GetServerMemoryTransferService() override { + return &serverMemoryTransferService; + } + + void SetUp() override { + WireTest::SetUp(); + + mockBufferMapReadCallback = std::make_unique>(); + mockBufferMapWriteCallback = std::make_unique>(); + mockCreateBufferMappedCallback = + std::make_unique>(); + + // TODO(enga): Make this thread-safe. + mBufferContent++; + mMappedBufferContent = 0; + mUpdatedBufferContent++; + mSerializeCreateInfo++; + mSerializeInitialDataInfo++; + mSerializeFlushInfo++; + } + + void TearDown() override { + WireTest::TearDown(); + + // Delete mocks so that expectations are checked + mockBufferMapReadCallback = nullptr; + mockBufferMapWriteCallback = nullptr; + mockCreateBufferMappedCallback = nullptr; + } + + void FlushClient(bool success = true) { + WireTest::FlushClient(success); + Mock::VerifyAndClearExpectations(&serverMemoryTransferService); + } + + void FlushServer(bool success = true) { + WireTest::FlushServer(success); + + Mock::VerifyAndClearExpectations(&mockBufferMapReadCallback); + Mock::VerifyAndClearExpectations(&mockBufferMapWriteCallback); + Mock::VerifyAndClearExpectations(&mockCreateBufferMappedCallback); + Mock::VerifyAndClearExpectations(&clientMemoryTransferService); + } + + protected: + using ClientReadHandle = client::MockMemoryTransferService::MockReadHandle; + using ServerReadHandle = server::MockMemoryTransferService::MockReadHandle; + using ClientWriteHandle = client::MockMemoryTransferService::MockWriteHandle; + using ServerWriteHandle = server::MockMemoryTransferService::MockWriteHandle; + + std::pair CreateBuffer() { + DawnBufferDescriptor descriptor; + descriptor.nextInChain = nullptr; + descriptor.size = sizeof(mBufferContent); + + DawnBuffer apiBuffer = api.GetNewBuffer(); + DawnBuffer buffer = dawnDeviceCreateBuffer(device, &descriptor); + + EXPECT_CALL(api, DeviceCreateBuffer(apiDevice, _)) + .WillOnce(Return(apiBuffer)) + .RetiresOnSaturation(); + + return std::make_pair(apiBuffer, buffer); + } + + std::pair CreateBufferMapped() { + DawnBufferDescriptor descriptor; + descriptor.nextInChain = nullptr; + descriptor.size = sizeof(mBufferContent); + + DawnBuffer apiBuffer = api.GetNewBuffer(); + + DawnCreateBufferMappedResult apiResult; + apiResult.buffer = apiBuffer; + apiResult.data = reinterpret_cast(&mMappedBufferContent); + apiResult.dataLength = sizeof(mMappedBufferContent); + + DawnCreateBufferMappedResult result = dawnDeviceCreateBufferMapped(device, &descriptor); + + EXPECT_CALL(api, DeviceCreateBufferMapped(apiDevice, _)) + .WillOnce(Return(apiResult)) + .RetiresOnSaturation(); + + return std::make_pair(apiResult, result); + } + + DawnCreateBufferMappedResult CreateBufferMappedAsync() { + DawnBufferDescriptor descriptor; + descriptor.nextInChain = nullptr; + descriptor.size = sizeof(mBufferContent); + + dawnDeviceCreateBufferMappedAsync(device, &descriptor, ToMockCreateBufferMappedCallback, + nullptr); + + DawnBuffer apiBuffer = api.GetNewBuffer(); + + DawnCreateBufferMappedResult apiResult; + apiResult.buffer = apiBuffer; + apiResult.data = reinterpret_cast(&mMappedBufferContent); + apiResult.dataLength = sizeof(mMappedBufferContent); + + EXPECT_CALL(api, DeviceCreateBufferMapped(apiDevice, _)) + .WillOnce(Return(apiResult)) + .RetiresOnSaturation(); + + return apiResult; + } + + ClientReadHandle* ExpectReadHandleCreation() { + // Create the handle first so we can use it in later expectations. + ClientReadHandle* handle = clientMemoryTransferService.NewReadHandle(); + + EXPECT_CALL(clientMemoryTransferService, OnCreateReadHandle(sizeof(mBufferContent))) + .WillOnce(InvokeWithoutArgs([=]() { + return handle; + })); + + return handle; + } + + void MockReadHandleCreationFailure() { + EXPECT_CALL(clientMemoryTransferService, OnCreateReadHandle(sizeof(mBufferContent))) + .WillOnce(InvokeWithoutArgs([=]() { return nullptr; })); + } + + void ExpectReadHandleSerialization(ClientReadHandle* handle) { + EXPECT_CALL(clientMemoryTransferService, OnReadHandleSerializeCreate(handle, _)) + .WillOnce(InvokeWithoutArgs([&]() { return sizeof(mSerializeCreateInfo); })) + .WillOnce(WithArg<1>([&](void* serializePointer) { + memcpy(serializePointer, &mSerializeCreateInfo, sizeof(mSerializeCreateInfo)); + return sizeof(mSerializeCreateInfo); + })); + } + + ServerReadHandle* ExpectServerReadHandleDeserialize() { + // Create the handle first so we can use it in later expectations. + ServerReadHandle* handle = serverMemoryTransferService.NewReadHandle(); + + EXPECT_CALL(serverMemoryTransferService, + OnDeserializeReadHandle(Pointee(Eq(mSerializeCreateInfo)), + sizeof(mSerializeCreateInfo), _)) + .WillOnce(WithArg<2>([=](server::MemoryTransferService::ReadHandle** readHandle) { + *readHandle = handle; + return true; + })); + + return handle; + } + + void MockServerReadHandleDeserializeFailure() { + EXPECT_CALL(serverMemoryTransferService, + OnDeserializeReadHandle(Pointee(Eq(mSerializeCreateInfo)), + sizeof(mSerializeCreateInfo), _)) + .WillOnce(InvokeWithoutArgs([&]() { return false; })); + } + + void ExpectServerReadHandleInitialize(ServerReadHandle* handle) { + EXPECT_CALL(serverMemoryTransferService, OnReadHandleSerializeInitialData(handle, _, _, _)) + .WillOnce(InvokeWithoutArgs([&]() { return sizeof(mSerializeInitialDataInfo); })) + .WillOnce(WithArg<3>([&](void* serializePointer) { + memcpy(serializePointer, &mSerializeInitialDataInfo, + sizeof(mSerializeInitialDataInfo)); + return sizeof(mSerializeInitialDataInfo); + })); + } + + void ExpectClientReadHandleDeserializeInitialize(ClientReadHandle* handle, + uint32_t* mappedData) { + EXPECT_CALL(clientMemoryTransferService, OnReadHandleDeserializeInitialData( + handle, Pointee(Eq(mSerializeInitialDataInfo)), + sizeof(mSerializeInitialDataInfo), _, _)) + .WillOnce(WithArgs<3, 4>([=](const void** data, size_t* dataLength) { + *data = mappedData; + *dataLength = sizeof(*mappedData); + return true; + })); + } + + void MockClientReadHandleDeserializeInitializeFailure(ClientReadHandle* handle) { + EXPECT_CALL(clientMemoryTransferService, OnReadHandleDeserializeInitialData( + handle, Pointee(Eq(mSerializeInitialDataInfo)), + sizeof(mSerializeInitialDataInfo), _, _)) + .WillOnce(InvokeWithoutArgs([&]() { return false; })); + } + + ClientWriteHandle* ExpectWriteHandleCreation() { + // Create the handle first so we can use it in later expectations. + ClientWriteHandle* handle = clientMemoryTransferService.NewWriteHandle(); + + EXPECT_CALL(clientMemoryTransferService, OnCreateWriteHandle(sizeof(mBufferContent))) + .WillOnce(InvokeWithoutArgs([=]() { + return handle; + })); + + return handle; + } + + void MockWriteHandleCreationFailure() { + EXPECT_CALL(clientMemoryTransferService, OnCreateWriteHandle(sizeof(mBufferContent))) + .WillOnce(InvokeWithoutArgs([=]() { return nullptr; })); + } + + void ExpectWriteHandleSerialization(ClientWriteHandle* handle) { + EXPECT_CALL(clientMemoryTransferService, OnWriteHandleSerializeCreate(handle, _)) + .WillOnce(InvokeWithoutArgs([&]() { return sizeof(mSerializeCreateInfo); })) + .WillOnce(WithArg<1>([&](void* serializePointer) { + memcpy(serializePointer, &mSerializeCreateInfo, sizeof(mSerializeCreateInfo)); + return sizeof(mSerializeCreateInfo); + })); + } + + ServerWriteHandle* ExpectServerWriteHandleDeserialization() { + // Create the handle first so it can be used in later expectations. + ServerWriteHandle* handle = serverMemoryTransferService.NewWriteHandle(); + + EXPECT_CALL(serverMemoryTransferService, + OnDeserializeWriteHandle(Pointee(Eq(mSerializeCreateInfo)), + sizeof(mSerializeCreateInfo), _)) + .WillOnce(WithArg<2>([=](server::MemoryTransferService::WriteHandle** writeHandle) { + *writeHandle = handle; + return true; + })); + + return handle; + } + + void MockServerWriteHandleDeserializeFailure() { + EXPECT_CALL(serverMemoryTransferService, + OnDeserializeWriteHandle(Pointee(Eq(mSerializeCreateInfo)), + sizeof(mSerializeCreateInfo), _)) + .WillOnce(InvokeWithoutArgs([&]() { + return false; + })); + } + + void ExpectClientWriteHandleOpen(ClientWriteHandle* handle, uint32_t* mappedData) { + EXPECT_CALL(clientMemoryTransferService, OnWriteHandleOpen(handle)) + .WillOnce(InvokeWithoutArgs([=]() { + return std::make_pair(mappedData, sizeof(*mappedData)); + })); + } + + void MockClientWriteHandleOpenFailure(ClientWriteHandle* handle) { + EXPECT_CALL(clientMemoryTransferService, OnWriteHandleOpen(handle)) + .WillOnce(InvokeWithoutArgs( + [&]() { return std::make_pair(nullptr, 0); })); + } + + void ExpectClientWriteHandleSerializeFlush(ClientWriteHandle* handle) { + EXPECT_CALL(clientMemoryTransferService, OnWriteHandleSerializeFlush(handle, _)) + .WillOnce(InvokeWithoutArgs([&]() { return sizeof(mSerializeFlushInfo); })) + .WillOnce(WithArg<1>([&](void* serializePointer) { + memcpy(serializePointer, &mSerializeFlushInfo, sizeof(mSerializeFlushInfo)); + return sizeof(mSerializeFlushInfo); + })); + } + + void ExpectServerWriteHandleDeserializeFlush(ServerWriteHandle* handle, uint32_t expectedData) { + EXPECT_CALL(serverMemoryTransferService, + OnWriteHandleDeserializeFlush(handle, Pointee(Eq(mSerializeFlushInfo)), + sizeof(mSerializeFlushInfo))) + .WillOnce(InvokeWithoutArgs([=]() { + // The handle data should be updated. + EXPECT_EQ(*handle->GetData(), expectedData); + return true; + })); + } + + void MockServerWriteHandleDeserializeFlushFailure(ServerWriteHandle* handle) { + EXPECT_CALL(serverMemoryTransferService, + OnWriteHandleDeserializeFlush(handle, Pointee(Eq(mSerializeFlushInfo)), + sizeof(mSerializeFlushInfo))) + .WillOnce(InvokeWithoutArgs([&]() { return false; })); + } + + // Arbitrary values used within tests to check if serialized data is correctly passed + // between the client and server. The static data changes between runs of the tests and + // test expectations will check that serialized values are passed to the respective deserialization + // function. + static uint32_t mSerializeCreateInfo; + static uint32_t mSerializeInitialDataInfo; + static uint32_t mSerializeFlushInfo; + + // Represents the buffer contents for the test. + static uint32_t mBufferContent; + + // The client's zero-initialized buffer for writing. + uint32_t mMappedBufferContent = 0; + + // |mMappedBufferContent| should be set equal to |mUpdatedBufferContent| when the client performs a write. + // Test expectations should check that |mBufferContent == mUpdatedBufferContent| after all writes are flushed. + static uint32_t mUpdatedBufferContent; + + testing::StrictMock serverMemoryTransferService; + testing::StrictMock clientMemoryTransferService; +}; + +uint32_t WireMemoryTransferServiceTests::mBufferContent = 1337; +uint32_t WireMemoryTransferServiceTests::mUpdatedBufferContent = 2349; +uint32_t WireMemoryTransferServiceTests::mSerializeCreateInfo = 4242; +uint32_t WireMemoryTransferServiceTests::mSerializeInitialDataInfo = 1394; +uint32_t WireMemoryTransferServiceTests::mSerializeFlushInfo = 1235; + +// Test successful MapRead. +TEST_F(WireMemoryTransferServiceTests, BufferMapReadSuccess) { + DawnBuffer buffer; + DawnBuffer apiBuffer; + std::tie(apiBuffer, buffer) = CreateBuffer(); + FlushClient(); + + // The client should create and serialize a ReadHandle on mapReadAsync. + ClientReadHandle* clientHandle = ExpectReadHandleCreation(); + ExpectReadHandleSerialization(clientHandle); + + dawnBufferMapReadAsync(buffer, ToMockBufferMapReadCallback, nullptr); + + // The server should deserialize the MapRead handle from the client and then serialize + // an initialization message. + ServerReadHandle* serverHandle = ExpectServerReadHandleDeserialize(); + ExpectServerReadHandleInitialize(serverHandle); + + // Mock a successful callback + EXPECT_CALL(api, OnBufferMapReadAsyncCallback(apiBuffer, _, _)) + .WillOnce(InvokeWithoutArgs([&]() { + api.CallMapReadCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, &mBufferContent, + sizeof(mBufferContent)); + })); + + FlushClient(); + + // The client receives a successful callback. + EXPECT_CALL(*mockBufferMapReadCallback, + Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, &mBufferContent, + sizeof(mBufferContent), _)) + .Times(1); + + // The client should receive the handle initialization message from the server. + ExpectClientReadHandleDeserializeInitialize(clientHandle, &mBufferContent); + + FlushServer(); + + // The handle is destroyed once the buffer is unmapped. + EXPECT_CALL(clientMemoryTransferService, OnReadHandleDestroy(clientHandle)).Times(1); + dawnBufferUnmap(buffer); + + EXPECT_CALL(serverMemoryTransferService, OnReadHandleDestroy(serverHandle)).Times(1); + EXPECT_CALL(api, BufferUnmap(apiBuffer)).Times(1); + + FlushClient(); +} + +// Test unsuccessful MapRead. +TEST_F(WireMemoryTransferServiceTests, BufferMapReadError) { + DawnBuffer buffer; + DawnBuffer apiBuffer; + std::tie(apiBuffer, buffer) = CreateBuffer(); + FlushClient(); + + // The client should create and serialize a ReadHandle on mapReadAsync. + ClientReadHandle* clientHandle = ExpectReadHandleCreation(); + ExpectReadHandleSerialization(clientHandle); + + dawnBufferMapReadAsync(buffer, ToMockBufferMapReadCallback, nullptr); + + // The server should deserialize the ReadHandle from the client. + ServerReadHandle* serverHandle = ExpectServerReadHandleDeserialize(); + + // Mock a failed callback. + EXPECT_CALL(api, OnBufferMapReadAsyncCallback(apiBuffer, _, _)) + .WillOnce(InvokeWithoutArgs([&]() { + api.CallMapReadCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_ERROR, nullptr, 0); + })); + + // Since the mapping failed, the handle is immediately destroyed. + EXPECT_CALL(serverMemoryTransferService, OnReadHandleDestroy(serverHandle)).Times(1); + + FlushClient(); + + // The client receives an error callback. + EXPECT_CALL(*mockBufferMapReadCallback, Call(DAWN_BUFFER_MAP_ASYNC_STATUS_ERROR, nullptr, 0, _)) + .Times(1); + + // The client receives the map failure and destroys the handle. + EXPECT_CALL(clientMemoryTransferService, OnReadHandleDestroy(clientHandle)).Times(1); + + FlushServer(); + + dawnBufferUnmap(buffer); + + EXPECT_CALL(api, BufferUnmap(apiBuffer)).Times(1); + + FlushClient(); +} + +// Test MapRead ReadHandle creation failure. +TEST_F(WireMemoryTransferServiceTests, BufferMapReadHandleCreationFailure) { + DawnBuffer buffer; + DawnBuffer apiBuffer; + std::tie(apiBuffer, buffer) = CreateBuffer(); + FlushClient(); + + // Mock a ReadHandle creation failure + MockReadHandleCreationFailure(); + + // Failed creation of a ReadHandle is a fatal failure and the client synchronously receives a + // CONTEXT_LOST callback. + EXPECT_CALL(*mockBufferMapReadCallback, + Call(DAWN_BUFFER_MAP_ASYNC_STATUS_CONTEXT_LOST, nullptr, 0, _)) + .Times(1); + + dawnBufferMapReadAsync(buffer, ToMockBufferMapReadCallback, nullptr); +} + +// Test MapRead DeserializeReadHandle failure. +TEST_F(WireMemoryTransferServiceTests, BufferMapReadDeserializeReadHandleFailure) { + DawnBuffer buffer; + DawnBuffer apiBuffer; + std::tie(apiBuffer, buffer) = CreateBuffer(); + FlushClient(); + + // The client should create and serialize a ReadHandle on mapReadAsync. + ClientReadHandle* clientHandle = ExpectReadHandleCreation(); + ExpectReadHandleSerialization(clientHandle); + + dawnBufferMapReadAsync(buffer, ToMockBufferMapReadCallback, nullptr); + + // Mock a Deserialization failure. + MockServerReadHandleDeserializeFailure(); + + FlushClient(false); + + // The server received a fatal failure and the client callback was never returned. + // It is called when the wire is destructed. + EXPECT_CALL(*mockBufferMapReadCallback, + Call(DAWN_BUFFER_MAP_ASYNC_STATUS_UNKNOWN, nullptr, 0, _)) + .Times(1); + + EXPECT_CALL(clientMemoryTransferService, OnReadHandleDestroy(clientHandle)).Times(1); +} + +// Test MapRead DeserializeInitialData failure. +TEST_F(WireMemoryTransferServiceTests, BufferMapReadDeserializeInitialDataFailure) { + DawnBuffer buffer; + DawnBuffer apiBuffer; + std::tie(apiBuffer, buffer) = CreateBuffer(); + FlushClient(); + + // The client should create and serialize a ReadHandle on mapReadAsync. + ClientReadHandle* clientHandle = ExpectReadHandleCreation(); + ExpectReadHandleSerialization(clientHandle); + + dawnBufferMapReadAsync(buffer, ToMockBufferMapReadCallback, nullptr); + + // The server should deserialize the MapRead handle from the client and then serialize + // an initialization message. + ServerReadHandle* serverHandle = ExpectServerReadHandleDeserialize(); + ExpectServerReadHandleInitialize(serverHandle); + + // Mock a successful callback + EXPECT_CALL(api, OnBufferMapReadAsyncCallback(apiBuffer, _, _)) + .WillOnce(InvokeWithoutArgs([&]() { + api.CallMapReadCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, &mBufferContent, + sizeof(mBufferContent)); + })); + + FlushClient(); + + // The client should receive the handle initialization message from the server. + // Mock a deserialization failure. + MockClientReadHandleDeserializeInitializeFailure(clientHandle); + + // Failed deserialization is a fatal failure and the client synchronously receives a + // CONTEXT_LOST callback. + EXPECT_CALL(*mockBufferMapReadCallback, + Call(DAWN_BUFFER_MAP_ASYNC_STATUS_CONTEXT_LOST, nullptr, 0, _)) + .Times(1); + + // The handle will be destroyed since deserializing failed. + EXPECT_CALL(clientMemoryTransferService, OnReadHandleDestroy(clientHandle)).Times(1); + + FlushServer(false); + + EXPECT_CALL(serverMemoryTransferService, OnReadHandleDestroy(serverHandle)).Times(1); +} + +// Test successful MapWrite. +TEST_F(WireMemoryTransferServiceTests, BufferMapWriteSuccess) { + DawnBuffer buffer; + DawnBuffer apiBuffer; + std::tie(apiBuffer, buffer) = CreateBuffer(); + FlushClient(); + + ClientWriteHandle* clientHandle = ExpectWriteHandleCreation(); + ExpectWriteHandleSerialization(clientHandle); + + dawnBufferMapWriteAsync(buffer, ToMockBufferMapWriteCallback, nullptr); + + // The server should then deserialize the WriteHandle from the client. + ServerWriteHandle* serverHandle = ExpectServerWriteHandleDeserialization(); + + // Mock a successful callback. + EXPECT_CALL(api, OnBufferMapWriteAsyncCallback(apiBuffer, _, _)) + .WillOnce(InvokeWithoutArgs([&]() { + api.CallMapWriteCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, + &mMappedBufferContent, sizeof(mMappedBufferContent)); + })); + + FlushClient(); + + // The client receives a successful callback. + EXPECT_CALL(*mockBufferMapWriteCallback, + Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, &mMappedBufferContent, + sizeof(mMappedBufferContent), _)) + .Times(1); + + // Since the mapping succeeds, the client opens the WriteHandle. + ExpectClientWriteHandleOpen(clientHandle, &mMappedBufferContent); + + FlushServer(); + + // The client writes to the handle contents. + mMappedBufferContent = mUpdatedBufferContent; + + // The client will then flush and destroy the handle on Unmap() + ExpectClientWriteHandleSerializeFlush(clientHandle); + EXPECT_CALL(clientMemoryTransferService, OnWriteHandleDestroy(clientHandle)).Times(1); + + dawnBufferUnmap(buffer); + + // The server deserializes the Flush message. + ExpectServerWriteHandleDeserializeFlush(serverHandle, mUpdatedBufferContent); + + // After the handle is updated it can be destroyed. + EXPECT_CALL(serverMemoryTransferService, OnWriteHandleDestroy(serverHandle)).Times(1); + EXPECT_CALL(api, BufferUnmap(apiBuffer)).Times(1); + + FlushClient(); +} + +// Test unsuccessful MapWrite. +TEST_F(WireMemoryTransferServiceTests, BufferMapWriteError) { + DawnBuffer buffer; + DawnBuffer apiBuffer; + std::tie(apiBuffer, buffer) = CreateBuffer(); + FlushClient(); + + // The client should create and serialize a WriteHandle on mapWriteAsync. + ClientWriteHandle* clientHandle = ExpectWriteHandleCreation(); + ExpectWriteHandleSerialization(clientHandle); + + dawnBufferMapWriteAsync(buffer, ToMockBufferMapWriteCallback, nullptr); + + // The server should then deserialize the WriteHandle from the client. + ServerWriteHandle* serverHandle = ExpectServerWriteHandleDeserialization(); + + // Mock an error callback. + EXPECT_CALL(api, OnBufferMapWriteAsyncCallback(apiBuffer, _, _)) + .WillOnce(InvokeWithoutArgs([&]() { + api.CallMapWriteCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_ERROR, nullptr, 0); + })); + + // Since the mapping fails, the handle is immediately destroyed because it won't be written. + EXPECT_CALL(serverMemoryTransferService, OnWriteHandleDestroy(serverHandle)).Times(1); + + FlushClient(); + + // The client receives an error callback. + EXPECT_CALL(*mockBufferMapWriteCallback, + Call(DAWN_BUFFER_MAP_ASYNC_STATUS_ERROR, nullptr, 0, _)) + .Times(1); + + // Client receives the map failure and destroys the handle. + EXPECT_CALL(clientMemoryTransferService, OnWriteHandleDestroy(clientHandle)).Times(1); + + FlushServer(); + + dawnBufferUnmap(buffer); + + EXPECT_CALL(api, BufferUnmap(apiBuffer)).Times(1); + + FlushClient(); +} + +// Test MapRead WriteHandle creation failure. +TEST_F(WireMemoryTransferServiceTests, BufferMapWriteHandleCreationFailure) { + DawnBuffer buffer; + DawnBuffer apiBuffer; + std::tie(apiBuffer, buffer) = CreateBuffer(); + FlushClient(); + + // Mock a WriteHandle creation failure + MockWriteHandleCreationFailure(); + + // Failed creation of a WriteHandle is a fatal failure and the client synchronously receives a + // CONTEXT_LOST callback. + EXPECT_CALL(*mockBufferMapWriteCallback, + Call(DAWN_BUFFER_MAP_ASYNC_STATUS_CONTEXT_LOST, nullptr, 0, _)) + .Times(1); + + dawnBufferMapWriteAsync(buffer, ToMockBufferMapWriteCallback, nullptr); +} + +// Test MapWrite DeserializeWriteHandle failure. +TEST_F(WireMemoryTransferServiceTests, BufferMapWriteDeserializeWriteHandleFailure) { + DawnBuffer buffer; + DawnBuffer apiBuffer; + std::tie(apiBuffer, buffer) = CreateBuffer(); + FlushClient(); + + // The client should create and serialize a WriteHandle on mapWriteAsync. + ClientWriteHandle* clientHandle = ExpectWriteHandleCreation(); + ExpectWriteHandleSerialization(clientHandle); + + dawnBufferMapWriteAsync(buffer, ToMockBufferMapWriteCallback, nullptr); + + // Mock a deserialization failure. + MockServerWriteHandleDeserializeFailure(); + + FlushClient(false); + + // The server hit a fatal failure and never returned the callback. The client callback is + // called when the wire is destructed. + EXPECT_CALL(*mockBufferMapWriteCallback, + Call(DAWN_BUFFER_MAP_ASYNC_STATUS_UNKNOWN, nullptr, 0, _)) + .Times(1); + + EXPECT_CALL(clientMemoryTransferService, OnWriteHandleDestroy(clientHandle)).Times(1); +} + +// Test MapWrite handle Open failure. +TEST_F(WireMemoryTransferServiceTests, BufferMapWriteHandleOpenFailure) { + DawnBuffer buffer; + DawnBuffer apiBuffer; + std::tie(apiBuffer, buffer) = CreateBuffer(); + FlushClient(); + + ClientWriteHandle* clientHandle = ExpectWriteHandleCreation(); + ExpectWriteHandleSerialization(clientHandle); + + dawnBufferMapWriteAsync(buffer, ToMockBufferMapWriteCallback, nullptr); + + // The server should then deserialize the WriteHandle from the client. + ServerWriteHandle* serverHandle = ExpectServerWriteHandleDeserialization(); + + // Mock a successful callback. + EXPECT_CALL(api, OnBufferMapWriteAsyncCallback(apiBuffer, _, _)) + .WillOnce(InvokeWithoutArgs([&]() { + api.CallMapWriteCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, + &mMappedBufferContent, sizeof(mMappedBufferContent)); + })); + + FlushClient(); + + // Since the mapping succeeds, the client opens the WriteHandle. + // Mock a failure. + MockClientWriteHandleOpenFailure(clientHandle); + + // Failing to open a handle is a fatal failure and the client receives a CONTEXT_LOST callback. + EXPECT_CALL(*mockBufferMapWriteCallback, + Call(DAWN_BUFFER_MAP_ASYNC_STATUS_CONTEXT_LOST, nullptr, 0, _)) + .Times(1); + + // Since opening the handle fails, it gets destroyed immediately. + EXPECT_CALL(clientMemoryTransferService, OnWriteHandleDestroy(clientHandle)).Times(1); + + FlushServer(false); + + EXPECT_CALL(serverMemoryTransferService, OnWriteHandleDestroy(serverHandle)).Times(1); +} + +// Test MapWrite DeserializeFlush failure. +TEST_F(WireMemoryTransferServiceTests, BufferMapWriteDeserializeFlushFailure) { + DawnBuffer buffer; + DawnBuffer apiBuffer; + std::tie(apiBuffer, buffer) = CreateBuffer(); + FlushClient(); + + ClientWriteHandle* clientHandle = ExpectWriteHandleCreation(); + ExpectWriteHandleSerialization(clientHandle); + + dawnBufferMapWriteAsync(buffer, ToMockBufferMapWriteCallback, nullptr); + + // The server should then deserialize the WriteHandle from the client. + ServerWriteHandle* serverHandle = ExpectServerWriteHandleDeserialization(); + + // Mock a successful callback. + EXPECT_CALL(api, OnBufferMapWriteAsyncCallback(apiBuffer, _, _)) + .WillOnce(InvokeWithoutArgs([&]() { + api.CallMapWriteCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, + &mMappedBufferContent, sizeof(mMappedBufferContent)); + })); + + FlushClient(); + + // The client receives a success callback. + EXPECT_CALL(*mockBufferMapWriteCallback, + Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, &mMappedBufferContent, + sizeof(mMappedBufferContent), _)) + .Times(1); + + // Since the mapping succeeds, the client opens the WriteHandle. + ExpectClientWriteHandleOpen(clientHandle, &mMappedBufferContent); + + FlushServer(); + + // The client writes to the handle contents. + mMappedBufferContent = mUpdatedBufferContent; + + // The client will then flush and destroy the handle on Unmap() + ExpectClientWriteHandleSerializeFlush(clientHandle); + EXPECT_CALL(clientMemoryTransferService, OnWriteHandleDestroy(clientHandle)).Times(1); + + dawnBufferUnmap(buffer); + + // The server deserializes the Flush message. Mock a deserialization failure. + MockServerWriteHandleDeserializeFlushFailure(serverHandle); + + FlushClient(false); + + EXPECT_CALL(serverMemoryTransferService, OnWriteHandleDestroy(serverHandle)).Times(1); +} + +// Test successful CreateBufferMappedAsync. +TEST_F(WireMemoryTransferServiceTests, CreateBufferMappedAsyncSuccess) { + // The client should create and serialize a WriteHandle on createBufferMappedAsync + ClientWriteHandle* clientHandle = ExpectWriteHandleCreation(); + ExpectWriteHandleSerialization(clientHandle); + + DawnCreateBufferMappedResult apiResult = CreateBufferMappedAsync(); + + // The server should then deserialize the WriteHandle from the client. + ServerWriteHandle* serverHandle = ExpectServerWriteHandleDeserialization(); + + FlushClient(); + + // The client receives a success callback. Save the buffer argument so we can call Unmap. + DawnBuffer buffer; + EXPECT_CALL(*mockCreateBufferMappedCallback, + Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, _, &mMappedBufferContent, + sizeof(mMappedBufferContent), _)) + + .WillOnce(SaveArg<1>(&buffer)); + + // Since the mapping succeeds, the client opens the WriteHandle. + ExpectClientWriteHandleOpen(clientHandle, &mMappedBufferContent); + + FlushServer(); + + // The client writes to the handle contents. + mMappedBufferContent = mUpdatedBufferContent; + + // The client will then flush and destroy the handle on Unmap() + ExpectClientWriteHandleSerializeFlush(clientHandle); + EXPECT_CALL(clientMemoryTransferService, OnWriteHandleDestroy(clientHandle)).Times(1); + + dawnBufferUnmap(buffer); + + // The server deserializes the Flush message. + ExpectServerWriteHandleDeserializeFlush(serverHandle, mUpdatedBufferContent); + + // After the handle is updated it can be destroyed. + EXPECT_CALL(serverMemoryTransferService, OnWriteHandleDestroy(serverHandle)).Times(1); + EXPECT_CALL(api, BufferUnmap(apiResult.buffer)).Times(1); + + FlushClient(); +} + +// Test CreateBufferMappedAsync WriteHandle creation failure. +TEST_F(WireMemoryTransferServiceTests, CreateBufferMappedAsyncWriteHandleCreationFailure) { + // Mock a WriteHandle creation failure + MockWriteHandleCreationFailure(); + + DawnBufferDescriptor descriptor; + descriptor.nextInChain = nullptr; + descriptor.size = sizeof(mBufferContent); + + // Failed creation of a WriteHandle is a fatal failure. The client synchronously receives + // a CONTEXT_LOST callback. + EXPECT_CALL(*mockCreateBufferMappedCallback, + Call(DAWN_BUFFER_MAP_ASYNC_STATUS_CONTEXT_LOST, _, nullptr, 0, _)) + .Times(1); + + dawnDeviceCreateBufferMappedAsync(device, &descriptor, ToMockCreateBufferMappedCallback, nullptr); +} + +// Test CreateBufferMappedAsync DeserializeWriteHandle failure. +TEST_F(WireMemoryTransferServiceTests, CreateBufferMappedAsyncDeserializeWriteHandleFailure) { + // The client should create and serialize a WriteHandle on createBufferMappedAsync + ClientWriteHandle* clientHandle = ExpectWriteHandleCreation(); + ExpectWriteHandleSerialization(clientHandle); + + DawnCreateBufferMappedResult apiResult = CreateBufferMappedAsync(); + DAWN_UNUSED(apiResult); + + // The server should then deserialize the WriteHandle from the client. + // Mock a deserialization failure. + MockServerWriteHandleDeserializeFailure(); + + FlushClient(false); + + // The server hit a fatal failure and never returned the callback. It is called when the + // wire is destructed. + EXPECT_CALL(*mockCreateBufferMappedCallback, + Call(DAWN_BUFFER_MAP_ASYNC_STATUS_UNKNOWN, _, nullptr, 0, _)) + .Times(1); + + EXPECT_CALL(clientMemoryTransferService, OnWriteHandleDestroy(clientHandle)).Times(1); +} + +// Test CreateBufferMappedAsync handle Open failure. +TEST_F(WireMemoryTransferServiceTests, CreateBufferMappedAsyncHandleOpenFailure) { + // The client should create and serialize a WriteHandle on createBufferMappedAsync + ClientWriteHandle* clientHandle = ExpectWriteHandleCreation(); + ExpectWriteHandleSerialization(clientHandle); + + DawnCreateBufferMappedResult apiResult = CreateBufferMappedAsync(); + DAWN_UNUSED(apiResult); + + // The server should then deserialize the WriteHandle from the client. + ServerWriteHandle* serverHandle = ExpectServerWriteHandleDeserialization(); + + FlushClient(); + + // Since the mapping succeeds, the client opens the WriteHandle. + MockClientWriteHandleOpenFailure(clientHandle); + + // Failing to open a handle is a fatal failure. The client receives a CONTEXT_LOST callback. + EXPECT_CALL(*mockCreateBufferMappedCallback, + Call(DAWN_BUFFER_MAP_ASYNC_STATUS_CONTEXT_LOST, _, nullptr, 0, _)) + .Times(1); + + // Since opening the handle fails, it is destroyed immediately. + EXPECT_CALL(clientMemoryTransferService, OnWriteHandleDestroy(clientHandle)).Times(1); + + FlushServer(false); + + EXPECT_CALL(serverMemoryTransferService, OnWriteHandleDestroy(serverHandle)).Times(1); +} + +// Test CreateBufferMappedAsync DeserializeFlush failure. +TEST_F(WireMemoryTransferServiceTests, CreateBufferMappedAsyncDeserializeFlushFailure) { + // The client should create and serialize a WriteHandle on createBufferMappedAsync + ClientWriteHandle* clientHandle = ExpectWriteHandleCreation(); + ExpectWriteHandleSerialization(clientHandle); + + DawnCreateBufferMappedResult apiResult = CreateBufferMappedAsync(); + DAWN_UNUSED(apiResult); + + // The server should then deserialize the WriteHandle from the client. + ServerWriteHandle* serverHandle = ExpectServerWriteHandleDeserialization(); + + FlushClient(); + + // The client receives a success callback. Save the buffer argument so we can call Unmap. + DawnBuffer buffer; + EXPECT_CALL(*mockCreateBufferMappedCallback, + Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, _, &mMappedBufferContent, + sizeof(mMappedBufferContent), _)) + + .WillOnce(SaveArg<1>(&buffer)); + + // Since the mapping succeeds, the client opens the WriteHandle. + ExpectClientWriteHandleOpen(clientHandle, &mMappedBufferContent); + + FlushServer(); + + // The client writes to the handle contents. + mMappedBufferContent = mUpdatedBufferContent; + + // The client will then flush and destroy the handle on Unmap() + ExpectClientWriteHandleSerializeFlush(clientHandle); + EXPECT_CALL(clientMemoryTransferService, OnWriteHandleDestroy(clientHandle)).Times(1); + + dawnBufferUnmap(buffer); + + // The server deserializes the Flush message. + // Mock a deserialization failure. + MockServerWriteHandleDeserializeFlushFailure(serverHandle); + + FlushClient(false); + + EXPECT_CALL(serverMemoryTransferService, OnWriteHandleDestroy(serverHandle)).Times(1); +} + +// Test successful CreateBufferMapped. +TEST_F(WireMemoryTransferServiceTests, CreateBufferMappedSuccess) { + // The client should create and serialize a WriteHandle on createBufferMapped. + ClientWriteHandle* clientHandle = ExpectWriteHandleCreation(); + + // Staging data is immediately available so the handle is Opened. + ExpectClientWriteHandleOpen(clientHandle, &mMappedBufferContent); + + ExpectWriteHandleSerialization(clientHandle); + + // The server should then deserialize the WriteHandle from the client. + ServerWriteHandle* serverHandle = ExpectServerWriteHandleDeserialization(); + + DawnCreateBufferMappedResult result; + DawnCreateBufferMappedResult apiResult; + std::tie(apiResult, result) = CreateBufferMapped(); + FlushClient(); + + // Update the mapped contents. + mMappedBufferContent = mUpdatedBufferContent; + + // When the client Unmaps the buffer, it will flush writes to the handle and destroy it. + ExpectClientWriteHandleSerializeFlush(clientHandle); + EXPECT_CALL(clientMemoryTransferService, OnWriteHandleDestroy(clientHandle)).Times(1); + + dawnBufferUnmap(result.buffer); + + // The server deserializes the Flush message. + ExpectServerWriteHandleDeserializeFlush(serverHandle, mUpdatedBufferContent); + + // After the handle is updated it can be destroyed. + EXPECT_CALL(serverMemoryTransferService, OnWriteHandleDestroy(serverHandle)).Times(1); + EXPECT_CALL(api, BufferUnmap(apiResult.buffer)).Times(1); + + FlushClient(); +} + +// Test CreateBufferMapped WriteHandle creation failure. +TEST_F(WireMemoryTransferServiceTests, CreateBufferMappedWriteHandleCreationFailure) { + // Mock a WriteHandle creation failure + MockWriteHandleCreationFailure(); + + DawnBufferDescriptor descriptor; + descriptor.nextInChain = nullptr; + descriptor.size = sizeof(mBufferContent); + + DawnCreateBufferMappedResult result = dawnDeviceCreateBufferMapped(device, &descriptor); + + // TODO(enga): Check that the client generated a context lost. + EXPECT_EQ(result.data, nullptr); + EXPECT_EQ(result.dataLength, 0u); +} + +// Test CreateBufferMapped DeserializeWriteHandle failure. +TEST_F(WireMemoryTransferServiceTests, CreateBufferMappedDeserializeWriteHandleFailure) { + // The client should create and serialize a WriteHandle on createBufferMapped. + ClientWriteHandle* clientHandle = ExpectWriteHandleCreation(); + + // Staging data is immediately available so the handle is Opened. + ExpectClientWriteHandleOpen(clientHandle, &mMappedBufferContent); + + ExpectWriteHandleSerialization(clientHandle); + + // The server should then deserialize the WriteHandle from the client. + MockServerWriteHandleDeserializeFailure(); + + DawnCreateBufferMappedResult result; + DawnCreateBufferMappedResult apiResult; + std::tie(apiResult, result) = CreateBufferMapped(); + FlushClient(false); + + EXPECT_CALL(clientMemoryTransferService, OnWriteHandleDestroy(clientHandle)).Times(1); +} + +// Test CreateBufferMapped handle Open failure. +TEST_F(WireMemoryTransferServiceTests, CreateBufferMappedHandleOpenFailure) { + // The client should create a WriteHandle on createBufferMapped. + ClientWriteHandle* clientHandle = ExpectWriteHandleCreation(); + + // Staging data is immediately available so the handle is Opened. + // Mock a failure. + MockClientWriteHandleOpenFailure(clientHandle); + + // Since synchronous opening of the handle failed, it is destroyed immediately. + // Note: The handle is not serialized because sychronously opening it failed. + EXPECT_CALL(clientMemoryTransferService, OnWriteHandleDestroy(clientHandle)).Times(1); + + DawnBufferDescriptor descriptor; + descriptor.nextInChain = nullptr; + descriptor.size = sizeof(mBufferContent); + + DawnCreateBufferMappedResult result = dawnDeviceCreateBufferMapped(device, &descriptor); + + // TODO(enga): Check that the client generated a context lost. + EXPECT_EQ(result.data, nullptr); + EXPECT_EQ(result.dataLength, 0u); +} + +// Test CreateBufferMapped DeserializeFlush failure. +TEST_F(WireMemoryTransferServiceTests, CreateBufferMappedDeserializeFlushFailure) { + // The client should create and serialize a WriteHandle on createBufferMapped. + ClientWriteHandle* clientHandle = ExpectWriteHandleCreation(); + + // Staging data is immediately available so the handle is Opened. + ExpectClientWriteHandleOpen(clientHandle, &mMappedBufferContent); + + ExpectWriteHandleSerialization(clientHandle); + + // The server should then deserialize the WriteHandle from the client. + ServerWriteHandle* serverHandle = ExpectServerWriteHandleDeserialization(); + + DawnCreateBufferMappedResult result; + DawnCreateBufferMappedResult apiResult; + std::tie(apiResult, result) = CreateBufferMapped(); + FlushClient(); + + // Update the mapped contents. + mMappedBufferContent = mUpdatedBufferContent; + + // When the client Unmaps the buffer, it will flush writes to the handle and destroy it. + ExpectClientWriteHandleSerializeFlush(clientHandle); + EXPECT_CALL(clientMemoryTransferService, OnWriteHandleDestroy(clientHandle)).Times(1); + + dawnBufferUnmap(result.buffer); + + // The server deserializes the Flush message. Mock a deserialization failure. + MockServerWriteHandleDeserializeFlushFailure(serverHandle); + + FlushClient(false); + + EXPECT_CALL(serverMemoryTransferService, OnWriteHandleDestroy(serverHandle)).Times(1); +} diff --git a/src/tests/unittests/wire/WireTest.cpp b/src/tests/unittests/wire/WireTest.cpp index 6222472649..f48696fda7 100644 --- a/src/tests/unittests/wire/WireTest.cpp +++ b/src/tests/unittests/wire/WireTest.cpp @@ -27,6 +27,14 @@ WireTest::WireTest() { WireTest::~WireTest() { } +client::MemoryTransferService* WireTest::GetClientMemoryTransferService() { + return nullptr; +} + +server::MemoryTransferService* WireTest::GetServerMemoryTransferService() { + return nullptr; +} + void WireTest::SetUp() { DawnProcTable mockProcs; DawnDevice mockDevice; @@ -43,12 +51,14 @@ void WireTest::SetUp() { serverDesc.device = mockDevice; serverDesc.procs = &mockProcs; serverDesc.serializer = mS2cBuf.get(); + serverDesc.memoryTransferService = GetServerMemoryTransferService(); mWireServer.reset(new WireServer(serverDesc)); mC2sBuf->SetHandler(mWireServer.get()); WireClientDescriptor clientDesc = {}; clientDesc.serializer = mC2sBuf.get(); + clientDesc.memoryTransferService = GetClientMemoryTransferService(); mWireClient.reset(new WireClient(clientDesc)); mS2cBuf->SetHandler(mWireClient.get()); @@ -69,17 +79,18 @@ void WireTest::TearDown() { // cannot be null. api.IgnoreAllReleaseCalls(); mWireClient = nullptr; + mWireServer = nullptr; } -void WireTest::FlushClient() { - ASSERT_TRUE(mC2sBuf->Flush()); +void WireTest::FlushClient(bool success) { + ASSERT_EQ(mC2sBuf->Flush(), success); Mock::VerifyAndClearExpectations(&api); SetupIgnoredCallExpectations(); } -void WireTest::FlushServer() { - ASSERT_TRUE(mS2cBuf->Flush()); +void WireTest::FlushServer(bool success) { + ASSERT_EQ(mS2cBuf->Flush(), success); } dawn_wire::WireServer* WireTest::GetWireServer() { diff --git a/src/tests/unittests/wire/WireTest.h b/src/tests/unittests/wire/WireTest.h index 3173292acf..9b40384c56 100644 --- a/src/tests/unittests/wire/WireTest.h +++ b/src/tests/unittests/wire/WireTest.h @@ -69,6 +69,12 @@ inline testing::Matcher> MatchesLambda(Lambda lamb namespace dawn_wire { class WireClient; class WireServer; + namespace client { + class MemoryTransferService; + } // namespace client + namespace server { + class MemoryTransferService; + } // namespace server } // namespace dawn_wire namespace utils { @@ -82,8 +88,9 @@ class WireTest : public testing::Test { void SetUp() override; void TearDown() override; - void FlushClient(); - void FlushServer(); + + void FlushClient(bool success = true); + void FlushServer(bool success = true); testing::StrictMock api; DawnDevice apiDevice; @@ -97,6 +104,9 @@ class WireTest : public testing::Test { private: void SetupIgnoredCallExpectations(); + virtual dawn_wire::client::MemoryTransferService* GetClientMemoryTransferService(); + virtual dawn_wire::server::MemoryTransferService* GetServerMemoryTransferService(); + std::unique_ptr mWireServer; std::unique_ptr mWireClient; std::unique_ptr mS2cBuf;