From 903a36904a37b8a8bc2e2a30d91c977c7e05b59a Mon Sep 17 00:00:00 2001 From: Jeffrey Morgan Date: Wed, 27 May 2015 14:20:44 -0700 Subject: [PATCH] Integration tests --- .circle.yml | 3 ++ .gitignore | 3 ++ __integration__/HubUtil-integration.js | 39 +++++++++------ __integration__/RegHubUtil-integration.js | 58 +++++++++++++++++++++-- src/actions/RepositoryServerActions.js | 3 +- src/actions/TagServerActions.js | 3 +- src/stores/TagStore.js | 5 ++ src/utils/HubUtil.js | 13 +++-- src/utils/RegHubUtil.js | 42 +++++++++++----- util/testenv.js | 2 +- 10 files changed, 136 insertions(+), 35 deletions(-) create mode 100644 .circle.yml diff --git a/.circle.yml b/.circle.yml new file mode 100644 index 0000000000..5ab4115a5d --- /dev/null +++ b/.circle.yml @@ -0,0 +1,3 @@ +test: + override: + - npm run integration diff --git a/.gitignore b/.gitignore index 5f98bcf389..3b0964fe5b 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,9 @@ npm-debug.log # Signing Identity identity* +# Integration test environment +integration + # Resources resources/docker-* resources/boot2docker-* diff --git a/__integration__/HubUtil-integration.js b/__integration__/HubUtil-integration.js index d6638c355d..cdde6a0c6d 100644 --- a/__integration__/HubUtil-integration.js +++ b/__integration__/HubUtil-integration.js @@ -1,23 +1,32 @@ jest.autoMockOff(); +let hubUtil = require('../src/utils/HubUtil'); +let Promise = require('bluebird'); + +jasmine.getEnv().DEFAULT_TIMEOUT_INTERVAL = 60000; + describe('HubUtil Integration Tests', () => { - describe('token refresh', () => { - it('re-auths if the token has expired', () => { - expect(true).toBe(true); + describe('auth', () => { + pit('successfully authenticates', () => { + return new Promise((resolve) => { + hubUtil.auth(process.env.INTEGRATION_USER, process.env.INTEGRATION_PASSWORD, (error, response, body) => { + expect(response.statusCode).toBe(200); + expect(error).toBe(null); + + let data = JSON.parse(body); + expect(data.token).toBeTruthy(); + resolve(); + }); + }); }); - }); - - describe('signup', () => { - it('returns a 204 and sets localstorage data', () => { - }); - }); - - describe('login', () => { - it('Returns a 401 with account not active string if not active', () => { - - }); - it('Returns a 401 if the password is wrong', () => { + pit('provides a 401 if credentials are incorrect', () => { + return new Promise((resolve) => { + hubUtil.auth(process.env.INTEGRATION_USER, 'incorrectpassword', (error, response) => { + expect(response.statusCode).toBe(401); + resolve(); + }); + }); }); }); }); diff --git a/__integration__/RegHubUtil-integration.js b/__integration__/RegHubUtil-integration.js index 782a499093..1f7b0f4f28 100644 --- a/__integration__/RegHubUtil-integration.js +++ b/__integration__/RegHubUtil-integration.js @@ -1,9 +1,61 @@ jest.autoMockOff(); -describe('RegHubUtil Integration Tests', () => { - describe('repos', () => { - it('returns set of repos', () => { +// One minute timeout for integration tests +jasmine.getEnv().DEFAULT_TIMEOUT_INTERVAL = 60000; +let _ = require('underscore'); +let regHubUtil = require('../src/utils/RegHubUtil'); +let hubUtil = require('../src/utils/hubUtil'); +let Promise = require('bluebird'); + +describe('RegHubUtil Integration Tests', () => { + describe('with login', () => { + pit('lists private repos', () => { + return new Promise((resolve) => { + hubUtil.login(process.env.INTEGRATION_USER, process.env.INTEGRATION_PASSWORD, () => { + regHubUtil.repos((error, repos) => { + expect(_.findWhere(repos, {name: 'test_private', is_private: true})).toBeTruthy(); + resolve(); + }); + }); + }); + }); + + pit('lists tags for a private repo', () => { + return new Promise((resolve) => { + hubUtil.login(process.env.INTEGRATION_USER, process.env.INTEGRATION_PASSWORD, () => { + regHubUtil.tags(`${process.env.INTEGRATION_USER}/test_private`, (error, tags) => { + expect(error).toBeFalsy(); + expect(tags).toEqual(['latest']); + resolve(); + }); + }); + }); + }); + }); + + describe('public repos', () => { + pit('lists repos', () => { + return new Promise((resolve) => { + hubUtil.login(process.env.INTEGRATION_USER, process.env.INTEGRATION_PASSWORD, () => { + regHubUtil.repos((error, repos) => { + expect(_.findWhere(repos, {name: 'test'})).toBeTruthy(); + resolve(); + }); + }); + }); + }); + + pit('lists tags for a repo', () => { + return new Promise((resolve) => { + hubUtil.login(process.env.INTEGRATION_USER, process.env.INTEGRATION_PASSWORD, () => { + regHubUtil.tags(`${process.env.INTEGRATION_USER}/test`, (error, tags) => { + expect(error).toBeFalsy(); + expect(tags).toEqual(['latest']); + resolve(); + }); + }); + }); }); }); }); diff --git a/src/actions/RepositoryServerActions.js b/src/actions/RepositoryServerActions.js index b49e4d60d6..9b4740ff3a 100644 --- a/src/actions/RepositoryServerActions.js +++ b/src/actions/RepositoryServerActions.js @@ -6,7 +6,8 @@ class RepositoryServerActions { 'reposLoading', 'resultsUpdated', 'recommendedUpdated', - 'reposUpdated' + 'reposUpdated', + 'error' ); } } diff --git a/src/actions/TagServerActions.js b/src/actions/TagServerActions.js index 4149b81cb4..d8356b6c82 100644 --- a/src/actions/TagServerActions.js +++ b/src/actions/TagServerActions.js @@ -3,7 +3,8 @@ import alt from '../alt'; class TagServerActions { constructor () { this.generateActions( - 'tagsUpdated' + 'tagsUpdated', + 'error' ); } } diff --git a/src/stores/TagStore.js b/src/stores/TagStore.js index 9293bb16c6..13a2b980cf 100644 --- a/src/stores/TagStore.js +++ b/src/stores/TagStore.js @@ -38,6 +38,11 @@ class TagStore { this.tags = {}; this.emitChange(); } + + error ({repo}) { + this.loading[repo] = false; + this.emitChange(); + } } export default alt.createStore(TagStore); diff --git a/src/utils/HubUtil.js b/src/utils/HubUtil.js index a4db7131f7..02ce497af8 100644 --- a/src/utils/HubUtil.js +++ b/src/utils/HubUtil.js @@ -2,6 +2,8 @@ var _ = require('underscore'); var request = require('request'); var accountServerActions = require('../actions/AccountServerActions'); +let HUB2_ENDPOINT = process.env.HUB2_ENDPOINT || 'https://hub.docker.com/v2'; + module.exports = { init: function () { accountServerActions.prompted({prompted: localStorage.getItem('auth.prompted')}); @@ -95,10 +97,11 @@ module.exports = { localStorage.removeItem('auth.config'); }, - login: function (username, password) { + login: function (username, password, callback) { this.auth(username, password, (error, response, body) => { if (error) { accountServerActions.errors({errors: {detail: error.message}}); + callback(error); return; } @@ -112,9 +115,11 @@ module.exports = { localStorage.setItem('auth.config', new Buffer(username + ':' + password).toString('base64')); accountServerActions.loggedin({username, verified: true}); accountServerActions.prompted({prompted: true}); + if (callback) { callback(); } require('./RegHubUtil').repos(); } else { accountServerActions.errors({errors: {detail: 'Did not receive login token.'}}); + if (callback) { callback(new Error('Did not receive login token.')); } } } else if (response.statusCode === 401) { if (data && data.detail && data.detail.indexOf('Account not active yet') !== -1) { @@ -123,15 +128,17 @@ module.exports = { localStorage.setItem('auth.username', username); localStorage.setItem('auth.verified', false); localStorage.setItem('auth.config', new Buffer(username + ':' + password).toString('base64')); + if (callback) { callback(); } } else { accountServerActions.errors({errors: data}); + if (callback) { callback(new Error(data.detail)); } } } }); }, auth: function (username, password, callback) { - request.post('https://hub.docker.com/v2/users/login/', {form: {username, password}}, (error, response, body) => { + request.post(`${HUB2_ENDPOINT}/users/login/`, {form: {username, password}}, (error, response, body) => { callback(error, response, body); }); }, @@ -153,7 +160,7 @@ module.exports = { // Signs up and places a token under ~/.dockercfg and saves a jwt to localstore signup: function (username, password, email, subscribe) { - request.post('https://hub.docker.com/v2/users/signup/', { + request.post('${HUB2_ENDPOINT}/users/signup/', { form: { username, password, diff --git a/src/utils/RegHubUtil.js b/src/utils/RegHubUtil.js index 3975ce96aa..25e9b3e603 100644 --- a/src/utils/RegHubUtil.js +++ b/src/utils/RegHubUtil.js @@ -5,7 +5,9 @@ var util = require('../utils/Util'); var hubUtil = require('../utils/HubUtil'); var repositoryServerActions = require('../actions/RepositoryServerActions'); var tagServerActions = require('../actions/TagServerActions'); +var Promise = require('bluebird'); +let REGHUB2_ENDPOINT = process.env.REGHUB2_ENDPOINT || 'https://registry.hub.docker.com/v2'; let searchReq = null; module.exports = { @@ -38,7 +40,7 @@ module.exports = { qs: {q: query, page} }, (error, response, body) => { if (error) { - repositoryServerActions.searchError({error}); + repositoryServerActions.error({error}); } let data = JSON.parse(body); @@ -66,7 +68,7 @@ module.exports = { } request.get({ - url: `https://registry.hub.docker.com/v2/repositories/${name}`, + url: `${REGHUB2_ENDPOINT}/repositories/${name}`, }, (error, response, body) => { if (error) { repositoryServerActions.error({error}); @@ -86,28 +88,38 @@ module.exports = { }); }, - tags: function (repo) { + tags: function (repo, callback) { hubUtil.request({ - url: `https://registry.hub.docker.com/v2/repositories/${repo}/tags` + url: `${REGHUB2_ENDPOINT}/repositories/${repo}/tags` }, (error, response, body) => { if (response.statusCode === 200) { let data = JSON.parse(body); tagServerActions.tagsUpdated({repo, tags: data.tags}); - } else if (response.statusCude === 401) { - return; + if (callback) { callback(null, data.tags); } + } else if (error || response.statusCode === 401) { + repositoryServerActions.error({repo}); + if (callback) { callback(new Error('Failed to fetch repos')); } } }); }, // Returns the base64 encoded index token or null if no token exists - repos: function () { + repos: function (callback) { repositoryServerActions.reposLoading({repos: []}); hubUtil.request({ - url: 'https://registry.hub.docker.com/v2/namespaces/', + url: `${REGHUB2_ENDPOINT}/namespaces/`, }, (error, response, body) => { if (error) { - repositoryServerActions.reposError({error}); + repositoryServerActions.error({error}); + if (callback) { callback(error); } + return; + } + + if (response.statusCode !== 200) { + let generalError = new Error('Failed to fetch repos'); + repositoryServerActions.error({error: generalError}); + if (callback) { callback({error: generalError}); } return; } @@ -115,10 +127,11 @@ module.exports = { let namespaces = data.namespaces; async.map(namespaces, (namespace, cb) => { hubUtil.request({ - url: `https://registry.hub.docker.com/v2/repositories/${namespace}` + url: `${REGHUB2_ENDPOINT}/repositories/${namespace}` }, (error, response, body) => { if (error) { - repositoryServerActions.reposError({error}); + repositoryServerActions.error({error}); + if (callback) { callback(error); } return; } @@ -126,6 +139,12 @@ module.exports = { cb(null, data.results); }); }, (error, lists) => { + if (error) { + repositoryServerActions.error({error}); + if (callback) { callback(error); } + return; + } + let repos = []; for (let list of lists) { repos = repos.concat(list); @@ -136,6 +155,7 @@ module.exports = { }); repositoryServerActions.reposUpdated({repos}); + if (callback) { callback(null, repos); } }); }); } diff --git a/util/testenv.js b/util/testenv.js index 55db09ad7b..d2a95c4a16 100644 --- a/util/testenv.js +++ b/util/testenv.js @@ -1,6 +1,6 @@ var mock = (function() { var store = {}; - return { + return { getItem: function(key) { return store[key]; },