Fix multiple device leaks in dawn_end2end_tests and dawn_unittests

Adds ForTesting APIs to the instance to track the number of devices.

Bug: dawn:1164
Change-Id: Ib743afb1e86ef16740d49613f43f9e2f009232bc
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/90583
Reviewed-by: Loko Kung <lokokung@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
diff --git a/include/dawn/native/DawnNative.h b/include/dawn/native/DawnNative.h
index ad4e610..9c60409 100644
--- a/include/dawn/native/DawnNative.h
+++ b/include/dawn/native/DawnNative.h
@@ -170,6 +170,8 @@
     // TODO(dawn:1374) Deprecate this once it is passed via the descriptor.
     void SetPlatform(dawn::platform::Platform* platform);
 
+    uint64_t GetDeviceCountForTesting() const;
+
     // Returns the underlying WGPUInstance object.
     WGPUInstance Get() const;
 
diff --git a/src/dawn/native/DawnNative.cpp b/src/dawn/native/DawnNative.cpp
index 69296ef..00b15cd 100644
--- a/src/dawn/native/DawnNative.cpp
+++ b/src/dawn/native/DawnNative.cpp
@@ -244,6 +244,10 @@
     mImpl->SetPlatform(platform);
 }
 
+uint64_t Instance::GetDeviceCountForTesting() const {
+    return mImpl->GetDeviceCountForTesting();
+}
+
 WGPUInstance Instance::Get() const {
     return ToAPI(mImpl);
 }
diff --git a/src/dawn/native/Device.cpp b/src/dawn/native/Device.cpp
index 26d5bb6..1f11514 100644
--- a/src/dawn/native/Device.cpp
+++ b/src/dawn/native/Device.cpp
@@ -171,6 +171,7 @@
 
 DeviceBase::DeviceBase(AdapterBase* adapter, const DeviceDescriptor* descriptor)
     : mInstance(adapter->GetInstance()), mAdapter(adapter), mNextPipelineCompatibilityToken(1) {
+    mInstance->IncrementDeviceCountForTesting();
     ASSERT(descriptor != nullptr);
 
     AdapterProperties adapterProperties;
@@ -220,6 +221,10 @@
     // We need to explicitly release the Queue before we complete the destructor so that the
     // Queue does not get destroyed after the Device.
     mQueue = nullptr;
+    // mInstance is not set for mock test devices.
+    if (mInstance != nullptr) {
+        mInstance->DecrementDeviceCountForTesting();
+    }
 }
 
 MaybeError DeviceBase::Initialize(Ref<QueueBase> defaultQueue) {
diff --git a/src/dawn/native/Instance.cpp b/src/dawn/native/Instance.cpp
index 1e25a3b..4047865 100644
--- a/src/dawn/native/Instance.cpp
+++ b/src/dawn/native/Instance.cpp
@@ -437,6 +437,18 @@
     return mBlobCache.get();
 }
 
+uint64_t InstanceBase::GetDeviceCountForTesting() const {
+    return mDeviceCountForTesting.load();
+}
+
+void InstanceBase::IncrementDeviceCountForTesting() {
+    mDeviceCountForTesting++;
+}
+
+void InstanceBase::DecrementDeviceCountForTesting() {
+    mDeviceCountForTesting--;
+}
+
 const std::vector<std::string>& InstanceBase::GetRuntimeSearchPaths() const {
     return mRuntimeSearchPaths;
 }
diff --git a/src/dawn/native/Instance.h b/src/dawn/native/Instance.h
index 0f3cb18..581cb85 100644
--- a/src/dawn/native/Instance.h
+++ b/src/dawn/native/Instance.h
@@ -84,6 +84,10 @@
     dawn::platform::Platform* GetPlatform();
     BlobCache* GetBlobCache();
 
+    uint64_t GetDeviceCountForTesting() const;
+    void IncrementDeviceCountForTesting();
+    void DecrementDeviceCountForTesting();
+
     const std::vector<std::string>& GetRuntimeSearchPaths() const;
 
     // Get backend-independent libraries that need to be loaded dynamically.
@@ -130,6 +134,8 @@
 #if defined(DAWN_USE_X11)
     std::unique_ptr<XlibXcbFunctions> mXlibXcbFunctions;
 #endif  // defined(DAWN_USE_X11)
+
+    std::atomic_uint64_t mDeviceCountForTesting{0};
 };
 
 }  // namespace dawn::native
diff --git a/src/dawn/tests/BUILD.gn b/src/dawn/tests/BUILD.gn
index b1a2b74..9f86b59 100644
--- a/src/dawn/tests/BUILD.gn
+++ b/src/dawn/tests/BUILD.gn
@@ -491,12 +491,6 @@
     "end2end/ViewportTests.cpp",
   ]
 
