libcloud-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From to...@apache.org
Subject [1/3] libcloud git commit: Add tests in Point DNS provider for Redirects and MailRedirects classes
Date Sat, 03 Oct 2015 19:54:40 GMT
Repository: libcloud
Updated Branches:
  refs/heads/trunk 1ab649685 -> 08556656a


Add tests in Point DNS provider for Redirects and MailRedirects classes

Closes #591

Signed-off-by: Tomaz Muraus <tomaz@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/58c4ec94
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/58c4ec94
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/58c4ec94

Branch: refs/heads/trunk
Commit: 58c4ec9446bd6d0216ca860048d4323d80c84dfd
Parents: 1ab6496
Author: Alejandro Pereira <alepereira.dev@gmail.com>
Authored: Wed Sep 30 20:48:50 2015 -0300
Committer: Tomaz Muraus <tomaz@apache.org>
Committed: Sat Oct 3 21:29:04 2015 +0200

----------------------------------------------------------------------
 libcloud/dns/drivers/pointdns.py                | 309 +++++++---
 .../fixtures/pointdns/_zones_1_ZONE_UPDATE.json |   9 +
 .../_zones_1_mail_redirects_CREATE.json         |   8 +
 .../_zones_1_mail_redirects_DELETE.json         |   5 +
 .../pointdns/_zones_1_mail_redirects_GET.json   |   8 +
 .../pointdns/_zones_1_mail_redirects_LIST.json  |  18 +
 .../_zones_1_mail_redirects_UPDATE.json         |   8 +
 .../pointdns/_zones_1_redirects_CREATE.json     |  11 +
 .../pointdns/_zones_1_redirects_DELETE.json     |   5 +
 .../pointdns/_zones_1_redirects_GET.json        |  11 +
 .../pointdns/_zones_1_redirects_LIST.json       |  24 +
 .../pointdns/_zones_1_redirects_UPDATE.json     |  11 +
 libcloud/test/dns/fixtures/pointdns/error.json  |   7 +
 .../test/dns/fixtures/pointdns/not_found.json   |   1 +
 .../dns/fixtures/pointdns/redirect_error.json   |  10 +
 libcloud/test/dns/test_pointdns.py              | 557 +++++++++++++++++++
 16 files changed, 917 insertions(+), 85 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/58c4ec94/libcloud/dns/drivers/pointdns.py
----------------------------------------------------------------------
diff --git a/libcloud/dns/drivers/pointdns.py b/libcloud/dns/drivers/pointdns.py
index acd99ca..b5f3cf0 100644
--- a/libcloud/dns/drivers/pointdns.py
+++ b/libcloud/dns/drivers/pointdns.py
@@ -17,28 +17,49 @@ Point DNS Driver
 """
 
 __all__ = [
+    'PointDNSException',
+    'Redirect',
+    'MailRedirect',
     'PointDNSDriver'
 ]
 
+import sys
+
 try:
     import simplejson as json
 except ImportError:
     import json
 
+from libcloud.utils.py3 import httplib
 from libcloud.common.types import MalformedResponseError
 from libcloud.common.pointdns import PointDNSConnection
+from libcloud.common.exceptions import BaseHTTPError
 from libcloud.dns.types import Provider, RecordType
 from libcloud.dns.types import ZoneDoesNotExistError
 from libcloud.dns.types import RecordDoesNotExistError
 from libcloud.dns.base import DNSDriver, Zone, Record
 
 
+class PointDNSException(Exception):
+
+    def __init__(self, code, message):
+        self.code = code
+        self.message = message
+        self.args = (code, message)
+
+    def __str__(self):
+        return "%s %s" % (self.code, self.message)
+
+    def __repr__(self):
+        return "PointDNSException %s %s" % (self.code, self.message)
+
+
 class Redirect(object):
     """
     Point DNS redirect.
     """
 
-    def __init__(self, id, name, data, type, driver, zone_id, iframe=None,
+    def __init__(self, id, name, data, type, driver, zone, iframe=None,
                  query=False):
         """
         :param id: Redirect id.
@@ -56,8 +77,8 @@ class Redirect(object):
         :param driver: DNSDriver instance.
         :type driver: :class:`DNSDriver`
 
-        :param zone_id: Zone id
-        :type zone_id: ``str``
+        :param zone: Zone where redirect belongs.
+        :type  zone: :class:`Zone`
 
         :param iframe: Title of iframe (optional).
         :type iframe: ``str``
@@ -71,7 +92,7 @@ class Redirect(object):
         self.data = data
         self.type = str(type) if type else None
         self.driver = driver
-        self.zone_id = zone_id
+        self.zone = zone
         self.iframe = iframe
         self.query = query
 
@@ -93,7 +114,7 @@ class MailRedirect(object):
     Point DNS mail redirect.
     """
 
-    def __init__(self, id, source, destination, zone_id, driver):
+    def __init__(self, id, source, destination, zone, driver):
         """
         :param id: MailRedirect id.
         :type id: ``str``
@@ -104,8 +125,8 @@ class MailRedirect(object):
         :param destination: The destination address of mail redirect.
         :type destination: ``str``
 
-        :param zone_id: Zone id
-        :type zone_id: ``str``
+        :param zone: Zone where mail redirect belongs.
+        :type  zone: :class:`Zone`
 
         :param driver: DNSDriver instance.
         :type driver: :class:`DNSDriver`
@@ -113,10 +134,10 @@ class MailRedirect(object):
         self.id = str(id) if id else None
         self.source = source
         self.destination = destination
-        self.zone_id = zone_id
+        self.zone = zone
         self.driver = driver
 
-    def update(self, destination, source=None, zone_id=None):
+    def update(self, destination, source=None):
         return self.driver.ex_update_mail_redirect(mail_r=self,
                                                    destination=destination,
                                                    source=None)
@@ -126,7 +147,7 @@ class MailRedirect(object):
 
     def __repr__(self):
         return ('<PointDNSMailRedirect: source=%s, destination=%s,zone=%s ...>'
-                % (self.source, self.destination, self.zone_id))
+                % (self.source, self.destination, self.zone.id))
 
 
 class PointDNSDriver(DNSDriver):
@@ -182,7 +203,8 @@ class PointDNSDriver(DNSDriver):
         """
         try:
             response = self.connection.request('/zones/%s' % zone_id)
-        except MalformedResponseError as e:
+        except MalformedResponseError:
+            e = sys.exc_info()[1]
             if e.body == 'Not found':
                 raise ZoneDoesNotExistError(driver=self,
                                             value="The zone doesn't exists",
@@ -207,7 +229,8 @@ class PointDNSDriver(DNSDriver):
         try:
             response = self.connection.request('/zones/%s/records/%s' %
                                                (zone_id, record_id))
-        except MalformedResponseError as e:
+        except MalformedResponseError:
+            e = sys.exc_info()[1]
             if e.body == 'Not found':
                 raise RecordDoesNotExistError(value="Record doesn't exists",
                                               driver=self,
@@ -238,35 +261,12 @@ class PointDNSDriver(DNSDriver):
         if extra is not None:
             r_json.update(extra)
         r_data = json.dumps({'zone': r_json})
-        response = self.connection.request('/zones', method='POST',
-                                           data=r_data)
-        zone = self._to_zone(response.object)
-        return zone
-
-    def update_zone(self, zone, domain, ttl=None, extra=None):
-        """
-        Update en existing zone.
-
-        :param zone: Zone to update.
-        :type  zone: :class:`Zone`
-
-        :param domain: Zone domain name (e.g. example.com)
-        :type  domain: ``str``
-
-        :param ttl: TTL for new records. (optional)
-        :type  ttl: ``int``
-
-        :param extra: Extra attributes (group, user-id). (optional)
-        :type  extra: ``dict``
-
-        :rtype: :class:`Zone`
-        """
-        r_json = {'name': domain}
-        if extra is not None:
-            r_json.update(extra)
-        r_data = json.dumps({'zone': r_json})
-        response = self.connection.request('/zones/%s' % zone.id,
-                                           method='PUT', data=r_data)
+        try:
+            response = self.connection.request('/zones', method='POST',
+                                               data=r_data)
+        except BaseHTTPError:
+            e = sys.exc_info()[1]
+            raise PointDNSException(e.code, e.message)
         zone = self._to_zone(response.object)
         return zone
 
@@ -298,11 +298,50 @@ class PointDNSDriver(DNSDriver):
         if extra is not None:
             r_json.update(extra)
         r_data = json.dumps({'zone_record': r_json})
-        response = self.connection.request('/zones/%s/records' % zone.id,
-                                           method='POST', data=r_data)
+        try:
+            response = self.connection.request('/zones/%s/records' % zone.id,
+                                               method='POST', data=r_data)
+        except BaseHTTPError:
+            e = sys.exc_info()[1]
+            raise PointDNSException(e.code, e.message)
         record = self._to_record(response.object, zone=zone)
         return record
 
+    def update_zone(self, zone, domain, ttl=None, extra=None):
+        """
+        Update en existing zone.
+
+        :param zone: Zone to update.
+        :type  zone: :class:`Zone`
+
+        :param domain: Zone domain name (e.g. example.com)
+        :type  domain: ``str``
+
+        :param ttl: TTL for new records. (optional)
+        :type  ttl: ``int``
+
+        :param extra: Extra attributes (group, user-id). (optional)
+        :type  extra: ``dict``
+
+        :rtype: :class:`Zone`
+        """
+        r_json = {'name': domain}
+        if extra is not None:
+            r_json.update(extra)
+        r_data = json.dumps({'zone': r_json})
+        try:
+            response = self.connection.request('/zones/%s' % zone.id,
+                                               method='PUT', data=r_data)
+        except (BaseHTTPError, MalformedResponseError):
+            e = sys.exc_info()[1]
+            if isinstance(e, MalformedResponseError) and e.body == 'Not found':
+                raise ZoneDoesNotExistError(value="Zone doesn't exists",
+                                            driver=self,
+                                            zone_id=zone.id)
+            raise PointDNSException(e.code, e.message)
+        zone = self._to_zone(response.object)
+        return zone
+
     def update_record(self, record, name, type, data, extra=None):
         """
         Update an existing record.
@@ -332,9 +371,17 @@ class PointDNSDriver(DNSDriver):
         if extra is not None:
             r_json.update(extra)
         r_data = json.dumps({'zone_record': r_json})
-        response = self.connection.request('/zones/%s/records/%s' %
-                                           (zone.id, record.id),
-                                           method='PUT', data=r_data)
+        try:
+            response = self.connection.request('/zones/%s/records/%s' %
+                                               (zone.id, record.id),
+                                               method='PUT', data=r_data)
+        except (BaseHTTPError, MalformedResponseError):
+            e = sys.exc_info()[1]
+            if isinstance(e, MalformedResponseError) and e.body == 'Not found':
+                raise RecordDoesNotExistError(value="Record doesn't exists",
+                                              driver=self,
+                                              record_id=record.id)
+            raise PointDNSException(e.code, e.message)
         record = self._to_record(response.object, zone=zone)
         return record
 
@@ -349,7 +396,15 @@ class PointDNSDriver(DNSDriver):
 
         :rtype: ``bool``
         """
-        self.connection.request('/zones/%s' % zone.id, method='DELETE')
+        try:
+            self.connection.request('/zones/%s' % zone.id, method='DELETE')
+        except MalformedResponseError:
+            e = sys.exc_info()[1]
+            if e.body == 'Not found':
+                raise ZoneDoesNotExistError(driver=self,
+                                            value="The zone doesn't exists",
+                                            zone_id=zone.id)
+            raise e
         return True
 
     def delete_record(self, record):
@@ -363,14 +418,25 @@ class PointDNSDriver(DNSDriver):
         """
         zone_id = record.zone.id
         record_id = record.id
-        self.connection.request('/zones/%s/records/%s' % (zone_id, record_id),
-                                method='DELETE')
+        try:
+            self.connection.request('/zones/%s/records/%s' % (zone_id,
+                                                              record_id),
+                                    method='DELETE')
+        except MalformedResponseError:
+            e = sys.exc_info()[1]
+            if e.body == 'Not found':
+                raise RecordDoesNotExistError(value="Record doesn't exists",
+                                              driver=self,
+                                              record_id=record_id)
+            raise e
         return True
 
     def ex_list_redirects(self, zone):
         """
         :param zone: Zone to list redirects for.
         :type zone: :class:`Zone`
+
+        :rtype: ``list`` of :class:`Record`
         """
         response = self.connection.request('/zones/%s/redirects' % zone.id)
         redirects = self._to_redirects(response.object, zone)
@@ -380,6 +446,8 @@ class PointDNSDriver(DNSDriver):
         """
         :param zone: Zone to list redirects for.
         :type zone: :class:`Zone`
+
+        :rtype: ``list`` of :class:`MailRedirect`
         """
         response = self.connection.request('/zones/%s/mail_redirects' %
                                            zone.id)
@@ -407,6 +475,8 @@ class PointDNSDriver(DNSDriver):
         :param query: boolean Information about including query string when
                       redirecting. (optional).
         :type query: ``bool``
+
+        :rtype: :class:`Record`
         """
         r_json = {'name': name, 'redirect_to': redirect_to}
         if type is not None:
@@ -416,9 +486,13 @@ class PointDNSDriver(DNSDriver):
         if query is not None:
             r_json['redirect_query_string'] = query
         r_data = json.dumps({'zone_redirect': r_json})
-        response = self.connection.request('/zones/%s/redirects' % zone.id,
-                                           method='POST', data=r_data)
-        redirect = self._to_redirect(response.object, zone.id)
+        try:
+            response = self.connection.request('/zones/%s/redirects' % zone.id,
+                                               method='POST', data=r_data)
+        except (BaseHTTPError, MalformedResponseError):
+            e = sys.exc_info()[1]
+            raise PointDNSException(e.code, e.message)
+        redirect = self._to_redirect(response.object, zone=zone)
         return redirect
 
     def ex_create_mail_redirect(self, destination, source, zone):
@@ -431,39 +505,64 @@ class PointDNSDriver(DNSDriver):
 
         :param zone: Zone to list redirects for.
         :type zone: :class:`Zone`
+
+        :rtype: ``list`` of :class:`MailRedirect`
         """
         r_json = {'destination_address': destination, 'source_address': source}
         r_data = json.dumps({'zone_mail_redirect': r_json})
-        response = self.connection.request('/zones/%s/mail_redirects' %
-                                           zone.id, method='POST',
-                                           data=r_data)
-        mail_redirect = self._to_mail_redirect(response.object, zone.id)
+        try:
+            response = self.connection.request('/zones/%s/mail_redirects' %
+                                               zone.id, method='POST',
+                                               data=r_data)
+        except (BaseHTTPError, MalformedResponseError):
+            e = sys.exc_info()[1]
+            raise PointDNSException(e.code, e.message)
+        mail_redirect = self._to_mail_redirect(response.object, zone=zone)
         return mail_redirect
 
-    def ex_get_redirect(self, zone, redirect_id):
+    def ex_get_redirect(self, zone_id, redirect_id):
         """
         :param zone: Zone to list redirects for.
         :type zone: :class:`Zone`
 
         :param redirect_id: Redirect id.
         :type redirect_id: ``str``
+
+        :rtype: ``list`` of :class:`Redirect`
         """
-        response = self.connection.request('/zones/%s/redirects/%s' %
-                                           (zone.id, redirect_id))
-        redirect = self._to_redirect(response.object, zone.id)
+        try:
+            response = self.connection.request('/zones/%s/redirects/%s' %
+                                               (zone_id, redirect_id))
+        except (BaseHTTPError, MalformedResponseError):
+            e = sys.exc_info()[1]
+            if isinstance(e, MalformedResponseError) and e.body == 'Not found':
+                raise PointDNSException(httplib.NOT_FOUND,
+                                        "Couldn't found redirect")
+            raise PointDNSException(e.code, e.message)
+        redirect = self._to_redirect(response.object, zone_id=zone_id)
         return redirect
 
-    def ex_get_mail_redirects(self, zone, mail_r_id):
+    def ex_get_mail_redirects(self, zone_id, mail_r_id):
         """
         :param zone: Zone to list redirects for.
         :type zone: :class:`Zone`
 
         :param mail_r_id: Mail redirect id.
         :type mail_r_id: ``str``
+
+        :rtype: ``list`` of :class:`MailRedirect`
         """
-        response = self.connection.request('/zones/%s/mail_redirects/%s' %
-                                           (zone.id, mail_r_id))
-        mail_redirect = self._to_mail_redirect(response.object, zone.id)
+        try:
+            response = self.connection.request('/zones/%s/mail_redirects/%s' %
+                                               (zone_id, mail_r_id))
+        except (BaseHTTPError, MalformedResponseError):
+            e = sys.exc_info()[1]
+            if isinstance(e, MalformedResponseError) and e.body == 'Not found':
+                raise PointDNSException(httplib.NOT_FOUND,
+                                        "Couldn't found mail redirect")
+            raise PointDNSException(e.code, e.message)
+        mail_redirect = self._to_mail_redirect(response.object,
+                                               zone_id=zone_id)
         return mail_redirect
 
     def ex_update_redirect(self, redirect, redirect_to=None, name=None,
@@ -488,8 +587,10 @@ class PointDNSDriver(DNSDriver):
         :param query: boolean Information about including query string when
                       redirecting. (optional).
         :type query: ``bool``
+
+        :rtype: ``list`` of :class:`Redirect`
         """
-        zone_id = redirect.zone_id
+        zone_id = redirect.zone.id
         r_json = {}
         if redirect_to is not None:
             r_json['redirect_to'] = redirect_to
@@ -502,10 +603,17 @@ class PointDNSDriver(DNSDriver):
         if query is not None:
             r_json['redirect_query_string'] = query
         r_data = json.dumps({'zone_redirect': r_json})
-        response = self.connection.request('/zones/%s/redirects/%s' %
-                                           (zone_id, redirect.id),
-                                           method='PUT', data=r_data)
-        redirect = self._to_redirect(response.object, zone_id=zone_id)
+        try:
+            response = self.connection.request('/zones/%s/redirects/%s' %
+                                               (zone_id, redirect.id),
+                                               method='PUT', data=r_data)
+        except (BaseHTTPError, MalformedResponseError):
+            e = sys.exc_info()[1]
+            if isinstance(e, MalformedResponseError) and e.body == 'Not found':
+                raise PointDNSException(httplib.NOT_FOUND,
+                                        "Couldn't found redirect")
+            raise PointDNSException(e.code, e.message)
+        redirect = self._to_redirect(response.object, zone=redirect.zone)
         return redirect
 
     def ex_update_mail_redirect(self, mail_r, destination, source=None):
@@ -518,39 +626,66 @@ class PointDNSDriver(DNSDriver):
 
         :param source: The source address of mail redirect. (optional)
         :type source: ``str``
+
+        :rtype: ``list`` of :class:`MailRedirect`
         """
-        zone_id = mail_r.zone_id
+        zone_id = mail_r.zone.id
         r_json = {'destination_address': destination}
         if source is not None:
             r_json['source_address'] = source
         r_data = json.dumps({'zone_redirect': r_json})
-        response = self.connection.request('/zones/%s/mail_redirects/%s' %
-                                           (zone_id, mail_r.id),
-                                           method='PUT', data=r_data)
+        try:
+            response = self.connection.request('/zones/%s/mail_redirects/%s' %
+                                               (zone_id, mail_r.id),
+                                               method='PUT', data=r_data)
+        except (BaseHTTPError, MalformedResponseError):
+            e = sys.exc_info()[1]
+            if isinstance(e, MalformedResponseError) and e.body == 'Not found':
+                raise PointDNSException(httplib.NOT_FOUND,
+                                        "Couldn't found mail redirect")
+            raise PointDNSException(e.code, e.message)
         mail_redirect = self._to_mail_redirect(response.object,
-                                               zone_id=zone_id)
+                                               zone=mail_r.zone)
         return mail_redirect
 
     def ex_delete_redirect(self, redirect):
         """
         :param mail_r: Redirect to delete
         :type mail_r: :class:`Redirect`
+
+        :rtype: ``bool``
         """
-        zone_id = redirect.zone_id
+        zone_id = redirect.zone.id
         redirect_id = redirect.id
-        self.connection.request('/zones/%s/redirects/%s' % (zone_id,
-                                redirect_id), method='DELETE')
+        try:
+            self.connection.request('/zones/%s/redirects/%s' % (zone_id,
+                                    redirect_id), method='DELETE')
+        except (BaseHTTPError, MalformedResponseError):
+            e = sys.exc_info()[1]
+            if isinstance(e, MalformedResponseError) and e.body == 'Not found':
+                raise PointDNSException(httplib.NOT_FOUND,
+                                        "Couldn't found redirect")
+            raise PointDNSException(e.code, e.message)
         return True
 
     def ex_delete_mail_redirect(self, mail_r):
         """
         :param mail_r: Mail redirect to update
         :type mail_r: :class:`MailRedirect`
+
+        :rtype: ``bool``
         """
-        zone_id = mail_r.zone_id
+        zone_id = mail_r.zone.id
         mail_r_id = mail_r.id
-        self.connection.request('/zones/%s/mail_redirects/%s' % (zone_id,
-                                mail_r_id), method='DELETE')
+        try:
+            self.connection.request('/zones/%s/mail_redirects/%s' % (zone_id,
+                                    mail_r_id), method='DELETE')
+        except (BaseHTTPError, MalformedResponseError):
+            e = sys.exc_info()[1]
+            if isinstance(e, MalformedResponseError) and e.body == 'Not found':
+                raise PointDNSException(httplib.NOT_FOUND,
+                                        "Couldn't found mail redirect")
+            raise PointDNSException(e.code, e.message)
         return True
 
     def _to_zones(self, data):
@@ -601,11 +736,13 @@ class PointDNSDriver(DNSDriver):
     def _to_redirects(self, data, zone):
         redirects = []
         for item in data:
-            redirect = self._to_redirect(item, zone.id)
+            redirect = self._to_redirect(item, zone=zone)
             redirects.append(redirect)
         return redirects
 
-    def _to_redirect(self, data, zone_id):
+    def _to_redirect(self, data, zone_id=None, zone=None):
+        if not zone:  # We need zone_id or zone
+            zone = self.get_zone(zone_id)
         record = data.get('zone_redirect')
         id = record.get('id')
         name = record.get('name')
@@ -613,7 +750,7 @@ class PointDNSDriver(DNSDriver):
         type = record.get('redirect_type')
         iframe = record.get('iframe_title')
         query = record.get('redirect_query_string')
