fix(kopiaui): adjust handling of default repository (#4561)

- Only create the default repository if no repositories are
  configured.
- Don't open repository window at startup if repositories are
  configured.

This introduces an additional env variable `KOPIA_CUSTOM_APPDATA`
which is used in the tests but could be used in other scenarios as
well.
This commit is contained in:
remigius42
2025-05-17 23:50:51 +02:00
committed by GitHub
parent db71fc3ba7
commit 36a68abc45
3 changed files with 125 additions and 17 deletions

View File

@@ -117,7 +117,7 @@ export function loadConfigs() {
count++;
});
if (!configs["repository"]) {
if (count === 0) {
configs["repository"] = true;
firstRun = true;
}

View File

@@ -21,6 +21,9 @@ let tray = null
let repositoryWindows = {};
let repoIDForWebContents = {};
if (process.env.KOPIA_CUSTOM_APPDATA) {
app.setPath('appData', process.env.KOPIA_CUSTOM_APPDATA);
}
if (isPortableConfig()) {
// in portable mode, write cache under 'repositories'
@@ -435,6 +438,7 @@ app.on('ready', () => {
app.testHooks = {
tray: tray,
showRepoWindow: showRepoWindow,
allConfigs: allConfigs,
}
}
@@ -582,6 +586,5 @@ function updateTrayContextMenu() {
] },
{ label: 'Quit', role: 'quit' },
]);
tray.setContextMenu(Menu.buildFromTemplate(template));
}

View File

@@ -1,9 +1,16 @@
import { test, expect } from '@playwright/test'
import { _electron as electron } from 'playwright'
import fs from 'fs';
import os from 'os';
import path from 'path';
const DEFAULT_REPO_ID = 'repository';
let electronApp
let mainPath
let executablePath
let tmpAppDataDir
function getKopiaUIDir() {
switch (process.platform + "/" + process.arch) {
@@ -44,22 +51,36 @@ function getExecutablePath(kopiauiDir) {
}
}
test.beforeAll(async () => {
const kopiauiDir = getKopiaUIDir();
expect(kopiauiDir).not.toBeNull();
/**
* Creates a temporary application data directory along with the kopia
* directory for testing purposes.
*
* @returns {string} The path to the created temporary directory.
*/
function createTemporaryAppDataDir() {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'kopia-test-'));
fs.mkdirSync(path.join(tmpDir, 'kopia'));
return tmpDir;
}
const mainPath = getMainPath(kopiauiDir);
const executablePath = getExecutablePath(kopiauiDir);
console.log('main path', mainPath);
console.log('executable path', executablePath);
process.env.CI = 'e2e'
process.env.KOPIA_UI_TESTING = '1'
electronApp = await electron.launch({
/**
* Launches a new instance of the Electron app with the given app data directory.
*
* Also captures page errors and console messages and logs them to the console.
*
* @param {string} appDataDir - the path to the app data directory
* @returns {Promise<Electron.App>} - a promise that resolves to the launched app
*/
async function launchApp(appDataDir) {
const electronApp = await electron.launch({
args: [mainPath],
executablePath: executablePath,
env: {
...process.env,
KOPIA_CUSTOM_APPDATA: appDataDir,
}
})
electronApp.on('window', async (page) => {
const filename = page.url()?.split('/').pop()
console.log(`Window opened: ${filename}`)
@@ -73,13 +94,49 @@ test.beforeAll(async () => {
console.log(msg.text())
})
})
return electronApp;
}
/**
* Waits for Kopia to start up by delaying for a specified duration.
*
* @returns {Promise<void>} A promise that resolves after the delay.
*/
function waitForKopiaToStartup() {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, 2500);
});
}
test.beforeAll(() => {
const kopiauiDir = getKopiaUIDir();
expect(kopiauiDir).not.toBeNull();
mainPath = getMainPath(kopiauiDir);
executablePath = getExecutablePath(kopiauiDir);
console.log('main path', mainPath);
console.log('executable path', executablePath);
process.env.CI = 'e2e';
process.env.KOPIA_UI_TESTING = '1';
})
test.beforeEach(async () => {
tmpAppDataDir = createTemporaryAppDataDir();
})
test.afterAll(async () => {
await electronApp.close()
test.afterEach(async () => {
await electronApp.close();
fs.rmSync(tmpAppDataDir, { recursive: true, force: true });
})
test('opens repository window', async () => {
test('opens repository window on first start', async () => {
electronApp = await launchApp(tmpAppDataDir);
await electronApp.evaluate(async ({app}) => {
app.testHooks.showRepoWindow('repository');
});
@@ -100,3 +157,51 @@ test('opens repository window', async () => {
return app.testHooks.tray.closeContextMenu();
})
});
test("adds default repository if no repository is configured", async () => {
electronApp = await launchApp(tmpAppDataDir);
await waitForKopiaToStartup();
const configs = await electronApp.evaluate(async ({app}) => {
return app.testHooks.allConfigs();
})
expect(configs).toStrictEqual([DEFAULT_REPO_ID]);
});
test("doesn't open repository window if the default repository config exists", async () => {
fs.writeFileSync(path.join(tmpAppDataDir, 'kopia', `${DEFAULT_REPO_ID}.config`), '');
electronApp = await launchApp(tmpAppDataDir);
await waitForKopiaToStartup();
const windows = electronApp.windows();
expect(windows).toHaveLength(0);
});
test.describe("when non-default repository config exists", () => {
const NON_DEFAULT_REPO_ID = 'repository-42';
test.beforeEach(async () => {
fs.writeFileSync(path.join(tmpAppDataDir, 'kopia', `${NON_DEFAULT_REPO_ID}.config`), '');
})
test("doesn't open repository window if non-default repository config exists", async () => {
electronApp = await launchApp(tmpAppDataDir);
await waitForKopiaToStartup();
const windows = electronApp.windows();
expect(windows).toHaveLength(0);
});
test("doesn't add default repository", async () => {
electronApp = await launchApp(tmpAppDataDir);
await waitForKopiaToStartup();
const configs = await electronApp.evaluate(async ({app}) => {
return app.testHooks.allConfigs();
})
expect(configs).toStrictEqual([NON_DEFAULT_REPO_ID]);
});
})