Skip to content

Commit 693bc07

Browse files
committed
feat(onboarding): update OnboardingTracker to support dynamic OS version path
- Refactored `OnboardingTracker` to utilize a configurable OS version file path based on the data directory. - Enhanced tests to verify behavior when the data directory is unavailable, ensuring fallback to the default version path. - Updated related logic to improve version tracking and persistence during application bootstrap. This update improves flexibility in OS version management and enhances the reliability of onboarding processes.
1 parent fcd1fa0 commit 693bc07

File tree

2 files changed

+33
-8
lines changed

2 files changed

+33
-8
lines changed

api/src/unraid-api/config/api-config.test.ts

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ describe('ApiConfigPersistence', () => {
106106

107107
describe('OnboardingTracker', () => {
108108
const trackerPath = path.join(PATHS_CONFIG_MODULES, 'onboarding-tracker.json');
109+
const dataDir = '/tmp/unraid-data';
110+
const versionFilePath = path.join(dataDir, 'unraid-version');
109111
let configService: ConfigService;
110112
let setMock: ReturnType<typeof vi.fn>;
111113
let configStore: Record<string, unknown>;
@@ -115,6 +117,7 @@ describe('OnboardingTracker', () => {
115117
setMock = vi.fn((key: string, value: unknown) => {
116118
configStore[key] = value;
117119
});
120+
configStore['PATHS_UNRAID_DATA'] = dataDir;
118121
configService = {
119122
set: setMock,
120123
get: vi.fn((key: string) => configStore[key]),
@@ -127,7 +130,7 @@ describe('OnboardingTracker', () => {
127130

128131
it('defers persisting last seen version until shutdown', async () => {
129132
mockReadFile.mockImplementation(async (filePath) => {
130-
if (filePath === '/etc/unraid-version') {
133+
if (filePath === versionFilePath) {
131134
return 'version="7.2.0-beta.3.4"\n';
132135
}
133136
throw Object.assign(new Error('Not found'), { code: 'ENOENT' });
@@ -154,7 +157,7 @@ describe('OnboardingTracker', () => {
154157

155158
it('does not rewrite when version has not changed', async () => {
156159
mockReadFile.mockImplementation(async (filePath) => {
157-
if (filePath === '/etc/unraid-version') {
160+
if (filePath === versionFilePath) {
158161
return 'version="6.12.0"\n';
159162
}
160163
if (filePath === trackerPath) {
@@ -192,9 +195,25 @@ describe('OnboardingTracker', () => {
192195
expect(mockAtomicWriteFile).not.toHaveBeenCalled();
193196
});
194197

195-
it('keeps previous version available to signal upgrade until shutdown', async () => {
198+
it('falls back to default version path when data directory is unavailable', async () => {
199+
delete configStore['PATHS_UNRAID_DATA'];
200+
196201
mockReadFile.mockImplementation(async (filePath) => {
197202
if (filePath === '/etc/unraid-version') {
203+
return 'version="7.3.0"\n';
204+
}
205+
throw Object.assign(new Error('Not found'), { code: 'ENOENT' });
206+
});
207+
208+
const tracker = new OnboardingTracker(configService);
209+
await tracker.onApplicationBootstrap();
210+
211+
expect(setMock).toHaveBeenCalledWith('onboardingTracker.currentVersion', '7.3.0');
212+
});
213+
214+
it('keeps previous version available to signal upgrade until shutdown', async () => {
215+
mockReadFile.mockImplementation(async (filePath) => {
216+
if (filePath === versionFilePath) {
198217
return 'version="7.1.0"\n';
199218
}
200219
if (filePath === trackerPath) {
@@ -239,7 +258,7 @@ describe('OnboardingTracker', () => {
239258

240259
it('marks onboarding steps complete for the current version without clearing upgrade flag', async () => {
241260
mockReadFile.mockImplementation(async (filePath) => {
242-
if (filePath === '/etc/unraid-version') {
261+
if (filePath === versionFilePath) {
243262
return 'version="7.2.0"\n';
244263
}
245264
if (filePath === trackerPath) {

api/src/unraid-api/config/onboarding-tracker.module.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { PATHS_CONFIG_MODULES } from '@app/environment.js';
1515

1616
const TRACKER_FILE_NAME = 'onboarding-tracker.json';
1717
const CONFIG_PREFIX = 'onboardingTracker';
18-
const OS_VERSION_FILE_PATH = '/etc/unraid-version';
18+
const DEFAULT_OS_VERSION_FILE_PATH = '/etc/unraid-version';
1919

2020
type CompletedStepState = {
2121
version: string;
@@ -41,8 +41,14 @@ export class OnboardingTracker implements OnApplicationBootstrap, OnApplicationS
4141
private state: TrackerState = {};
4242
private sessionLastTrackedVersion?: string;
4343
private currentVersion?: string;
44+
private readonly versionFilePath: string;
4445

45-
constructor(private readonly configService: ConfigService) {}
46+
constructor(private readonly configService: ConfigService) {
47+
const unraidDataDir = this.configService.get<string>('PATHS_UNRAID_DATA');
48+
this.versionFilePath = unraidDataDir
49+
? path.join(unraidDataDir, 'unraid-version')
50+
: DEFAULT_OS_VERSION_FILE_PATH;
51+
}
4652

4753
async onApplicationBootstrap() {
4854
this.currentVersion = await this.readCurrentVersion();
@@ -164,11 +170,11 @@ export class OnboardingTracker implements OnApplicationBootstrap, OnApplicationS
164170

165171
private async readCurrentVersion(): Promise<string | undefined> {
166172
try {
167-
const contents = await readFile(OS_VERSION_FILE_PATH, 'utf8');
173+
const contents = await readFile(this.versionFilePath, 'utf8');
168174
const match = contents.match(/^\s*version\s*=\s*"([^"]+)"\s*$/m);
169175
return match?.[1]?.trim() || undefined;
170176
} catch (error) {
171-
this.logger.error(error, `Failed to read current OS version from ${OS_VERSION_FILE_PATH}`);
177+
this.logger.error(error, `Failed to read current OS version from ${this.versionFilePath}`);
172178
return undefined;
173179
}
174180
}

0 commit comments

Comments
 (0)