Skip to content

Commit 7628bdd

Browse files
more unit test fixes
1 parent ce515d7 commit 7628bdd

File tree

10 files changed

+95
-98
lines changed

10 files changed

+95
-98
lines changed

SoftLayer/CLI/environment.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
:license: MIT, see LICENSE for more details.
77
"""
88
import importlib
9+
from json.decoder import JSONDecodeError
910

1011
import click
1112
import pkg_resources
@@ -35,6 +36,7 @@ def __init__(self):
3536

3637
self.client = None
3738
self.console = Console()
39+
self.err_console = Console(stderr=True)
3840
self.format = 'table'
3941
self.skip_confirmations = False
4042
self.config_file = None
@@ -44,7 +46,11 @@ def __init__(self):
4446
def out(self, output):
4547
"""Outputs a string to the console (stdout)."""
4648
if self.format == 'json':
47-
self.console.print_json(output)
49+
try:
50+
self.console.print_json(output)
51+
# Tried to print not-json, so just print it out normally...
52+
except JSONDecodeError as ex:
53+
click.echo(output)
4854
elif self.format == 'jsonraw':
4955
# Using Rich here is problematic because in the unit tests it thinks the terminal is 80 characters wide
5056
# and only prints out that many characters.
@@ -59,8 +65,8 @@ def out(self, output):
5965

6066
def err(self, output, newline=True):
6167
"""Outputs an error string to the console (stderr)."""
62-
error_console = Console(stderr=True)
63-
error_console.print(output)
68+
69+
self.err_console.print(output, overflow='ignore', new_line_start=newline)
6470

6571
def fmt(self, output, fmt=None):
6672
"""Format output based on current the environment format."""

SoftLayer/CLI/firewall/add.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""Create new firewall."""
1+
"""Add a server to the firewall"""
22
# :license: MIT, see LICENSE for more details.
33

44
import click
@@ -36,16 +36,14 @@ def cli(env, target, firewall_type, high_availability):
3636
pkg = mgr.get_standard_package(target, is_virt=False)
3737

3838
if not pkg:
39-
exceptions.CLIAbort(
40-
"Unable to add firewall - Is network public enabled?")
39+
exceptions.CLIAbort("Unable to add firewall - Is network public enabled?")
4140

42-
env.out("******************")
43-
env.out("Product: %s" % pkg[0]['description'])
44-
env.out("Price: $%s monthly" % pkg[0]['prices'][0]['recurringFee'])
45-
env.out("******************")
41+
click.echo("******************")
42+
click.echo("Product: %s" % pkg[0]['description'])
43+
click.echo("Price: $%s monthly" % pkg[0]['prices'][0]['recurringFee'])
44+
click.echo("******************")
4645

47-
if not formatting.confirm("This action will incur charges on your "
48-
"account. Continue?"):
46+
if not formatting.confirm("This action will incur charges on your account. Continue?"):
4947
raise exceptions.CLIAbort('Aborted.')
5048

5149
if firewall_type == 'vlan':
@@ -55,4 +53,4 @@ def cli(env, target, firewall_type, high_availability):
5553
elif firewall_type == 'server':
5654
mgr.add_standard_firewall(target, is_virt=False)
5755

58-
env.fout("Firewall is being created!")
56+
click.echo("Firewall is being created!")

SoftLayer/CLI/formatting.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ def format_output(data, fmt='table'): # pylint: disable=R0911,R0912
3939

4040
# responds to .to_python()
4141
if hasattr(data, 'to_python'):
42-
print("to_python()")
4342
if fmt == 'json':
4443
return json.dumps(format_output(data, fmt='python'), indent=4, cls=CLIJSONEncoder)
4544
elif fmt == 'jsonraw':
@@ -49,13 +48,11 @@ def format_output(data, fmt='table'): # pylint: disable=R0911,R0912
4948

5049
# responds to .formatted
5150
if hasattr(data, 'formatted'):
52-
print("formatted()")
5351
if fmt == 'table':
5452
return data.formatted
5553

5654
# responds to .separator
5755
if hasattr(data, 'separator'):
58-
print("FUCKING THISNGS UP HERE")
5956
output = [format_output(d, fmt=fmt) for d in data if d]
6057
return str(SequentialOutput(data.separator, output))
6158

