balena-supervisor/test/03-config.spec.coffee
Cameron Diver 39d8ac0133
Change config function providers to be mutable
Also change logsChannelSecret value to be queried with the api backend,
so that logs are not shared between instances. This has been implemented
as the first config function provider with mutability.

Change-type: minor
Closes: #675
Signed-off-by: Cameron Diver <cameron@resin.io>
2018-06-26 14:02:25 +01:00

134 lines
4.7 KiB
CoffeeScript

prepare = require './lib/prepare'
Promise = require 'bluebird'
m = require 'mochainon'
{ expect } = m.chai
fs = Promise.promisifyAll(require('fs'))
m.chai.use(require('chai-events'))
DB = require('../src/db')
Config = require('../src/config')
constants = require('../src/lib/constants')
describe 'Config', ->
before ->
prepare()
@db = new DB()
@conf = new Config({ @db })
@initialization = @db.init().then =>
@conf.init()
it 'uses the correct config.json path', ->
expect(@conf.configJsonBackend.path()).to.eventually.equal('test/data/config.json')
it 'uses the correct config.json path from the root mount when passed as argument to the constructor', ->
conf2 = new Config({ @db, configPath: '/foo.json' })
expect(conf2.configJsonBackend.path()).to.eventually.equal('test/data/foo.json')
it 'initializes correctly', ->
expect(@initialization).to.be.fulfilled
it 'reads and exposes values from the config.json', ->
promise = @conf.get('applicationId')
expect(promise).to.eventually.equal(78373)
it 'allows reading several values in one getMany call', ->
promise = @conf.getMany([ 'applicationId', 'apiEndpoint' ])
expect(promise).to.eventually.deep.equal({ applicationId: 78373, apiEndpoint: 'https://api.resin.io' })
it 'provides the correct pubnub config', ->
promise = @conf.get('pubnub')
expect(promise).to.eventually.deep.equal({ subscribe_key: 'foo', publish_key: 'bar', ssl: true })
it 'generates a uuid and stores it in config.json', ->
promise = @conf.get('uuid')
promise2 = fs.readFileAsync('./test/data/config.json').then(JSON.parse).get('uuid')
Promise.all([
expect(promise).to.be.fulfilled
expect(promise2).to.be.fulfilled
]).then ([uuid1, uuid2]) ->
expect(uuid1).to.be.a('string')
expect(uuid1).to.have.lengthOf(62)
expect(uuid1).to.equal(uuid2)
it 'does not allow setting an immutable field', ->
promise = @conf.set({ username: 'somebody else' })
# We catch it to avoid the unhandled error log
promise.catch(->)
expect(promise).to.be.rejected
it 'allows setting both config.json and database fields transparently', ->
promise = @conf.set({ appUpdatePollInterval: 30000, name: 'a new device name' }).then =>
@conf.getMany([ 'appUpdatePollInterval', 'name' ])
expect(promise).to.eventually.deep.equal({ appUpdatePollInterval: 30000, name: 'a new device name' })
it 'allows removing a db key', ->
promise = @conf.remove('name').then =>
@conf.get('name')
expect(promise).to.be.fulfilled
expect(promise).to.eventually.be.undefined
it 'allows deleting a config.json key and returns a default value if none is set', ->
promise = @conf.remove('appUpdatePollInterval').then =>
@conf.get('appUpdatePollInterval')
expect(promise).to.be.fulfilled
expect(promise).to.eventually.equal(60000)
it 'allows deleting a config.json key if it is null', ->
promise = @conf.set('apiKey': null).then =>
@conf.get('apiKey')
expect(promise).to.be.fulfilled
expect(promise).to.eventually.be.undefined
.then ->
fs.readFileAsync('./test/data/config.json')
.then(JSON.parse)
.then (confFromFile) ->
expect(confFromFile).to.not.have.property('apiKey')
it 'does not allow modifying or removing a function value', ->
promise1 = @conf.remove('version')
promise1.catch(->)
promise2 = @conf.set(version: '2.0')
promise2.catch(->)
Promise.all([
expect(promise1).to.be.rejected
expect(promise2).to.be.rejected
])
it 'throws when asked for an unknown key', ->
promise = @conf.get('unknownInvalidValue')
promise.catch(->)
expect(promise).to.be.rejected
it 'emits a change event when values are set', (done) ->
@conf.on 'change', (val) ->
expect(val).to.deep.equal({ name: 'someValue' })
done()
@conf.set({ name: 'someValue' })
expect(@conf).to.emit('change')
return
it "returns an undefined OS variant if it doesn't exist", ->
oldPath = constants.hostOSVersionPath
constants.hostOSVersionPath = 'test/data/etc/os-release-novariant'
@conf.get('osVariant')
.then (osVariant) ->
constants.hostOSVersionPath = oldPath
expect(osVariant).to.be.undefined
describe.only 'Function config providers', ->
it 'should allow setting of mutable function config options', ->
@conf.set({ logsChannelSecret: 'test' })
.then =>
expect(@conf.get('logsChannelSecret')).to.eventually.equal('test')
it 'should allow removing of mutabe function config options', ->
@conf.remove('logsChannelSecret')
.then =>
expect(@conf.get('logsChannelSecret')).to.eventually.be.undefined
it 'should throw if a non-mutable function provider is set', ->
expect(@conf.set({ version: 'some-version' })).to.be.rejected
it 'should throw if a non-mutbale function provider is removed', ->
expect(@conf.remove('version')).to.be.rejected