[LIBCLOUD-969] Add pricing information to UpCloud's driver list_sizes Signed-off-by: Quentin Pradet <[email protected]>
Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/721a83ae Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/721a83ae Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/721a83ae Branch: refs/heads/trunk Commit: 721a83aec40894bd8e3be03cb5e4cea0fd278696 Parents: dcb0cef Author: Mika Lackman <[email protected]> Authored: Mon Dec 11 11:04:16 2017 +0200 Committer: Quentin Pradet <[email protected]> Committed: Thu Dec 14 21:40:32 2017 +0400 ---------------------------------------------------------------------- libcloud/common/upcloud.py | 34 + libcloud/compute/drivers/upcloud.py | 17 +- libcloud/test/common/test_upcloud.py | 26 + .../compute/fixtures/upcloud/api_1_2_price.json | 683 +++++++++++++++++++ libcloud/test/compute/test_upcloud.py | 53 +- 5 files changed, 804 insertions(+), 9 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/libcloud/blob/721a83ae/libcloud/common/upcloud.py ---------------------------------------------------------------------- diff --git a/libcloud/common/upcloud.py b/libcloud/common/upcloud.py index 05fb5c2..c3fc6f7 100644 --- a/libcloud/common/upcloud.py +++ b/libcloud/common/upcloud.py @@ -199,6 +199,40 @@ class UpcloudNodeOperations(object): method='DELETE') +class PlanPrice(object): + """ + Helper class to construct plan price in different zones + + :param zone_prices: List of prices in different zones in UpCloud + :type zone_prices: ```list``` + + """ + + def __init__(self, zone_prices): + self._zone_prices = zone_prices + + def get_prices_in_zones(self, plan_name): + """ + Returns list of prices in different zones, + [{'zone_id': 'uk-lon1', 'price': 1.588'},...] + If plan is not found in a zone, price is set to None. + + :param plan_name: Name of the plan + :type plan_name: ```str``` + + rtype: ``list`` + """ + server_plan_name = 'server_plan_' + plan_name + + prices = [] + + for zone_price in self._zone_prices: + zone_id = zone_price['name'] + price = zone_price.get(server_plan_name, {}).get('price') + prices.append({'zone_id': zone_id, 'price': price}) + return prices + + class _LoginUser(object): def __init__(self, user_id, auth=None): http://git-wip-us.apache.org/repos/asf/libcloud/blob/721a83ae/libcloud/compute/drivers/upcloud.py ---------------------------------------------------------------------- diff --git a/libcloud/compute/drivers/upcloud.py b/libcloud/compute/drivers/upcloud.py index 3d98d2f..e0357fc 100644 --- a/libcloud/compute/drivers/upcloud.py +++ b/libcloud/compute/drivers/upcloud.py @@ -27,6 +27,7 @@ from libcloud.common.types import InvalidCredsError from libcloud.common.upcloud import UpcloudCreateNodeRequestBody from libcloud.common.upcloud import UpcloudNodeDestroyer from libcloud.common.upcloud import UpcloudNodeOperations +from libcloud.common.upcloud import PlanPrice class UpcloudResponse(JsonResponse): @@ -109,10 +110,16 @@ class UpcloudDriver(NodeDriver): """ List available plans + Note: Node.price will be always None, because the pricing depends, + where the Node is hosted. Node.extra['zones'] will contain + pricing for different hosting zones. + :rtype: ``list`` of :class:`NodeSize` """ + prices_response = self.connection.request('1.2/price') response = self.connection.request('1.2/plan') - return self._to_node_sizes(response.object['plans']['plan']) + return self._to_node_sizes(response.object['plans']['plan'], + prices_response.object['prices']['zone']) def list_images(self): """ @@ -263,11 +270,13 @@ class UpcloudDriver(NodeDriver): Zone_id format [country]_[city][number], like fi_hel1""" return zone_id.split('-')[0].upper() - def _to_node_sizes(self, plans): - return [self._construct_node_size(plan) for plan in plans] + def _to_node_sizes(self, plans, prices): + plan_price = PlanPrice(prices) + return [self._construct_node_size(plan, plan_price) for plan in plans] - def _construct_node_size(self, plan): + def _construct_node_size(self, plan, plan_price): extra = self._copy_dict(('core_number', 'storage_tier'), plan) + extra['zones'] = plan_price.get_prices_in_zones(plan['name']) return NodeSize(id=plan['name'], name=plan['name'], ram=plan['memory_amount'], disk=plan['storage_size'], http://git-wip-us.apache.org/repos/asf/libcloud/blob/721a83ae/libcloud/test/common/test_upcloud.py ---------------------------------------------------------------------- diff --git a/libcloud/test/common/test_upcloud.py b/libcloud/test/common/test_upcloud.py index 37bef0d..886a01a 100644 --- a/libcloud/test/common/test_upcloud.py +++ b/libcloud/test/common/test_upcloud.py @@ -20,6 +20,7 @@ from mock import Mock, call from libcloud.common.upcloud import UpcloudCreateNodeRequestBody, UpcloudNodeDestroyer, UpcloudNodeOperations from libcloud.common.upcloud import _StorageDevice from libcloud.common.upcloud import UpcloudTimeoutException +from libcloud.common.upcloud import PlanPrice from libcloud.compute.base import NodeImage, NodeSize, NodeLocation, NodeAuthSSHKey from libcloud.test import unittest @@ -262,5 +263,30 @@ class TestUpcloudNodeDestroyer(unittest.TestCase): self.assertTrue(self.destroyer.destroy_node(1)) +class TestPlanPrice(unittest.TestCase): + + def test_zone_prices(self): + prices = [{'name': 'uk-lon1', 'server_plan_1xCPU-1GB': {'amount': 1, 'price': 1.488}}, + {'name': 'fi-hel1', 'server_plan_1xCPU-1GB': {'amount': 1, 'price': 1.588}}] + pp = PlanPrice(prices) + + zone_prices = pp.get_prices_in_zones('1xCPU-1GB') + + self.assertEqual(len(zone_prices), 2) + self.assertIn({'zone_id': 'uk-lon1', 'price': 1.488}, zone_prices) + self.assertIn({'zone_id': 'fi-hel1', 'price': 1.588}, zone_prices) + + def test_plan_not_found_in_zone(self): + prices = [{'name': 'uk-lon1', 'server_plan_1xCPU-1GB': {'amount': 1, 'price': 1.488}}, + {'name': 'fi-hel1', 'server_plan_4xCPU-1GB': {'amount': 1, 'price': 1.588}}] + pp = PlanPrice(prices) + + zone_prices = pp.get_prices_in_zones('1xCPU-1GB') + + self.assertEqual(len(zone_prices), 2) + self.assertIn({'zone_id': 'uk-lon1', 'price': 1.488}, zone_prices) + self.assertIn({'zone_id': 'fi-hel1', 'price': None}, zone_prices) + + if __name__ == '__main__': sys.exit(unittest.main()) http://git-wip-us.apache.org/repos/asf/libcloud/blob/721a83ae/libcloud/test/compute/fixtures/upcloud/api_1_2_price.json ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/upcloud/api_1_2_price.json b/libcloud/test/compute/fixtures/upcloud/api_1_2_price.json new file mode 100644 index 0000000..3b9d3c6 --- /dev/null +++ b/libcloud/test/compute/fixtures/upcloud/api_1_2_price.json @@ -0,0 +1,683 @@ +{ + "prices" : { + "zone" : [ + { + "firewall" : { + "amount" : 1, + "price" : 0.56 + }, + "io_request_backup" : { + "amount" : 1000000, + "price" : 0 + }, + "io_request_maxiops" : { + "amount" : 1000000, + "price" : 0 + }, + "ipv4_address" : { + "amount" : 1, + "price" : 0.336 + }, + "ipv6_address" : { + "amount" : 1, + "price" : 0 + }, + "name" : "de-fra1", + "public_ipv4_bandwidth_in" : { + "amount" : 1, + "price" : 0 + }, + "public_ipv4_bandwidth_out" : { + "amount" : 1, + "price" : 5.6 + }, + "public_ipv6_bandwidth_in" : { + "amount" : 1, + "price" : 0 + }, + "public_ipv6_bandwidth_out" : { + "amount" : 1, + "price" : 5.6 + }, + "server_core" : { + "amount" : 1, + "price" : 1.12 + }, + "server_memory" : { + "amount" : 256, + "price" : 0.14 + }, + "server_plan_12xCPU-32GB" : { + "amount" : 1, + "price" : 47.619 + }, + "server_plan_16xCPU-48GB" : { + "amount" : 1, + "price" : 71.4286 + }, + "server_plan_1xCPU-1GB" : { + "amount" : 1, + "price" : 1.488 + }, + "server_plan_20xCPU-64GB" : { + "amount" : 1, + "price" : 95.2381 + }, + "server_plan_2xCPU-2GB" : { + "amount" : 1, + "price" : 2.976 + }, + "server_plan_4xCPU-4GB" : { + "amount" : 1, + "price" : 5.952 + }, + "server_plan_6xCPU-8GB" : { + "amount" : 1, + "price" : 11.905 + }, + "server_plan_8xCPU-16GB" : { + "amount" : 1, + "price" : 23.8095 + }, + "storage_backup" : { + "amount" : 1, + "price" : 0.0078 + }, + "storage_maxiops" : { + "amount" : 1, + "price" : 0.031 + }, + "storage_template" : { + "amount" : 1, + "price" : 0.031 + } + }, + { + "firewall" : { + "amount" : 1, + "price" : 0.56 + }, + "io_request_backup" : { + "amount" : 1000000, + "price" : 0 + }, + "io_request_hdd" : { + "amount" : 1000000, + "price" : 0 + }, + "io_request_maxiops" : { + "amount" : 1000000, + "price" : 0 + }, + "ipv4_address" : { + "amount" : 1, + "price" : 0.336 + }, + "ipv6_address" : { + "amount" : 1, + "price" : 0 + }, + "name" : "fi-dev2", + "public_ipv4_bandwidth_in" : { + "amount" : 1, + "price" : 0 + }, + "public_ipv4_bandwidth_out" : { + "amount" : 1, + "price" : 5.6 + }, + "public_ipv6_bandwidth_in" : { + "amount" : 1, + "price" : 0 + }, + "public_ipv6_bandwidth_out" : { + "amount" : 1, + "price" : 5.6 + }, + "server_core" : { + "amount" : 1, + "price" : 1.24 + }, + "server_memory" : { + "amount" : 256, + "price" : 0.34 + }, + "server_plan_12xCPU-32GB" : { + "amount" : 1, + "price" : 71.4286 + }, + "server_plan_16xCPU-48GB" : { + "amount" : 1, + "price" : 107.1429 + }, + "server_plan_1xCPU-1GB" : { + "amount" : 1, + "price" : 2.232 + }, + "server_plan_20xCPU-64GB" : { + "amount" : 1, + "price" : 142.8571 + }, + "server_plan_2xCPU-2GB" : { + "amount" : 1, + "price" : 4.464 + }, + "server_plan_4xCPU-4GB" : { + "amount" : 1, + "price" : 8.928 + }, + "server_plan_6xCPU-8GB" : { + "amount" : 1, + "price" : 17.857 + }, + "server_plan_8xCPU-16GB" : { + "amount" : 1, + "price" : 35.7143 + }, + "storage_backup" : { + "amount" : 1, + "price" : 0.0078 + }, + "storage_hdd" : { + "amount" : 1, + "price" : 0.0145 + }, + "storage_maxiops" : { + "amount" : 1, + "price" : 0.031 + }, + "storage_template" : { + "amount" : 1, + "price" : 0.031 + } + }, + { + "firewall" : { + "amount" : 1, + "price" : 0.56 + }, + "io_request_backup" : { + "amount" : 1000000, + "price" : 0 + }, + "io_request_hdd" : { + "amount" : 1000000, + "price" : 0 + }, + "io_request_maxiops" : { + "amount" : 1000000, + "price" : 0 + }, + "io_request_ssd" : { + "amount" : 1000000, + "price" : 0 + }, + "ipv4_address" : { + "amount" : 1, + "price" : 0.336 + }, + "ipv6_address" : { + "amount" : 1, + "price" : 0 + }, + "name" : "fi-hel1", + "public_ipv4_bandwidth_in" : { + "amount" : 1, + "price" : 0 + }, + "public_ipv4_bandwidth_out" : { + "amount" : 1, + "price" : 5.6 + }, + "public_ipv6_bandwidth_in" : { + "amount" : 1, + "price" : 0 + }, + "public_ipv6_bandwidth_out" : { + "amount" : 1, + "price" : 5.6 + }, + "server_core" : { + "amount" : 1, + "price" : 1.24 + }, + "server_memory" : { + "amount" : 256, + "price" : 0.34 + }, + "server_plan_12xCPU-32GB" : { + "amount" : 1, + "price" : 71.4286 + }, + "server_plan_16xCPU-48GB" : { + "amount" : 1, + "price" : 107.1429 + }, + "server_plan_1xCPU-1GB" : { + "amount" : 1, + "price" : 2.232 + }, + "server_plan_20xCPU-64GB" : { + "amount" : 1, + "price" : 142.8571 + }, + "server_plan_2xCPU-2GB" : { + "amount" : 1, + "price" : 4.464 + }, + "server_plan_4xCPU-4GB" : { + "amount" : 1, + "price" : 8.928 + }, + "server_plan_6xCPU-8GB" : { + "amount" : 1, + "price" : 17.857 + }, + "server_plan_8xCPU-16GB" : { + "amount" : 1, + "price" : 35.7143 + }, + "storage_backup" : { + "amount" : 1, + "price" : 0.0078 + }, + "storage_hdd" : { + "amount" : 1, + "price" : 0.0145 + }, + "storage_maxiops" : { + "amount" : 1, + "price" : 0.031 + }, + "storage_ssd" : { + "amount" : 1, + "price" : 0.056 + }, + "storage_template" : { + "amount" : 1, + "price" : 0.031 + } + }, + { + "firewall" : { + "amount" : 1, + "price" : 0.56 + }, + "io_request_backup" : { + "amount" : 1000000, + "price" : 0 + }, + "io_request_maxiops" : { + "amount" : 1000000, + "price" : 0 + }, + "ipv4_address" : { + "amount" : 1, + "price" : 0.336 + }, + "ipv6_address" : { + "amount" : 1, + "price" : 0 + }, + "name" : "nl-ams1", + "public_ipv4_bandwidth_in" : { + "amount" : 1, + "price" : 0 + }, + "public_ipv4_bandwidth_out" : { + "amount" : 1, + "price" : 5.6 + }, + "public_ipv6_bandwidth_in" : { + "amount" : 1, + "price" : 0 + }, + "public_ipv6_bandwidth_out" : { + "amount" : 1, + "price" : 5.6 + }, + "server_core" : { + "amount" : 1, + "price" : 1.12 + }, + "server_memory" : { + "amount" : 256, + "price" : 0.14 + }, + "server_plan_12xCPU-32GB" : { + "amount" : 1, + "price" : 47.619 + }, + "server_plan_16xCPU-48GB" : { + "amount" : 1, + "price" : 71.4286 + }, + "server_plan_1xCPU-1GB" : { + "amount" : 1, + "price" : 1.488 + }, + "server_plan_20xCPU-64GB" : { + "amount" : 1, + "price" : 95.2381 + }, + "server_plan_2xCPU-2GB" : { + "amount" : 1, + "price" : 2.976 + }, + "server_plan_4xCPU-4GB" : { + "amount" : 1, + "price" : 5.952 + }, + "server_plan_6xCPU-8GB" : { + "amount" : 1, + "price" : 11.905 + }, + "server_plan_8xCPU-16GB" : { + "amount" : 1, + "price" : 23.8095 + }, + "storage_backup" : { + "amount" : 1, + "price" : 0.0078 + }, + "storage_maxiops" : { + "amount" : 1, + "price" : 0.031 + }, + "storage_template" : { + "amount" : 1, + "price" : 0.031 + } + }, + { + "firewall" : { + "amount" : 1, + "price" : 0.56 + }, + "io_request_backup" : { + "amount" : 1000000, + "price" : 0 + }, + "io_request_maxiops" : { + "amount" : 1000000, + "price" : 0 + }, + "ipv4_address" : { + "amount" : 1, + "price" : 0.336 + }, + "ipv6_address" : { + "amount" : 1, + "price" : 0 + }, + "name" : "sg-sin1", + "public_ipv4_bandwidth_in" : { + "amount" : 1, + "price" : 0 + }, + "public_ipv4_bandwidth_out" : { + "amount" : 1, + "price" : 5.6 + }, + "public_ipv6_bandwidth_in" : { + "amount" : 1, + "price" : 0 + }, + "public_ipv6_bandwidth_out" : { + "amount" : 1, + "price" : 5.6 + }, + "server_core" : { + "amount" : 1, + "price" : 1.12 + }, + "server_memory" : { + "amount" : 256, + "price" : 0.14 + }, + "server_plan_12xCPU-32GB" : { + "amount" : 1, + "price" : 47.619 + }, + "server_plan_16xCPU-48GB" : { + "amount" : 1, + "price" : 71.4286 + }, + "server_plan_1xCPU-1GB" : { + "amount" : 1, + "price" : 1.488 + }, + "server_plan_20xCPU-64GB" : { + "amount" : 1, + "price" : 95.2381 + }, + "server_plan_2xCPU-2GB" : { + "amount" : 1, + "price" : 2.976 + }, + "server_plan_4xCPU-4GB" : { + "amount" : 1, + "price" : 5.952 + }, + "server_plan_6xCPU-8GB" : { + "amount" : 1, + "price" : 11.905 + }, + "server_plan_8xCPU-16GB" : { + "amount" : 1, + "price" : 23.8095 + }, + "storage_backup" : { + "amount" : 1, + "price" : 0.0078 + }, + "storage_maxiops" : { + "amount" : 1, + "price" : 0.031 + }, + "storage_template" : { + "amount" : 1, + "price" : 0.031 + } + }, + { + "firewall" : { + "amount" : 1, + "price" : 0.56 + }, + "io_request_backup" : { + "amount" : 1000000, + "price" : 0 + }, + "io_request_hdd" : { + "amount" : 1000000, + "price" : 0 + }, + "io_request_maxiops" : { + "amount" : 1000000, + "price" : 0 + }, + "io_request_ssd" : { + "amount" : 1000000, + "price" : 0 + }, + "ipv4_address" : { + "amount" : 1, + "price" : 0.336 + }, + "ipv6_address" : { + "amount" : 1, + "price" : 0 + }, + "name" : "uk-lon1", + "public_ipv4_bandwidth_in" : { + "amount" : 1, + "price" : 0 + }, + "public_ipv4_bandwidth_out" : { + "amount" : 1, + "price" : 5.6 + }, + "public_ipv6_bandwidth_in" : { + "amount" : 1, + "price" : 0 + }, + "public_ipv6_bandwidth_out" : { + "amount" : 1, + "price" : 5.6 + }, + "server_core" : { + "amount" : 1, + "price" : 1.12 + }, + "server_memory" : { + "amount" : 256, + "price" : 0.14 + }, + "server_plan_12xCPU-32GB" : { + "amount" : 1, + "price" : 47.619 + }, + "server_plan_16xCPU-48GB" : { + "amount" : 1, + "price" : 71.4286 + }, + "server_plan_1xCPU-1GB" : { + "amount" : 1, + "price" : 1.488 + }, + "server_plan_20xCPU-64GB" : { + "amount" : 1, + "price" : 95.2381 + }, + "server_plan_2xCPU-2GB" : { + "amount" : 1, + "price" : 2.976 + }, + "server_plan_4xCPU-4GB" : { + "amount" : 1, + "price" : 5.952 + }, + "server_plan_6xCPU-8GB" : { + "amount" : 1, + "price" : 11.905 + }, + "server_plan_8xCPU-16GB" : { + "amount" : 1, + "price" : 23.8095 + }, + "storage_backup" : { + "amount" : 1, + "price" : 0.0078 + }, + "storage_hdd" : { + "amount" : 1, + "price" : 0.0078 + }, + "storage_maxiops" : { + "amount" : 1, + "price" : 0.031 + }, + "storage_ssd" : { + "amount" : 1, + "price" : 0.031 + }, + "storage_template" : { + "amount" : 1, + "price" : 0.031 + } + }, + { + "firewall" : { + "amount" : 1, + "price" : 0.56 + }, + "io_request_backup" : { + "amount" : 1000000, + "price" : 0 + }, + "io_request_maxiops" : { + "amount" : 1000000, + "price" : 0 + }, + "ipv4_address" : { + "amount" : 1, + "price" : 0.336 + }, + "ipv6_address" : { + "amount" : 1, + "price" : 0 + }, + "name" : "us-chi1", + "public_ipv4_bandwidth_in" : { + "amount" : 1, + "price" : 0 + }, + "public_ipv4_bandwidth_out" : { + "amount" : 1, + "price" : 5.6 + }, + "public_ipv6_bandwidth_in" : { + "amount" : 1, + "price" : 0 + }, + "public_ipv6_bandwidth_out" : { + "amount" : 1, + "price" : 5.6 + }, + "server_core" : { + "amount" : 1, + "price" : 1.12 + }, + "server_memory" : { + "amount" : 256, + "price" : 0.14 + }, + "server_plan_12xCPU-32GB" : { + "amount" : 1, + "price" : 47.619 + }, + "server_plan_16xCPU-48GB" : { + "amount" : 1, + "price" : 71.4286 + }, + "server_plan_1xCPU-1GB" : { + "amount" : 1, + "price" : 1.488 + }, + "server_plan_20xCPU-64GB" : { + "amount" : 1, + "price" : 95.2381 + }, + "server_plan_2xCPU-2GB" : { + "amount" : 1, + "price" : 2.976 + }, + "server_plan_4xCPU-4GB" : { + "amount" : 1, + "price" : 5.952 + }, + "server_plan_6xCPU-8GB" : { + "amount" : 1, + "price" : 11.905 + }, + "server_plan_8xCPU-16GB" : { + "amount" : 1, + "price" : 23.8095 + }, + "storage_backup" : { + "amount" : 1, + "price" : 0.0078 + }, + "storage_maxiops" : { + "amount" : 1, + "price" : 0.031 + }, + "storage_template" : { + "amount" : 1, + "price" : 0.031 + } + } + ] + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/721a83ae/libcloud/test/compute/test_upcloud.py ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/test_upcloud.py b/libcloud/test/compute/test_upcloud.py index 951ee29..56aebe2 100644 --- a/libcloud/test/compute/test_upcloud.py +++ b/libcloud/test/compute/test_upcloud.py @@ -35,7 +35,8 @@ class UpcloudPersistResponse(UpcloudResponse): def parse_body(self): import os - path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), os.path.pardir, 'compute', 'fixtures', 'upcloud')) + path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), os.path.pardir, + 'compute', 'fixtures', 'upcloud')) filename = 'api' + self.request.path_url.replace('/', '_').replace('.', '_') + '.json' filename = os.path.join(path, filename) if not os.path.exists(filename): @@ -83,6 +84,36 @@ class UpcloudDriverTests(LibcloudTestCase): def test_list_sizes(self): sizes = self.driver.list_sizes() self.assertTrue(len(sizes) >= 1) + expected_zones = [ + { + 'zone_id': 'de-fra1', + 'price': 1.488 + }, + { + 'zone_id': 'fi-dev2', + 'price': 2.232 + }, + { + 'zone_id': 'fi-hel1', + 'price': 2.232 + }, + { + 'zone_id': 'nl-ams1', + 'price': 1.488 + }, + { + 'zone_id': 'sg-sin1', + 'price': 1.488 + }, + { + 'zone_id': 'uk-lon1', + 'price': 1.488 + }, + { + 'zone_id': 'us-chi1', + 'price': 1.488 + } + ] expected_node_size = NodeSize(id='1xCPU-1GB', name='1xCPU-1GB', ram=1024, @@ -91,7 +122,8 @@ class UpcloudDriverTests(LibcloudTestCase): price=None, driver=self.driver, extra={'core_number': 1, - 'storage_tier': 'maxiops'}) + 'storage_tier': 'maxiops', + 'zones': expected_zones}) self.assert_object(expected_node_size, objects=sizes) def test_list_images(self): @@ -101,7 +133,7 @@ class UpcloudDriverTests(LibcloudTestCase): name='Windows Server 2003 R2 Standard (CD 1)', driver=self.driver, extra={'access': 'public', - 'licence': 0, + 'license': 0, 'size': 1, 'state': 'online', 'type': 'cdrom'}) @@ -189,8 +221,15 @@ class UpcloudDriverTests(LibcloudTestCase): return expected_data == actual_data def dicts_equals(self, d1, d2): - """Assumes dicts to contain only hashable types""" - return set(d1.values()) == set(d2.values()) + dict_keys_same = set(d1.keys()) == set(d2.keys()) + if not dict_keys_same: + return False + + for key in d1.keys(): + if d1[key] != d2[key]: + return False + + return True class UpcloudMockHttp(MockHttp): @@ -219,6 +258,10 @@ class UpcloudMockHttp(MockHttp): body = self.fixtures.load('api_1_2_storage_template.json') return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + def _1_2_price(self, method, url, body, headers): + body = self.fixtures.load('api_1_2_price.json') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + def _1_2_server(self, method, url, body, headers): if method == 'POST': dbody = json.loads(body)
