summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorentin Ardeois <cardeois@internap.com>2016-11-22 13:51:46 -0500
committerCorentin Ardeois <cardeois@internap.com>2016-11-23 09:53:27 -0500
commitbeec17c6e489ba4ed7af110174fcc0b775c45417 (patch)
treec0a7e018976025177f1b2451222e9933ff290678
parentcffe4a7c94aa579f4211b9b134d2d8bb5c5345a0 (diff)
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
Notes
Notes (review): Code-Review+2: Vitaly Kramskikh <vkramskikh@mirantis.com> Workflow+1: Vitaly Kramskikh <vkramskikh@mirantis.com> Verified+2: Jenkins Submitted-by: Jenkins Submitted-at: Fri, 02 Dec 2016 13:03:22 +0000 Reviewed-on: https://review.openstack.org/400935 Project: openstack/js-openstack-lib Branch: refs/heads/master
-rw-r--r--src/keystone.js11
-rw-r--r--src/util/abstractService.js23
-rw-r--r--src/util/version.js60
-rw-r--r--test/functional/glanceTest.js10
-rw-r--r--test/functional/keystoneTest.js10
-rw-r--r--test/functional/neutronTest.js10
-rw-r--r--test/unit/glanceTest.js15
-rw-r--r--test/unit/helpers/data/versions.js10
-rw-r--r--test/unit/keystoneTest.js37
-rw-r--r--test/unit/neutronTest.js16
-rw-r--r--test/unit/util/abstractServiceTest.js40
-rw-r--r--test/unit/util/versionTest.js59
12 files changed, 176 insertions, 125 deletions
diff --git a/src/keystone.js b/src/keystone.js
index f678f7c..583c0b7 100644
--- a/src/keystone.js
+++ b/src/keystone.js
@@ -7,7 +7,7 @@ import AbstractService from './util/abstractService';
7 * @ignore 7 * @ignore
8 */ 8 */
9const supportedKeystoneVersions = [ 9const supportedKeystoneVersions = [
10 'v3.7' 10 'v3.1'
11]; 11];
12 12
13export default class Keystone extends AbstractService { 13export default class Keystone extends AbstractService {
@@ -59,12 +59,13 @@ export default class Keystone extends AbstractService {
59 } 59 }
60 60
61 /** 61 /**
62 * Retrieve all the API versions available. 62 * Retrieve all the raw API versions available.
63 * 63 *
64 * @returns {Promise.<T>} A promise that will resolve with the list of API versions. 64 * @returns {Promise.<Object[]>} A promise that will resolve with the list of raw versions.
65 * @protected
65 */ 66 */
66 versions() { 67 _rawVersions() {
67 return super.versions() 68 return super._rawVersions()
68 .then((versions) => versions.values); 69 .then((versions) => versions.values);
69 } 70 }
70 71
diff --git a/src/util/abstractService.js b/src/util/abstractService.js
index 517f9e1..501b5e5 100644
--- a/src/util/abstractService.js
+++ b/src/util/abstractService.js
@@ -15,6 +15,7 @@
15 */ 15 */
16 16
17import Http from './http'; 17import Http from './http';
18import Version from './version';
18import URL from 'url-parse'; 19import URL from 'url-parse';
19 20
20export default class AbstractService { 21export default class AbstractService {
@@ -64,9 +65,25 @@ export default class AbstractService {
64 /** 65 /**
65 * Retrieve all the API versions available. 66 * Retrieve all the API versions available.
66 * 67 *
67 * @returns {Promise.<T>} A promise that will resolve with the list of API versions. 68 * @returns {Promise.<Version[]>} A promise that will resolve with the list of API versions.
68 */ 69 */
69 versions() { 70 versions() {
71 return this._rawVersions().then((versions) => {
72 return versions.map((rawVersion) => {
73 const version = new Version(rawVersion.id);
74 version.links = rawVersion.links;
75 return version;
76 });
77 });
78 }
79
80 /**
81 * Retrieve all the raw API versions available.
82 *
83 * @returns {Promise.<Object[]>} A promise that will resolve with the list of raw versions.
84 * @protected
85 */
86 _rawVersions() {
70 return new Promise((resolve, reject) => { 87 return new Promise((resolve, reject) => {
71 let promise = this.http 88 let promise = this.http
72 .httpGet(this._endpointUrl) 89 .httpGet(this._endpointUrl)
@@ -92,14 +109,14 @@ export default class AbstractService {
92 /** 109 /**
93 * Retrieve the API version declaration that is currently in use by this instance. 110 * Retrieve the API version declaration that is currently in use by this instance.
94 * 111 *
95 * @returns {Promise.<T>} A promise that will resolve with the specific API version. 112 * @returns {Promise.<Version>} A promise that will resolve with the specific API version.
96 */ 113 */
97 version() { 114 version() {
98 return this 115 return this
99 .versions() 116 .versions()
100 .then((versions) => { 117 .then((versions) => {
101 for (let version of versions) { 118 for (let version of versions) {
102 if (this.supportedVersions.indexOf(version.id) > -1) { 119 if (this.supportedVersions.find(version.supports)) {
103 return version; 120 return version;
104 } 121 }
105 } 122 }
diff --git a/src/util/version.js b/src/util/version.js
index cb92cd2..2dc1ad4 100644
--- a/src/util/version.js
+++ b/src/util/version.js
@@ -57,9 +57,29 @@ export default class Version {
57 } 57 }
58 58
59 /** 59 /**
60 * The links of the service
61 *
62 * @returns {Object[]} The list of links.
63 */
64 get links() {
65 return this._links || null;
66 }
67
68 /**
69 * Sets the links of the service
70 *
71 * @param {Object[]} links The links to be set
72 */
73 set links(links) {
74 if (Array.isArray(links)) {
75 this._links = links;
76 }
77 }
78
79 /**
60 * Create a new instance of a service version. 80 * Create a new instance of a service version.
61 * 81 *
62 * @param {String} service The name of the service. 82 * @param {String} [service] The name of the service.
63 * @param {String} versionString The version string for this service. 83 * @param {String} versionString The version string for this service.
64 */ 84 */
65 constructor(service, versionString) { 85 constructor(service, versionString) {
@@ -89,6 +109,10 @@ export default class Version {
89 this._minor = parseInt(results[6], 10); 109 this._minor = parseInt(results[6], 10);
90 this._patch = parseInt(results[8], 10); 110 this._patch = parseInt(results[8], 10);
91 } 111 }
112 this._links = null;
113
114 this.equals = this.equals.bind(this);
115 this.supports = this.supports.bind(this);
92 } 116 }
93 117
94 /** 118 /**
@@ -112,4 +136,38 @@ export default class Version {
112 version.patch === this.patch && 136 version.patch === this.patch &&
113 version.service === this.service; 137 version.service === this.service;
114 } 138 }
139
140 /**
141 * Verifies compatibility of this instance to another instance. Major version should be equal and
142 * minor version should be greater or equal than `version` parameter.
143 *
144 * @param {String|Version} version the version to support.
145 * @returns {boolean} True if the version is compatible, otherwise false
146 */
147 supports(version) {
148 if (!(version instanceof Version)) {
149 if (typeof version === 'string') {
150 version = new Version(version);
151 } else {
152 return false;
153 }
154 }
155
156 const compatibleVersion = version.service === this.service &&
157 version.major === this.major &&
158 version.minor <= this.minor;
159
160 if (compatibleVersion && version.minor === this.minor) {
161 return version.patch <= this.patch;
162 }
163 return compatibleVersion;
164 }
165
166 toString() {
167 let version = `${this.major}.${this.minor}`;
168 if (this.patch) {
169 version = `${version}.${this.patch}`;
170 }
171 return version;
172 }
115} 173}
diff --git a/test/functional/glanceTest.js b/test/functional/glanceTest.js
index e64be7f..d6b00a5 100644
--- a/test/functional/glanceTest.js
+++ b/test/functional/glanceTest.js
@@ -50,7 +50,7 @@ describe("Glance", () => {
50 describe("version()", () => { 50 describe("version()", () => {
51 51
52 const supportedApiVersions = [ 52 const supportedApiVersions = [
53 new Version('image 2.3') 53 new Version('2.4')
54 ]; 54 ];
55 55
56 /** 56 /**
@@ -61,11 +61,7 @@ describe("Glance", () => {
61 configPromise 61 configPromise
62 .then((config) => new Glance(config)) 62 .then((config) => new Glance(config))
63 .then((glance) => glance.version()) 63 .then((glance) => glance.version())
64 .then((version) => { 64 .then((apiVersion) => {
65
66 // Quick sanity check.
67 const apiVersion = new Version('image', version.id);
68
69 for (let i = 0; i < supportedApiVersions.length; i++) { 65 for (let i = 0; i < supportedApiVersions.length; i++) {
70 let supportedVersion = supportedApiVersions[i]; 66 let supportedVersion = supportedApiVersions[i];
71 if (apiVersion.equals(supportedVersion)) { 67 if (apiVersion.equals(supportedVersion)) {
@@ -73,7 +69,7 @@ describe("Glance", () => {
73 return; 69 return;
74 } 70 }
75 } 71 }
76 fail("Current devstack glance version is not supported."); 72 fail(`Current devstack glance version (${apiVersion}) is not supported.`);
77 done(); 73 done();
78 }) 74 })
79 .catch((error) => done.fail(error)); 75 .catch((error) => done.fail(error));
diff --git a/test/functional/keystoneTest.js b/test/functional/keystoneTest.js
index 93ac168..c759301 100644
--- a/test/functional/keystoneTest.js
+++ b/test/functional/keystoneTest.js
@@ -43,7 +43,7 @@ describe("Keystone", () => {
43 describe("version()", () => { 43 describe("version()", () => {
44 44
45 const supportedApiVersions = [ 45 const supportedApiVersions = [
46 new Version('identity 3.7') 46 new Version('3.7')
47 ]; 47 ];
48 48
49 /** 49 /**
@@ -52,11 +52,7 @@ describe("Keystone", () => {
52 */ 52 */
53 it("should return a supported version.", (done) => { 53 it("should return a supported version.", (done) => {
54 keystone.version() 54 keystone.version()
55 .then((version) => { 55 .then((apiVersion) => {
56
57 // Quick sanity check.
58 const apiVersion = new Version('identity', version.id);
59
60 for (let i = 0; i < supportedApiVersions.length; i++) { 56 for (let i = 0; i < supportedApiVersions.length; i++) {
61 let supportedVersion = supportedApiVersions[i]; 57 let supportedVersion = supportedApiVersions[i];
62 if (apiVersion.equals(supportedVersion)) { 58 if (apiVersion.equals(supportedVersion)) {
@@ -64,7 +60,7 @@ describe("Keystone", () => {
64 return; 60 return;
65 } 61 }
66 } 62 }
67 fail("Current devstack keystone version is not supported."); 63 fail(`Current devstack keystone version (${apiVersion}) is not supported.`);
68 done(); 64 done();
69 }) 65 })
70 .catch((response) => response.json() 66 .catch((response) => response.json()
diff --git a/test/functional/neutronTest.js b/test/functional/neutronTest.js
index 7deee5f..652499b 100644
--- a/test/functional/neutronTest.js
+++ b/test/functional/neutronTest.js
@@ -50,7 +50,7 @@ describe("neutron", () => {
50 describe("version()", () => { 50 describe("version()", () => {
51 51
52 const supportedApiVersions = [ 52 const supportedApiVersions = [
53 new Version('network 2.0') 53 new Version('2.0')
54 ]; 54 ];
55 55
56 /** 56 /**
@@ -61,11 +61,7 @@ describe("neutron", () => {
61 configPromise 61 configPromise
62 .then((config) => new Neutron(config)) 62 .then((config) => new Neutron(config))
63 .then((neutron) => neutron.version()) 63 .then((neutron) => neutron.version())
64 .then((version) => { 64 .then((apiVersion) => {
65
66 // Quick sanity check.
67 const apiVersion = new Version('network', version.id);
68
69 for (let i = 0; i < supportedApiVersions.length; i++) { 65 for (let i = 0; i < supportedApiVersions.length; i++) {
70 let supportedVersion = supportedApiVersions[i]; 66 let supportedVersion = supportedApiVersions[i];
71 if (apiVersion.equals(supportedVersion)) { 67 if (apiVersion.equals(supportedVersion)) {
@@ -73,7 +69,7 @@ describe("neutron", () => {
73 return; 69 return;
74 } 70 }
75 } 71 }
76 fail("Current devstack neutron version is not supported."); 72 fail(`Current devstack neutron version (${apiVersion}) is not supported.`);
77 done(); 73 done();
78 }) 74 })
79 .catch((error) => done.fail(error)); 75 .catch((error) => done.fail(error));
diff --git a/test/unit/glanceTest.js b/test/unit/glanceTest.js
index f3f794d..898b623 100644
--- a/test/unit/glanceTest.js
+++ b/test/unit/glanceTest.js
@@ -31,21 +31,6 @@ describe('Glance', () => {
31 expect(() => new Glance()).toThrow(); 31 expect(() => new Glance()).toThrow();
32 }); 32 });
33 33
34 describe("version()", () => {
35 it("Should return a supported version of the glance API.", (done) => {
36 const glance = new Glance(mockData.config);
37
38 fetchMock.mock(mockData.root());
39
40 glance.version()
41 .then((version) => {
42 expect(version.id).toEqual('v2.3');
43 done();
44 })
45 .catch((error) => done.fail(error));
46 });
47 });
48
49 describe("serviceEndpoint()", () => { 34 describe("serviceEndpoint()", () => {
50 it("Should return a valid endpoint to the glance API.", (done) => { 35 it("Should return a valid endpoint to the glance API.", (done) => {
51 const glance = new Glance(mockData.config); 36 const glance = new Glance(mockData.config);
diff --git a/test/unit/helpers/data/versions.js b/test/unit/helpers/data/versions.js
index ec6a43e..e637dd3 100644
--- a/test/unit/helpers/data/versions.js
+++ b/test/unit/helpers/data/versions.js
@@ -77,16 +77,6 @@ function rootResponse() {
77 }, 77 },
78 { 78 {
79 status: "SUPPORTED", 79 status: "SUPPORTED",
80 id: "v2.0",
81 links: [
82 {
83 href: `${rootUrl}v2/`,
84 rel: "self"
85 }
86 ]
87 },
88 {
89 status: "SUPPORTED",
90 id: "v1.1", 80 id: "v1.1",
91 links: [ 81 links: [
92 { 82 {
diff --git a/test/unit/keystoneTest.js b/test/unit/keystoneTest.js
index 647cd61..e21f458 100644
--- a/test/unit/keystoneTest.js
+++ b/test/unit/keystoneTest.js
@@ -15,43 +15,6 @@ describe('Keystone', () => {
15 expect(() => new Keystone()).toThrow(); 15 expect(() => new Keystone()).toThrow();
16 }); 16 });
17 17
18 describe("versions()", () => {
19
20 /**
21 * Keystone needs an explicit test, as it uses a slightly different data format
22 * than other services.
23 */
24 it("Should return a list of all versions available on this clouds' keystone", (done) => {
25 const keystone = new Keystone(mockData.config);
26
27 fetchMock.mock(mockData.root());
28
29 keystone.versions()
30 .then((versions) => {
31 // Quick sanity check.
32 expect(versions.length).toBe(2);
33 done();
34 })
35 .catch((error) => done.fail(error));
36 });
37 });
38
39 describe("version()", () => {
40
41 it("Should return a supported version of the keystone API.", (done) => {
42 const keystone = new Keystone(mockData.config);
43
44 fetchMock.mock(mockData.root());
45
46 keystone.version()
47 .then((version) => {
48 expect(version.id).toEqual('v3.7');
49 done();
50 })
51 .catch((error) => done.fail(error));
52 });
53 });
54
55 describe("serviceEndpoint()", () => { 18 describe("serviceEndpoint()", () => {
56 it("Should return a valid endpoint to the keystone API.", (done) => { 19 it("Should return a valid endpoint to the keystone API.", (done) => {
57 const keystone = new Keystone(mockData.config); 20 const keystone = new Keystone(mockData.config);
diff --git a/test/unit/neutronTest.js b/test/unit/neutronTest.js
index 2c802fa..e31f592 100644
--- a/test/unit/neutronTest.js
+++ b/test/unit/neutronTest.js
@@ -36,22 +36,6 @@ describe('neutron', () => {
36 } 36 }
37 }); 37 });
38 38
39 describe("versions()", () => {
40 it("Should return a list of all versions available on this clouds' NEUTRON", (done) => {
41 const neutron = new Neutron(mockData.config);
42
43 fetchMock.mock(mockData.root());
44
45 neutron.versions()
46 .then((versions) => {
47 // Quick sanity check.
48 expect(versions.length).toBe(1);
49 done();
50 })
51 .catch((error) => done.fail(error));
52 });
53 });
54
55 describe("networkList()", () => { 39 describe("networkList()", () => {
56 let neutron = null; 40 let neutron = null;
57 41
diff --git a/test/unit/util/abstractServiceTest.js b/test/unit/util/abstractServiceTest.js
index d819fc0..99f74bb 100644
--- a/test/unit/util/abstractServiceTest.js
+++ b/test/unit/util/abstractServiceTest.js
@@ -53,21 +53,12 @@ describe('AbstractService', () => {
53 service.versions() 53 service.versions()
54 .then((versions) => { 54 .then((versions) => {
55 // Quick sanity check. 55 // Quick sanity check.
56 expect(versions.length).toBe(6); 56 expect(versions.length).toBe(5);
57 done(); 57 expect(versions[0].major).toEqual(2);
58 }) 58 expect(versions[0].minor).toEqual(3);
59 .catch((error) => done.fail(error)); 59 expect(versions[0].patch).toEqual(0);
60 }); 60 expect(versions[0].links).not.toBe(null);
61 61 expect(versions[0].links[0].href).toEqual('http://example.com/v2/');
62 it("Should return a list of all versions available from this resource", (done) => {
63 const service = new AbstractService(mockData.rootUrl, mockData.versions);
64
65 fetchMock.mock(mockData.rootResponse());
66
67 service.versions()
68 .then((versions) => {
69 // Quick sanity check.
70 expect(versions.length).toBe(6);
71 done(); 62 done();
72 }) 63 })
73 .catch((error) => done.fail(error)); 64 .catch((error) => done.fail(error));
@@ -84,7 +75,7 @@ describe('AbstractService', () => {
84 service.versions() 75 service.versions()
85 .then((versions) => { 76 .then((versions) => {
86 // Quick sanity check. 77 // Quick sanity check.
87 expect(versions.length).toBe(6); 78 expect(versions.length).toBe(5);
88 done(); 79 done();
89 }) 80 })
90 .catch((error) => done.fail(error)); 81 .catch((error) => done.fail(error));
@@ -132,7 +123,22 @@ describe('AbstractService', () => {
132 123
133 service.version() 124 service.version()
134 .then((version) => { 125 .then((version) => {
135 expect(version.id).toEqual('v2.3'); 126 expect(version.equals('v2.3')).toBe(true);
127 done();
128 })
129 .catch((error) => done.fail(error));
130 });
131
132 it("Should return the latest compatible version of the service API.", (done) => {
133 const service = new AbstractService(mockData.rootUrl, [
134 'v2.0'
135 ]);
136
137 fetchMock.mock(mockData.rootResponse());
138
139 service.version()
140 .then((version) => {
141 expect(version.equals('v2.3')).toBe(true);
136 done(); 142 done();
137 }) 143 })
138 .catch((error) => done.fail(error)); 144 .catch((error) => done.fail(error));
diff --git a/test/unit/util/versionTest.js b/test/unit/util/versionTest.js
index e23f518..7f73b88 100644
--- a/test/unit/util/versionTest.js
+++ b/test/unit/util/versionTest.js
@@ -96,4 +96,63 @@ describe('Version', () => {
96 // Other tests... 96 // Other tests...
97 expect(v2.equals({})).toBe(false); 97 expect(v2.equals({})).toBe(false);
98 }); 98 });
99
100 it("should test for correct compatibility", () => {
101 const v1 = new Version("compute", "1.3.2");
102
103 // String tests
104 expect(v1.supports("compute 1.0.0")).toBe(true);
105 expect(v1.supports("compute 1.0.1")).toBe(true);
106 expect(v1.supports("compute 1.3.0")).toBe(true);
107 expect(v1.supports("compute 1.3.3")).toBe(false);
108 expect(v1.supports("compute 1.4.0")).toBe(false);
109 expect(v1.supports("compute 2.3.0")).toBe(false);
110
111 // Version tests
112 expect(v1.supports(new Version("compute", "1.0.0"))).toBe(true);
113 expect(v1.supports(new Version("compute", "1.0.1"))).toBe(true);
114 expect(v1.supports(new Version("compute", "1.3.0"))).toBe(true);
115 expect(v1.supports(new Version("compute", "1.3.3"))).toBe(false);
116 expect(v1.supports(new Version("compute", "1.4.0"))).toBe(false);
117 expect(v1.supports(new Version("compute", "2.3.0"))).toBe(false);
118
119 const v2 = new Version("1.3.2");
120 // String tests
121 expect(v2.supports("1.0.0")).toBe(true);
122 expect(v2.supports("1.0.1")).toBe(true);
123 expect(v2.supports("1.3.0")).toBe(true);
124 expect(v2.supports("1.3.3")).toBe(false);
125 expect(v2.supports("1.4.0")).toBe(false);
126 expect(v2.supports("2.3.0")).toBe(false);
127
128 // Version tests
129 expect(v2.supports(new Version("1.0.0"))).toBe(true);
130 expect(v2.supports(new Version("1.0.1"))).toBe(true);
131 expect(v2.supports(new Version("1.3.0"))).toBe(true);
132 expect(v2.supports(new Version("1.3.3"))).toBe(false);
133 expect(v2.supports(new Version("1.4.0"))).toBe(false);
134 expect(v2.supports(new Version("2.3.0"))).toBe(false);
135 });
136
137 it("should store links", () => {
138 const v1 = new Version("compute", "1.3.2");
139
140 expect(v1.links).toBe(null);
141
142 v1.links = 'wrong data';
143 expect(v1.links).toBe(null);
144
145 v1.links = [
146 {
147 href: `http://example.org/v2/`,
148 rel: "self"
149 }
150 ];
151 expect(v1.links).not.toBe(null);
152 expect(v1.links.length).toBe(1);
153 expect(v1.links[0]).toEqual({
154 href: "http://example.org/v2/",
155 rel: "self"
156 });
157 });
99}); 158});