SoftLayer/CLI/order/preset_list.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,6 @@ def cli(env, package_keyname, keyword, prices):
3535
slcli order preset-list BARE_METAL_SERVER --keyword gpu
3636
3737
"""
38-
39-
tables = []
40-
table = formatting.Table(COLUMNS)
4138
manager = ordering.OrderingManager(env.client)
4239

4340
_filter = {}
@@ -46,7 +43,7 @@ def cli(env, package_keyname, keyword, prices):
4643
presets = manager.list_presets(package_keyname, filter=_filter)
4744

4845
if prices:
49-
table_prices = formatting.Table(['keyName', 'priceId', 'Hourly', 'Monthly', 'Restriction', 'Location'])
46+
table = formatting.Table(['keyName', 'priceId', 'Hourly', 'Monthly', 'Restriction', 'Location'])
5047
for price in presets:
5148
locations = []
5249
if price['locations'] != []:
@@ -55,21 +52,21 @@ def cli(env, package_keyname, keyword, prices):
5552
cr_max = get_item_price_data(price['prices'][0], 'capacityRestrictionMaximum')
5653
cr_min = get_item_price_data(price['prices'][0], 'capacityRestrictionMinimum')
5754
cr_type = get_item_price_data(price['prices'][0], 'capacityRestrictionType')
58-
table_prices.add_row([price['keyName'], price['id'],
59-
get_item_price_data(price['prices'][0], 'hourlyRecurringFee'),
60-
get_item_price_data(price['prices'][0], 'recurringFee'),
61-
"%s - %s %s" % (cr_min, cr_max, cr_type), str(locations)])
62-
tables.append(table_prices)
55+
table.add_row([price['keyName'], price['id'],
56+
get_item_price_data(price['prices'][0], 'hourlyRecurringFee'),
57+
get_item_price_data(price['prices'][0], 'recurringFee'),
58+
"%s - %s %s" % (cr_min, cr_max, cr_type), str(locations)])
6359

6460
else:
61+
table = formatting.Table(COLUMNS)
6562
for preset in presets:
6663
table.add_row([
6764
str(preset['name']).strip(),
6865
str(preset['keyName']).strip(),
6966
str(preset['description']).strip()
7067
])
71-
tables.append(table)
72-
env.fout(tables)
68+
69+
env.fout(table)
7370

7471

7572
def get_item_price_data(price, item_attribute):

SoftLayer/CLI/vpn/ipsec/configure.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ def cli(env, context_id):
2424

2525
succeeded = manager.apply_configuration(context_id)
2626
if succeeded:
27-
env.out('Configuration request received for context #{}'
28-
.format(context_id))
27+
click.echo('Configuration request received for context #{}'.format(context_id))
2928
else:
30-
raise CLIHalt('Failed to enqueue configuration request for context #{}'
31-
.format(context_id))
29+
raise CLIHalt('Failed to enqueue configuration request for context #{}'.format(context_id))

SoftLayer/CLI/vpn/ipsec/detail.py

Lines changed: 19 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -38,26 +38,19 @@ def cli(env, context_id, include):
3838
manager = SoftLayer.IPSECManager(env.client)
3939
context = manager.get_tunnel_context(context_id, mask=mask)
4040

41-
env.out('Context Details:')
4241
env.fout(_get_context_table(context))
4342

4443
for relation in include:
4544
if relation == 'at':
46-
env.out('Address Translations:')
47-
env.fout(_get_address_translations_table(
48-
context.get('addressTranslations', [])))
45+
env.fout(_get_address_translations_table(context.get('addressTranslations', [])))
4946
elif relation == 'is':
50-
env.out('Internal Subnets:')
51-
env.fout(_get_subnets_table(context.get('internalSubnets', [])))
47+
env.fout(_get_subnets_table(context.get('internalSubnets', []), title="Internal Subnets"))
5248
elif relation == 'rs':
53-
env.out('Remote Subnets:')
54-
env.fout(_get_subnets_table(context.get('customerSubnets', [])))
49+
env.fout(_get_subnets_table(context.get('customerSubnets', []), title="Remote Subnets"))
5550
elif relation == 'sr':
56-
env.out('Static Subnets:')
57-
env.fout(_get_subnets_table(context.get('staticRouteSubnets', [])))
51+
env.fout(_get_subnets_table(context.get('staticRouteSubnets', []), title="Static Subnets"))
5852
elif relation == 'ss':
59-
env.out('Service Subnets:')
60-
env.fout(_get_subnets_table(context.get('serviceSubnets', [])))
53+
env.fout(_get_subnets_table(context.get('serviceSubnets', []), title="Service Subnets"))
6154

6255

6356
def _get_address_translations_table(address_translations):
@@ -71,29 +64,24 @@ def _get_address_translations_table(address_translations):
7164
'static IP address id',
7265
'remote IP address',
7366
'remote IP address id',
74-
'note'])
67+
'note'], title="Address Translations")
7568
for address_translation in address_translations:
7669
table.add_row([address_translation.get('id', ''),
77-
address_translation.get('internalIpAddressRecord', {})
78-
.get('ipAddress', ''),
70+
address_translation.get('internalIpAddressRecord', {}).get('ipAddress', ''),
7971
address_translation.get('internalIpAddressId', ''),
80-
address_translation.get('customerIpAddressRecord', {})
81-
.get('ipAddress', ''),
72+
address_translation.get('customerIpAddressRecord', {}).get('ipAddress', ''),
8273
address_translation.get('customerIpAddressId', ''),
8374
address_translation.get('notes', '')])
8475
return table
8576

8677

87-
def _get_subnets_table(subnets):
78+
def _get_subnets_table(subnets, title):
8879
"""Yields a formatted table to print subnet details.
8980
9081
:param List[dict] subnets: List of subnets.
9182
:return Table: Formatted for subnet output.
9283
"""
93-
table = formatting.Table(['id',
94-
'network identifier',
95-
'cidr',
96-
'note'])
84+
table = formatting.Table(['id', 'network identifier', 'cidr', 'note'], title=title)
9785
for subnet in subnets:
9886
table.add_row([subnet.get('id', ''),
9987
subnet.get('networkIdentifier', ''),
@@ -163,34 +151,26 @@ def _get_context_table(context):
163151
:param dict context: The tunnel context
164152
:return Table: Formatted for tunnel context output
165153
"""
166-
table = formatting.KeyValueTable(['name', 'value'])
154+
table = formatting.KeyValueTable(['name', 'value'], title='Context Details')
167155
table.align['name'] = 'r'
168156
table.align['value'] = 'l'
169157

170158
table.add_row(['id', context.get('id', '')])
171159
table.add_row(['name', context.get('name', '')])
172160
table.add_row(['friendly name', context.get('friendlyName', '')])
173-
table.add_row(['internal peer IP address',
174-
context.get('internalPeerIpAddress', '')])
175-
table.add_row(['remote peer IP address',
176-
context.get('customerPeerIpAddress', '')])
177-
table.add_row(['advanced configuration flag',
178-
context.get('advancedConfigurationFlag', '')])
161+
table.add_row(['internal peer IP address', context.get('internalPeerIpAddress', '')])
162+
table.add_row(['remote peer IP address', context.get('customerPeerIpAddress', '')])
163+
table.add_row(['advanced configuration flag', context.get('advancedConfigurationFlag', '')])
179164
table.add_row(['preshared key', context.get('presharedKey', '')])
180-
table.add_row(['phase 1 authentication',
181-
context.get('phaseOneAuthentication', '')])
182-
table.add_row(['phase 1 diffie hellman group',
183-
context.get('phaseOneDiffieHellmanGroup', '')])
165+
table.add_row(['phase 1 authentication', context.get('phaseOneAuthentication', '')])
166+
table.add_row(['phase 1 diffie hellman group', context.get('phaseOneDiffieHellmanGroup', '')])
184167
table.add_row(['phase 1 encryption', context.get('phaseOneEncryption', '')])
185168
table.add_row(['phase 1 key life', context.get('phaseOneKeylife', '')])
186-
table.add_row(['phase 2 authentication',
187-
context.get('phaseTwoAuthentication', '')])
188-
table.add_row(['phase 2 diffie hellman group',
189-
context.get('phaseTwoDiffieHellmanGroup', '')])
169+
table.add_row(['phase 2 authentication', context.get('phaseTwoAuthentication', '')])
170+
table.add_row(['phase 2 diffie hellman group', context.get('phaseTwoDiffieHellmanGroup', '')])
190171
table.add_row(['phase 2 encryption', context.get('phaseTwoEncryption', '')])
191172
table.add_row(['phase 2 key life', context.get('phaseTwoKeylife', '')])
192-
table.add_row(['phase 2 perfect forward secrecy',
193-
context.get('phaseTwoPerfectForwardSecrecy', '')])
173+
table.add_row(['phase 2 perfect forward secrecy', context.get('phaseTwoPerfectForwardSecrecy', '')])
194174
table.add_row(['created', context.get('createDate')])
195175
table.add_row(['modified', context.get('modifyDate')])
196176
return table

