Allow semver comparison on l4t versions in contracts

We add an implicit .0 to the end of l4t versions which do not fulfill
semver, which allows us to always match using comparison operators, such
as < and <=.

Change-type: minor
Signed-off-by: Cameron Diver <cameron@balena.io>
This commit is contained in:
Cameron Diver 2020-03-06 10:28:23 +00:00
parent 7d47661928
commit 5c50f656c3
2 changed files with 122 additions and 23 deletions

View File

@ -69,7 +69,15 @@ export async function getL4tVersion(): Promise<string | undefined> {
return;
}
return match[1];
let res = match[1];
if (match[2] == null) {
// We were only provided with 2 version numbers
// We add a .0 onto the end, to allow always being
// able to use semver comparisons
res += '.0';
}
return res;
} catch (e) {
log.error('Could not detect l4t version! Error: ', e);
return;

View File

@ -410,36 +410,127 @@ describe('Container contracts', () => {
});
describe('L4T version detection', () => {
it('should correctly parse L4T version strings', async () => {
let execStub = stub(child_process, 'exec').returns(
Promise.resolve([
Buffer.from('4.9.140-l4t-r32.2+g3dcbed5'),
Buffer.from(''),
]),
);
expect(await osRelease.getL4tVersion()).to.equal('32.2');
expect(execStub.callCount).to.equal(1);
execStub.restore();
let execStub: SinonStub;
const seedExec = (version: string) => {
execStub = stub(child_process, 'exec').returns(
Promise.resolve([
Buffer.from('4.4.38-l4t-r28.2+g174510d'),
Buffer.from(''),
]),
Promise.resolve([Buffer.from(version), Buffer.from('')]),
);
expect(await osRelease.getL4tVersion()).to.equal('28.2');
};
afterEach(() => {
execStub.restore();
});
it('should correctly parse L4T version strings', async () => {
seedExec('4.9.140-l4t-r32.2+g3dcbed5');
expect(await osRelease.getL4tVersion()).to.equal('32.2.0');
expect(execStub.callCount).to.equal(1);
execStub.restore();
seedExec('4.4.38-l4t-r28.2+g174510d');
expect(await osRelease.getL4tVersion()).to.equal('28.2.0');
expect(execStub.callCount).to.equal(1);
});
it('should correctly handle l4t versions which contain three numbers', async () => {
seedExec('4.4.38-l4t-r32.3.1+g174510d');
expect(await osRelease.getL4tVersion()).to.equal('32.3.1');
expect(execStub.callCount).to.equal(1);
});
it('should return undefined when there is no l4t string in uname', async () => {
const execStub = stub(child_process, 'exec').returns(
Promise.resolve([Buffer.from('4.18.14-yocto-standard'), Buffer.from('')]),
);
seedExec('4.18.14-yocto-standard');
expect(await osRelease.getL4tVersion()).to.be.undefined;
execStub.restore();
});
describe('L4T comparison', () => {
it('should allow semver matching even when l4t does not fulfill semver', async () => {
seedExec('4.4.38-l4t-r31.0');
expect(
await containerContractsFulfilled({
service: {
contract: {
type: 'sw.container',
slug: 'user-container',
requires: [
{
type: 'sw.l4t',
version: '>=31.0.0',
},
],
},
optional: false,
},
}),
)
.to.have.property('valid')
.that.equals(true);
expect(
await containerContractsFulfilled({
service: {
contract: {
type: 'sw.container',
slug: 'user-container',
requires: [
{
type: 'sw.l4t',
version: '<31.0.0',
},
],
},
optional: false,
},
}),
)
.to.have.property('valid')
.that.equals(false);
});
it('should allow semver matching when l4t does fulfill semver', async () => {
seedExec('4.4.38-l4t-r31.0.1');
expect(
await containerContractsFulfilled({
service: {
contract: {
type: 'sw.container',
slug: 'user-container',
requires: [
{
type: 'sw.l4t',
version: '>=31.0.0',
},
],
},
optional: false,
},
}),
)
.to.have.property('valid')
.that.equals(true);
expect(
await containerContractsFulfilled({
service: {
contract: {
type: 'sw.container',
slug: 'user-container',
requires: [
{
type: 'sw.l4t',
version: '<31.0.0',
},
],
},
optional: false,
},
}),
)
.to.have.property('valid')
.that.equals(false);
});
});
});