148 lines
5.4 KiB
JavaScript
148 lines
5.4 KiB
JavaScript
"use strict";
|
|
|
|
const test = require("node:test");
|
|
const assert = require("node:assert/strict");
|
|
const fs = require("fs");
|
|
const os = require("os");
|
|
const path = require("path");
|
|
|
|
const { uploadLogFile, isUnauthorizedError } = require("../lib/logUpload");
|
|
|
|
function fakeLogger() {
|
|
const infos = [];
|
|
const warnings = [];
|
|
const errors = [];
|
|
return {
|
|
infos,
|
|
warnings,
|
|
errors,
|
|
info: (msg) => infos.push(msg),
|
|
warn: (msg) => warnings.push(msg),
|
|
error: (msg) => errors.push(msg),
|
|
currentLogFilePath: () => fakeLogger.logFilePath,
|
|
};
|
|
}
|
|
|
|
function withTempLogFile(fn) {
|
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "log-upload-test-"));
|
|
const logFilePath = path.join(dir, "backup-202607.log");
|
|
fs.writeFileSync(logFilePath, "dummy log");
|
|
return fn(logFilePath);
|
|
}
|
|
|
|
test("401なしで成功した場合はそのままアップロード成功ログを出す", async () => {
|
|
await withTempLogFile(async (logFilePath) => {
|
|
const logger = fakeLogger();
|
|
logger.currentLogFilePath = () => logFilePath;
|
|
const uploadCalls = [];
|
|
const drive = {
|
|
resolveSharedDriveId: async () => {
|
|
throw new Error("呼ばれないはず(sharedriveId指定済み)");
|
|
},
|
|
ensureFolder: async () => ({ fileId: "logs-folder" }),
|
|
uploadFile: async (token) => {
|
|
uploadCalls.push(token);
|
|
return { fileId: "f1" };
|
|
},
|
|
};
|
|
const getUserAccessToken = async () => {
|
|
throw new Error("呼ばれないはず(accessToken指定済み)");
|
|
};
|
|
|
|
await uploadLogFile(
|
|
{ accessToken: "token-1", sharedriveId: "drive-1", backupFolderId: "folder-1" },
|
|
{ logger, drive, getUserAccessToken }
|
|
);
|
|
|
|
assert.deepEqual(uploadCalls, ["token-1"]);
|
|
assert.ok(logger.infos.some((m) => m.includes("ログファイルアップロード成功")));
|
|
assert.equal(logger.errors.length, 0);
|
|
});
|
|
});
|
|
|
|
test("401エラー発生時はアクセストークンを再取得して1回だけリトライし成功する", async () => {
|
|
await withTempLogFile(async (logFilePath) => {
|
|
const logger = fakeLogger();
|
|
logger.currentLogFilePath = () => logFilePath;
|
|
const uploadCalls = [];
|
|
let refreshCalls = 0;
|
|
const drive = {
|
|
ensureFolder: async () => ({ fileId: "logs-folder" }),
|
|
uploadFile: async (token) => {
|
|
uploadCalls.push(token);
|
|
if (uploadCalls.length === 1) {
|
|
throw new Error("アップロード失敗: 401 UNAUTHORIZED");
|
|
}
|
|
return { fileId: "f1" };
|
|
},
|
|
};
|
|
const getUserAccessToken = async () => {
|
|
refreshCalls += 1;
|
|
return `fresh-token-${refreshCalls}`;
|
|
};
|
|
|
|
await uploadLogFile(
|
|
{ accessToken: "expired-token", sharedriveId: "drive-1", backupFolderId: "folder-1" },
|
|
{ logger, drive, getUserAccessToken }
|
|
);
|
|
|
|
assert.deepEqual(uploadCalls, ["expired-token", "fresh-token-1"]);
|
|
assert.equal(refreshCalls, 1);
|
|
assert.ok(logger.warnings.some((m) => m.includes("401")));
|
|
assert.ok(logger.infos.some((m) => m.includes("ログファイルアップロード成功")));
|
|
assert.equal(logger.errors.length, 0);
|
|
});
|
|
});
|
|
|
|
test("401エラーでリトライも失敗した場合は失敗ログを出す", async () => {
|
|
await withTempLogFile(async (logFilePath) => {
|
|
const logger = fakeLogger();
|
|
logger.currentLogFilePath = () => logFilePath;
|
|
const drive = {
|
|
ensureFolder: async () => ({ fileId: "logs-folder" }),
|
|
uploadFile: async () => {
|
|
throw new Error("アップロード失敗: 401 UNAUTHORIZED");
|
|
},
|
|
};
|
|
const getUserAccessToken = async () => "fresh-token";
|
|
|
|
await uploadLogFile(
|
|
{ accessToken: "expired-token", sharedriveId: "drive-1", backupFolderId: "folder-1" },
|
|
{ logger, drive, getUserAccessToken }
|
|
);
|
|
|
|
assert.ok(logger.errors.some((m) => m.includes("リトライ後")));
|
|
});
|
|
});
|
|
|
|
test("401以外のエラーはリトライせず失敗ログを出す", async () => {
|
|
await withTempLogFile(async (logFilePath) => {
|
|
const logger = fakeLogger();
|
|
logger.currentLogFilePath = () => logFilePath;
|
|
let refreshCalls = 0;
|
|
const drive = {
|
|
ensureFolder: async () => ({ fileId: "logs-folder" }),
|
|
uploadFile: async () => {
|
|
throw new Error("アップロード失敗: 500 Internal Server Error");
|
|
},
|
|
};
|
|
const getUserAccessToken = async () => {
|
|
refreshCalls += 1;
|
|
return "fresh-token";
|
|
};
|
|
|
|
await uploadLogFile(
|
|
{ accessToken: "token-1", sharedriveId: "drive-1", backupFolderId: "folder-1" },
|
|
{ logger, drive, getUserAccessToken }
|
|
);
|
|
|
|
assert.equal(refreshCalls, 0);
|
|
assert.ok(logger.errors.some((m) => m.includes("ログファイルアップロード失敗")));
|
|
});
|
|
});
|
|
|
|
test("isUnauthorizedError: 401を含むメッセージを検知する", () => {
|
|
assert.equal(isUnauthorizedError(new Error("失敗: 401 UNAUTHORIZED")), true);
|
|
assert.equal(isUnauthorizedError(new Error("失敗: 500 Internal Server Error")), false);
|
|
});
|