Use serviceEndpoint compatible with versions
This patch adds a more flexible selection of version in AbstractService. A version will be selected if it's compatible with the 'supportedVersions'. Example: supportedVersions = ['v3.1']; All minor versions above 3.1 will be compatible (3.1.2, 3.2, 3.3 etc) However 4.x will not be compatible Change-Id: Icd540449ebf6a09d9bb7e1d25a85e2dbe787c5a4
This commit is contained in:
parent
cffe4a7c94
commit
beec17c6e4
|
@ -7,7 +7,7 @@ import AbstractService from './util/abstractService';
|
|||
* @ignore
|
||||
*/
|
||||
const supportedKeystoneVersions = [
|
||||
'v3.7'
|
||||
'v3.1'
|
||||
];
|
||||
|
||||
export default class Keystone extends AbstractService {
|
||||
|
@ -59,12 +59,13 @@ export default class Keystone extends AbstractService {
|
|||
}
|
||||
|
||||
/**
|
||||
* Retrieve all the API versions available.
|
||||
* Retrieve all the raw API versions available.
|
||||
*
|
||||
* @returns {Promise.<T>} A promise that will resolve with the list of API versions.
|
||||
* @returns {Promise.<Object[]>} A promise that will resolve with the list of raw versions.
|
||||
* @protected
|
||||
*/
|
||||
versions() {
|
||||
return super.versions()
|
||||
_rawVersions() {
|
||||
return super._rawVersions()
|
||||
.then((versions) => versions.values);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
|
||||
import Http from './http';
|
||||
import Version from './version';
|
||||
import URL from 'url-parse';
|
||||
|
||||
export default class AbstractService {
|
||||
|
@ -64,9 +65,25 @@ export default class AbstractService {
|
|||
/**
|
||||
* Retrieve all the API versions available.
|
||||
*
|
||||
* @returns {Promise.<T>} A promise that will resolve with the list of API versions.
|
||||
* @returns {Promise.<Version[]>} A promise that will resolve with the list of API versions.
|
||||
*/
|
||||
versions() {
|
||||
return this._rawVersions().then((versions) => {
|
||||
return versions.map((rawVersion) => {
|
||||
const version = new Version(rawVersion.id);
|
||||
version.links = rawVersion.links;
|
||||
return version;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all the raw API versions available.
|
||||
*
|
||||
* @returns {Promise.<Object[]>} A promise that will resolve with the list of raw versions.
|
||||
* @protected
|
||||
*/
|
||||
_rawVersions() {
|
||||
return new Promise((resolve, reject) => {
|
||||
let promise = this.http
|
||||
.httpGet(this._endpointUrl)
|
||||
|
@ -92,14 +109,14 @@ export default class AbstractService {
|
|||
/**
|
||||
* Retrieve the API version declaration that is currently in use by this instance.
|
||||
*
|
||||
* @returns {Promise.<T>} A promise that will resolve with the specific API version.
|
||||
* @returns {Promise.<Version>} A promise that will resolve with the specific API version.
|
||||
*/
|
||||
version() {
|
||||
return this
|
||||
.versions()
|
||||
.then((versions) => {
|
||||
for (let version of versions) {
|
||||
if (this.supportedVersions.indexOf(version.id) > -1) {
|
||||
if (this.supportedVersions.find(version.supports)) {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,10 +56,30 @@ export default class Version {
|
|||
return this._patch || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The links of the service
|
||||
*
|
||||
* @returns {Object[]} The list of links.
|
||||
*/
|
||||
get links() {
|
||||
return this._links || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the links of the service
|
||||
*
|
||||
* @param {Object[]} links The links to be set
|
||||
*/
|
||||
set links(links) {
|
||||
if (Array.isArray(links)) {
|
||||
this._links = links;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of a service version.
|
||||
*
|
||||
* @param {String} service The name of the service.
|
||||
* @param {String} [service] The name of the service.
|
||||
* @param {String} versionString The version string for this service.
|
||||
*/
|
||||
constructor(service, versionString) {
|
||||
|
@ -89,6 +109,10 @@ export default class Version {
|
|||
this._minor = parseInt(results[6], 10);
|
||||
this._patch = parseInt(results[8], 10);
|
||||
}
|
||||
this._links = null;
|
||||
|
||||
this.equals = this.equals.bind(this);
|
||||
this.supports = this.supports.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -112,4 +136,38 @@ export default class Version {
|
|||
version.patch === this.patch &&
|
||||
version.service === this.service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies compatibility of this instance to another instance. Major version should be equal and
|
||||
* minor version should be greater or equal than `version` parameter.
|
||||
*
|
||||
* @param {String|Version} version the version to support.
|
||||
* @returns {boolean} True if the version is compatible, otherwise false
|
||||
*/
|
||||
supports(version) {
|
||||
if (!(version instanceof Version)) {
|
||||
if (typeof version === 'string') {
|
||||
version = new Version(version);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const compatibleVersion = version.service === this.service &&
|
||||
version.major === this.major &&
|
||||
version.minor <= this.minor;
|
||||
|
||||
if (compatibleVersion && version.minor === this.minor) {
|
||||
return version.patch <= this.patch;
|
||||
}
|
||||
return compatibleVersion;
|
||||
}
|
||||
|
||||
toString() {
|
||||
let version = `${this.major}.${this.minor}`;
|
||||
if (this.patch) {
|
||||
version = `${version}.${this.patch}`;
|
||||
}
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ describe("Glance", () => {
|
|||
describe("version()", () => {
|
||||
|
||||
const supportedApiVersions = [
|
||||
new Version('image 2.3')
|
||||
new Version('2.4')
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -61,11 +61,7 @@ describe("Glance", () => {
|
|||
configPromise
|
||||
.then((config) => new Glance(config))
|
||||
.then((glance) => glance.version())
|
||||
.then((version) => {
|
||||
|
||||
// Quick sanity check.
|
||||
const apiVersion = new Version('image', version.id);
|
||||
|
||||
.then((apiVersion) => {
|
||||
for (let i = 0; i < supportedApiVersions.length; i++) {
|
||||
let supportedVersion = supportedApiVersions[i];
|
||||
if (apiVersion.equals(supportedVersion)) {
|
||||
|
@ -73,7 +69,7 @@ describe("Glance", () => {
|
|||
return;
|
||||
}
|
||||
}
|
||||
fail("Current devstack glance version is not supported.");
|
||||
fail(`Current devstack glance version (${apiVersion}) is not supported.`);
|
||||
done();
|
||||
})
|
||||
.catch((error) => done.fail(error));
|
||||
|
|
|
@ -43,7 +43,7 @@ describe("Keystone", () => {
|
|||
describe("version()", () => {
|
||||
|
||||
const supportedApiVersions = [
|
||||
new Version('identity 3.7')
|
||||
new Version('3.7')
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -52,11 +52,7 @@ describe("Keystone", () => {
|
|||
*/
|
||||
it("should return a supported version.", (done) => {
|
||||
keystone.version()
|
||||
.then((version) => {
|
||||
|
||||
// Quick sanity check.
|
||||
const apiVersion = new Version('identity', version.id);
|
||||
|
||||
.then((apiVersion) => {
|
||||
for (let i = 0; i < supportedApiVersions.length; i++) {
|
||||
let supportedVersion = supportedApiVersions[i];
|
||||
if (apiVersion.equals(supportedVersion)) {
|
||||
|
@ -64,7 +60,7 @@ describe("Keystone", () => {
|
|||
return;
|
||||
}
|
||||
}
|
||||
fail("Current devstack keystone version is not supported.");
|
||||
fail(`Current devstack keystone version (${apiVersion}) is not supported.`);
|
||||
done();
|
||||
})
|
||||
.catch((response) => response.json()
|
||||
|
|
|
@ -50,7 +50,7 @@ describe("neutron", () => {
|
|||
describe("version()", () => {
|
||||
|
||||
const supportedApiVersions = [
|
||||
new Version('network 2.0')
|
||||
new Version('2.0')
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -61,11 +61,7 @@ describe("neutron", () => {
|
|||
configPromise
|
||||
.then((config) => new Neutron(config))
|
||||
.then((neutron) => neutron.version())
|
||||
.then((version) => {
|
||||
|
||||
// Quick sanity check.
|
||||
const apiVersion = new Version('network', version.id);
|
||||
|
||||
.then((apiVersion) => {
|
||||
for (let i = 0; i < supportedApiVersions.length; i++) {
|
||||
let supportedVersion = supportedApiVersions[i];
|
||||
if (apiVersion.equals(supportedVersion)) {
|
||||
|
@ -73,7 +69,7 @@ describe("neutron", () => {
|
|||
return;
|
||||
}
|
||||
}
|
||||
fail("Current devstack neutron version is not supported.");
|
||||
fail(`Current devstack neutron version (${apiVersion}) is not supported.`);
|
||||
done();
|
||||
})
|
||||
.catch((error) => done.fail(error));
|
||||
|
|
|
@ -31,21 +31,6 @@ describe('Glance', () => {
|
|||
expect(() => new Glance()).toThrow();
|
||||
});
|
||||
|
||||
describe("version()", () => {
|
||||
it("Should return a supported version of the glance API.", (done) => {
|
||||
const glance = new Glance(mockData.config);
|
||||
|
||||
fetchMock.mock(mockData.root());
|
||||
|
||||
glance.version()
|
||||
.then((version) => {
|
||||
expect(version.id).toEqual('v2.3');
|
||||
done();
|
||||
})
|
||||
.catch((error) => done.fail(error));
|
||||
});
|
||||
});
|
||||
|
||||
describe("serviceEndpoint()", () => {
|
||||
it("Should return a valid endpoint to the glance API.", (done) => {
|
||||
const glance = new Glance(mockData.config);
|
||||
|
|
|
@ -75,16 +75,6 @@ function rootResponse() {
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
status: "SUPPORTED",
|
||||
id: "v2.0",
|
||||
links: [
|
||||
{
|
||||
href: `${rootUrl}v2/`,
|
||||
rel: "self"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
status: "SUPPORTED",
|
||||
id: "v1.1",
|
||||
|
|
|
@ -15,43 +15,6 @@ describe('Keystone', () => {
|
|||
expect(() => new Keystone()).toThrow();
|
||||
});
|
||||
|
||||
describe("versions()", () => {
|
||||
|
||||
/**
|
||||
* Keystone needs an explicit test, as it uses a slightly different data format
|
||||
* than other services.
|
||||
*/
|
||||
it("Should return a list of all versions available on this clouds' keystone", (done) => {
|
||||
const keystone = new Keystone(mockData.config);
|
||||
|
||||
fetchMock.mock(mockData.root());
|
||||
|
||||
keystone.versions()
|
||||
.then((versions) => {
|
||||
// Quick sanity check.
|
||||
expect(versions.length).toBe(2);
|
||||
done();
|
||||
})
|
||||
.catch((error) => done.fail(error));
|
||||
});
|
||||
});
|
||||
|
||||
describe("version()", () => {
|
||||
|
||||
it("Should return a supported version of the keystone API.", (done) => {
|
||||
const keystone = new Keystone(mockData.config);
|
||||
|
||||
fetchMock.mock(mockData.root());
|
||||
|
||||
keystone.version()
|
||||
.then((version) => {
|
||||
expect(version.id).toEqual('v3.7');
|
||||
done();
|
||||
})
|
||||
.catch((error) => done.fail(error));
|
||||
});
|
||||
});
|
||||
|
||||
describe("serviceEndpoint()", () => {
|
||||
it("Should return a valid endpoint to the keystone API.", (done) => {
|
||||
const keystone = new Keystone(mockData.config);
|
||||
|
|
|
@ -36,22 +36,6 @@ describe('neutron', () => {
|
|||
}
|
||||
});
|
||||
|
||||
describe("versions()", () => {
|
||||
it("Should return a list of all versions available on this clouds' NEUTRON", (done) => {
|
||||
const neutron = new Neutron(mockData.config);
|
||||
|
||||
fetchMock.mock(mockData.root());
|
||||
|
||||
neutron.versions()
|
||||
.then((versions) => {
|
||||
// Quick sanity check.
|
||||
expect(versions.length).toBe(1);
|
||||
done();
|
||||
})
|
||||
.catch((error) => done.fail(error));
|
||||
});
|
||||
});
|
||||
|
||||
describe("networkList()", () => {
|
||||
let neutron = null;
|
||||
|
||||
|
|
|
@ -53,21 +53,12 @@ describe('AbstractService', () => {
|
|||
service.versions()
|
||||
.then((versions) => {
|
||||
// Quick sanity check.
|
||||
expect(versions.length).toBe(6);
|
||||
done();
|
||||
})
|
||||
.catch((error) => done.fail(error));
|
||||
});
|
||||
|
||||
it("Should return a list of all versions available from this resource", (done) => {
|
||||
const service = new AbstractService(mockData.rootUrl, mockData.versions);
|
||||
|
||||
fetchMock.mock(mockData.rootResponse());
|
||||
|
||||
service.versions()
|
||||
.then((versions) => {
|
||||
// Quick sanity check.
|
||||
expect(versions.length).toBe(6);
|
||||
expect(versions.length).toBe(5);
|
||||
expect(versions[0].major).toEqual(2);
|
||||
expect(versions[0].minor).toEqual(3);
|
||||
expect(versions[0].patch).toEqual(0);
|
||||
expect(versions[0].links).not.toBe(null);
|
||||
expect(versions[0].links[0].href).toEqual('http://example.com/v2/');
|
||||
done();
|
||||
})
|
||||
.catch((error) => done.fail(error));
|
||||
|
@ -84,7 +75,7 @@ describe('AbstractService', () => {
|
|||
service.versions()
|
||||
.then((versions) => {
|
||||
// Quick sanity check.
|
||||
expect(versions.length).toBe(6);
|
||||
expect(versions.length).toBe(5);
|
||||
done();
|
||||
})
|
||||
.catch((error) => done.fail(error));
|
||||
|
@ -132,7 +123,22 @@ describe('AbstractService', () => {
|
|||
|
||||
service.version()
|
||||
.then((version) => {
|
||||
expect(version.id).toEqual('v2.3');
|
||||
expect(version.equals('v2.3')).toBe(true);
|
||||
done();
|
||||
})
|
||||
.catch((error) => done.fail(error));
|
||||
});
|
||||
|
||||
it("Should return the latest compatible version of the service API.", (done) => {
|
||||
const service = new AbstractService(mockData.rootUrl, [
|
||||
'v2.0'
|
||||
]);
|
||||
|
||||
fetchMock.mock(mockData.rootResponse());
|
||||
|
||||
service.version()
|
||||
.then((version) => {
|
||||
expect(version.equals('v2.3')).toBe(true);
|
||||
done();
|
||||
})
|
||||
.catch((error) => done.fail(error));
|
||||
|
|
|
@ -96,4 +96,63 @@ describe('Version', () => {
|
|||
// Other tests...
|
||||
expect(v2.equals({})).toBe(false);
|
||||
});
|
||||
|
||||
it("should test for correct compatibility", () => {
|
||||
const v1 = new Version("compute", "1.3.2");
|
||||
|
||||
// String tests
|
||||
expect(v1.supports("compute 1.0.0")).toBe(true);
|
||||
expect(v1.supports("compute 1.0.1")).toBe(true);
|
||||
expect(v1.supports("compute 1.3.0")).toBe(true);
|
||||
expect(v1.supports("compute 1.3.3")).toBe(false);
|
||||
expect(v1.supports("compute 1.4.0")).toBe(false);
|
||||
expect(v1.supports("compute 2.3.0")).toBe(false);
|
||||
|
||||
// Version tests
|
||||
expect(v1.supports(new Version("compute", "1.0.0"))).toBe(true);
|
||||
expect(v1.supports(new Version("compute", "1.0.1"))).toBe(true);
|
||||
expect(v1.supports(new Version("compute", "1.3.0"))).toBe(true);
|
||||
expect(v1.supports(new Version("compute", "1.3.3"))).toBe(false);
|
||||
expect(v1.supports(new Version("compute", "1.4.0"))).toBe(false);
|
||||
expect(v1.supports(new Version("compute", "2.3.0"))).toBe(false);
|
||||
|
||||
const v2 = new Version("1.3.2");
|
||||
// String tests
|
||||
expect(v2.supports("1.0.0")).toBe(true);
|
||||
expect(v2.supports("1.0.1")).toBe(true);
|
||||
expect(v2.supports("1.3.0")).toBe(true);
|
||||
expect(v2.supports("1.3.3")).toBe(false);
|
||||
expect(v2.supports("1.4.0")).toBe(false);
|
||||
expect(v2.supports("2.3.0")).toBe(false);
|
||||
|
||||
// Version tests
|
||||
expect(v2.supports(new Version("1.0.0"))).toBe(true);
|
||||
expect(v2.supports(new Version("1.0.1"))).toBe(true);
|
||||
expect(v2.supports(new Version("1.3.0"))).toBe(true);
|
||||
expect(v2.supports(new Version("1.3.3"))).toBe(false);
|
||||
expect(v2.supports(new Version("1.4.0"))).toBe(false);
|
||||
expect(v2.supports(new Version("2.3.0"))).toBe(false);
|
||||
});
|
||||
|
||||
it("should store links", () => {
|
||||
const v1 = new Version("compute", "1.3.2");
|
||||
|
||||
expect(v1.links).toBe(null);
|
||||
|
||||
v1.links = 'wrong data';
|
||||
expect(v1.links).toBe(null);
|
||||
|
||||
v1.links = [
|
||||
{
|
||||
href: `http://example.org/v2/`,
|
||||
rel: "self"
|
||||
}
|
||||
];
|
||||
expect(v1.links).not.toBe(null);
|
||||
expect(v1.links.length).toBe(1);
|
||||
expect(v1.links[0]).toEqual({
|
||||
href: "http://example.org/v2/",
|
||||
rel: "self"
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue