Repository: softlayer/softlayer-python
Pull request #1036 (2018-09-07 22:05:20)

vs create flavor test
Fixed vs create with flavor data test https://github.com/softlayer/softlayer-python/issues/1033


Patch:
diff --git a/SoftLayer/CLI/virt/create.py b/SoftLayer/CLI/virt/create.py
index a0997704..ee904ba6 100644
--- a/SoftLayer/CLI/virt/create.py
+++ b/SoftLayer/CLI/virt/create.py
@@ -270,33 +270,19 @@ def cli(env, **args):
     output = []
     if args.get('test'):
         result = vsi.verify_create_instance(**data)
-        total_monthly = 0.0
-        total_hourly = 0.0
-
-        table = formatting.Table(['Item', 'cost'])
-        table.align['Item'] = 'r'
-        table.align['cost'] = 'r'
-
-        for price in result['prices']:
-            total_monthly += float(price.get('recurringFee', 0.0))
-            total_hourly += float(price.get('hourlyRecurringFee', 0.0))
-            if args.get('billing') == 'hourly':
-                rate = "%.2f" % float(price['hourlyRecurringFee'])
-            elif args.get('billing') == 'monthly':
-                rate = "%.2f" % float(price['recurringFee'])
-
-            table.add_row([price['item']['description'], rate])
-
-        total = 0
-        if args.get('billing') == 'hourly':
-            total = total_hourly
-        elif args.get('billing') == 'monthly':
-            total = total_monthly
-
-        billing_rate = 'monthly'
-        if args.get('billing') == 'hourly':
-            billing_rate = 'hourly'
-        table.add_row(['Total %s cost' % billing_rate, "%.2f" % total])
+
+        if result['presetId']:
+            ordering_mgr = SoftLayer.OrderingManager(env.client)
+            item_prices = ordering_mgr.get_item_prices(result['packageId'])
+            preset_prices = ordering_mgr.get_preset_prices(result['presetId'])
+            search_keys = ["guest_core", "ram"]
+            for price in preset_prices['prices']:
+                if price['item']['itemCategory']['categoryCode'] in search_keys:
+                    item_key_name = price['item']['keyName']
+                    _add_item_prices(item_key_name, item_prices, result)
+
+        table = _build_receipt_table(result['prices'], args.get('billing'))
+
         output.append(table)
         output.append(formatting.FormattedItem(
             None,
@@ -334,6 +320,35 @@ def cli(env, **args):
     env.fout(output)
 
 
+def _add_item_prices(item_key_name, item_prices, result):
+    """Add the flavor item prices to the rest o the items prices"""
+    for item in item_prices:
+        if item_key_name == item['item']['keyName']:
+            if 'pricingLocationGroup' in item:
+                for location in item['pricingLocationGroup']['locations']:
+                    if result['location'] == str(location['id']):
+                        result['prices'].append(item)
+
+
+def _build_receipt_table(prices, billing="hourly"):
+    """Retrieve the total recurring fee of the items prices"""
+    total = 0.000
+    table = formatting.Table(['Cost', 'Item'])
+    table.align['Cost'] = 'r'
+    table.align['Item'] = 'l'
+    for price in prices:
+        rate = 0.000
+        if billing == "hourly":
+            rate += float(price.get('hourlyRecurringFee', 0.000))
+        else:
+            rate += float(price.get('recurringFee', 0.000))
+        total += rate
+
+        table.add_row(["%.3f" % rate, price['item']['description']])
+    table.add_row(["%.3f" % total, "Total %s cost" % billing])
+    return table
+
+
 def _validate_args(env, args):
     """Raises an ArgumentError if the given arguments are not valid."""
 
diff --git a/SoftLayer/fixtures/SoftLayer_Product_Package.py b/SoftLayer/fixtures/SoftLayer_Product_Package.py
index 2642b77e..b7b00878 100644
--- a/SoftLayer/fixtures/SoftLayer_Product_Package.py
+++ b/SoftLayer/fixtures/SoftLayer_Product_Package.py
@@ -916,7 +916,7 @@
         'prices': [{'id': 611}],
     }]
 
-getItemPrices = [
+getItemPricesISCSI = [
     {
         'currentPriceFlag': '',
         'id': 2152,
@@ -1341,6 +1341,179 @@
     }]
 }]
 
