From 79065b8d3fdbccf33a23dbcddc9bb6ac3a8290c6 Mon Sep 17 00:00:00 2001
From: David Mehren <git@herrmehren.de>
Date: Thu, 22 Apr 2021 21:29:23 +0200
Subject: [PATCH] Media E2E tests: Add error handling for upload cleanup

Previously, `fs.rmdir` was called multiple times on the same path,
even when the path was already deleted.
This causes test failures in Node 16.

This commit extracts the cleanup code into a utility function
and ensures that no error is thrown when the given path is already deleted.

Signed-off-by: David Mehren <git@herrmehren.de>
---
 test/private-api/media.e2e-spec.ts |  7 ++++---
 test/public-api/media.e2e-spec.ts  |  7 ++++---
 test/utils.ts                      | 23 +++++++++++++++++++++++
 3 files changed, 31 insertions(+), 6 deletions(-)
 create mode 100644 test/utils.ts

diff --git a/test/private-api/media.e2e-spec.ts b/test/private-api/media.e2e-spec.ts
index 7bda9c2bb..890ca9f48 100644
--- a/test/private-api/media.e2e-spec.ts
+++ b/test/private-api/media.e2e-spec.ts
@@ -26,6 +26,7 @@ import { join } from 'path';
 import { PrivateApiModule } from '../../src/api/private/private-api.module';
 import { UsersService } from '../../src/users/users.service';
 import { ConsoleLoggerService } from '../../src/logger/console-logger.service';
+import { ensureDeleted } from '../utils';
 
 describe('Media', () => {
   let app: NestExpressApplication;
@@ -95,7 +96,7 @@ describe('Media', () => {
     });
     describe('fails:', () => {
       beforeEach(async () => {
-        await fs.rmdir(uploadPath, { recursive: true });
+        await ensureDeleted(uploadPath);
       });
       it('MIME type not supported', async () => {
         await request(app.getHttpServer())
@@ -125,14 +126,14 @@ describe('Media', () => {
           .expect(500);
       });
       afterEach(async () => {
-        await fs.rmdir(uploadPath, { recursive: true });
+        await ensureDeleted(uploadPath);
       });
     });
   });
 
   afterAll(async () => {
     // Delete the upload folder
-    await fs.rmdir(uploadPath, { recursive: true });
+    await ensureDeleted(uploadPath);
     await app.close();
   });
 });
diff --git a/test/public-api/media.e2e-spec.ts b/test/public-api/media.e2e-spec.ts
index 01cd708bf..b2687591f 100644
--- a/test/public-api/media.e2e-spec.ts
+++ b/test/public-api/media.e2e-spec.ts
@@ -25,6 +25,7 @@ import { TokenAuthGuard } from '../../src/auth/token-auth.guard';
 import { MockAuthGuard } from '../../src/auth/mock-auth.guard';
 import { join } from 'path';
 import { ConsoleLoggerService } from '../../src/logger/console-logger.service';
+import { ensureDeleted } from '../utils';
 
 describe('Media', () => {
   let app: NestExpressApplication;
@@ -91,7 +92,7 @@ describe('Media', () => {
     });
     describe('fails:', () => {
       beforeEach(async () => {
-        await fs.rmdir(uploadPath, { recursive: true });
+        await ensureDeleted(uploadPath);
       });
       it('MIME type not supported', async () => {
         await request(app.getHttpServer())
@@ -121,7 +122,7 @@ describe('Media', () => {
           .expect(500);
       });
       afterEach(async () => {
-        await fs.rmdir(uploadPath, { recursive: true });
+        await ensureDeleted(uploadPath);
       });
     });
   });
@@ -141,7 +142,7 @@ describe('Media', () => {
 
   afterAll(async () => {
     // Delete the upload folder
-    await fs.rmdir(uploadPath, { recursive: true });
+    await ensureDeleted(uploadPath);
     await app.close();
   });
 });
diff --git a/test/utils.ts b/test/utils.ts
new file mode 100644
index 000000000..90caccdc2
--- /dev/null
+++ b/test/utils.ts
@@ -0,0 +1,23 @@
+/*
+ * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { promises as fs } from 'fs';
+
+/**
+ * Ensures the directory at `path` is deleted.
+ * If `path` does not exist, nothing happens.
+ */
+export async function ensureDeleted(path: string): Promise<void> {
+  try {
+    await fs.rmdir(path, { recursive: true });
+  } catch (e) {
+    if (e.code && e.code == 'ENOENT') {
+      // ignore error, path is already deleted
+      return;
+    }
+    throw e;
+  }
+}