Callback reentrancy tests
Some tests to make sure new requests inside user callback
is okay.
Bug: dawn:1091
Change-Id: I4c53d7fb6637f77e5af6fd0a78d879a2431d4ac8
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/63041
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Shrek Shao <shrekshao@google.com>
diff --git a/src/tests/unittests/wire/WireBufferMappingTests.cpp b/src/tests/unittests/wire/WireBufferMappingTests.cpp
index 22d8109..582cff8 100644
--- a/src/tests/unittests/wire/WireBufferMappingTests.cpp
+++ b/src/tests/unittests/wire/WireBufferMappingTests.cpp
@@ -751,3 +751,67 @@
EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_DeviceLost, this)).Times(1);
wgpuBufferMapAsync(buffer, WGPUMapMode_Read, 0, kBufferSize, ToMockBufferMapCallback, this);
}
+
+// Hack to pass in test context into user callback
+struct TestData {
+ WireBufferMappingTests* pTest;
+ WGPUBuffer* pTestBuffer;
+ size_t numRequests;
+};
+
+static void ToMockBufferMapCallbackWithNewRequests(WGPUBufferMapAsyncStatus status,
+ void* userdata) {
+ TestData* testData = reinterpret_cast<TestData*>(userdata);
+ // Mimic the user callback is sending new requests
+ ASSERT_NE(testData, nullptr);
+ ASSERT_NE(testData->pTest, nullptr);
+ ASSERT_NE(testData->pTestBuffer, nullptr);
+
+ mockBufferMapCallback->Call(status, testData->pTest);
+
+ // Send the requests a number of times
+ for (size_t i = 0; i < testData->numRequests; i++) {
+ wgpuBufferMapAsync(*(testData->pTestBuffer), WGPUMapMode_Write, 0, sizeof(uint32_t),
+ ToMockBufferMapCallback, testData->pTest);
+ }
+}
+
+// Test that requests inside user callbacks before disconnect are called
+TEST_F(WireBufferMappingTests, MapInsideCallbackBeforeDisconnect) {
+ SetupBuffer(WGPUMapMode_Write);
+ TestData testData = {this, &buffer, 10};
+ wgpuBufferMapAsync(buffer, WGPUMapMode_Write, 0, kBufferSize,
+ ToMockBufferMapCallbackWithNewRequests, &testData);
+
+ EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Write, 0, kBufferSize, _, _))
+ .WillOnce(InvokeWithoutArgs([&]() {
+ api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
+ }));
+ EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize)).Times(1);
+
+ FlushClient();
+
+ EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_DeviceLost, this))
+ .Times(1 + testData.numRequests);
+ GetWireClient()->Disconnect();
+}
+
+// Test that requests inside user callbacks before object destruction are called
+TEST_F(WireBufferMappingWriteTests, MapInsideCallbackBeforeDestruction) {
+ TestData testData = {this, &buffer, 10};
+ wgpuBufferMapAsync(buffer, WGPUMapMode_Write, 0, kBufferSize,
+ ToMockBufferMapCallbackWithNewRequests, &testData);
+
+ EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Write, 0, kBufferSize, _, _))
+ .WillOnce(InvokeWithoutArgs([&]() {
+ api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
+ }));
+ EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize)).Times(1);
+
+ FlushClient();
+
+ EXPECT_CALL(*mockBufferMapCallback,
+ Call(WGPUBufferMapAsyncStatus_DestroyedBeforeCallback, this))
+ .Times(1 + testData.numRequests);
+ wgpuBufferRelease(buffer);
+}
\ No newline at end of file
diff --git a/src/tests/unittests/wire/WireQueueTests.cpp b/src/tests/unittests/wire/WireQueueTests.cpp
index 0dd340c..6045e4f 100644
--- a/src/tests/unittests/wire/WireQueueTests.cpp
+++ b/src/tests/unittests/wire/WireQueueTests.cpp
@@ -37,8 +37,8 @@
}
void TearDown() override {
- mockQueueWorkDoneCallback = nullptr;
WireTest::TearDown();
+ mockQueueWorkDoneCallback = nullptr;
}
void FlushServer() {
@@ -97,3 +97,44 @@
.Times(1);
wgpuQueueOnSubmittedWorkDone(queue, 0u, ToMockQueueWorkDone, this);
}
+
+// Hack to pass in test context into user callback
+struct TestData {
+ WireQueueTests* pTest;
+ WGPUQueue* pTestQueue;
+ size_t numRequests;
+};
+
+static void ToMockQueueWorkDoneWithNewRequests(WGPUQueueWorkDoneStatus status, void* userdata) {
+ TestData* testData = reinterpret_cast<TestData*>(userdata);
+ // Mimic the user callback is sending new requests
+ ASSERT_NE(testData, nullptr);
+ ASSERT_NE(testData->pTest, nullptr);
+ ASSERT_NE(testData->pTestQueue, nullptr);
+ mockQueueWorkDoneCallback->Call(status, testData->pTest);
+
+ // Send the requests a number of times
+ for (size_t i = 0; i < testData->numRequests; i++) {
+ wgpuQueueOnSubmittedWorkDone(*(testData->pTestQueue), 0u, ToMockQueueWorkDone,
+ testData->pTest);
+ }
+}
+
+// Test that requests inside user callbacks before disconnect are called
+TEST_F(WireQueueTests, OnSubmittedWorkDoneInsideCallbackBeforeDisconnect) {
+ TestData testData = {this, &queue, 10};
+ wgpuQueueOnSubmittedWorkDone(queue, 0u, ToMockQueueWorkDoneWithNewRequests, &testData);
+ EXPECT_CALL(api, OnQueueOnSubmittedWorkDone(apiQueue, 0u, _, _))
+ .WillOnce(InvokeWithoutArgs([&]() {
+ api.CallQueueOnSubmittedWorkDoneCallback(apiQueue, WGPUQueueWorkDoneStatus_Error);
+ }));
+ FlushClient();
+
+ EXPECT_CALL(*mockQueueWorkDoneCallback, Call(WGPUQueueWorkDoneStatus_DeviceLost, this))
+ .Times(1 + testData.numRequests);
+ GetWireClient()->Disconnect();
+}
+
+// Only one default queue is supported now so we cannot test ~Queue triggering ClearAllCallbacks
+// since it is always destructed after the test TearDown, and we cannot create a new queue obj
+// with wgpuDeviceGetQueue
diff --git a/src/tests/unittests/wire/WireShaderModuleTests.cpp b/src/tests/unittests/wire/WireShaderModuleTests.cpp
index 4b2db4d..a999dff 100644
--- a/src/tests/unittests/wire/WireShaderModuleTests.cpp
+++ b/src/tests/unittests/wire/WireShaderModuleTests.cpp
@@ -149,3 +149,78 @@
Call(WGPUCompilationInfoRequestStatus_DeviceLost, nullptr, _));
wgpuShaderModuleGetCompilationInfo(shaderModule, ToMockGetCompilationInfoCallback, nullptr);
}
+
+// Hack to pass in test context into user callback
+struct TestData {
+ WireShaderModuleTests* pTest;
+ WGPUShaderModule* pTestShaderModule;
+ size_t numRequests;
+};
+
+static void ToMockBufferMapCallbackWithNewRequests(WGPUCompilationInfoRequestStatus status,
+ const WGPUCompilationInfo* info,
+ void* userdata) {
+ TestData* testData = reinterpret_cast<TestData*>(userdata);
+ // Mimic the user callback is sending new requests
+ ASSERT_NE(testData, nullptr);
+ ASSERT_NE(testData->pTest, nullptr);
+ ASSERT_NE(testData->pTestShaderModule, nullptr);
+
+ mockCompilationInfoCallback->Call(status, info, testData->pTest);
+
+ // Send the requests a number of times
+ for (size_t i = 0; i < testData->numRequests; i++) {
+ wgpuShaderModuleGetCompilationInfo(*(testData->pTestShaderModule),
+ ToMockGetCompilationInfoCallback, nullptr);
+ }
+}
+
+// Test that requests inside user callbacks before disconnect are called
+TEST_F(WireShaderModuleTests, GetCompilationInfoInsideCallbackBeforeDisconnect) {
+ TestData testData = {this, &shaderModule, 10};
+
+ wgpuShaderModuleGetCompilationInfo(shaderModule, ToMockBufferMapCallbackWithNewRequests,
+ &testData);
+
+ WGPUCompilationMessage message = {"Test Message", WGPUCompilationMessageType_Info, 2, 4, 6, 8};
+ WGPUCompilationInfo compilationInfo;
+ compilationInfo.messageCount = 1;
+ compilationInfo.messages = &message;
+
+ EXPECT_CALL(api, OnShaderModuleGetCompilationInfo(apiShaderModule, _, _))
+ .WillOnce(InvokeWithoutArgs([&]() {
+ api.CallShaderModuleGetCompilationInfoCallback(
+ apiShaderModule, WGPUCompilationInfoRequestStatus_Success, &compilationInfo);
+ }));
+ FlushClient();
+
+ EXPECT_CALL(*mockCompilationInfoCallback,
+ Call(WGPUCompilationInfoRequestStatus_DeviceLost, nullptr, _))
+ .Times(1 + testData.numRequests);
+ GetWireClient()->Disconnect();
+}
+
+// Test that requests inside user callbacks before object destruction are called
+TEST_F(WireShaderModuleTests, GetCompilationInfoInsideCallbackBeforeDestruction) {
+ TestData testData = {this, &shaderModule, 10};
+
+ wgpuShaderModuleGetCompilationInfo(shaderModule, ToMockBufferMapCallbackWithNewRequests,
+ &testData);
+
+ WGPUCompilationMessage message = {"Test Message", WGPUCompilationMessageType_Info, 2, 4, 6, 8};
+ WGPUCompilationInfo compilationInfo;
+ compilationInfo.messageCount = 1;
+ compilationInfo.messages = &message;
+
+ EXPECT_CALL(api, OnShaderModuleGetCompilationInfo(apiShaderModule, _, _))
+ .WillOnce(InvokeWithoutArgs([&]() {
+ api.CallShaderModuleGetCompilationInfoCallback(
+ apiShaderModule, WGPUCompilationInfoRequestStatus_Success, &compilationInfo);
+ }));
+ FlushClient();
+
+ EXPECT_CALL(*mockCompilationInfoCallback,
+ Call(WGPUCompilationInfoRequestStatus_Unknown, nullptr, _))
+ .Times(1 + testData.numRequests);
+ wgpuShaderModuleRelease(shaderModule);
+}
\ No newline at end of file