+getItemPrices = [
+    {
+        "hourlyRecurringFee": ".093",
+        "id": 204015,
+        "recurringFee": "62",
+        "item": {
+            "description": "4 x 2.0 GHz or higher Cores",
+            "id": 859,
+            "keyName": "GUEST_CORES_4",
+        },
+        "pricingLocationGroup": {
+            "id": 503,
+            "locations": [
+                {
+                    "id": 449610,
+                    "longName": "Montreal 1",
+                    "name": "mon01",
+                    "statusId": 2
+                },
+                {
+                    "id": 449618,
+                    "longName": "Montreal 2",
+                    "name": "mon02",
+                    "statusId": 2
+                },
+                {
+                    "id": 448994,
+                    "longName": "Toronto 1",
+                    "name": "tor01",
+                    "statusId": 2
+                },
+                {
+                    "id": 350993,
+                    "longName": "Toronto 2",
+                    "name": "tor02",
+                    "statusId": 2
+                },
+                {
+                    "id": 221894,
+                    "longName": "Amsterdam 2",
+                    "name": "ams02",
+                    "statusId": 2
+                },
+                {
+                    "id": 265592,
+                    "longName": "Amsterdam 1",
+                    "name": "ams01",
+                    "statusId": 2
+                },
+                {
+                    "id": 814994,
+                    "longName": "Amsterdam 3",
+                    "name": "ams03",
+                    "statusId": 2
+                }
+            ]
+        }
+    },
+    {
+        "hourlyRecurringFee": ".006",
+        "id": 204663,
+        "recurringFee": "4.1",
+        "item": {
+            "description": "100 GB (LOCAL)",
+            "id": 3899,
+            "keyName": "GUEST_DISK_100_GB_LOCAL_3",
+        },
+        "pricingLocationGroup": {
+            "id": 503,
+            "locations": [
+                {
+                    "id": 449610,
+                    "longName": "Montreal 1",
+                    "name": "mon01",
+                    "statusId": 2
+                },
+                {
+                    "id": 449618,
+                    "longName": "Montreal 2",
+                    "name": "mon02",
+                    "statusId": 2
+                },
+                {
+                    "id": 448994,
+                    "longName": "Toronto 1",
+                    "name": "tor01",
+                    "statusId": 2
+                },
+                {
+                    "id": 350993,
+                    "longName": "Toronto 2",
+                    "name": "tor02",
+                    "statusId": 2
+                },
+                {
+                    "id": 221894,
+                    "longName": "Amsterdam 2",
+                    "name": "ams02",
+                    "statusId": 2
+                },
+                {
+                    "id": 265592,
+                    "longName": "Amsterdam 1",
+                    "name": "ams01",
+                    "statusId": 2
+                },
+                {
+                    "id": 814994,
+                    "longName": "Amsterdam 3",
+                    "name": "ams03",
+                    "statusId": 2
+                }
+            ]
+        }
+    },
+    {
+        "hourlyRecurringFee": ".217",
+        "id": 204255,
+        "recurringFee": "144",
+        "item": {
+            "description": "16 GB ",
+            "id": 1017,
+            "keyName": "RAM_16_GB",
+        },
+        "pricingLocationGroup": {
+            "id": 503,
+            "locations": [
+                {
+                    "id": 449610,
+                    "longName": "Montreal 1",
+                    "name": "mon01",
+                    "statusId": 2
+                },
+                {
+                    "id": 449618,
+                    "longName": "Montreal 2",
+                    "name": "mon02",
+                    "statusId": 2
+                },
+                {
+                    "id": 448994,
+                    "longName": "Toronto 1",
+                    "name": "tor01",
+                    "statusId": 2
+                },
+                {
+                    "id": 350993,
+                    "longName": "Toronto 2",
+                    "name": "tor02",
+                    "statusId": 2
+                },
+                {
+                    "id": 221894,
+                    "longName": "Amsterdam 2",
+                    "name": "ams02",
+                    "statusId": 2
+                },
+                {
+                    "id": 265592,
+                    "longName": "Amsterdam 1",
+                    "name": "ams01",
+                    "statusId": 2
+                },
+                {
+                    "id": 814994,
+                    "longName": "Amsterdam 3",
+                    "name": "ams03",
+                    "statusId": 2
+                }
+            ]
+        }
+    }
+]
 getActivePresets = [
     {
         "description": "M1.64x512x25",
diff --git a/SoftLayer/fixtures/SoftLayer_Product_Package_Preset.py b/SoftLayer/fixtures/SoftLayer_Product_Package_Preset.py
new file mode 100644
index 00000000..d111b959
--- /dev/null
+++ b/SoftLayer/fixtures/SoftLayer_Product_Package_Preset.py
@@ -0,0 +1,62 @@
+getObject = {
+    "id": 405,
+    "keyName": "AC1_8X60X25",
+    "prices": [
+        {
+            "hourlyRecurringFee": "1.425",
+            "id": 207345,
+            "recurringFee": "936.23",
+            "item": {
+                "description": "1 x P100 GPU",
+                "id": 10933,
+                "keyName": "1_X_P100_GPU",
+                "itemCategory": {
+                    "categoryCode": "guest_pcie_device0",
+                    "id": 1259
+                }
+            }
+        },
+        {
+            "hourlyRecurringFee": "0",
+            "id": 2202,
+            "recurringFee": "0",
+            "item": {
+                "description": "25 GB (SAN)",
+                "id": 1178,
+                "keyName": "GUEST_DISK_25_GB_SAN",
+                "itemCategory": {
+                    "categoryCode": "guest_disk0",
+                    "id": 81
+                }
+            }
+        },
+        {
+            "hourlyRecurringFee": ".342",
+            "id": 207361,
+            "recurringFee": "224.69",
+            "item": {
+                "description": "60 GB",
+                "id": 10939,
+                "keyName": "RAM_0_UNIT_PLACEHOLDER_10",
+                "itemCategory": {
+                    "categoryCode": "ram",
+                    "id": 3
+                }
+            }
+        },
+        {
+            "hourlyRecurringFee": ".181",
+            "id": 209595,
+            "recurringFee": "118.26",
+            "item": {
+                "description": "8 x 2.0 GHz or higher Cores",
+                "id": 11307,
+                "keyName": "GUEST_CORE_8",
+                "itemCategory": {
+                    "categoryCode": "guest_core",
+                    "id": 80
+                }
+            }
+        }
+    ]
+}
diff --git a/SoftLayer/fixtures/SoftLayer_Virtual_Guest.py b/SoftLayer/fixtures/SoftLayer_Virtual_Guest.py
index ac20acb9..69a1b95e 100644
--- a/SoftLayer/fixtures/SoftLayer_Virtual_Guest.py
+++ b/SoftLayer/fixtures/SoftLayer_Virtual_Guest.py
@@ -423,7 +423,113 @@
 setPublicNetworkInterfaceSpeed = True
 createObject = getObject
 createObjects = [getObject]
-generateOrderTemplate = {}
+generateOrderTemplate = {
+    "imageTemplateId": None,
+    "location": "1854895",
+    "packageId": 835,
+    "presetId": 405,
+    "prices": [
+        {
+            "hourlyRecurringFee": "0",
+            "id": 45466,
+            "recurringFee": "0",
+            "item": {
+                "description": "CentOS 7.x - Minimal Install (64 bit)"
+            }
+        },
+        {
+            "hourlyRecurringFee": "0",
+            "id": 2202,
+            "recurringFee": "0",
+            "item": {
+                "description": "25 GB (SAN)"
+            }
+        },
+        {
+            "hourlyRecurringFee": "0",
+            "id": 905,
+            "recurringFee": "0",
+            "item": {
+                "description": "Reboot / Remote Console"
+            }
+        },
+        {
+            "hourlyRecurringFee": ".02",
+            "id": 899,
+            "recurringFee": "10",
+            "item": {
+                "description": "1 Gbps Private Network Uplink"
+            }
+        },
+        {
+            "hourlyRecurringFee": "0",
+            "id": 1800,
+            "item": {
+                "description": "0 GB Bandwidth Allotment"
+            }
+        },
+        {
+            "hourlyRecurringFee": "0",
+            "id": 21,
+            "recurringFee": "0",
+            "item": {
+                "description": "1 IP Address"
+            }
+        },
+        {
+            "hourlyRecurringFee": "0",
+            "id": 55,
+            "recurringFee": "0",
+            "item": {
+                "description": "Host Ping"
+            }
+        },
+        {
+            "hourlyRecurringFee": "0",
+            "id": 57,
+            "recurringFee": "0",
+            "item": {
+                "description": "Email and Ticket"
+            }
+        },
+        {
+            "hourlyRecurringFee": "0",
+            "id": 58,
+            "recurringFee": "0",
+            "item": {
+                "description": "Automated Notification"
+            }
+        },
+        {
+            "hourlyRecurringFee": "0",
+            "id": 420,
+            "recurringFee": "0",
+            "item": {
+                "description": "Unlimited SSL VPN Users & 1 PPTP VPN User per account"
+            }
+        },
+        {
+            "hourlyRecurringFee": "0",
+            "id": 418,
+            "recurringFee": "0",
+            "item": {
+                "description": "Nessus Vulnerability Assessment & Reporting"
+            }
+        }
+    ],
+    "quantity": 1,
+    "sourceVirtualGuestId": None,
+    "sshKeys": [],
+    "useHourlyPricing": True,
+    "virtualGuests": [
+        {
+            "domain": "test.local",
+            "hostname": "test"
+        }
+    ],
+    "complexType": "SoftLayer_Container_Product_Order_Virtual_Guest"
+}
+
 setUserMetadata = ['meta']
 reloadOperatingSystem = 'OK'
 setTags = True
diff --git a/SoftLayer/managers/ordering.py b/SoftLayer/managers/ordering.py
index 3677eced..01a182ae 100644
--- a/SoftLayer/managers/ordering.py
+++ b/SoftLayer/managers/ordering.py
@@ -34,6 +34,7 @@ def __init__(self, client):
         self.package_svc = client['Product_Package']
         self.order_svc = client['Product_Order']
         self.billing_svc = client['Billing_Order']
+        self.package_preset = client['Product_Package_Preset']
 
     def get_packages_of_type(self, package_types, mask=None):
         """Get packages that match a certain type.
@@ -369,6 +370,34 @@ def get_price_id_list(self, package_keyname, item_keynames):
 
         return prices
 
+    def get_preset_prices(self, preset):
+        """Get preset item prices.
+
+        Retrieve a SoftLayer_Product_Package_Preset record.
+
+        :param int preset: preset identifier.
+        :returns: A list of price IDs associated with the given preset_id.
+
+        """
+        mask = 'mask[prices[item]]'
+
+        prices = self.package_preset.getObject(id=preset, mask=mask)
+        return prices
+
+    def get_item_prices(self, package_id):
+        """Get item prices.
+
+        Retrieve a SoftLayer_Product_Package item prices record.
+
+        :param int package_id: package identifier.
+        :returns: A list of price IDs associated with the given package.
+
+        """
+        mask = 'mask[pricingLocationGroup[locations]]'
+
+        prices = self.package_svc.getItemPrices(id=package_id, mask=mask)
+        return prices
+
     def verify_order(self, package_keyname, location, item_keynames, complex_type=None,
                      hourly=True, preset_keyname=None, extras=None, quantity=1):
         """Verifies an order with the given package and prices.


Test patch:
diff --git a/tests/CLI/modules/vs_tests.py b/tests/CLI/modules/vs_tests.py
index 28496344..d22fcddc 100644
--- a/tests/CLI/modules/vs_tests.py
+++ b/tests/CLI/modules/vs_tests.py
@@ -672,7 +672,18 @@ def test_create_vs_test(self, confirm_mock):
                                    '--memory', '2048MB', '--datacenter',
                                    'TEST00', '--os', 'UBUNTU_LATEST'])
 
