From ce54e287a7a23a42921c59d1f5d844958ad04ca2 Mon Sep 17 00:00:00 2001
From: Benjamin Bertrand <benjamin.bertrand@esss.se>
Date: Tue, 29 Jan 2019 15:11:02 +0100
Subject: [PATCH] Catch exception raised by Unique Validator

The MAC field has both a Regexp and Unique validators.
In wtforms, the validation doesn't stop on the first error (all
validators are run).
In case of invalid mac address, the Unique validator makes a request to
the database that raises a DataError. This exception has to be catched.

JIRA INFRA-777 #action In Progress
---
 app/validators.py            |  2 ++
 tests/functional/test_web.py | 52 ++++++++++++++++++++++++++++++++++--
 2 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/app/validators.py b/app/validators.py
index 0248e7a..575bc87 100644
--- a/app/validators.py
+++ b/app/validators.py
@@ -80,6 +80,8 @@ class Unique(object):
                 raise ValidationError(self.message)
         except sa.orm.exc.NoResultFound:
             pass
+        except sa.exc.DataError as e:
+            raise ValidationError(f"DBAPIError: {e.orig}")
 
 
 class UniqueAccrossModels:
diff --git a/tests/functional/test_web.py b/tests/functional/test_web.py
index 757e5e9..820a667 100644
--- a/tests/functional/test_web.py
+++ b/tests/functional/test_web.py
@@ -327,9 +327,11 @@ def test_create_host(client, domain_factory, network_factory, device_type):
     logout(client)
     # Success with user_prod user
     login(client, "user_prod", "userprod")
-    response = client.post(f"/network/hosts/create", data=form)
-    assert response.status_code == 302
+    response = client.post(f"/network/hosts/create", data=form, follow_redirects=True)
+    assert response.status_code == 200
     # The host was created
+    assert b"created!" in response.data
+    assert b"View host" in response.data
     host = models.Host.query.filter_by(name=name).first()
     assert host is not None
     assert host.interfaces[0].ip == ip
@@ -337,6 +339,52 @@ def test_create_host(client, domain_factory, network_factory, device_type):
     assert host.interfaces[0].name == name
 
 
+def test_create_host_invalid_fields(
+    session, client, domain_factory, network_factory, device_type
+):
+    domain = domain_factory(name="prod.example.org")
+    network = network_factory(
+        address="192.168.1.0/24",
+        first_ip="192.168.1.10",
+        last_ip="192.168.1.250",
+        domain=domain,
+    )
+    name = "myhost"
+    ip = "192.168.1.11"
+    mac = "02:42:42:45:3c:89"
+    form = {
+        "network_id": network.id,
+        "name": name,
+        "device_type_id": device_type.id,
+        "ip": ip,
+        "mac": mac,
+        "description": "test",
+        "ansible_vars": "",
+        "ansible_groups": [],
+        "tags": [],
+        "random_mac": False,
+        "cnames_string": "",
+    }
+    login(client, "user_prod", "userprod")
+    # Invalid mac
+    data = form.copy()
+    data["mac"] = "ea:ea:60:45:a8:96:se"
+    response = client.post(f"/network/hosts/create", data=data, follow_redirects=True)
+    assert response.status_code == 200
+    assert b"Register new host" in response.data
+    assert b"Invalid MAC address" in response.data
+    # An exception was raised during validation (on Select in the Unique Validator),
+    # so we need to rollback.
+    session.rollback()
+    # Invalid hostname
+    data = form.copy()
+    data["name"] = "invalid_host"
+    response = client.post(f"/network/hosts/create", data=data, follow_redirects=True)
+    assert response.status_code == 200
+    assert b"Register new host" in response.data
+    assert b"Invalid input" in response.data
+
+
 def test_create_interface(
     client, host_factory, domain_factory, network_factory, interface_factory
 ):
-- 
GitLab