balena-settings-storage
Version:
Balena settings storage utilities
199 lines (163 loc) • 5.61 kB
text/typescript
import * as chai from 'chai';
import { expect } from 'chai';
import * as sinon from 'sinon';
import * as chaiAsPromised from 'chai-as-promised';
import { BalenaSettingsPermissionError } from 'balena-errors';
chai.use(chaiAsPromised);
import { createStorage } from '../lib/stores/local-storage';
import { getStorage } from '..';
const IS_BROWSER = typeof window !== 'undefined';
let dataDirectory: string | undefined;
let fs: typeof import('fs');
let path: typeof import('path');
if (!IS_BROWSER) {
// tslint:disable no-var-requires
fs = require('fs');
path = require('path');
const settings =
require('balena-settings-client') as typeof import('balena-settings-client');
dataDirectory = settings.get<string>('dataDirectory');
}
const localStorage = createStorage(dataDirectory);
const storage = getStorage({ dataDirectory });
// tslint:disable no-unused-expression
describe('Storage:', () => {
beforeEach(() => storage.clear());
after(() => storage.clear());
describe('given numbers', () => {
it('should be able to save a float number', () =>
storage.set('pi', 3.14).then(() => {
return expect(storage.get('pi')).to.eventually.equal(3.14);
}));
it('should be able to save an integer number', () =>
storage.set('age', 34).then(() => {
return expect(storage.get('age')).to.eventually.equal(34);
}));
it('should be able to save a string number containin numbers as a string', () =>
storage.set('pi', 'pi=3.14').then(() => {
return expect(storage.get('pi')).to.eventually.equal('pi=3.14');
}));
});
describe('given objects', () => {
it('should be able to save a plain object', () =>
storage.set('pi', { value: 3.14 }).then(() => {
return expect(storage.get('pi')).to.eventually.deep.equal({
value: 3.14,
});
}));
it('should be able to save an empty object', () =>
storage.set('empty', {}).then(() => {
return expect(storage.get('empty')).to.eventually.deep.equal({});
}));
});
describe('.set()', () => {
describe('given a key does not exist', () => {
it('should be able to set a value', () => {
return expect(storage.get('foobar'))
.to.eventually.equal(undefined)
.then(() => storage.set('foobar', 'Hello'))
.then(() => {
return expect(storage.get('foobar')).to.eventually.equal('Hello');
});
});
});
describe('given a key already exist', () => {
beforeEach(() => storage.set('foobar', 'Hello'));
afterEach(() => storage.remove('foobar'));
it('should be able to change the value', () => {
return expect(storage.get('foobar'))
.to.eventually.equal('Hello')
.then(() => storage.set('foobar', 'World'))
.then(() =>
expect(storage.get('foobar')).to.eventually.equal('World'),
);
});
});
});
describe('.get()', () => {
describe('given a key does not exist', () => {
it('should eventually be undefined', () =>
expect(storage.get('foobar')).to.eventually.equal(undefined));
});
describe('given a key already exist', () => {
beforeEach(() => storage.set('foobar', 'Hello'));
it('should eventually be the value', () =>
expect(storage.get('foobar')).to.eventually.equal('Hello'));
});
describe('given getItem throws an error', () => {
let getItemStub: any;
beforeEach(() => {
getItemStub = sinon.stub(localStorage, 'getItem');
getItemStub.throws(new Error('ENOENT'));
});
afterEach(() => {
getItemStub.restore();
});
it('should eventually be undefined', () =>
expect(storage.get('foobar')).to.eventually.equal(undefined));
});
describe('given an externally saved value', () => {
// this test is node-specific
if (IS_BROWSER) {
return;
}
describe('with expected file access', () => {
let fooPath: string;
beforeEach(() => {
fooPath = path.join(dataDirectory!, 'foo');
fs.writeFileSync(fooPath, 'hello world');
});
afterEach(() => {
fs.unlinkSync(fooPath);
});
it('should be able to read back', () =>
expect(storage.get('foo')).to.eventually.equal('hello world'));
});
describe('with no read access', () => {
let fsReadFileStub: any;
beforeEach(() => {
fsReadFileStub = sinon.stub(fs.promises, 'readFile');
fsReadFileStub.rejects({ code: 'EACCES' });
});
afterEach(() => {
fsReadFileStub.restore();
});
it('should raise an error', () => {
return expect(storage.get('bar')).to.eventually.be.rejectedWith(
BalenaSettingsPermissionError,
);
});
});
});
});
describe('.has()', () => {
describe('given a key does not exist', () => {
it('should eventually be false', () =>
expect(storage.has('foobar')).to.eventually.equal(false));
});
describe('given a key already exist', () => {
beforeEach(() => storage.set('foobar', 'Hello'));
it('should eventually be true', () =>
expect(storage.has('foobar')).to.eventually.equal(true));
});
});
describe('.remove()', () => {
describe('given a key does not exist', () => {
it('should do nothing', () => {
expect(storage.has('foobar')).to.eventually.equal(false);
return storage
.remove('foobar')
.then(() => expect(storage.has('foobar')).to.eventually.equal(false));
});
});
describe('given a key already exist', () => {
beforeEach(() => storage.set('foobar', 'Hello'));
it('should remove the key', () => {
return expect(storage.has('foobar'))
.to.eventually.equal(true)
.then(() => storage.remove('foobar'))
.then(() => expect(storage.has('foobar')).to.eventually.equal(false));
});
});
});
});