LoseForTesting can only be called once

Bug: chromium:1061878, dawn:68
Change-Id: Ieb35bdefc22299f828fe21e43d85fefabf500e27
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/17140
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Natasha Lee <natlee@microsoft.com>
diff --git a/src/dawn_native/Device.cpp b/src/dawn_native/Device.cpp
index 6e41e56..81fdee4 100644
--- a/src/dawn_native/Device.cpp
+++ b/src/dawn_native/Device.cpp
@@ -196,6 +196,10 @@
     }
 
     void DeviceBase::LoseForTesting() {
+        if (mLossStatus == LossStatus::AlreadyLost) {
+            return;
+        }
+
         mLossStatus = LossStatus::BeingLost;
         // Assert that errors are device loss so that we can continue with destruction
         AssertAndIgnoreDeviceLossError(WaitForIdleForDestruction());
diff --git a/src/tests/end2end/DeviceLostTests.cpp b/src/tests/end2end/DeviceLostTests.cpp
index 10afcd2..b06377c 100644
--- a/src/tests/end2end/DeviceLostTests.cpp
+++ b/src/tests/end2end/DeviceLostTests.cpp
@@ -459,4 +459,16 @@
     EXPECT_EQ(fence.GetCompletedValue(), 2u);
 }
 
+// Test that LostForTesting can only be called on one time
+TEST_P(DeviceLostTest, LoseForTestingOnce) {
+    // First LoseForTesting call should occur normally
+    SetCallbackAndLoseForTesting();
+
+    // Second LoseForTesting call should result in no callbacks. The LoseForTesting will return
+    // without doing anything when it sees that device has already been lost.
+    device.SetDeviceLostCallback(ToMockDeviceLostCallback, this);
+    EXPECT_CALL(*mockDeviceLostCallback, Call(_, this)).Times(0);
+    device.LoseForTesting();
+}
+
 DAWN_INSTANTIATE_TEST(DeviceLostTest, D3D12Backend(), VulkanBackend());