-        return Redirect(id, name, redirect_to, type, self, zone_id,
+        return Redirect(id, name, redirect_to, type, self, zone,
                         iframe=iframe, query=query)
 
     def _to_mail_redirects(self, data, zone):
@@ -623,9 +760,11 @@ class PointDNSDriver(DNSDriver):
             mail_redirects.append(mail_redirect)
         return mail_redirects
 
-    def _to_mail_redirect(self, data, zone_id):
+    def _to_mail_redirect(self, data, zone_id=None, zone=None):
+        if not zone:  # We need zone_id or zone
+            zone = self.get_zone(zone_id)
         record = data.get('zone_mail_redirect')
         id = record.get('id')
         destination = record.get('destination_address')
         source = record.get('source_address')
-        return MailRedirect(id, source, destination, zone_id, self)
+        return MailRedirect(id, source, destination, zone, self)

http://git-wip-us.apache.org/repos/asf/libcloud/blob/58c4ec94/libcloud/test/dns/fixtures/pointdns/_zones_1_ZONE_UPDATE.json
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/pointdns/_zones_1_ZONE_UPDATE.json b/libcloud/test/dns/fixtures/pointdns/_zones_1_ZONE_UPDATE.json
new file mode 100644
index 0000000..2c83f26
--- /dev/null
+++ b/libcloud/test/dns/fixtures/pointdns/_zones_1_ZONE_UPDATE.json
@@ -0,0 +1,9 @@
+{
+    "zone": {
+        "id": 1,
+        "name": "example.com",
+        "group": "Other Group",
+        "user-id": 6,
+        "ttl": 3600
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/58c4ec94/libcloud/test/dns/fixtures/pointdns/_zones_1_mail_redirects_CREATE.json
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/pointdns/_zones_1_mail_redirects_CREATE.json b/libcloud/test/dns/fixtures/pointdns/_zones_1_mail_redirects_CREATE.json
new file mode 100644
index 0000000..f6f6d3c
--- /dev/null
+++ b/libcloud/test/dns/fixtures/pointdns/_zones_1_mail_redirects_CREATE.json
@@ -0,0 +1,8 @@
+{
+    "zone_mail_redirect": {
+        "source_address": "admin",
+        "destination_address": "user@example-site.com",
+        "id": 5,
+        "zone_id": 1
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/58c4ec94/libcloud/test/dns/fixtures/pointdns/_zones_1_mail_redirects_DELETE.json
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/pointdns/_zones_1_mail_redirects_DELETE.json b/libcloud/test/dns/fixtures/pointdns/_zones_1_mail_redirects_DELETE.json
new file mode 100644
index 0000000..bde522d
--- /dev/null
+++ b/libcloud/test/dns/fixtures/pointdns/_zones_1_mail_redirects_DELETE.json
@@ -0,0 +1,5 @@
+{
+    "zone_mail_redirect": {
+        "status": "OK"
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/58c4ec94/libcloud/test/dns/fixtures/pointdns/_zones_1_mail_redirects_GET.json
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/pointdns/_zones_1_mail_redirects_GET.json b/libcloud/test/dns/fixtures/pointdns/_zones_1_mail_redirects_GET.json
new file mode 100644
index 0000000..f6f6d3c
--- /dev/null
+++ b/libcloud/test/dns/fixtures/pointdns/_zones_1_mail_redirects_GET.json
@@ -0,0 +1,8 @@
+{
+    "zone_mail_redirect": {
+        "source_address": "admin",
+        "destination_address": "user@example-site.com",
+        "id": 5,
+        "zone_id": 1
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/58c4ec94/libcloud/test/dns/fixtures/pointdns/_zones_1_mail_redirects_LIST.json
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/pointdns/_zones_1_mail_redirects_LIST.json b/libcloud/test/dns/fixtures/pointdns/_zones_1_mail_redirects_LIST.json
new file mode 100644
index 0000000..e28c237
--- /dev/null
+++ b/libcloud/test/dns/fixtures/pointdns/_zones_1_mail_redirects_LIST.json
@@ -0,0 +1,18 @@
+[
+    {
+        "zone_mail_redirect": {
+            "source_address": "admin",
+            "destination_address": "user@example-site.com",
+            "id": 5,
+            "zone_id": 1
+        }
+    },
+    {
+        "zone_mail_redirect": {
+            "source_address": "new_admin",
+            "destination_address": "second.user@example-site.com",
+            "id": 7,
+            "zone_id": 1
+        }
+    }
+]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/58c4ec94/libcloud/test/dns/fixtures/pointdns/_zones_1_mail_redirects_UPDATE.json
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/pointdns/_zones_1_mail_redirects_UPDATE.json b/libcloud/test/dns/fixtures/pointdns/_zones_1_mail_redirects_UPDATE.json
new file mode 100644
index 0000000..c3c43bd
--- /dev/null
+++ b/libcloud/test/dns/fixtures/pointdns/_zones_1_mail_redirects_UPDATE.json
@@ -0,0 +1,8 @@
+{
+    "zone_mail_redirect": {
+        "source_address": "new_admin",
+        "destination_address": "new_user@example-site.com",
+        "id": 5,
+        "zone_id": 1
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/58c4ec94/libcloud/test/dns/fixtures/pointdns/_zones_1_redirects_CREATE.json
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/pointdns/_zones_1_redirects_CREATE.json b/libcloud/test/dns/fixtures/pointdns/_zones_1_redirects_CREATE.json
new file mode 100644
index 0000000..af8da48
--- /dev/null
+++ b/libcloud/test/dns/fixtures/pointdns/_zones_1_redirects_CREATE.json
@@ -0,0 +1,11 @@
+{
+    "zone_redirect": {
+        "name": "redirect2.domain1.com.",
+        "redirect_to": "http://other.com",
+        "id": 36843229,
+        "redirect_type": 302,
+        "iframe_title": "An Iframe",
+        "redirect_query_string": true,
+        "zone_id": 1
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/58c4ec94/libcloud/test/dns/fixtures/pointdns/_zones_1_redirects_DELETE.json
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/pointdns/_zones_1_redirects_DELETE.json b/libcloud/test/dns/fixtures/pointdns/_zones_1_redirects_DELETE.json
new file mode 100644
index 0000000..9e52b2d
--- /dev/null
+++ b/libcloud/test/dns/fixtures/pointdns/_zones_1_redirects_DELETE.json
@@ -0,0 +1,5 @@
+{
+    "zone_redirect": {
+        "status": "OK"
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/58c4ec94/libcloud/test/dns/fixtures/pointdns/_zones_1_redirects_GET.json
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/pointdns/_zones_1_redirects_GET.json b/libcloud/test/dns/fixtures/pointdns/_zones_1_redirects_GET.json
new file mode 100644
index 0000000..da4379d
--- /dev/null
+++ b/libcloud/test/dns/fixtures/pointdns/_zones_1_redirects_GET.json
@@ -0,0 +1,11 @@
+{
+    "zone_redirect": {
+        "name": "redirect2.domain1.com.",
+        "redirect_to": "http://other.com",
+        "id": 36843229,
+        "redirect_type": 302,
+        "iframe_title": null,
+        "redirect_query_string": false,
+        "zone_id": 162949
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/58c4ec94/libcloud/test/dns/fixtures/pointdns/_zones_1_redirects_LIST.json
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/pointdns/_zones_1_redirects_LIST.json b/libcloud/test/dns/fixtures/pointdns/_zones_1_redirects_LIST.json
new file mode 100644
index 0000000..da3eba3
--- /dev/null
+++ b/libcloud/test/dns/fixtures/pointdns/_zones_1_redirects_LIST.json
@@ -0,0 +1,24 @@
+[
+    {
+        "zone_redirect": {
+            "name": "redirect2.domain1.com.",
+            "redirect_to": "http://other.com",
+            "id": 36843229,
+            "redirect_type": 302,
+            "iframe_title": null,
+            "redirect_query_string": false,
+            "zone_id": 1
+        }
+    },
+    {
+        "zone_redirect": {
+            "name": "redirect1.domain1.com.",
+            "redirect_to": "http://someother.com",
+            "id": 36843497,
+            "redirect_type": 302,
+            "iframe_title": null,
+            "redirect_query_string": false,
+            "zone_id": 1
+        }
+    }
+]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/58c4ec94/libcloud/test/dns/fixtures/pointdns/_zones_1_redirects_UPDATE.json
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/pointdns/_zones_1_redirects_UPDATE.json b/libcloud/test/dns/fixtures/pointdns/_zones_1_redirects_UPDATE.json
new file mode 100644
index 0000000..2077d28
--- /dev/null
+++ b/libcloud/test/dns/fixtures/pointdns/_zones_1_redirects_UPDATE.json
@@ -0,0 +1,11 @@
+{
+    "zone_redirect": {
+        "name": "redirect3.domain1.com.",
+        "redirect_to": "http://updatedother.com",
+        "id": 36843229,
+        "redirect_type": 302,
+        "iframe_title": null,
+        "redirect_query_string": false,
+        "zone_id": 1
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/58c4ec94/libcloud/test/dns/fixtures/pointdns/error.json
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/pointdns/error.json b/libcloud/test/dns/fixtures/pointdns/error.json
new file mode 100644
index 0000000..8093d4c
--- /dev/null
+++ b/libcloud/test/dns/fixtures/pointdns/error.json
@@ -0,0 +1,7 @@
+{
+    "zone": {
+        "base": [
+            "You have reached domains limit. Please upgrade your plan to add more."
+        ]
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/58c4ec94/libcloud/test/dns/fixtures/pointdns/not_found.json
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/pointdns/not_found.json b/libcloud/test/dns/fixtures/pointdns/not_found.json
new file mode 100644
index 0000000..ec6f9ab
--- /dev/null
+++ b/libcloud/test/dns/fixtures/pointdns/not_found.json
@@ -0,0 +1 @@
+Not found
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/58c4ec94/libcloud/test/dns/fixtures/pointdns/redirect_error.json
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/pointdns/redirect_error.json b/libcloud/test/dns/fixtures/pointdns/redirect_error.json
new file mode 100644
index 0000000..5b6672d
--- /dev/null
+++ b/libcloud/test/dns/fixtures/pointdns/redirect_error.json
@@ -0,0 +1,10 @@
+{
+    "zone_redirect": {
+        "redirect_type": [
+            "is not included in the list"
+        ],
+        "name": [
+            "There is already A type record or redirect for this subdomain. Please remove it first."
+        ]
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/58c4ec94/libcloud/test/dns/test_pointdns.py
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/test_pointdns.py b/libcloud/test/dns/test_pointdns.py
index aa85e9b..570cc4a 100644
--- a/libcloud/test/dns/test_pointdns.py
+++ b/libcloud/test/dns/test_pointdns.py
@@ -18,7 +18,10 @@ import unittest
 from libcloud.utils.py3 import httplib
 
 from libcloud.dns.types import RecordType
+from libcloud.dns.types import ZoneDoesNotExistError
+from libcloud.dns.types import RecordDoesNotExistError
 from libcloud.dns.drivers.pointdns import PointDNSDriver
+from libcloud.dns.drivers.pointdns import PointDNSException
 
 from libcloud.test import MockHttp
 from libcloud.test.file_fixtures import DNSFileFixtures
@@ -99,6 +102,15 @@ class PointDNSTests(unittest.TestCase):
         self.assertEqual(zone1.ttl, 3600)
         self.assertHasKeys(zone1.extra, ['group', 'user-id'])
 
+    def test_get_zone_zone_not_exists(self):
+        PointDNSMockHttp.type = 'GET_ZONE_NOT_EXIST'
+        try:
+            self.driver.get_zone(zone_id='1')
+        except ZoneDoesNotExistError:
+            pass
+        else:
+            self.fail('Exception was not thrown')
+
     def test_get_record_success(self):
         PointDNSMockHttp.type = 'GET'
         record = self.driver.get_record(zone_id='1',
@@ -109,6 +121,16 @@ class PointDNSTests(unittest.TestCase):
         self.assertEqual(record.data, '1.2.3.4')
         self.assertHasKeys(record.extra, ['ttl', 'zone_id', 'aux'])
 
+    def test_get_record_record_not_exists(self):
+        PointDNSMockHttp.type = 'GET_RECORD_NOT_EXIST'
+        try:
+            self.driver.get_record(zone_id='1',
+                                   record_id='141')
+        except RecordDoesNotExistError:
+            pass
+        else:
+            self.fail('Exception was not thrown')
+
     def test_create_zone_success(self):
         PointDNSMockHttp.type = 'CREATE'
         zone = self.driver.create_zone(domain='example.com')
@@ -118,6 +140,15 @@ class PointDNSTests(unittest.TestCase):
         self.assertEqual(zone.type, 'master')
         self.assertHasKeys(zone.extra, ['group', 'user-id'])
 
+    def test_create_zone_with_error(self):
+        PointDNSMockHttp.type = 'CREATE_ZONE_WITH_ERROR'
+        try:
+            self.driver.create_zone(domain='example.com')
+        except PointDNSException:
+            pass
+        else:
+            self.fail('Exception was not thrown')
+
     def test_create_record_success(self):
         PointDNSMockHttp.type = 'GET'
         zone = self.driver.list_zones()[0]
@@ -131,6 +162,40 @@ class PointDNSTests(unittest.TestCase):
         self.assertEqual(record.data, '1.2.3.4')
         self.assertHasKeys(record.extra, ['ttl', 'zone_id', 'aux'])
 
+    def test_create_record_with_error(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        PointDNSMockHttp.type = 'CREATE_WITH_ERROR'
+        try:
+            self.driver.create_record(name='site.example.com',
+                                      zone=zone, type=RecordType.A,
+                                      data='1.2.3.4')
+        except PointDNSException:
+            pass
+        else:
+            self.fail('Exception was not thrown')
+
+    def test_update_zone_success(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        PointDNSMockHttp.type = 'ZONE_UPDATE'
+        extra = {'user-id': 6}
+        _zone = self.driver.update_zone(zone, zone.domain, zone.ttl,
+                                        extra=extra)
+        self.assertEqual(_zone.extra.get('user-id'), 6)
+
+    def test_update_zone_with_error(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        PointDNSMockHttp.type = 'UPDATE_ZONE_WITH_ERROR'
+        extra = {'user-id': 6}
+        try:
+            self.driver.update_zone(zone, zone.domain, zone.ttl, extra=extra)
+        except PointDNSException:
+            pass
+        else:
+            self.fail('Exception was not thrown')
+
     def test_update_record_success(self):
         PointDNSMockHttp.type = 'GET'
         record = self.driver.get_record(zone_id='1',
@@ -145,6 +210,21 @@ class PointDNSTests(unittest.TestCase):
         self.assertEqual(record1.data, '1.2.3.5')
         self.assertEqual(record1.extra.get('ttl'), 4500)
 
+    def test_update_record_with_error(self):
+        PointDNSMockHttp.type = 'GET'
+        record = self.driver.get_record(zone_id='1',
+                                        record_id='141')
+        PointDNSMockHttp.type = 'UPDATE_RECORD_WITH_ERROR'
+        extra = {'ttl': 4500}
+        try:
+            self.driver.update_record(record=record, name='updated.com',
+                                      type=RecordType.A, data='1.2.3.5',
+                                      extra=extra)
+        except PointDNSException:
+            pass
+        else:
+            self.fail('Exception was not thrown')
+
     def test_delete_zone_success(self):
         PointDNSMockHttp.type = 'GET'
         zone = self.driver.list_zones()[0]
@@ -152,6 +232,17 @@ class PointDNSTests(unittest.TestCase):
         status = self.driver.delete_zone(zone=zone)
         self.assertTrue(status)
 
+    def test_delete_zone_zone_not_exists(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        PointDNSMockHttp.type = 'DELETE_ZONE_NOT_EXIST'
+        try:
+            self.driver.delete_zone(zone=zone)
+        except ZoneDoesNotExistError:
+            pass
+        else:
+            self.fail('Exception was not thrown')
+
     def test_delete_record_success(self):
         PointDNSMockHttp.type = 'GET'
         zone = self.driver.list_zones()[0]
@@ -162,6 +253,319 @@ class PointDNSTests(unittest.TestCase):
         status = self.driver.delete_record(record=record)
         self.assertTrue(status)
 
+    def test_delete_record_record_not_exists(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        records = self.driver.list_records(zone=zone)
+        self.assertEqual(len(records), 2)
+        record = records[1]
+        PointDNSMockHttp.type = 'DELETE_RECORD_NOT_EXIST'
+        try:
+            self.driver.delete_record(record=record)
+        except RecordDoesNotExistError:
+            pass
+        else:
+            self.fail('Exception was not thrown')
+
+    def test_ex_list_redirects_success(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        PointDNSMockHttp.type = 'LIST'
+        redirects = self.driver.ex_list_redirects(zone)
+        self.assertEqual(len(redirects), 2)
+
+        redirect1 = redirects[0]
+        self.assertEqual(redirect1.id, '36843229')
+        self.assertEqual(redirect1.name, 'redirect2.domain1.com.')
+        self.assertEqual(redirect1.type, '302')
+        self.assertEqual(redirect1.data, 'http://other.com')
+        self.assertEqual(redirect1.iframe, None)
+        self.assertEqual(redirect1.query, False)
+        self.assertEqual(zone, redirect1.zone)
+
+        redirect2 = redirects[1]
+        self.assertEqual(redirect2.id, '36843497')
+        self.assertEqual(redirect2.name, 'redirect1.domain1.com.')
+        self.assertEqual(redirect2.type, '302')
+        self.assertEqual(redirect2.data, 'http://someother.com')
+        self.assertEqual(redirect2.iframe, None)
+        self.assertEqual(redirect2.query, False)
+        self.assertEqual(zone, redirect1.zone)
+
+    def test_ex_list_mail_redirects(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        PointDNSMockHttp.type = 'LIST'
+        mail_redirects = self.driver.ex_list_mail_redirects(zone)
+        self.assertEqual(len(mail_redirects), 2)
+
+        mail_redirect1 = mail_redirects[0]
+        self.assertEqual(mail_redirect1.id, '5')
+        self.assertEqual(mail_redirect1.source, 'admin')
+        self.assertEqual(mail_redirect1.destination, 'user@example-site.com')
+        self.assertEqual(zone, mail_redirect1.zone)
+
+        mail_redirect2 = mail_redirects[1]
+        self.assertEqual(mail_redirect2.id, '7')
+        self.assertEqual(mail_redirect2.source, 'new_admin')
+        self.assertEqual(mail_redirect2.destination,
+                         'second.user@example-site.com')
+        self.assertEqual(zone, mail_redirect2.zone)
+
+    def test_ex_create_redirect(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        PointDNSMockHttp.type = 'CREATE'
+        redirect = self.driver.ex_create_redirect('http://other.com',
+                                                  'redirect2', '302', zone,
+                                                  iframe='An Iframe',
+                                                  query=True)
+        self.assertEqual(redirect.id, '36843229')
+        self.assertEqual(redirect.name, 'redirect2.domain1.com.')
+        self.assertEqual(redirect.type, '302')
+        self.assertEqual(redirect.data, 'http://other.com')
+        self.assertEqual(redirect.iframe, 'An Iframe')
+        self.assertEqual(redirect.query, True)
+        self.assertEqual(zone.id, redirect.zone.id)
+
+    def test_ex_create_redirect_with_error(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        PointDNSMockHttp.type = 'CREATE_WITH_ERROR'
+        try:
+            self.driver.ex_create_redirect('http://other.com', 'redirect2',
+                                           '302', zone, iframe='An Iframe',
+                                           query=True)
+        except PointDNSException:
+            e = sys.exc_info()[1]
+            # The API actually responds with httplib.UNPROCESSABLE_ENTITY code,
+            # but httplib.responses doesn't have it.
+            self.assertEqual(e.code, httplib.METHOD_NOT_ALLOWED)
+        else:
+            self.fail('Exception was not thrown')
+
+    def test_ex_create_mail_redirect(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        PointDNSMockHttp.type = 'CREATE'
+        mail_redirect = self.driver.ex_create_mail_redirect(
+            'user@example-site.com', 'admin', zone)
+        self.assertEqual(mail_redirect.id, '5')
+        self.assertEqual(mail_redirect.source, 'admin')
+        self.assertEqual(mail_redirect.destination, 'user@example-site.com')
+        self.assertEqual(zone.id, mail_redirect.zone.id)
+
+    def test_ex_create_mail_redirect_with_error(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        PointDNSMockHttp.type = 'CREATE_WITH_ERROR'
+        try:
+            self.driver.ex_create_mail_redirect('user@example-site.com',
+                                                'admin', zone)
+        except PointDNSException:
+            e = sys.exc_info()[1]
+            # The API actually responds with httplib.UNPROCESSABLE_ENTITY code,
+            # but httplib.responses doesn't have it.
+            self.assertEqual(e.code, httplib.METHOD_NOT_ALLOWED)
+        else:
+            self.fail('Exception was not thrown')
+
+    def test_ex_get_redirect(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        redirect = self.driver.ex_get_redirect(zone.id, '36843229')
+        self.assertEqual(redirect.id, '36843229')
+        self.assertEqual(redirect.name, 'redirect2.domain1.com.')
+        self.assertEqual(redirect.type, '302')
+        self.assertEqual(redirect.data, 'http://other.com')
+        self.assertEqual(redirect.iframe, None)
+        self.assertEqual(redirect.query, False)
+        self.assertEqual(zone.id, redirect.zone.id)
+
+    def test_ex_get_redirect_with_error(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        PointDNSMockHttp.type = 'GET_WITH_ERROR'
+        try:
+            self.driver.ex_get_redirect(zone.id, '36843229')
+        except PointDNSException:
+            e = sys.exc_info()[1]
+            # The API actually responds with httplib.UNPROCESSABLE_ENTITY code,
+            # but httplib.responses doesn't have it.
+            self.assertEqual(e.code, httplib.METHOD_NOT_ALLOWED)
+        else:
+            self.fail('Exception was not thrown')
+
+    def test_ex_get_redirect_not_found(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        PointDNSMockHttp.type = 'GET_NOT_FOUND'
+        try:
+            self.driver.ex_get_redirect(zone.id, '36843229')
+        except PointDNSException:
+            e = sys.exc_info()[1]
+            self.assertEqual(e.code, httplib.NOT_FOUND)
+            self.assertEqual(e.message, "Couldn't found redirect")
+        else:
+            self.fail('Exception was not thrown')
+
+    def test_ex_get_mail_redirects(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        mail_redirect = self.driver.ex_get_mail_redirects(zone.id, '5')
+        self.assertEqual(mail_redirect.id, '5')
+        self.assertEqual(mail_redirect.source, 'admin')
+        self.assertEqual(mail_redirect.destination, 'user@example-site.com')
+        self.assertEqual(zone.id, mail_redirect.zone.id)
+
+    def test_ex_get_mail_redirects_with_error(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        PointDNSMockHttp.type = 'GET_WITH_ERROR'
+        try:
+            self.driver.ex_get_mail_redirects(zone.id, '5')
+        except PointDNSException:
+            e = sys.exc_info()[1]
+            # The API actually responds with httplib.UNPROCESSABLE_ENTITY code,
+            # but httplib.responses doesn't have it.
+            self.assertEqual(e.code, httplib.METHOD_NOT_ALLOWED)
+        else:
+            self.fail('Exception was not thrown')
+
+    def test_ex_update_redirect(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        redirect = self.driver.ex_get_redirect(zone.id, '36843229')
+        PointDNSMockHttp.type = 'UPDATE'
+        _redirect = self.driver.ex_update_redirect(
+            redirect, 'http://updatedother.com', 'redirect3', '302')
+        self.assertEqual(_redirect.id, '36843229')
+        self.assertEqual(_redirect.name, 'redirect3.domain1.com.')
+        self.assertEqual(_redirect.type, '302')
+        self.assertEqual(_redirect.data, 'http://updatedother.com')
+        self.assertEqual(_redirect.iframe, None)
+        self.assertEqual(_redirect.query, False)
+        self.assertEqual(zone.id, _redirect.zone.id)
+
+    def test_ex_update_redirect_with_error(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        redirect = self.driver.ex_get_redirect(zone.id, '36843229')
+        PointDNSMockHttp.type = 'UPDATE_WITH_ERROR'
+        try:
+            self.driver.ex_update_redirect(
+                redirect, 'http://updatedother.com', 'redirect3', '302')
+        except PointDNSException:
+            e = sys.exc_info()[1]
+            # The API actually responds with httplib.UNPROCESSABLE_ENTITY code,
+            # but httplib.responses doesn't have it.
+            self.assertEqual(e.code, httplib.METHOD_NOT_ALLOWED)
+        else:
+            self.fail('Exception was not thrown')
+
+    def test_ex_update_mail_redirect(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        mailredirect = self.driver.ex_get_mail_redirects(zone.id, '5')
+        PointDNSMockHttp.type = 'UPDATE'
+        _mailredirect = self.driver.ex_update_mail_redirect(
+            mailredirect, 'new_user@example-site.com', 'new_admin')
+        self.assertEqual(_mailredirect.id, '5')
+        self.assertEqual(_mailredirect.source, 'new_admin')
+        self.assertEqual(_mailredirect.destination,
+                         'new_user@example-site.com')
+        self.assertEqual(zone.id, _mailredirect.zone.id)
+
+    def test_ex_update_mail_redirect_with_error(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        mailredirect = self.driver.ex_get_mail_redirects(zone.id, '5')
+        PointDNSMockHttp.type = 'UPDATE_WITH_ERROR'
+        try:
+            self.driver.ex_update_mail_redirect(
+                mailredirect, 'new_user@example-site.com', 'new_admin')
+        except PointDNSException:
+            e = sys.exc_info()[1]
+            # The API actually responds with httplib.UNPROCESSABLE_ENTITY code,
+            # but httplib.responses doesn't have it.
+            self.assertEqual(e.code, httplib.METHOD_NOT_ALLOWED)
+        else:
+            self.fail('Exception was not thrown')
+
+    def test_ex_delete_redirect(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        redirect = self.driver.ex_get_redirect(zone.id, '36843229')
+        PointDNSMockHttp.type = 'DELETE'
+        status = self.driver.ex_delete_redirect(redirect)
+        self.assertTrue(status)
+
+    def test_ex_delete_redirect_with_error(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        redirect = self.driver.ex_get_redirect(zone.id, '36843229')
+        PointDNSMockHttp.type = 'DELETE_WITH_ERROR'
+        try:
+            self.driver.ex_delete_redirect(redirect)
+        except PointDNSException:
+            e = sys.exc_info()[1]
+            # The API actually responds with httplib.UNPROCESSABLE_ENTITY code,
+            # but httplib.responses doesn't have it.
+            self.assertEqual(e.code, httplib.METHOD_NOT_ALLOWED)
+        else:
+            self.fail('Exception was not thrown')
+
+    def test_ex_delete_redirect_not_found(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        redirect = self.driver.ex_get_redirect(zone.id, '36843229')
+        PointDNSMockHttp.type = 'DELETE_NOT_FOUND'
+        try:
+            self.driver.ex_delete_redirect(redirect)
+        except PointDNSException:
+            e = sys.exc_info()[1]
+            self.assertEqual(e.code, httplib.NOT_FOUND)
+            self.assertEqual(e.message, "Couldn't found redirect")
+        else:
+            self.fail('Exception was not thrown')
+
+    def test_ex_delete_mail_redirect(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        mailredirect = self.driver.ex_get_mail_redirects(zone.id, '5')
+        PointDNSMockHttp.type = 'DELETE'
+        status = self.driver.ex_delete_mail_redirect(mailredirect)
+        self.assertTrue(status)
+
+    def test_ex_delete_mail_redirect_with_error(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        mailredirect = self.driver.ex_get_mail_redirects(zone.id, '5')
+        PointDNSMockHttp.type = 'DELETE_WITH_ERROR'
+        try:
+            self.driver.ex_delete_mail_redirect(mailredirect)
+        except PointDNSException:
+            e = sys.exc_info()[1]
+            # The API actually responds with httplib.UNPROCESSABLE_ENTITY code,
+            # but httplib.responses doesn't have it.
+            self.assertEqual(e.code, httplib.METHOD_NOT_ALLOWED)
+        else:
+            self.fail('Exception was not thrown')
+
+    def test_ex_delete_mail_redirect_not_found(self):
+        PointDNSMockHttp.type = 'GET'
+        zone = self.driver.list_zones()[0]
+        mailredirect = self.driver.ex_get_mail_redirects(zone.id, '5')
+        PointDNSMockHttp.type = 'DELETE_NOT_FOUND'
+        try:
+            self.driver.ex_delete_mail_redirect(mailredirect)
+        except PointDNSException:
+            e = sys.exc_info()[1]
+            self.assertEqual(e.code, httplib.NOT_FOUND)
+            self.assertEqual(e.message, "Couldn't found mail redirect")
+        else:
+            self.fail('Exception was not thrown')
+
 
 class PointDNSMockHttp(MockHttp):
     fixtures = DNSFileFixtures('pointdns')
@@ -174,10 +578,29 @@ class PointDNSMockHttp(MockHttp):
         body = self.fixtures.load('_zones_CREATE.json')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
 
+    def _zones_CREATE_ZONE_WITH_ERROR(self, method, url, body, headers):
+        body = self.fixtures.load('error.json')
+        return (httplib.PAYMENT_REQUIRED, body, {},
+                httplib.responses[httplib.PAYMENT_REQUIRED])
+
     def _zones_1_GET(self, method, url, body, headers):
         body = self.fixtures.load('_zones_GET_1.json')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
 
+    def _zones_1_ZONE_UPDATE(self, method, url, body, headers):
+        body = self.fixtures.load('_zones_1_ZONE_UPDATE.json')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _zones_1_UPDATE_ZONE_WITH_ERROR(self, method, url, body, headers):
+        body = self.fixtures.load('error.json')
+        return (httplib.PAYMENT_REQUIRED, body, {},
+                httplib.responses[httplib.PAYMENT_REQUIRED])
+
+    def _zones_1_GET_ZONE_NOT_EXIST(self, method, url, body, headers):
+        body = self.fixtures.load('not_found.json')
+        return (httplib.NOT_FOUND, body, {},
+                httplib.responses[httplib.NOT_FOUND])
+
     def _zones_example_com_UPDATE(self, method, url, body, headers):
         body = self.fixtures.load('_zones_example_com_UPDATE.json')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
@@ -186,14 +609,30 @@ class PointDNSMockHttp(MockHttp):
         body = self.fixtures.load('_zones_1_DELETE.json')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
 
+    def _zones_1_DELETE_ZONE_NOT_EXIST(self, method, url, body, headers):
+        body = self.fixtures.load('not_found.json')
+        return (httplib.NOT_FOUND, body, {},
+                httplib.responses[httplib.NOT_FOUND])
+
     def _zones_1_records_CREATE(self, method, url, body, headers):
         body = self.fixtures.load('_zones_example_com_records_CREATE.json')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
 
+    def _zones_1_records_CREATE_WITH_ERROR(self, method, url, body, headers):
+        body = self.fixtures.load('error.json')
+        return (httplib.PAYMENT_REQUIRED, body, {},
+                httplib.responses[httplib.PAYMENT_REQUIRED])
+
     def _zones_1_records_GET(self, method, url, body, headers):
         body = self.fixtures.load('_zones_1_records_GET.json')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
 
+    def _zones_1_records_141_GET_RECORD_NOT_EXIST(self, method, url, body,
+                                                  headers):
+        body = self.fixtures.load('not_found.json')
+        return (httplib.NOT_FOUND, body, {},
+                httplib.responses[httplib.NOT_FOUND])
+
     def _zones_1_records_141_GET(self, method, url, body, headers):
         body = self.fixtures.load('_zones_1_records_141_GET.json')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
@@ -202,9 +641,127 @@ class PointDNSMockHttp(MockHttp):
         body = self.fixtures.load('_zones_1_records_141_UPDATE.json')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
 
+    def _zones_1_records_141_UPDATE_RECORD_WITH_ERROR(self, method, url, body,
+                                                      headers):
+        body = self.fixtures.load('error.json')
+        return (httplib.PAYMENT_REQUIRED, body, {},
+                httplib.responses[httplib.PAYMENT_REQUIRED])
+
     def _zones_1_records_150_DELETE(self, method, url, body, headers):
         body = self.fixtures.load('_zones_1_records_150_DELETE.json')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
 
+    def _zones_1_records_150_DELETE_RECORD_NOT_EXIST(self, method, url, body,
+                                                     headers):
+        body = self.fixtures.load('not_found.json')
+        return (httplib.NOT_FOUND, body, {},
+                httplib.responses[httplib.NOT_FOUND])
+
+    def _zones_1_redirects_LIST(self, method, url, body, headers):
+        body = self.fixtures.load('_zones_1_redirects_LIST.json')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _zones_1_mail_redirects_LIST(self, method, url, body, headers):
+        body = self.fixtures.load('_zones_1_mail_redirects_LIST.json')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _zones_1_redirects_CREATE(self, method, url, body, headers):
+        body = self.fixtures.load('_zones_1_redirects_CREATE.json')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _zones_1_redirects_CREATE_WITH_ERROR(self, method, url, body, headers):
+        body = self.fixtures.load('redirect_error.json')
+        return (httplib.METHOD_NOT_ALLOWED, body, {},
+                httplib.responses[httplib.METHOD_NOT_ALLOWED])
+
+    def _zones_1_mail_redirects_CREATE(self, method, url, body, headers):
+        body = self.fixtures.load('_zones_1_mail_redirects_CREATE.json')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _zones_1_mail_redirects_CREATE_WITH_ERROR(self, method, url, body,
+                                                  headers):
+        body = self.fixtures.load('redirect_error.json')
+        return (httplib.METHOD_NOT_ALLOWED, body, {},
+                httplib.responses[httplib.METHOD_NOT_ALLOWED])
+
+    def _zones_1_redirects_36843229_GET_WITH_ERROR(self, method, url, body,
+                                                   headers):
+        body = self.fixtures.load('redirect_error.json')
+        return (httplib.METHOD_NOT_ALLOWED, body, {},
+                httplib.responses[httplib.METHOD_NOT_ALLOWED])
+
+    def _zones_1_redirects_36843229_GET(self, method, url, body, headers):
+        body = self.fixtures.load('_zones_1_redirects_GET.json')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _zones_1_redirects_36843229_GET_NOT_FOUND(self, method, url, body,
+                                                  headers):
+        body = self.fixtures.load('not_found.json')
+        return (httplib.NOT_FOUND, body, {},
+                httplib.responses[httplib.NOT_FOUND])
+
+    def _zones_1_mail_redirects_5_GET(self, method, url, body, headers):
+        body = self.fixtures.load('_zones_1_mail_redirects_GET.json')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _zones_1_mail_redirects_5_GET_WITH_ERROR(self, method, url, body,
+                                                 headers):
+        body = self.fixtures.load('redirect_error.json')
+        return (httplib.METHOD_NOT_ALLOWED, body, {},
+                httplib.responses[httplib.METHOD_NOT_ALLOWED])
+
+    def _zones_1_redirects_36843229_UPDATE(self, method, url, body, headers):
+        body = self.fixtures.load('_zones_1_redirects_UPDATE.json')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _zones_1_redirects_36843229_UPDATE_WITH_ERROR(self, method, url, body,
+                                                      headers):
+        body = self.fixtures.load('redirect_error.json')
+        return (httplib.METHOD_NOT_ALLOWED, body, {},
+                httplib.responses[httplib.METHOD_NOT_ALLOWED])
+
+    def _zones_1_mail_redirects_5_UPDATE(self, method, url, body, headers):
+        body = self.fixtures.load('_zones_1_mail_redirects_UPDATE.json')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _zones_1_mail_redirects_5_UPDATE_WITH_ERROR(self, method, url, body,
+                                                    headers):
+        body = self.fixtures.load('redirect_error.json')
+        return (httplib.METHOD_NOT_ALLOWED, body, {},
+                httplib.responses[httplib.METHOD_NOT_ALLOWED])
+
+    def _zones_1_redirects_36843229_DELETE(self, method, url, body, headers):
+        body = self.fixtures.load('_zones_1_redirects_DELETE.json')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _zones_1_mail_redirects_5_DELETE(self, method, url, body, headers):
+        body = self.fixtures.load('_zones_1_mail_redirects_DELETE.json')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _zones_1_redirects_36843229_DELETE_WITH_ERROR(self, method, url, body,
+                                                      headers):
+        body = self.fixtures.load('redirect_error.json')
+        return (httplib.METHOD_NOT_ALLOWED, body, {},
+                httplib.responses[httplib.METHOD_NOT_ALLOWED])
+
+    def _zones_1_mail_redirects_5_DELETE_WITH_ERROR(self, method, url, body,
+                                                    headers):
+        body = self.fixtures.load('redirect_error.json')
+        return (httplib.METHOD_NOT_ALLOWED, body, {},
+                httplib.responses[httplib.METHOD_NOT_ALLOWED])
+
+    def _zones_1_redirects_36843229_DELETE_NOT_FOUND(self, method, url, body,
+                                                     headers):
+        body = self.fixtures.load('not_found.json')
+        return (httplib.NOT_FOUND, body, {},
+                httplib.responses[httplib.NOT_FOUND])
+
+    def _zones_1_mail_redirects_5_DELETE_NOT_FOUND(self, method, url, body,
+                                                   headers):
+        body = self.fixtures.load('not_found.json')
+        return (httplib.NOT_FOUND, body, {},
+                httplib.responses[httplib.NOT_FOUND])
+
+
 if __name__ == '__main__':
     sys.exit(unittest.main())


Mime
View raw message