• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 
17 #include "dawn_wire/WireClient.h"
18 
19 using namespace testing;
20 using namespace dawn_wire;
21 
22 namespace {
23 
24     // Mock classes to add expectations on the wire calling callbacks
25     class MockDeviceErrorCallback {
26       public:
27         MOCK_METHOD(void, Call, (WGPUErrorType type, const char* message, void* userdata));
28     };
29 
30     std::unique_ptr<StrictMock<MockDeviceErrorCallback>> mockDeviceErrorCallback;
ToMockDeviceErrorCallback(WGPUErrorType type,const char * message,void * userdata)31     void ToMockDeviceErrorCallback(WGPUErrorType type, const char* message, void* userdata) {
32         mockDeviceErrorCallback->Call(type, message, userdata);
33     }
34 
35     class MockDevicePopErrorScopeCallback {
36       public:
37         MOCK_METHOD(void, Call, (WGPUErrorType type, const char* message, void* userdata));
38     };
39 
40     std::unique_ptr<StrictMock<MockDevicePopErrorScopeCallback>> mockDevicePopErrorScopeCallback;
ToMockDevicePopErrorScopeCallback(WGPUErrorType type,const char * message,void * userdata)41     void ToMockDevicePopErrorScopeCallback(WGPUErrorType type,
42                                            const char* message,
43                                            void* userdata) {
44         mockDevicePopErrorScopeCallback->Call(type, message, userdata);
45     }
46 
47     class MockDeviceLoggingCallback {
48       public:
49         MOCK_METHOD(void, Call, (WGPULoggingType type, const char* message, void* userdata));
50     };
51 
52     std::unique_ptr<StrictMock<MockDeviceLoggingCallback>> mockDeviceLoggingCallback;
ToMockDeviceLoggingCallback(WGPULoggingType type,const char * message,void * userdata)53     void ToMockDeviceLoggingCallback(WGPULoggingType type, const char* message, void* userdata) {
54         mockDeviceLoggingCallback->Call(type, message, userdata);
55     }
56 
57     class MockDeviceLostCallback {
58       public:
59         MOCK_METHOD(void, Call, (WGPUDeviceLostReason reason, const char* message, void* userdata));
60     };
61 
62     std::unique_ptr<StrictMock<MockDeviceLostCallback>> mockDeviceLostCallback;
ToMockDeviceLostCallback(WGPUDeviceLostReason reason,const char * message,void * userdata)63     void ToMockDeviceLostCallback(WGPUDeviceLostReason reason,
64                                   const char* message,
65                                   void* userdata) {
66         mockDeviceLostCallback->Call(reason, message, userdata);
67     }
68 
69 }  // anonymous namespace
70 
71 class WireErrorCallbackTests : public WireTest {
72   public:
WireErrorCallbackTests()73     WireErrorCallbackTests() {
74     }
75     ~WireErrorCallbackTests() override = default;
76 
SetUp()77     void SetUp() override {
78         WireTest::SetUp();
79 
80         mockDeviceErrorCallback = std::make_unique<StrictMock<MockDeviceErrorCallback>>();
81         mockDeviceLoggingCallback = std::make_unique<StrictMock<MockDeviceLoggingCallback>>();
82         mockDevicePopErrorScopeCallback =
83             std::make_unique<StrictMock<MockDevicePopErrorScopeCallback>>();
84         mockDeviceLostCallback = std::make_unique<StrictMock<MockDeviceLostCallback>>();
85     }
86 
TearDown()87     void TearDown() override {
88         WireTest::TearDown();
89 
90         mockDeviceErrorCallback = nullptr;
91         mockDeviceLoggingCallback = nullptr;
92         mockDevicePopErrorScopeCallback = nullptr;
93         mockDeviceLostCallback = nullptr;
94     }
95 
FlushServer()96     void FlushServer() {
97         WireTest::FlushServer();
98 
99         Mock::VerifyAndClearExpectations(&mockDeviceErrorCallback);
100         Mock::VerifyAndClearExpectations(&mockDevicePopErrorScopeCallback);
101     }
102 };
103 
104 // Test the return wire for device error callbacks
TEST_F(WireErrorCallbackTests,DeviceErrorCallback)105 TEST_F(WireErrorCallbackTests, DeviceErrorCallback) {
106     wgpuDeviceSetUncapturedErrorCallback(device, ToMockDeviceErrorCallback, this);
107 
108     // Setting the error callback should stay on the client side and do nothing
109     FlushClient();
110 
111     // Calling the callback on the server side will result in the callback being called on the
112     // client side
113     api.CallDeviceSetUncapturedErrorCallbackCallback(apiDevice, WGPUErrorType_Validation,
114                                                      "Some error message");
115 
116     EXPECT_CALL(*mockDeviceErrorCallback,
117                 Call(WGPUErrorType_Validation, StrEq("Some error message"), this))
118         .Times(1);
119 
120     FlushServer();
121 }
122 
123 // Test the return wire for device user warning callbacks
TEST_F(WireErrorCallbackTests,DeviceLoggingCallback)124 TEST_F(WireErrorCallbackTests, DeviceLoggingCallback) {
125     wgpuDeviceSetLoggingCallback(device, ToMockDeviceLoggingCallback, this);
126 
127     // Setting the injected warning callback should stay on the client side and do nothing
128     FlushClient();
129 
130     // Calling the callback on the server side will result in the callback being called on the
131     // client side
132     api.CallDeviceSetLoggingCallbackCallback(apiDevice, WGPULoggingType_Info, "Some message");
133 
134     EXPECT_CALL(*mockDeviceLoggingCallback, Call(WGPULoggingType_Info, StrEq("Some message"), this))
135         .Times(1);
136 
137     FlushServer();
138 }
139 
140 // Test the return wire for error scopes.
TEST_F(WireErrorCallbackTests,PushPopErrorScopeCallback)141 TEST_F(WireErrorCallbackTests, PushPopErrorScopeCallback) {
142     wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
143     EXPECT_CALL(api, DevicePushErrorScope(apiDevice, WGPUErrorFilter_Validation)).Times(1);
144 
145     FlushClient();
146 
147     wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this);
148 
149     WGPUErrorCallback callback;
150     void* userdata;
151     EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _, _))
152         .WillOnce(DoAll(SaveArg<1>(&callback), SaveArg<2>(&userdata), Return(true)));
153 
154     FlushClient();
155 
156     callback(WGPUErrorType_Validation, "Some error message", userdata);
157     EXPECT_CALL(*mockDevicePopErrorScopeCallback,
158                 Call(WGPUErrorType_Validation, StrEq("Some error message"), this))
159         .Times(1);
160 
161     FlushServer();
162 }
163 
164 // Test the return wire for error scopes when callbacks return in a various orders.
TEST_F(WireErrorCallbackTests,PopErrorScopeCallbackOrdering)165 TEST_F(WireErrorCallbackTests, PopErrorScopeCallbackOrdering) {
166     // Two error scopes are popped, and the first one returns first.
167     {
168         wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
169         wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
170         EXPECT_CALL(api, DevicePushErrorScope(apiDevice, WGPUErrorFilter_Validation)).Times(2);
171 
172         FlushClient();
173 
174         wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this);
175         wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this + 1);
176 
177         WGPUErrorCallback callback1;
178         WGPUErrorCallback callback2;
179         void* userdata1;
180         void* userdata2;
181         EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _, _))
182             .WillOnce(DoAll(SaveArg<1>(&callback1), SaveArg<2>(&userdata1), Return(true)))
183             .WillOnce(DoAll(SaveArg<1>(&callback2), SaveArg<2>(&userdata2), Return(true)));
184 
185         FlushClient();
186 
187         callback1(WGPUErrorType_Validation, "First error message", userdata1);
188         EXPECT_CALL(*mockDevicePopErrorScopeCallback,
189                     Call(WGPUErrorType_Validation, StrEq("First error message"), this))
190             .Times(1);
191         FlushServer();
192 
193         callback2(WGPUErrorType_Validation, "Second error message", userdata2);
194         EXPECT_CALL(*mockDevicePopErrorScopeCallback,
195                     Call(WGPUErrorType_Validation, StrEq("Second error message"), this + 1))
196             .Times(1);
197         FlushServer();
198     }
199 
200     // Two error scopes are popped, and the second one returns first.
201     {
202         wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
203         wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
204         EXPECT_CALL(api, DevicePushErrorScope(apiDevice, WGPUErrorFilter_Validation)).Times(2);
205 
206         FlushClient();
207 
208         wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this);
209         wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this + 1);
210 
211         WGPUErrorCallback callback1;
212         WGPUErrorCallback callback2;
213         void* userdata1;
214         void* userdata2;
215         EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _, _))
216             .WillOnce(DoAll(SaveArg<1>(&callback1), SaveArg<2>(&userdata1), Return(true)))
217             .WillOnce(DoAll(SaveArg<1>(&callback2), SaveArg<2>(&userdata2), Return(true)));
218 
219         FlushClient();
220 
221         callback2(WGPUErrorType_Validation, "Second error message", userdata2);
222         EXPECT_CALL(*mockDevicePopErrorScopeCallback,
223                     Call(WGPUErrorType_Validation, StrEq("Second error message"), this + 1))
224             .Times(1);
225         FlushServer();
226 
227         callback1(WGPUErrorType_Validation, "First error message", userdata1);
228         EXPECT_CALL(*mockDevicePopErrorScopeCallback,
229                     Call(WGPUErrorType_Validation, StrEq("First error message"), this))
230             .Times(1);
231         FlushServer();
232     }
233 }
234 
235 // Test the return wire for error scopes in flight when the device is destroyed.
TEST_F(WireErrorCallbackTests,PopErrorScopeDeviceDestroyed)236 TEST_F(WireErrorCallbackTests, PopErrorScopeDeviceDestroyed) {
237     wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
238     EXPECT_CALL(api, DevicePushErrorScope(apiDevice, WGPUErrorFilter_Validation)).Times(1);
239 
240     FlushClient();
241 
242     EXPECT_TRUE(wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this));
243 
244     EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _, _)).WillOnce(Return(true));
245     FlushClient();
246 
247     // Incomplete callback called in Device destructor.
248     EXPECT_CALL(*mockDevicePopErrorScopeCallback,
249                 Call(WGPUErrorType_Unknown, ValidStringMessage(), this))
250         .Times(1);
251 }
252 
253 // Test that registering a callback then wire disconnect calls the callback with
254 // DeviceLost.
TEST_F(WireErrorCallbackTests,PopErrorScopeThenDisconnect)255 TEST_F(WireErrorCallbackTests, PopErrorScopeThenDisconnect) {
256     wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
257     EXPECT_CALL(api, DevicePushErrorScope(apiDevice, WGPUErrorFilter_Validation)).Times(1);
258 
259     EXPECT_TRUE(wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this));
260     EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _, _)).WillOnce(Return(true));
261 
262     FlushClient();
263 
264     EXPECT_CALL(*mockDevicePopErrorScopeCallback,
265                 Call(WGPUErrorType_DeviceLost, ValidStringMessage(), this))
266         .Times(1);
267     GetWireClient()->Disconnect();
268 }
269 
270 // Test that registering a callback after wire disconnect calls the callback with
271 // DeviceLost.
TEST_F(WireErrorCallbackTests,PopErrorScopeAfterDisconnect)272 TEST_F(WireErrorCallbackTests, PopErrorScopeAfterDisconnect) {
273     wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
274     EXPECT_CALL(api, DevicePushErrorScope(apiDevice, WGPUErrorFilter_Validation)).Times(1);
275 
276     FlushClient();
277 
278     GetWireClient()->Disconnect();
279 
280     EXPECT_CALL(*mockDevicePopErrorScopeCallback,
281                 Call(WGPUErrorType_DeviceLost, ValidStringMessage(), this))
282         .Times(1);
283     EXPECT_TRUE(wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this));
284 }
285 
286 // Test that PopErrorScope returns false if there are no error scopes.
TEST_F(WireErrorCallbackTests,PopErrorScopeEmptyStack)287 TEST_F(WireErrorCallbackTests, PopErrorScopeEmptyStack) {
288     // Empty stack
289     { EXPECT_FALSE(wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this)); }
290 
291     // Pop too many times
292     {
293         wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
294         EXPECT_CALL(api, DevicePushErrorScope(apiDevice, WGPUErrorFilter_Validation)).Times(1);
295 
296         EXPECT_TRUE(wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this));
297         EXPECT_FALSE(wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this + 1));
298 
299         WGPUErrorCallback callback;
300         void* userdata;
301         EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _, _))
302             .WillOnce(DoAll(SaveArg<1>(&callback), SaveArg<2>(&userdata), Return(true)));
303 
304         FlushClient();
305 
306         callback(WGPUErrorType_Validation, "Some error message", userdata);
307         EXPECT_CALL(*mockDevicePopErrorScopeCallback,
308                     Call(WGPUErrorType_Validation, StrEq("Some error message"), this))
309             .Times(1);
310 
311         FlushServer();
312     }
313 }
314 
315 // Test the return wire for device lost callback
TEST_F(WireErrorCallbackTests,DeviceLostCallback)316 TEST_F(WireErrorCallbackTests, DeviceLostCallback) {
317     wgpuDeviceSetDeviceLostCallback(device, ToMockDeviceLostCallback, this);
318 
319     // Setting the error callback should stay on the client side and do nothing
320     FlushClient();
321 
322     // Calling the callback on the server side will result in the callback being called on the
323     // client side
324     api.CallDeviceSetDeviceLostCallbackCallback(apiDevice, WGPUDeviceLostReason_Undefined,
325                                                 "Some error message");
326 
327     EXPECT_CALL(*mockDeviceLostCallback,
328                 Call(WGPUDeviceLostReason_Undefined, StrEq("Some error message"), this))
329         .Times(1);
330 
331     FlushServer();
332 }
333