-  # Validation tests that need OS windows live in end2end tests.
-  sources += [
-    "unittests/validation/ValidationTest.cpp",
-    "unittests/validation/ValidationTest.h",
-  ]
-
   libs = []
 
   if (dawn_enable_d3d12) {
diff --git a/src/dawn/tests/DawnNativeTest.cpp b/src/dawn/tests/DawnNativeTest.cpp
index c07c5c2..163413d 100644
--- a/src/dawn/tests/DawnNativeTest.cpp
+++ b/src/dawn/tests/DawnNativeTest.cpp
@@ -62,7 +62,7 @@
 
     ASSERT(foundNullAdapter);
 
-    device = wgpu::Device(CreateTestDevice());
+    device = wgpu::Device::Acquire(CreateTestDevice());
     device.SetUncapturedErrorCallback(DawnNativeTest::OnDeviceError, nullptr);
 }
 
diff --git a/src/dawn/tests/DawnTest.cpp b/src/dawn/tests/DawnTest.cpp
index 148bf0a..a5dffad 100644
--- a/src/dawn/tests/DawnTest.cpp
+++ b/src/dawn/tests/DawnTest.cpp
@@ -723,6 +723,9 @@
         mBackendAdapter.ResetInternalDeviceForTesting();
     }
     mWireHelper.reset();
+
+    // Check that all devices were destructed.
+    EXPECT_EQ(gTestEnv->GetInstance()->GetDeviceCountForTesting(), 0u);
 }
 
 bool DawnTestBase::IsD3D12() const {
diff --git a/src/dawn/tests/unittests/FeatureTests.cpp b/src/dawn/tests/unittests/FeatureTests.cpp
index 9fb6248..cb7d701 100644
--- a/src/dawn/tests/unittests/FeatureTests.cpp
+++ b/src/dawn/tests/unittests/FeatureTests.cpp
@@ -84,5 +84,6 @@
         wgpu::FeatureName enabledFeature;
         deviceBase->APIEnumerateFeatures(&enabledFeature);
         EXPECT_EQ(enabledFeature, featureName);
+        deviceBase->APIRelease();
     }
 }
