blob: 0d136fda394b2ef4896f75222e29c034693ea238 [file] [log] [blame]
Corentin Wallez0ae00a12019-03-28 17:12:47 +00001// Copyright 2019 The Dawn Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "tests/unittests/wire/WireTest.h"
16
Austin Engb70a5b02020-11-11 21:01:18 +000017#include "dawn_wire/WireClient.h"
18
Corentin Wallez0ae00a12019-03-28 17:12:47 +000019using namespace testing;
20using namespace dawn_wire;
21
22namespace {
23
24 // Mock classes to add expectations on the wire calling callbacks
25 class MockDeviceErrorCallback {
26 public:
Corentin Wallezf9412052020-04-16 16:39:06 +000027 MOCK_METHOD(void, Call, (WGPUErrorType type, const char* message, void* userdata));
Corentin Wallez0ae00a12019-03-28 17:12:47 +000028 };
29
30 std::unique_ptr<StrictMock<MockDeviceErrorCallback>> mockDeviceErrorCallback;
Corentin Wallez45b51f52019-10-28 22:15:47 +000031 void ToMockDeviceErrorCallback(WGPUErrorType type, const char* message, void* userdata) {
Austin Engcb0cb652019-08-27 21:41:56 +000032 mockDeviceErrorCallback->Call(type, message, userdata);
Corentin Wallez0ae00a12019-03-28 17:12:47 +000033 }
34
Austin Eng45238d72019-09-04 22:54:03 +000035 class MockDevicePopErrorScopeCallback {
36 public:
Corentin Wallezf9412052020-04-16 16:39:06 +000037 MOCK_METHOD(void, Call, (WGPUErrorType type, const char* message, void* userdata));
Austin Eng45238d72019-09-04 22:54:03 +000038 };
39
40 std::unique_ptr<StrictMock<MockDevicePopErrorScopeCallback>> mockDevicePopErrorScopeCallback;
Corentin Wallez45b51f52019-10-28 22:15:47 +000041 void ToMockDevicePopErrorScopeCallback(WGPUErrorType type,
42 const char* message,
43 void* userdata) {
Austin Eng45238d72019-09-04 22:54:03 +000044 mockDevicePopErrorScopeCallback->Call(type, message, userdata);
45 }
46
Natasha Lee9bba4a92019-12-18 18:59:20 +000047 class MockDeviceLostCallback {
48 public:
Corentin Wallezf9412052020-04-16 16:39:06 +000049 MOCK_METHOD(void, Call, (const char* message, void* userdata));
Natasha Lee9bba4a92019-12-18 18:59:20 +000050 };
51
52 std::unique_ptr<StrictMock<MockDeviceLostCallback>> mockDeviceLostCallback;
53 void ToMockDeviceLostCallback(const char* message, void* userdata) {
54 mockDeviceLostCallback->Call(message, userdata);
55 }
56
Corentin Wallez0ae00a12019-03-28 17:12:47 +000057} // anonymous namespace
58
59class WireErrorCallbackTests : public WireTest {
60 public:
61 WireErrorCallbackTests() {
62 }
63 ~WireErrorCallbackTests() override = default;
64
65 void SetUp() override {
66 WireTest::SetUp();
67
68 mockDeviceErrorCallback = std::make_unique<StrictMock<MockDeviceErrorCallback>>();
Kai Ninomiya2afea0c2020-07-10 20:33:08 +000069 mockDevicePopErrorScopeCallback =
70 std::make_unique<StrictMock<MockDevicePopErrorScopeCallback>>();
Natasha Lee9bba4a92019-12-18 18:59:20 +000071 mockDeviceLostCallback = std::make_unique<StrictMock<MockDeviceLostCallback>>();
Corentin Wallez0ae00a12019-03-28 17:12:47 +000072 }
73
74 void TearDown() override {
75 WireTest::TearDown();
76
77 mockDeviceErrorCallback = nullptr;
Austin Eng45238d72019-09-04 22:54:03 +000078 mockDevicePopErrorScopeCallback = nullptr;
Natasha Lee9bba4a92019-12-18 18:59:20 +000079 mockDeviceLostCallback = nullptr;
Corentin Wallez0ae00a12019-03-28 17:12:47 +000080 }
81
82 void FlushServer() {
83 WireTest::FlushServer();
84
85 Mock::VerifyAndClearExpectations(&mockDeviceErrorCallback);
Austin Eng45238d72019-09-04 22:54:03 +000086 Mock::VerifyAndClearExpectations(&mockDevicePopErrorScopeCallback);
Corentin Wallez0ae00a12019-03-28 17:12:47 +000087 }
88};
89
90// Test the return wire for device error callbacks
91TEST_F(WireErrorCallbackTests, DeviceErrorCallback) {
Corentin Wallez45b51f52019-10-28 22:15:47 +000092 wgpuDeviceSetUncapturedErrorCallback(device, ToMockDeviceErrorCallback, this);
Corentin Wallez0ae00a12019-03-28 17:12:47 +000093
94 // Setting the error callback should stay on the client side and do nothing
95 FlushClient();
96
97 // Calling the callback on the server side will result in the callback being called on the
98 // client side
Austin Eng8d38c012020-12-17 17:59:37 +000099 api.CallDeviceSetUncapturedErrorCallbackCallback(apiDevice, WGPUErrorType_Validation,
100 "Some error message");
Corentin Wallez0ae00a12019-03-28 17:12:47 +0000101
Corentin Wallez45b51f52019-10-28 22:15:47 +0000102 EXPECT_CALL(*mockDeviceErrorCallback,
103 Call(WGPUErrorType_Validation, StrEq("Some error message"), this))
104 .Times(1);
Corentin Wallez0ae00a12019-03-28 17:12:47 +0000105
106 FlushServer();
107}
Austin Eng45238d72019-09-04 22:54:03 +0000108
109// Test the return wire for error scopes.
110TEST_F(WireErrorCallbackTests, PushPopErrorScopeCallback) {
Corentin Wallez45b51f52019-10-28 22:15:47 +0000111 wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
112 EXPECT_CALL(api, DevicePushErrorScope(apiDevice, WGPUErrorFilter_Validation)).Times(1);
Austin Eng45238d72019-09-04 22:54:03 +0000113
114 FlushClient();
115
Corentin Wallez45b51f52019-10-28 22:15:47 +0000116 wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this);
Austin Eng45238d72019-09-04 22:54:03 +0000117
Corentin Wallez45b51f52019-10-28 22:15:47 +0000118 WGPUErrorCallback callback;
Austin Eng45238d72019-09-04 22:54:03 +0000119 void* userdata;
Austin Eng8d38c012020-12-17 17:59:37 +0000120 EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _, _))
Austin Eng45238d72019-09-04 22:54:03 +0000121 .WillOnce(DoAll(SaveArg<1>(&callback), SaveArg<2>(&userdata), Return(true)));
122
123 FlushClient();
124
Corentin Wallez45b51f52019-10-28 22:15:47 +0000125 callback(WGPUErrorType_Validation, "Some error message", userdata);
126 EXPECT_CALL(*mockDevicePopErrorScopeCallback,
127 Call(WGPUErrorType_Validation, StrEq("Some error message"), this))
128 .Times(1);
Austin Eng45238d72019-09-04 22:54:03 +0000129
130 FlushServer();
131}
132
133// Test the return wire for error scopes when callbacks return in a various orders.
134TEST_F(WireErrorCallbackTests, PopErrorScopeCallbackOrdering) {
135 // Two error scopes are popped, and the first one returns first.
136 {
Corentin Wallez45b51f52019-10-28 22:15:47 +0000137 wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
138 wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
139 EXPECT_CALL(api, DevicePushErrorScope(apiDevice, WGPUErrorFilter_Validation)).Times(2);
Austin Eng45238d72019-09-04 22:54:03 +0000140
141 FlushClient();
142
Corentin Wallez45b51f52019-10-28 22:15:47 +0000143 wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this);
144 wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this + 1);
Austin Eng45238d72019-09-04 22:54:03 +0000145
Corentin Wallez45b51f52019-10-28 22:15:47 +0000146 WGPUErrorCallback callback1;
147 WGPUErrorCallback callback2;
Austin Eng45238d72019-09-04 22:54:03 +0000148 void* userdata1;
149 void* userdata2;
Austin Eng8d38c012020-12-17 17:59:37 +0000150 EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _, _))
Austin Eng45238d72019-09-04 22:54:03 +0000151 .WillOnce(DoAll(SaveArg<1>(&callback1), SaveArg<2>(&userdata1), Return(true)))
152 .WillOnce(DoAll(SaveArg<1>(&callback2), SaveArg<2>(&userdata2), Return(true)));
153
154 FlushClient();
155
Corentin Wallez45b51f52019-10-28 22:15:47 +0000156 callback1(WGPUErrorType_Validation, "First error message", userdata1);
Austin Eng45238d72019-09-04 22:54:03 +0000157 EXPECT_CALL(*mockDevicePopErrorScopeCallback,
Corentin Wallez45b51f52019-10-28 22:15:47 +0000158 Call(WGPUErrorType_Validation, StrEq("First error message"), this))
159 .Times(1);
Austin Eng45238d72019-09-04 22:54:03 +0000160 FlushServer();
161
Corentin Wallez45b51f52019-10-28 22:15:47 +0000162 callback2(WGPUErrorType_Validation, "Second error message", userdata2);
Austin Eng45238d72019-09-04 22:54:03 +0000163 EXPECT_CALL(*mockDevicePopErrorScopeCallback,
Corentin Wallez45b51f52019-10-28 22:15:47 +0000164 Call(WGPUErrorType_Validation, StrEq("Second error message"), this + 1))
165 .Times(1);
Austin Eng45238d72019-09-04 22:54:03 +0000166 FlushServer();
167 }
168
169 // Two error scopes are popped, and the second one returns first.
170 {
Corentin Wallez45b51f52019-10-28 22:15:47 +0000171 wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
172 wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
173 EXPECT_CALL(api, DevicePushErrorScope(apiDevice, WGPUErrorFilter_Validation)).Times(2);
Austin Eng45238d72019-09-04 22:54:03 +0000174
175 FlushClient();
176
Corentin Wallez45b51f52019-10-28 22:15:47 +0000177 wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this);
178 wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this + 1);
Austin Eng45238d72019-09-04 22:54:03 +0000179
Corentin Wallez45b51f52019-10-28 22:15:47 +0000180 WGPUErrorCallback callback1;
181 WGPUErrorCallback callback2;
Austin Eng45238d72019-09-04 22:54:03 +0000182 void* userdata1;
183 void* userdata2;
Austin Eng8d38c012020-12-17 17:59:37 +0000184 EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _, _))
Austin Eng45238d72019-09-04 22:54:03 +0000185 .WillOnce(DoAll(SaveArg<1>(&callback1), SaveArg<2>(&userdata1), Return(true)))
186 .WillOnce(DoAll(SaveArg<1>(&callback2), SaveArg<2>(&userdata2), Return(true)));
187
188 FlushClient();
189
Corentin Wallez45b51f52019-10-28 22:15:47 +0000190 callback2(WGPUErrorType_Validation, "Second error message", userdata2);
Austin Eng45238d72019-09-04 22:54:03 +0000191 EXPECT_CALL(*mockDevicePopErrorScopeCallback,
Corentin Wallez45b51f52019-10-28 22:15:47 +0000192 Call(WGPUErrorType_Validation, StrEq("Second error message"), this + 1))
193 .Times(1);
Austin Eng45238d72019-09-04 22:54:03 +0000194 FlushServer();
195
Corentin Wallez45b51f52019-10-28 22:15:47 +0000196 callback1(WGPUErrorType_Validation, "First error message", userdata1);
Austin Eng45238d72019-09-04 22:54:03 +0000197 EXPECT_CALL(*mockDevicePopErrorScopeCallback,
Corentin Wallez45b51f52019-10-28 22:15:47 +0000198 Call(WGPUErrorType_Validation, StrEq("First error message"), this))
199 .Times(1);
Austin Eng45238d72019-09-04 22:54:03 +0000200 FlushServer();
201 }
202}
203
204// Test the return wire for error scopes in flight when the device is destroyed.
205TEST_F(WireErrorCallbackTests, PopErrorScopeDeviceDestroyed) {
Corentin Wallez45b51f52019-10-28 22:15:47 +0000206 wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
207 EXPECT_CALL(api, DevicePushErrorScope(apiDevice, WGPUErrorFilter_Validation)).Times(1);
Austin Eng45238d72019-09-04 22:54:03 +0000208
209 FlushClient();
210
Corentin Wallez45b51f52019-10-28 22:15:47 +0000211 EXPECT_TRUE(wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this));
Austin Eng45238d72019-09-04 22:54:03 +0000212
Austin Eng8d38c012020-12-17 17:59:37 +0000213 EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _, _)).WillOnce(Return(true));
Austin Eng45238d72019-09-04 22:54:03 +0000214 FlushClient();
215
216 // Incomplete callback called in Device destructor.
Corentin Wallez45b51f52019-10-28 22:15:47 +0000217 EXPECT_CALL(*mockDevicePopErrorScopeCallback,
218 Call(WGPUErrorType_Unknown, ValidStringMessage(), this))
219 .Times(1);
Austin Eng45238d72019-09-04 22:54:03 +0000220}
221
Austin Engb70a5b02020-11-11 21:01:18 +0000222// Test that registering a callback then wire disconnect calls the callback with
223// DeviceLost.
224TEST_F(WireErrorCallbackTests, PopErrorScopeThenDisconnect) {
225 wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
226 EXPECT_CALL(api, DevicePushErrorScope(apiDevice, WGPUErrorFilter_Validation)).Times(1);
227
228 EXPECT_TRUE(wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this));
Austin Eng8d38c012020-12-17 17:59:37 +0000229 EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _, _)).WillOnce(Return(true));
Austin Engb70a5b02020-11-11 21:01:18 +0000230
231 FlushClient();
232
233 EXPECT_CALL(*mockDevicePopErrorScopeCallback,
234 Call(WGPUErrorType_DeviceLost, ValidStringMessage(), this))
235 .Times(1);
236 GetWireClient()->Disconnect();
237}
238
Austin Eng7ceffe82020-11-12 18:03:42 +0000239// Test that registering a callback after wire disconnect calls the callback with
240// DeviceLost.
241TEST_F(WireErrorCallbackTests, PopErrorScopeAfterDisconnect) {
242 wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
243 EXPECT_CALL(api, DevicePushErrorScope(apiDevice, WGPUErrorFilter_Validation)).Times(1);
244
245 FlushClient();
246
247 GetWireClient()->Disconnect();
248
249 EXPECT_CALL(*mockDevicePopErrorScopeCallback,
250 Call(WGPUErrorType_DeviceLost, ValidStringMessage(), this))
251 .Times(1);
252 EXPECT_TRUE(wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this));
253}
254
Austin Eng45238d72019-09-04 22:54:03 +0000255// Test that PopErrorScope returns false if there are no error scopes.
256TEST_F(WireErrorCallbackTests, PopErrorScopeEmptyStack) {
257 // Empty stack
Corentin Wallez45b51f52019-10-28 22:15:47 +0000258 { EXPECT_FALSE(wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this)); }
Austin Eng45238d72019-09-04 22:54:03 +0000259
260 // Pop too many times
261 {
Corentin Wallez45b51f52019-10-28 22:15:47 +0000262 wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
263 EXPECT_CALL(api, DevicePushErrorScope(apiDevice, WGPUErrorFilter_Validation)).Times(1);
Austin Eng45238d72019-09-04 22:54:03 +0000264
Corentin Wallez45b51f52019-10-28 22:15:47 +0000265 EXPECT_TRUE(wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this));
266 EXPECT_FALSE(wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this + 1));
Austin Eng45238d72019-09-04 22:54:03 +0000267
Corentin Wallez45b51f52019-10-28 22:15:47 +0000268 WGPUErrorCallback callback;
Austin Eng45238d72019-09-04 22:54:03 +0000269 void* userdata;
Austin Eng8d38c012020-12-17 17:59:37 +0000270 EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _, _))
Austin Eng45238d72019-09-04 22:54:03 +0000271 .WillOnce(DoAll(SaveArg<1>(&callback), SaveArg<2>(&userdata), Return(true)));
272
273 FlushClient();
274
Corentin Wallez45b51f52019-10-28 22:15:47 +0000275 callback(WGPUErrorType_Validation, "Some error message", userdata);
276 EXPECT_CALL(*mockDevicePopErrorScopeCallback,
277 Call(WGPUErrorType_Validation, StrEq("Some error message"), this))
278 .Times(1);
Austin Eng45238d72019-09-04 22:54:03 +0000279
280 FlushServer();
281 }
282}
Natasha Lee9bba4a92019-12-18 18:59:20 +0000283
284// Test the return wire for device lost callback
285TEST_F(WireErrorCallbackTests, DeviceLostCallback) {
286 wgpuDeviceSetDeviceLostCallback(device, ToMockDeviceLostCallback, this);
287
288 // Setting the error callback should stay on the client side and do nothing
289 FlushClient();
290
291 // Calling the callback on the server side will result in the callback being called on the
292 // client side
Austin Eng8d38c012020-12-17 17:59:37 +0000293 api.CallDeviceSetDeviceLostCallbackCallback(apiDevice, "Some error message");
Natasha Lee9bba4a92019-12-18 18:59:20 +0000294
295 EXPECT_CALL(*mockDeviceLostCallback, Call(StrEq("Some error message"), this)).Times(1);
296
297 FlushServer();
298}