-
Notifications
You must be signed in to change notification settings - Fork 227
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(spaces): Move command 'spaces:vpn:connections' to CLI (#2875)
* Move command 'spaces:vpn:connections' to CLI * Migrating missing unit tests for lib file * Removing package 'spaces'
- Loading branch information
Showing
28 changed files
with
246 additions
and
2,208 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import {Command, flags} from '@heroku-cli/command' | ||
import {ux} from '@oclif/core' | ||
import * as Heroku from '@heroku-cli/schema' | ||
import heredoc from 'tsheredoc' | ||
import {displayVPNStatus} from '../../../lib/spaces/format' | ||
|
||
type VpnConnectionTunnels = Required<Heroku.PrivateSpacesVpn>['tunnels'] | ||
|
||
export default class Connections extends Command { | ||
static topic = 'spaces' | ||
static description = 'list the VPN Connections for a space' | ||
static example = heredoc` | ||
$ heroku spaces:vpn:connections --space my-space | ||
=== my-space VPN Connections | ||
Name Status Tunnels | ||
────── ────── ─────── | ||
office active UP/UP | ||
` | ||
static flags = { | ||
space: flags.string({char: 's', description: 'space to get VPN connections from', required: true}), | ||
json: flags.boolean({description: 'output in json format'}), | ||
} | ||
|
||
public async run(): Promise<void> { | ||
const {flags} = await this.parse(Connections) | ||
const {space, json} = flags | ||
const {body: connections} = await this.heroku.get<Required<Heroku.PrivateSpacesVpn>[]>(`/spaces/${space}/vpn-connections`) | ||
this.render(space, connections, json) | ||
} | ||
|
||
protected render(space: string, connections: Required<Heroku.PrivateSpacesVpn>[], json: boolean) { | ||
if (json) { | ||
ux.styledJSON(connections) | ||
} else { | ||
this.displayVPNConnections(space, connections) | ||
} | ||
} | ||
|
||
protected displayVPNConnections(space: string, connections: Required<Heroku.PrivateSpacesVpn>[]) { | ||
if (connections.length === 0) { | ||
ux.log('No VPN Connections have been created yet') | ||
return | ||
} | ||
|
||
ux.styledHeader(`${space} VPN Connections`) | ||
|
||
ux.table( | ||
connections, | ||
{ | ||
Name: { | ||
get: c => c.name || c.id, | ||
}, | ||
Status: { | ||
get: c => displayVPNStatus(c.status), | ||
}, | ||
Tunnels: { | ||
get: c => this.tunnelFormat(c.tunnels), | ||
}, | ||
}, | ||
) | ||
} | ||
|
||
protected tunnelFormat(t: VpnConnectionTunnels) { | ||
return t.map(tunnel => displayVPNStatus(tunnel.status)).join('/') | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
113 changes: 113 additions & 0 deletions
113
packages/cli/test/unit/commands/spaces/vpn/connections.unit.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import {stdout} from 'stdout-stderr' | ||
import Cmd from '../../../../../src/commands/spaces/vpn/connections' | ||
import runCommand from '../../../../helpers/runCommand' | ||
import * as nock from 'nock' | ||
import {expect} from 'chai' | ||
import heredoc from 'tsheredoc' | ||
|
||
describe('spaces:vpn:connections', function () { | ||
afterEach(function () { | ||
nock.cleanAll() | ||
}) | ||
|
||
const space = { | ||
id: '123456789012', | ||
name: 'office', | ||
public_ip: '35.161.69.30', | ||
routable_cidrs: [ | ||
'172.16.0.0/16', | ||
], | ||
ike_version: 1, | ||
space_cidr_block: '10.0.0.0/16', | ||
status: 'active', | ||
status_message: 'Active', | ||
tunnels: [ | ||
{ | ||
last_status_change: '2016-10-25T22:10:05Z', | ||
ip: '52.44.146.197', | ||
customer_ip: '52.44.146.197', | ||
pre_shared_key: 'secret', | ||
status: 'UP', | ||
status_message: 'status message', | ||
}, | ||
{ | ||
last_status_change: '2016-10-25T22:09:05Z', | ||
ip: '52.44.146.196', | ||
customer_ip: '52.44.146.196', | ||
pre_shared_key: 'secret', | ||
status: 'UP', | ||
status_message: 'status message', | ||
}, | ||
], | ||
} | ||
|
||
it('displays no connection message if none exist', async function () { | ||
const api = nock('https://api.heroku.com') | ||
.get('/spaces/my-space/vpn-connections') | ||
.reply(200, []) | ||
|
||
await runCommand(Cmd, [ | ||
'--space', | ||
'my-space', | ||
]) | ||
|
||
api.done() | ||
expect(stdout.output).to.eq('No VPN Connections have been created yet\n') | ||
}) | ||
|
||
it('displays VPN Connections', async function () { | ||
const api = nock('https://api.heroku.com') | ||
.get('/spaces/my-space/vpn-connections') | ||
.reply(200, [space]) | ||
|
||
await runCommand(Cmd, [ | ||
'--space', | ||
'my-space', | ||
]) | ||
|
||
api.done() | ||
expect(stdout.output).to.eq(heredoc` | ||
=== my-space VPN Connections | ||
Name Status Tunnels | ||
────── ────── ─────── | ||
office active UP/UP | ||
`) | ||
}) | ||
|
||
it('displays VPN Connection ID when name is unavailable', async function () { | ||
const conn = {...space, name: ''} | ||
const api = nock('https://api.heroku.com') | ||
.get('/spaces/my-space/vpn-connections') | ||
.reply(200, [conn]) | ||
|
||
await runCommand(Cmd, [ | ||
'--space', | ||
'my-space', | ||
]) | ||
|
||
api.done() | ||
expect(stdout.output).to.eq(heredoc` | ||
=== my-space VPN Connections | ||
Name Status Tunnels | ||
──────────── ────── ─────── | ||
123456789012 active UP/UP | ||
`) | ||
}) | ||
|
||
it('displays VPN Connections in JSON', async function () { | ||
const api = nock('https://api.heroku.com') | ||
.get('/spaces/my-space/vpn-connections') | ||
.reply(200, [space]) | ||
|
||
await runCommand(Cmd, [ | ||
'--space', | ||
'my-space', | ||
'--json', | ||
]) | ||
|
||
api.done() | ||
expect(JSON.parse(stdout.output)).to.eql([space]) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import {expect} from 'chai' | ||
import {displayCIDR, hostStatus, peeringStatus, displayVPNStatus} from '../../../../src/lib/spaces/format' | ||
|
||
describe('displayCIDR', function () { | ||
it('formats an array of cidrs', function () { | ||
return expect(displayCIDR(['a', 'b'])).to.eq('a, b') | ||
}) | ||
|
||
it('formats an array with a single cidr', function () { | ||
return expect(displayCIDR(['a'])).to.eq('a') | ||
}) | ||
|
||
it('returns empty string if cidr has no value', function () { | ||
// eslint-disable-next-line unicorn/no-useless-undefined | ||
return expect(displayCIDR(undefined)).to.eq('') | ||
}) | ||
}) | ||
|
||
describe('hostStatus', function () { | ||
it('returns ANSI colorized host status if status meets switch statement condition, uncolorized value if it does not', function () { | ||
expect(hostStatus('available')).to.eq('\u001B[32mavailable\u001B[39m') | ||
expect(hostStatus('under-assessment')).to.eq('\u001B[33munder-assessment\u001B[39m') | ||
expect(hostStatus('permanent-failure')).to.eq('\u001B[31mpermanent-failure\u001B[39m') | ||
expect(hostStatus('released-permanent-failure')).to.eq('\u001B[31mreleased-permanent-failure\u001B[39m') | ||
expect(hostStatus('released')).to.eq('\u001B[2mreleased\u001B[22m') | ||
expect(hostStatus('foo')).to.eq('foo') | ||
}) | ||
}) | ||
|
||
describe('displayVPNStatus', function () { | ||
it('returns ANSI colorized VPN status if status meets switch statement condition, uncolorized value if it does not', function () { | ||
expect(displayVPNStatus('UP')).to.eq('\u001B[32mUP\u001B[39m') | ||
expect(displayVPNStatus('available')).to.eq('\u001B[32mavailable\u001B[39m') | ||
expect(displayVPNStatus('pending')).to.eq('\u001B[33mpending\u001B[39m') | ||
expect(displayVPNStatus('provisioning')).to.eq('\u001B[33mprovisioning\u001B[39m') | ||
expect(displayVPNStatus('deprovisioning')).to.eq('\u001B[33mdeprovisioning\u001B[39m') | ||
expect(displayVPNStatus('DOWN')).to.eq('\u001B[31mDOWN\u001B[39m') | ||
expect(displayVPNStatus('deleting')).to.eq('\u001B[31mdeleting\u001B[39m') | ||
expect(displayVPNStatus('deleted')).to.eq('\u001B[31mdeleted\u001B[39m') | ||
expect(displayVPNStatus('foo')).to.eq('foo') | ||
}) | ||
}) | ||
|
||
describe('peeringStatus', function () { | ||
it('returns ANSI colorized peering status if status meets switch statement condition, uncolorized value if it does not', function () { | ||
expect(peeringStatus('active')).to.eq('\u001B[32mactive\u001B[39m') | ||
expect(peeringStatus('pending-acceptance')).to.eq('\u001B[33mpending-acceptance\u001B[39m') | ||
expect(peeringStatus('provisioning')).to.eq('\u001B[33mprovisioning\u001B[39m') | ||
expect(peeringStatus('expired')).to.eq('\u001B[31mexpired\u001B[39m') | ||
expect(peeringStatus('failed')).to.eq('\u001B[31mfailed\u001B[39m') | ||
expect(peeringStatus('deleted')).to.eq('\u001B[31mdeleted\u001B[39m') | ||
expect(peeringStatus('rejected')).to.eq('\u001B[31mrejected\u001B[39m') | ||
expect(peeringStatus('foo')).to.eq('foo') | ||
}) | ||
}) | ||
|
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.