diff --git a/src/dawn/tests/unittests/validation/DeviceValidationTests.cpp b/src/dawn/tests/unittests/validation/DeviceValidationTests.cpp
index e393924..9ffba5d 100644
--- a/src/dawn/tests/unittests/validation/DeviceValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/DeviceValidationTests.cpp
@@ -23,8 +23,8 @@
 class RequestDeviceValidationTest : public ValidationTest {
   protected:
     void SetUp() override {
-        DAWN_SKIP_TEST_IF(UsesWire());
         ValidationTest::SetUp();
+        DAWN_SKIP_TEST_IF(UsesWire());
     }
 
     static void ExpectRequestDeviceSuccess(WGPURequestDeviceStatus status,
diff --git a/src/dawn/tests/unittests/validation/LabelTests.cpp b/src/dawn/tests/unittests/validation/LabelTests.cpp
index 5b1b3ea..ebecbf6 100644
--- a/src/dawn/tests/unittests/validation/LabelTests.cpp
+++ b/src/dawn/tests/unittests/validation/LabelTests.cpp
@@ -325,7 +325,7 @@
     // The label should be empty if one was not set.
     {
         wgpu::DeviceDescriptor descriptor;
-        wgpu::Device labelDevice = adapter.CreateDevice(&descriptor);
+        wgpu::Device labelDevice = wgpu::Device::Acquire(adapter.CreateDevice(&descriptor));
         std::string readbackLabel =
             dawn::native::GetObjectLabelForTesting(labelDevice.GetQueue().Get());
         ASSERT_TRUE(readbackLabel.empty());
@@ -334,7 +334,7 @@
     // Test setting a label through API
     {
         wgpu::DeviceDescriptor descriptor;
-        wgpu::Device labelDevice = adapter.CreateDevice(&descriptor);
+        wgpu::Device labelDevice = wgpu::Device::Acquire(adapter.CreateDevice(&descriptor));
         labelDevice.GetQueue().SetLabel(label.c_str());
         std::string readbackLabel =
             dawn::native::GetObjectLabelForTesting(labelDevice.GetQueue().Get());
@@ -345,7 +345,7 @@
     {
         wgpu::DeviceDescriptor descriptor;
         descriptor.defaultQueue.label = label.c_str();
-        wgpu::Device labelDevice = adapter.CreateDevice(&descriptor);
+        wgpu::Device labelDevice = wgpu::Device::Acquire(adapter.CreateDevice(&descriptor));
         std::string readbackLabel =
             dawn::native::GetObjectLabelForTesting(labelDevice.GetQueue().Get());
         ASSERT_EQ(label, readbackLabel);
diff --git a/src/dawn/tests/unittests/validation/ToggleValidationTests.cpp b/src/dawn/tests/unittests/validation/ToggleValidationTests.cpp
index 1c0d9be..677f6e2 100644
--- a/src/dawn/tests/unittests/validation/ToggleValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/ToggleValidationTests.cpp
@@ -18,7 +18,12 @@
 
 namespace {
 
-class ToggleValidationTest : public ValidationTest {};
+class ToggleValidationTest : public ValidationTest {
+    void SetUp() override {
+        ValidationTest::SetUp();
+        DAWN_SKIP_TEST_IF(UsesWire());
+    }
+};
 
 // Tests querying the detail of a toggle from dawn::native::InstanceBase works correctly.
 TEST_F(ToggleValidationTest, QueryToggleInfo) {
@@ -51,8 +56,8 @@
         togglesDesc.forceEnabledToggles = &kValidToggleName;
         togglesDesc.forceEnabledTogglesCount = 1;
 
-        WGPUDevice deviceWithToggle = adapter.CreateDevice(&descriptor);
-        std::vector<const char*> toggleNames = dawn::native::GetTogglesUsed(deviceWithToggle);
+        wgpu::Device deviceWithToggle = wgpu::Device::Acquire(adapter.CreateDevice(&descriptor));
+        std::vector<const char*> toggleNames = dawn::native::GetTogglesUsed(deviceWithToggle.Get());
         bool validToggleExists = false;
         for (const char* toggle : toggleNames) {
             if (strcmp(toggle, kValidToggleName) == 0) {
@@ -71,8 +76,8 @@
         togglesDesc.forceEnabledToggles = &kInvalidToggleName;
         togglesDesc.forceEnabledTogglesCount = 1;
 
-        WGPUDevice deviceWithToggle = adapter.CreateDevice(&descriptor);
-        std::vector<const char*> toggleNames = dawn::native::GetTogglesUsed(deviceWithToggle);
+        wgpu::Device deviceWithToggle = wgpu::Device::Acquire(adapter.CreateDevice(&descriptor));
+        std::vector<const char*> toggleNames = dawn::native::GetTogglesUsed(deviceWithToggle.Get());
         bool InvalidToggleExists = false;
         for (const char* toggle : toggleNames) {
             if (strcmp(toggle, kInvalidToggleName) == 0) {
@@ -91,8 +96,8 @@
     togglesDesc.forceEnabledToggles = &kValidToggleName;
     togglesDesc.forceEnabledTogglesCount = 1;
 
-    WGPUDevice deviceWithToggle = adapter.CreateDevice(&descriptor);
-    std::vector<const char*> toggleNames = dawn::native::GetTogglesUsed(deviceWithToggle);
+    wgpu::Device deviceWithToggle = wgpu::Device::Acquire(adapter.CreateDevice(&descriptor));
+    std::vector<const char*> toggleNames = dawn::native::GetTogglesUsed(deviceWithToggle.Get());
     bool validToggleExists = false;
     for (const char* toggle : toggleNames) {
         if (strcmp(toggle, kValidToggleName) == 0) {
diff --git a/src/dawn/tests/unittests/validation/ValidationTest.cpp b/src/dawn/tests/unittests/validation/ValidationTest.cpp
index 38908b5..14d5372 100644
--- a/src/dawn/tests/unittests/validation/ValidationTest.cpp
+++ b/src/dawn/tests/unittests/validation/ValidationTest.cpp
@@ -118,6 +118,9 @@
     // will call a nullptr
     device = wgpu::Device();
     mWireHelper.reset();
+
+    // Check that all devices were destructed.
+    EXPECT_EQ(instance->GetDeviceCountForTesting(), 0u);
 }
 
 void ValidationTest::TearDown() {
diff --git a/src/dawn/tests/white_box/VulkanImageWrappingTests_DmaBuf.cpp b/src/dawn/tests/white_box/VulkanImageWrappingTests_DmaBuf.cpp
index cccaadc..bf37359 100644
--- a/src/dawn/tests/white_box/VulkanImageWrappingTests_DmaBuf.cpp
+++ b/src/dawn/tests/white_box/VulkanImageWrappingTests_DmaBuf.cpp
@@ -118,7 +118,8 @@
         descriptorDmaBuf.stride = textureDmaBuf->stride;
         descriptorDmaBuf.drmModifier = textureDmaBuf->drmModifier;
 
-        return dawn::native::vulkan::WrapVulkanImage(device.Get(), &descriptorDmaBuf);
+        return wgpu::Texture::Acquire(
+            dawn::native::vulkan::WrapVulkanImage(device.Get(), &descriptorDmaBuf));
     }
 
     bool ExportImage(const wgpu::Texture& texture,
diff --git a/src/dawn/tests/white_box/VulkanImageWrappingTests_OpaqueFD.cpp b/src/dawn/tests/white_box/VulkanImageWrappingTests_OpaqueFD.cpp
index c92181c..e8e8a59 100644
--- a/src/dawn/tests/white_box/VulkanImageWrappingTests_OpaqueFD.cpp
+++ b/src/dawn/tests/white_box/VulkanImageWrappingTests_OpaqueFD.cpp
@@ -141,7 +141,8 @@
         descriptorOpaqueFD.memoryTypeIndex = textureOpaqueFD->memoryTypeIndex;
         descriptorOpaqueFD.waitFDs = std::move(waitFDs);
 
-        return dawn::native::vulkan::WrapVulkanImage(device.Get(), &descriptorOpaqueFD);
+        return wgpu::Texture::Acquire(
+            dawn::native::vulkan::WrapVulkanImage(device.Get(), &descriptorOpaqueFD));
     }
 
     bool ExportImage(const wgpu::Texture& texture,