SoftLayer/utils.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
"""
88
import collections
99
import datetime
10+
from json import JSONDecoder, JSONDecodeError
1011
import re
1112
import time
1213

14+
1315
# pylint: disable=no-member, invalid-name
1416

1517
UUID_RE = re.compile(r'^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$', re.I)
@@ -432,3 +434,28 @@ def format_comment(comment, max_line_length=60):
432434
def clean_dict(dictionary):
433435
"""Removes any `None` entires from the dictionary"""
434436
return {k: v for k, v in dictionary.items() if v}
437+
438+
439+
NOT_WHITESPACE = re.compile(r'[^\s]')
440+
def decode_stacked(document, pos=0, decoder=JSONDecoder()):
441+
"""Used for converting CLI output to JSON datastructures. Specially for unit tests
442+
443+
https://stackoverflow.com/questions/27907633/how-to-extract-multiple-json-objects-from-one-file
444+
Example::
445+
split_output = []
446+
# Converts Rich JSON output to actual JSON data. JSON UTIL
447+
for table in utils.decode_stacked(result.output):
448+
split_output.append(table)
449+
"""
450+
while True:
451+
match = NOT_WHITESPACE.search(document, pos)
452+
if not match:
453+
return
454+
pos = match.start()
455+
456+
try:
457+
obj, pos = decoder.raw_decode(document, pos)
458+
except JSONDecodeError:
459+
# do something sensible if there's some error
460+
raise
461+
yield obj

tests/CLI/modules/ipsec_tests.py

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from SoftLayer.CLI.exceptions import ArgumentError
1111
from SoftLayer.CLI.exceptions import CLIHalt
1212
from SoftLayer import testing
13+
from SoftLayer import utils
1314

1415

1516
class IPSECTests(testing.TestCase):
@@ -60,8 +61,7 @@ def test_ipsec_detail(self):
6061
'addressTranslations[internalIpAddressRecord[ipAddress],'
6162
'customerIpAddressRecord[ipAddress]],internalSubnets,'
6263
'customerSubnets,staticRouteSubnets,serviceSubnets]]')
63-
mock = self.set_mock('SoftLayer_Account',
64-
'getNetworkTunnelContexts')
64+
mock = self.set_mock('SoftLayer_Account', 'getNetworkTunnelContexts')
6565
mock.return_value = [{
6666
'id': 445,
6767
'name': 'der tunnel',
@@ -114,19 +114,16 @@ def test_ipsec_detail(self):
114114
'note': 'Static Network'
115115
}]
116116
}]
117-
result = self.run_command(['ipsec', 'detail', '445', '-iat', '-iis',
118-
'-irs', '-isr', '-iss'])
119-
empty, output = result.output.split('Context Details:\n')
120-
context, output = output.split('Address Translations:\n')
121-
translations, output = output.split('Internal Subnets:\n')
122-
internal_subnets, output = output.split('Remote Subnets:\n')
123-
remote_subnets, output = output.split('Static Subnets:\n')
124-
static_subnets, service_subnets = output.split('Service Subnets:\n')
117+
result = self.run_command(['ipsec', 'detail', '445', '-iat', '-iis', '-irs', '-isr', '-iss'])
118+
119+
split_output = []
120+
# Converts Rich JSON output to actual JSON data. JSON UTIL
121+
for table in utils.decode_stacked(result.output):
122+
split_output.append(table)
125123

124+
self.assertEqual(6, len(split_output))
126125
self.assert_no_fail(result)
127-
self.assert_called_with('SoftLayer_Account',
128-
'getNetworkTunnelContexts',
129-
mask=_mask)
126+
self.assert_called_with('SoftLayer_Account', 'getNetworkTunnelContexts', mask=_mask)
130127
self.assertEqual({'id': 445,
131128
'name': 'der tunnel',
132129
'friendly name': 'the tunnel',
@@ -145,34 +142,34 @@ def test_ipsec_detail(self):
145142
'phase 2 perfect forward secrecy': 0,
146143
'created': '2017-05-17T12:00:00-06:00',
147144
'modified': '2017-05-17T12:01:00-06:00'},
148-
json.loads(context))
145+
split_output[0])
149146
self.assertEqual([{'id': 872341,
150147
'remote IP address': '50.0.0.1',
151148
'remote IP address id': 872422,
152149
'static IP address': '10.0.0.1',
153150
'static IP address id': 982341,
154151
'note': 'surprise!'}],
155-
json.loads(translations))
152+
split_output[1])
156153
self.assertEqual([{'id': 324113,
157154
'network identifier': '10.20.0.0',
158155
'cidr': 29,
159156
'note': 'Private Network'}],
160-
json.loads(internal_subnets))
157+
split_output[2])
161158
self.assertEqual([{'id': 873411,
162159
'network identifier': '50.0.0.0',
163160
'cidr': 26,
164161
'note': 'Offsite Network'}],
165-
json.loads(remote_subnets))
162+
split_output[3])
166163
self.assertEqual([{'id': 998232,
167164
'network identifier': '50.50.0.0',
168165
'cidr': 29,
169166
'note': 'Static Network'}],
170-
json.loads(static_subnets))
167+
split_output[4])
171168
self.assertEqual([{'id': 565312,
172169
'network identifier': '100.10.0.0',
173170
'cidr': 26,
174171
'note': 'Service Network'}],
175-
json.loads(service_subnets))
172+
split_output[5])
176173

177174
def test_ipsec_list(self):
178175
mock = self.set_mock('SoftLayer_Account', 'getNetworkTunnelContexts')

0 commit comments

Comments
 (0)