Skip to content

Commit

Permalink
[feat]: handle non-existing directories as empty if they have a meta …
Browse files Browse the repository at this point in the history
…file (#2999)

* add failing tests

* fix unused import

* now test should fail due to missing meta

* fix tests now

* also add a negative test

* fix neg test
  • Loading branch information
foxriver76 authored Jan 9, 2025
1 parent f005b73 commit d6fa20b
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 9 deletions.
37 changes: 33 additions & 4 deletions packages/controller/test/lib/testFiles.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { TestContext } from '../_Types.js';
import { objectsUtils as utils } from '@iobroker/db-objects-redis';

export function register(it: Mocha.TestFunction, expect: Chai.ExpectStatic, context: TestContext): void {
const testName = `${context.name} ${context.adapterShortName} files: `;
Expand All @@ -10,7 +9,7 @@ export function register(it: Mocha.TestFunction, expect: Chai.ExpectStatic, cont
const fileName = 'testFile.bin';
const dataBinary = Buffer.from('1234');
// create an object of type file first
await context.adapter.setForeignObjectAsync(objId, {
await context.adapter.setForeignObject(objId, {
type: 'meta',
common: {
name: 'Files and more',
Expand Down Expand Up @@ -224,12 +223,42 @@ export function register(it: Mocha.TestFunction, expect: Chai.ExpectStatic, cont
});
});

it(`${testName}should respond with 'ERROR_NOT_FOUND' if calling readDir on a single file`, async () => {
it(`${testName}should read empty directory`, async () => {
const objects = context.objects;
const id = `${testId}.meta.files`;

await objects.setObject(id, {
type: 'meta',
common: { name: 'test', type: 'meta.user' },
native: {},
});

const res = await objects.readDirAsync(id, '');
expect(res).to.be.empty;
});

it(`${testName}should read empty directory with path`, async () => {
const objects = context.objects;
const id = `${testId}.meta.files`;

const res = await objects.readDirAsync(id, 'random/path');
expect(res).to.be.empty;
});

it(`${testName}should not read directory without meta object`, () => {
const objects = context.objects;
const id = `${testId}.meta.nonExisting`;

expect(objects.readDirAsync(id, '')).to.be.eventually.rejectedWith(`${id} is not an object of type "meta"`);
});

it(`${testName}should respond with empty array if calling readDir on a single file`, async () => {
const objects = context.objects;
const fileName = 'dir/notADir.txt';

await objects.writeFileAsync(testId, fileName, 'dataInFile');
expect(objects.readDirAsync(testId, fileName)).to.be.eventually.rejectedWith(utils.ERRORS.ERROR_NOT_FOUND);
const res = await objects.readDirAsync(testId, fileName);
expect(res).to.be.empty;
});

it(`${testName}should read file and prevent path traversing`, done => {
Expand Down
16 changes: 11 additions & 5 deletions packages/db-objects-redis/src/lib/objects/objectsInRedisClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -847,15 +847,15 @@ export class ObjectsInRedisClient {
async validateMetaObject(id: string): Promise<void> {
if (this.existingMetaObjects[id] === undefined) {
// if not cached -> getObject
const obj = await this.getObjectAsync(id);
const obj = await this.getObject(id);
if (obj && obj.type === 'meta') {
this.existingMetaObjects[id] = true;
} else {
this.existingMetaObjects[id] = false;
return Promise.reject(new Error(`${id} is not an object of type "meta"`));
throw new Error(`${id} is not an object of type "meta"`);
}
} else if (this.existingMetaObjects[id] === false) {
return Promise.reject(new Error(`${id} is not an object of type "meta"`));
throw new Error(`${id} is not an object of type "meta"`);
}
}

Expand Down Expand Up @@ -990,7 +990,7 @@ export class ObjectsInRedisClient {
const obj = await this.getObject(id);
if (obj && !obj.acl) {
obj.acl = defaultAcl;
await this.setObjectAsync(id, obj, null);
await this.setObject(id, obj, null);
}
} catch (e) {
this.log.error(
Expand Down Expand Up @@ -1442,6 +1442,12 @@ export class ObjectsInRedisClient {
return tools.maybeCallbackWithError(callback, null, result);
}

try {
await this.validateMetaObject(id);
} catch (e) {
return tools.maybeCallbackWithRedisError(callback, e);
}

const dirID = this.getFileId(id, `${name}${name.length ? '/' : ''}*`);

let keys;
Expand All @@ -1462,7 +1468,7 @@ export class ObjectsInRedisClient {
const dirs: string[] = [];
const deepLevel = baseName.split('/').length;
if (!keys || !keys.length) {
return tools.maybeCallbackWithError(callback, ERRORS.ERROR_NOT_FOUND, []);
return tools.maybeCallbackWithError(callback, null, []);
}
keys = keys.sort().filter(key => {
if (key.endsWith('$%$meta')) {
Expand Down

0 comments on commit d6fa20b

Please sign in to comment.