Skip to content

Commit c958891

Browse files
committed
test: Improve coverage
1 parent becc3a8 commit c958891

1 file changed

Lines changed: 184 additions & 26 deletions

File tree

packages/project/test/lib/cache/CacheCleanup.js

Lines changed: 184 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,20 @@ import test from "ava";
22
import path from "node:path";
33
import fs from "node:fs/promises";
44
import {rimraf} from "rimraf";
5-
import {cleanCache} from "../../../lib/cache/CacheCleanup.js";
5+
import {cleanCache, getCacheInfo} from "../../../lib/cache/CacheCleanup.js";
66

77
const TEST_DIR = path.join(import.meta.dirname, "..", "..", "tmp", "CacheCleanup");
88

99
test.after.always(async () => {
1010
await rimraf(TEST_DIR).catch(() => {});
1111
});
1212

13-
/**
14-
* Create a unique test directory for each test.
15-
*
16-
* @param {object} t AVA test context
17-
* @returns {string} Path to the ui5DataDir fixture
18-
*/
1913
function createTestDir(t) {
2014
const dir = path.join(TEST_DIR, `test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
2115
t.context.ui5DataDir = dir;
2216
return dir;
2317
}
2418

25-
/**
26-
* Create a framework package fixture.
27-
*
28-
* @param {string} ui5DataDir Base data directory
29-
* @param {string} scope Package scope (e.g., "@openui5")
30-
* @param {string} name Package name (e.g., "sap.ui.core")
31-
* @param {string} version Version string
32-
* @param {object} [options]
33-
* @param {Date} [options.mtime] Custom mtime for the package file
34-
* @returns {Promise<void>}
35-
*/
3619
async function createPackage(ui5DataDir, scope, name, version, {mtime} = {}) {
3720
const pkgDir = path.join(ui5DataDir, "framework", "packages", scope, name, version);
3821
await fs.mkdir(pkgDir, {recursive: true});
@@ -43,7 +26,7 @@ async function createPackage(ui5DataDir, scope, name, version, {mtime} = {}) {
4326
}
4427
}
4528

46-
// ===== cleanCache: empty/nonexistent dir =====
29+
// ===== cleanCache tests =====
4730

4831
test("cleanCache: returns empty result for nonexistent directory", async (t) => {
4932
const result = await cleanCache({ui5DataDir: "/tmp/nonexistent-ui5-dir-test"});
@@ -52,8 +35,6 @@ test("cleanCache: returns empty result for nonexistent directory", async (t) =>
5235
t.deepEqual(result.entries, []);
5336
});
5437

55-
// ===== cleanCache: clean all =====
56-
5738
test("cleanCache: clean all removes framework packages", async (t) => {
5839
const ui5DataDir = createTestDir(t);
5940
await createPackage(ui5DataDir, "@openui5", "sap.ui.core", "1.120.0");
@@ -67,14 +48,11 @@ test("cleanCache: clean all removes framework packages", async (t) => {
6748
t.is(frameworkEntries[0].path, "framework");
6849
});
6950

70-
// ===== cleanCache: build cache (full clean) =====
71-
7251
test("cleanCache: clean all clears buildCache database", async (t) => {
7352
const ui5DataDir = createTestDir(t);
7453
const buildCacheDir = path.join(ui5DataDir, "buildCache", "v0_7");
7554
await fs.mkdir(buildCacheDir, {recursive: true});
7655

77-
// Create a real SQLite database with tables and some data
7856
const {DatabaseSync} = await import("node:sqlite");
7957
const dbPath = path.join(buildCacheDir, "cache.db");
8058
const db = new DatabaseSync(dbPath);
@@ -95,15 +73,195 @@ test("cleanCache: clean all clears buildCache database", async (t) => {
9573
const buildCacheEntry = result.entries.find((e) => e.type === "buildCache");
9674
t.truthy(buildCacheEntry);
9775

98-
// Verify directory and DB file still exist
9976
await fs.access(buildCacheDir);
10077
await fs.access(dbPath);
10178

102-
// Verify tables are empty
10379
const dbAfter = new DatabaseSync(dbPath);
10480
const contentCount = dbAfter.prepare("SELECT COUNT(*) as count FROM content").get().count;
10581
const indexCount = dbAfter.prepare("SELECT COUNT(*) as count FROM index_cache").get().count;
10682
t.is(contentCount, 0);
10783
t.is(indexCount, 0);
10884
dbAfter.close();
10985
});
86+
87+
test("cleanCache: skips empty framework directory", async (t) => {
88+
const ui5DataDir = createTestDir(t);
89+
const frameworkDir = path.join(ui5DataDir, "framework");
90+
await fs.mkdir(frameworkDir, {recursive: true});
91+
92+
const result = await cleanCache({ui5DataDir});
93+
94+
t.is(result.totalCount, 0);
95+
const frameworkEntries = result.entries.filter((e) => e.type === "framework");
96+
t.is(frameworkEntries.length, 0);
97+
});
98+
99+
test("cleanCache: cleans both framework and build cache", async (t) => {
100+
const ui5DataDir = createTestDir(t);
101+
102+
await createPackage(ui5DataDir, "@openui5", "sap.ui.core", "1.120.0");
103+
104+
const buildCacheDir = path.join(ui5DataDir, "buildCache", "v0_7");
105+
await fs.mkdir(buildCacheDir, {recursive: true});
106+
const {DatabaseSync} = await import("node:sqlite");
107+
const dbPath = path.join(buildCacheDir, "cache.db");
108+
const db = new DatabaseSync(dbPath);
109+
db.exec(`
110+
CREATE TABLE content (integrity TEXT);
111+
CREATE TABLE index_cache (project_id TEXT);
112+
CREATE TABLE stage_metadata (project_id TEXT);
113+
CREATE TABLE task_metadata (project_id TEXT);
114+
CREATE TABLE result_metadata (project_id TEXT);
115+
`);
116+
db.exec("INSERT INTO content VALUES ('test')");
117+
db.close();
118+
119+
const result = await cleanCache({ui5DataDir});
120+
121+
t.true(result.totalCount >= 1); // At least framework
122+
t.truthy(result.entries.find((e) => e.type === "framework"));
123+
t.true(result.totalSize > 0);
124+
// Build cache may also be cleaned
125+
if (result.totalCount === 2) {
126+
t.truthy(result.entries.find((e) => e.type === "buildCache"));
127+
}
128+
});
129+
130+
test("cleanCache: handles corrupted database gracefully", async (t) => {
131+
const ui5DataDir = createTestDir(t);
132+
const buildCacheDir = path.join(ui5DataDir, "buildCache", "v0_7");
133+
await fs.mkdir(buildCacheDir, {recursive: true});
134+
135+
await fs.writeFile(path.join(buildCacheDir, "cache.db"), "not a valid database");
136+
137+
const result = await cleanCache({ui5DataDir});
138+
139+
t.pass();
140+
const buildEntries = result.entries.filter((e) => e.type === "buildCache");
141+
t.is(buildEntries.length, 0);
142+
});
143+
144+
// ===== getCacheInfo tests =====
145+
146+
test("getCacheInfo: returns empty array for nonexistent directory", async (t) => {
147+
const items = await getCacheInfo({ui5DataDir: "/tmp/nonexistent-ui5-dir-test"});
148+
t.deepEqual(items, []);
149+
});
150+
151+
test("getCacheInfo: detects framework cache with size", async (t) => {
152+
const ui5DataDir = createTestDir(t);
153+
await createPackage(ui5DataDir, "@openui5", "sap.ui.core", "1.120.0");
154+
155+
const items = await getCacheInfo({ui5DataDir});
156+
157+
const frameworkItem = items.find((item) => item.path === "framework/");
158+
t.truthy(frameworkItem);
159+
t.true(frameworkItem.size > 0);
160+
t.is(frameworkItem.type, "directory");
161+
});
162+
163+
test("getCacheInfo: skips empty framework directory", async (t) => {
164+
const ui5DataDir = createTestDir(t);
165+
const frameworkDir = path.join(ui5DataDir, "framework");
166+
await fs.mkdir(frameworkDir, {recursive: true});
167+
168+
const items = await getCacheInfo({ui5DataDir});
169+
170+
const frameworkItem = items.find((item) => item.path === "framework/");
171+
t.falsy(frameworkItem);
172+
});
173+
174+
test("getCacheInfo: detects build cache with records", async (t) => {
175+
const ui5DataDir = createTestDir(t);
176+
const buildCacheDir = path.join(ui5DataDir, "buildCache", "v0_7");
177+
await fs.mkdir(buildCacheDir, {recursive: true});
178+
179+
const {DatabaseSync} = await import("node:sqlite");
180+
const dbPath = path.join(buildCacheDir, "cache.db");
181+
const db = new DatabaseSync(dbPath);
182+
db.exec(`
183+
CREATE TABLE content (integrity TEXT PRIMARY KEY, data BLOB);
184+
CREATE TABLE index_cache (project_id TEXT, build_signature TEXT, kind TEXT, data BLOB);
185+
CREATE TABLE stage_metadata
186+
(project_id TEXT, build_signature TEXT, stage_id TEXT, stage_signature TEXT, data BLOB);
187+
CREATE TABLE task_metadata (project_id TEXT, build_signature TEXT, task_name TEXT, type TEXT, data BLOB);
188+
CREATE TABLE result_metadata (project_id TEXT, build_signature TEXT, stage_signature TEXT, data BLOB);
189+
`);
190+
db.exec("INSERT INTO content VALUES ('test-integrity', 'test-data')");
191+
db.close();
192+
193+
const items = await getCacheInfo({ui5DataDir});
194+
195+
const buildItem = items.find((item) => item.type === "database");
196+
t.truthy(buildItem);
197+
t.is(buildItem.path, "buildCache/v0_7 (database records)");
198+
t.true(buildItem.size > 0);
199+
});
200+
201+
test("getCacheInfo: skips build cache with no records", async (t) => {
202+
const ui5DataDir = createTestDir(t);
203+
const buildCacheDir = path.join(ui5DataDir, "buildCache", "v0_7");
204+
await fs.mkdir(buildCacheDir, {recursive: true});
205+
206+
const {DatabaseSync} = await import("node:sqlite");
207+
const dbPath = path.join(buildCacheDir, "cache.db");
208+
const db = new DatabaseSync(dbPath);
209+
db.exec(`
210+
CREATE TABLE content (integrity TEXT PRIMARY KEY, data BLOB);
211+
CREATE TABLE index_cache (project_id TEXT, build_signature TEXT, kind TEXT, data BLOB);
212+
CREATE TABLE stage_metadata
213+
(project_id TEXT, build_signature TEXT, stage_id TEXT, stage_signature TEXT, data BLOB);
214+
CREATE TABLE task_metadata (project_id TEXT, build_signature TEXT, task_name TEXT, type TEXT, data BLOB);
215+
CREATE TABLE result_metadata (project_id TEXT, build_signature TEXT, stage_signature TEXT, data BLOB);
216+
`);
217+
db.close();
218+
219+
const items = await getCacheInfo({ui5DataDir});
220+
221+
const buildItem = items.find((item) => item.type === "database");
222+
t.falsy(buildItem);
223+
});
224+
225+
test("getCacheInfo: handles corrupted database gracefully", async (t) => {
226+
const ui5DataDir = createTestDir(t);
227+
const buildCacheDir = path.join(ui5DataDir, "buildCache", "v0_7");
228+
await fs.mkdir(buildCacheDir, {recursive: true});
229+
230+
await fs.writeFile(path.join(buildCacheDir, "cache.db"), "not a valid database");
231+
232+
const items = await getCacheInfo({ui5DataDir});
233+
234+
t.pass();
235+
const buildItem = items.find((item) => item.type === "database");
236+
t.falsy(buildItem);
237+
});
238+
239+
test("getCacheInfo: detects both framework and build cache", async (t) => {
240+
const ui5DataDir = createTestDir(t);
241+
242+
await createPackage(ui5DataDir, "@openui5", "sap.ui.core", "1.120.0");
243+
244+
const buildCacheDir = path.join(ui5DataDir, "buildCache", "v0_7");
245+
await fs.mkdir(buildCacheDir, {recursive: true});
246+
const {DatabaseSync} = await import("node:sqlite");
247+
const dbPath = path.join(buildCacheDir, "cache.db");
248+
const db = new DatabaseSync(dbPath);
249+
db.exec(`
250+
CREATE TABLE content (integrity TEXT);
251+
CREATE TABLE index_cache (project_id TEXT);
252+
CREATE TABLE stage_metadata (project_id TEXT);
253+
CREATE TABLE task_metadata (project_id TEXT);
254+
CREATE TABLE result_metadata (project_id TEXT);
255+
`);
256+
db.exec("INSERT INTO content VALUES ('test')");
257+
db.close();
258+
259+
const items = await getCacheInfo({ui5DataDir});
260+
261+
t.true(items.length >= 1); // At least framework
262+
t.truthy(items.find((item) => item.path === "framework/"));
263+
// Build cache may also be detected
264+
if (items.length === 2) {
265+
t.truthy(items.find((item) => item.type === "database"));
266+
}
267+
});

0 commit comments

Comments
 (0)