-        self.assertEqual(result.exit_code, -1)
+        self.assertEqual(result.exit_code, 0)
+
+    @mock.patch('SoftLayer.CLI.formatting.confirm')
+    def test_create_vs_flavor_test(self, confirm_mock):
+        confirm_mock.return_value = True
+
+        result = self.run_command(['vs', 'create', '--test', '--hostname', 'TEST',
+                                   '--domain', 'TESTING', '--flavor', 'B1_2X8X25',
+                                   '--datacenter', 'TEST00', '--os', 'UBUNTU_LATEST'])
+
+        self.assert_no_fail(result)
+        self.assertEqual(result.exit_code, 0)
 
     def test_create_vs_bad_memory(self):
         result = self.run_command(['vs', 'create', '--hostname', 'TEST',
diff --git a/tests/managers/ordering_tests.py b/tests/managers/ordering_tests.py
index 5149f6ed..0ea7c754 100644
--- a/tests/managers/ordering_tests.py
+++ b/tests/managers/ordering_tests.py
@@ -68,6 +68,18 @@ def test_get_package_id_by_type_returns_valid_id(self):
 
         self.assertEqual(46, package_id)
 
+    def test_get_preset_prices(self):
+        result = self.ordering.get_preset_prices(405)
+
+        self.assertEqual(result, fixtures.SoftLayer_Product_Package_Preset.getObject)
+        self.assert_called_with('SoftLayer_Product_Package_Preset', 'getObject')
+
+    def test_get_item_prices(self):
+        result = self.ordering.get_item_prices(835)
+
+        self.assertEqual(result, fixtures.SoftLayer_Product_Package.getItemPrices)
+        self.assert_called_with('SoftLayer_Product_Package', 'getItemPrices')
+
     def test_get_package_id_by_type_fails_for_nonexistent_package_type(self):
         p_mock = self.set_mock('SoftLayer_Product_Package', 'getAllObjects')
         p_mock.return_value = []