# -*- coding: utf-8 -*- """ tests.functional.test_web ~~~~~~~~~~~~~~~~~~~~~~~~~ This module defines basic web tests. :copyright: (c) 2017 European Spallation Source ERIC :license: BSD 2-Clause, see LICENSE for more details. """ import pytest import re from app import models def login(client, username, password): data = {"username": username, "password": password} return client.post("/user/login", data=data, follow_redirects=True) def logout(client): return client.get("/user/logout", follow_redirects=True) @pytest.fixture def logged_client(client): login(client, "user_ro", "userro") yield client logout(client) @pytest.fixture def logged_rw_client(client): login(client, "user_rw", "userrw") yield client logout(client) @pytest.fixture def logged_admin_client(client): login(client, "admin", "adminpasswd") yield client logout(client) @pytest.fixture def no_login_check_client(request, app): app.config["LOGIN_DISABLED"] = True client = app.test_client() # We still need to login, otherwise an AnonymousUserMixin is returned # An AnonymousUser doesn't have all the User methods login(client, "user_ro", "userro") yield client app.config["LOGIN_DISABLED"] = False logout(client) def test_login_logout(client): response = login(client, "unknown", "invalid") assert b"<title>Login - CSEntry</title>" in response.data response = login(client, "user_rw", "invalid") assert b"<title>Login - CSEntry</title>" in response.data response = login(client, "user_rw", "userrw") assert b"Control System Entry" in response.data assert b"User RW" in response.data response = logout(client) assert b"<title>Login - CSEntry</title>" in response.data def test_index(logged_client): response = logged_client.get("/") assert b"Control System Entry" in response.data assert b"User RO" in response.data @pytest.mark.parametrize("url", ["/", "/inventory/items", "/network/hosts"]) def test_protected_url_get(url, client): response = client.get(url) assert response.status_code == 302 assert "/user/login" in response.headers["Location"] login(client, "user_ro", "userro") response = client.get(url) assert response.status_code == 200 @pytest.mark.parametrize("url", ["/network/networks", "/network/scopes"]) def test_admin_protected_url_get(url, client): login(client, "user_rw", "userrw") response = client.get(url) assert response.status_code == 403 logout(client) login(client, "admin", "adminpasswd") response = client.get(url) assert response.status_code == 200 @pytest.mark.parametrize( "url", ["/inventory/_retrieve_items", "/network/_retrieve_hosts"] ) def test_protected_url_post(url, client): response = client.post(url) assert response.status_code == 302 assert "/user/login" in response.headers["Location"] login(client, "user_ro", "userro") response = client.post(url) assert response.status_code == 200 def test_retrieve_items(logged_client, item_factory): response = logged_client.post("/inventory/_retrieve_items") assert response.get_json()["data"] == [] serial_numbers = ("12345", "45678") for sn in serial_numbers: item_factory(serial_number=sn) response = logged_client.post("/inventory/_retrieve_items") items = response.get_json()["data"] assert set(serial_numbers) == set(item["serial_number"] for item in items) assert len(items[0]) == 18 def test_retrieve_items_pagination(logged_client, item_factory): for sn in range(1000, 1030): item_factory(serial_number=sn) response = logged_client.post( "/inventory/_retrieve_items", data={"draw": "50", "length": 10, "start": 0} ) r = response.get_json() assert r["draw"] == 50 assert r["recordsTotal"] == 30 assert r["recordsFiltered"] == 30 assert len(r["data"]) == 10 serial_numbers = [item["serial_number"] for item in r["data"]] response = logged_client.post( "/inventory/_retrieve_items", data={"draw": "51", "length": 10, "start": 10} ) serial_numbers.extend( [item["serial_number"] for item in response.get_json()["data"]] ) response = logged_client.post( "/inventory/_retrieve_items", data={"draw": "52", "length": 10, "start": 20} ) serial_numbers.extend( [item["serial_number"] for item in response.get_json()["data"]] ) assert sorted(serial_numbers) == list(str(i) for i in range(1000, 1030)) def test_retrieve_items_filter(logged_client, item_factory): for sn in range(1000, 1010): item_factory(serial_number=sn) response = logged_client.post( "/inventory/_retrieve_items", data={ "draw": "50", "length": 20, "start": 0, "search[value]": "serial_number:1005", }, ) r = response.get_json() assert r["recordsTotal"] == 10 assert r["recordsFiltered"] == 1 assert len(r["data"]) == 1 assert r["data"][0]["serial_number"] == "1005" def test_retrieve_items_sort(logged_client, item_factory): serial_numbers = ["AAA001", "AAB034", "AAA100", "AAB001"] for sn in serial_numbers: item_factory(serial_number=sn) response = logged_client.post( "/inventory/_retrieve_items", data={ "draw": "50", "length": 20, "start": 0, "order[0][column]": "3", "columns[3][data]": "serial_number", }, ) items = response.get_json()["data"] assert sorted(serial_numbers) == [item["serial_number"] for item in items] response = logged_client.post( "/inventory/_retrieve_items", data={ "draw": "50", "length": 20, "start": 0, "order[0][column]": "3", "order[0][dir]": "desc", "columns[3][data]": "serial_number", }, ) items = response.get_json()["data"] assert sorted(serial_numbers, reverse=True) == [ item["serial_number"] for item in items ] def test_retrieve_items_case_insensitive(logged_client, model_factory, item_factory): juniper_model = model_factory(name="Juniper") item_factory(serial_number="BBB001", model=juniper_model) item_factory(serial_number="ABB042") response = logged_client.post( "/inventory/_retrieve_items", data={"draw": "50", "length": 20, "start": 0, "search[value]": "juniper"}, ) r = response.get_json() assert r["recordsTotal"] == 2 assert r["recordsFiltered"] == 1 assert len(r["data"]) == 1 assert r["data"][0]["model"] == "Juniper" def test_retrieve_items_one_word(logged_client, manufacturer_factory, item_factory): manufacturer = manufacturer_factory(name="Concurrent Technologies") item_factory(serial_number="AAA001", manufacturer=manufacturer) item_factory(serial_number="ABB042") response = logged_client.post( "/inventory/_retrieve_items", data={"draw": "50", "length": 20, "start": 0, "search[value]": "concurrent"}, ) r = response.get_json() assert r["recordsTotal"] == 2 assert r["recordsFiltered"] == 1 assert len(r["data"]) == 1 assert r["data"][0]["manufacturer"] == "Concurrent Technologies" def test_generate_random_mac(logged_client): response = logged_client.get("/network/_generate_random_mac") mac = response.get_json()["data"]["mac"] assert re.match("^(?:[0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$", mac) is not None assert mac.startswith("02:42:42") def test_retrieve_hosts(logged_client, interface_factory, host_factory): response = logged_client.post("/network/_retrieve_hosts") assert response.get_json()["data"] == [] host1 = host_factory(name="host1") host2 = host_factory(name="host2") interface_factory(name="host1", host=host1) interface_factory(name="host2", host=host2) response = logged_client.post("/network/_retrieve_hosts") hosts = response.get_json()["data"] assert {host1.name, host2.name} == set(host["name"] for host in hosts) assert len(hosts[0]) == 15 assert len(hosts[0]["interfaces"][0]) == 15 def test_retrieve_hosts_by_ip(logged_client, interface_factory): interface1 = interface_factory() interface_factory() response = logged_client.post( "/network/_retrieve_hosts", data={"draw": "50", "length": 20, "start": 0, "search[value]": interface1.ip}, ) r = response.get_json() assert r["recordsTotal"] == 2 assert r["recordsFiltered"] == 1 assert len(r["data"]) == 1 assert r["data"][0]["name"] == interface1.host.name def test_retrieve_sensitive_hosts( client, network_scope_factory, network_factory, host_factory, interface_factory ): scope = network_scope_factory(name="ProdNetworks", supernet="192.168.0.0/16") network1 = network_factory( address="192.168.1.0/24", first_ip="192.168.1.10", last_ip="192.168.1.250", sensitive=False, scope=scope, ) network2 = network_factory( address="192.168.2.0/24", first_ip="192.168.2.10", last_ip="192.168.2.250", sensitive=True, scope=scope, ) host1 = host_factory() interface_factory(name=host1.name, host=host1, network=network1, ip="192.168.1.10") host2 = host_factory() interface_factory(name=host2.name, host=host2, network=network2, ip="192.168.2.10") host3 = host_factory() interface_factory(name=host3.name, host=host3, network=network2, ip="192.168.2.11") # Normal users can't see hosts on sensitive networks login(client, "user_lab", "userlab") response = client.post("/network/_retrieve_hosts") r = response.get_json() assert r["recordsTotal"] == 3 assert r["recordsFiltered"] == 1 assert len(r["data"]) == 1 assert r["data"][0]["name"] == host1.name logout(client) # admin users can see all hosts login(client, "admin", "adminpasswd") response = client.post("/network/_retrieve_hosts",) r = response.get_json() assert r["recordsTotal"] == 3 assert r["recordsFiltered"] == 3 assert len(r["data"]) == 3 def test_delete_interface_from_index( no_login_check_client, interface_factory, host_factory ): host1 = host_factory(name="host1") interface_factory(name="host1", host=host1) interface2 = interface_factory(name="host1b", host=host1) # The interface is in the index instances, nb = models.Host.search("host1b") assert list(instances) == [host1] assert nb == 1 # Delete the interface response = no_login_check_client.post( "/network/interfaces/delete", data={"interface_id": interface2.id} ) assert response.status_code == 302 # It's not in the database anymore assert models.Interface.query.get(interface2.id) is None # Neither in the index instances, nb = models.Host.search("host1b") assert list(instances) == [] assert nb == 0 # But host1 is still in the index instances, nb = models.Host.search("host1") assert list(instances) == [host1] assert nb == 1 def test_edit_item_comment_in_index( logged_rw_client, item_factory, item_comment_factory ): item1 = item_factory(ics_id="AAA001") comment = item_comment_factory(body="Hello", item_id=item1.id) assert item1.comments == [comment] # Edit the comment body = "Hello world!" response = logged_rw_client.post( f"/inventory/items/comment/edit/{comment.id}", data={"body": body} ) assert response.status_code == 302 # The comment was updated in the database updated_comment = models.ItemComment.query.get(comment.id) assert updated_comment.body == body # And in the index instances, nb = models.Item.search("world") assert list(instances) == [item1] def test_create_host(client, network_scope_factory, network_factory, device_type): scope = network_scope_factory(name="ProdNetworks", supernet="192.168.0.0/16") network = network_factory( address="192.168.1.0/24", first_ip="192.168.1.10", last_ip="192.168.1.250", scope=scope, ) 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, "is_ioc": False, "ip": ip, "mac": mac, "description": "test", "ansible_vars": "foo: hello", "ansible_groups": [], "random_mac": False, "cnames_string": "", } # Invalid network_id with user_lab user # (form validation error because the network is not part of the choices # for this user) login(client, "user_lab", "userlab") response = client.post(f"/network/hosts/create", data=form) assert response.status_code == 200 # The host wasn't created assert models.Host.query.filter_by(name=name).first() is None logout(client) # Success with user_prod user login(client, "user_prod", "userprod") 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 assert host.interfaces[0].mac == mac assert host.interfaces[0].name == name def test_create_host_invalid_fields( session, client, network_scope_factory, network_factory, device_type ): scope = network_scope_factory(name="ProdNetworks", supernet="192.168.0.0/16") network = network_factory( address="192.168.1.0/24", first_ip="192.168.1.10", last_ip="192.168.1.250", scope=scope, ) 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, "is_ioc": False, "ip": ip, "mac": mac, "description": "test", "ansible_vars": "", "ansible_groups": [], "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, network_scope_factory, network_factory, interface_factory ): host = host_factory(name="myhost") scope = network_scope_factory(name="ProdNetworks", supernet="192.168.0.0/16") network1 = network_factory(scope=scope) interface_factory(network=network1, host=host) network2 = network_factory( address="192.168.2.0/24", first_ip="192.168.2.10", last_ip="192.168.2.250", scope=scope, ) name = host.name + "-2" ip = "192.168.2.11" mac = "02:42:42:46:3c:75" form = { "host_id": host.id, "interface_name": name, "network_id": network2.id, "random_mac": False, "ip": ip, "mac": mac, "cnames_string": "", } # Permission denied # user_lab doesn't have permissions for the host domain: prod.example.org login(client, "user_lab", "userlab") response = client.post(f"/network/interfaces/create/{host.name}", data=form) assert response.status_code == 403 # The host wasn't created assert models.Interface.query.filter_by(name=name).first() is None logout(client) # Success with user_prod user login(client, "user_prod", "userprod") response = client.post(f"/network/interfaces/create/{host.name}", data=form) assert response.status_code == 302 # The interface was created interface = models.Interface.query.filter_by(name=name).first() assert interface is not None assert interface.ip == ip assert interface.mac == mac assert interface.name == name assert interface.host == host def test_add_interface_to_empty_host( client, host_factory, network_scope_factory, network_factory ): host = host_factory(name="myhost") scope = network_scope_factory(name="ProdNetworks", supernet="192.168.0.0/16") network = network_factory( address="192.168.2.0/24", first_ip="192.168.2.10", last_ip="192.168.2.250", scope=scope, ) name = host.name ip = "192.168.2.11" mac = "02:42:42:46:3c:75" form = { "host_id": host.id, "interface_name": name, "network_id": network.id, "random_mac": False, "ip": ip, "mac": mac, "cnames_string": "", } # user_lab doesn't have permissions for the network domain: prod.example.org # form validation will fail because the network_id won't be in the choices login(client, "user_lab", "userlab") response = client.post(f"/network/interfaces/create/{host.name}", data=form) assert response.status_code == 200 # The host wasn't created assert models.Interface.query.filter_by(name=name).first() is None logout(client) # Success with user_prod user login(client, "user_prod", "userprod") response = client.post(f"/network/interfaces/create/{host.name}", data=form) assert response.status_code == 302 # The interface was created interface = models.Interface.query.filter_by(name=name).first() assert interface.ip == ip assert interface.mac == mac assert interface.name == name assert interface.host == host def check_vm_creation_response(response, success=True): assert response.status_code == 200 assert (b"View task" in response.data) is success assert (b"View host" in response.data) is not success assert (b"Please contact an admin user" in response.data) is not success def test_create_vm( client, network_scope_factory, network_factory, device_type_factory, host_factory, interface_factory, ): virtualmachine = device_type_factory(name="VirtualMachine") scope_prod = network_scope_factory(name="ProdNetworks") scope_lab = network_scope_factory(name="LabNetworks") network_prod = network_factory(scope=scope_prod) network_lab = network_factory(scope=scope_lab) vm_prod = host_factory(device_type=virtualmachine) interface_factory(name=vm_prod.name, host=vm_prod, network=network_prod) vioc_prod = host_factory(device_type=virtualmachine, is_ioc=True) interface_factory(name=vioc_prod.name, host=vioc_prod, network=network_prod) vm_lab = host_factory(device_type=virtualmachine) interface_factory(name=vm_lab.name, host=vm_lab, network=network_lab) vioc_lab = host_factory(device_type=virtualmachine, is_ioc=True) interface_factory(name=vioc_lab.name, host=vioc_lab, network=network_lab) form = {"cores": 1, "memory": 4, "disk": 15, "osversion": "centos7"} # User has access to the lab networks and can create VM and VIOC there login(client, "user_lab", "userlab") response = client.post( f"/network/hosts/view/{vm_prod.name}", data=form, follow_redirects=True ) check_vm_creation_response(response, success=False) response = client.post( f"/network/hosts/view/{vioc_prod.name}", data=form, follow_redirects=True ) check_vm_creation_response(response, success=False) response = client.post( f"/network/hosts/view/{vm_lab.name}", data=form, follow_redirects=True ) check_vm_creation_response(response, success=True) response = client.post( f"/network/hosts/view/{vioc_lab.name}", data=form, follow_redirects=True ) check_vm_creation_response(response, success=True) logout(client) # User has access to the prod networks but can only create VIOC due to ALLOWED_VM_CREATION_DOMAINS login(client, "user_prod", "userprod") response = client.post( f"/network/hosts/view/{vm_prod.name}", data=form, follow_redirects=True ) check_vm_creation_response(response, success=False) response = client.post( f"/network/hosts/view/{vioc_prod.name}", data=form, follow_redirects=True ) check_vm_creation_response(response, success=True) response = client.post( f"/network/hosts/view/{vm_lab.name}", data=form, follow_redirects=True ) check_vm_creation_response(response, success=False) response = client.post( f"/network/hosts/view/{vioc_lab.name}", data=form, follow_redirects=True ) check_vm_creation_response(response, success=False) def test_delete_host_as_admin(logged_admin_client, host_factory, user_factory): # admin can delete any host admin = models.User.query.filter_by(username="admin").first() user1 = user_factory(username="user1") host1 = host_factory(name="host1", user=admin) host2 = host_factory(name="host2", user=user1) assert len(models.Host.query.all()) == 2 response = logged_admin_client.post( "/network/hosts/delete", data={"host_id": host1.id} ) assert response.status_code == 302 response = logged_admin_client.post( "/network/hosts/delete", data={"host_id": host2.id} ) assert response.status_code == 302 assert len(models.Host.query.all()) == 0 def test_delete_host_as_normal_user(logged_rw_client, host_factory, user_factory): # a normal user can only delete its own hosts user_rw = models.User.query.filter_by(username="user_rw").first() user1 = user_factory(username="user1") host1 = host_factory(name="host1", user=user_rw) host2 = host_factory(name="host2", user=user1) assert len(models.Host.query.all()) == 2 # user_rw can delete its host response = logged_rw_client.post( "/network/hosts/delete", data={"host_id": host1.id} ) assert response.status_code == 302 # user_rw can't delete host owned by user1 response = logged_rw_client.post( "/network/hosts/delete", data={"host_id": host2.id} ) assert response.status_code == 403 assert len(models.Host.query.all()) == 1 def test_create_network_scope(logged_admin_client, domain_factory): domain = domain_factory(name="prod.example.org") name = "MyNetworks" first_vlan = 200 last_vlan = 300 supernet = "192.168.0.0/16" form = { "name": name, "first_vlan": first_vlan, "last_vlan": last_vlan, "supernet": supernet, "domain_id": domain.id, } response = logged_admin_client.post("/network/scopes/create", data=form) assert response.status_code == 302 # The network scope was created scope = models.NetworkScope.query.filter_by(name=name).first() assert scope is not None assert scope.name == name assert scope.first_vlan == first_vlan assert scope.last_vlan == last_vlan assert scope.supernet == supernet def test_create_network_scope_no_vlan(logged_admin_client, domain_factory): domain = domain_factory(name="lab.example.org") name = "NoVlan" supernet = "192.168.0.0/16" form = { "name": name, "first_vlan": "", "last_vlan": None, "supernet": supernet, "domain_id": domain.id, } response = logged_admin_client.post("/network/scopes/create", data=form) assert response.status_code == 302 # The network scope was created scope = models.NetworkScope.query.filter_by(name=name).first() assert scope is not None assert scope.name == name assert scope.first_vlan is None assert scope.last_vlan is None assert scope.supernet == supernet def test_create_network(logged_admin_client, domain_factory, network_scope_factory): domain = domain_factory(name="lab.example.org") scope = network_scope_factory( name="MyNetworks", first_vlan=100, last_vlan=200, supernet="192.168.0.0/16", domain_id=domain.id, ) vlan_name = "my-network" form = { "scope_id": scope.id, "vlan_name": vlan_name, "vlan_id": 101, "address": "192.168.0.0/24", "first_ip": "192.168.0.11", "last_ip": "192.168.0.249", "gateway": "192.168.0.254", "domain_id": domain.id, "admin_only": False, } response = logged_admin_client.post("/network/networks/create", data=form) assert response.status_code == 302 # The network was created network = models.Network.query.filter_by(vlan_name=vlan_name).first() assert network is not None assert network.vlan_name == vlan_name assert network.address == form["address"] assert network.vlan_id == form["vlan_id"] def test_create_network_no_vlan( logged_admin_client, domain_factory, network_scope_factory ): domain = domain_factory(name="lab.example.org") scope = network_scope_factory( name="NoVlanNetworks", first_vlan=None, last_vlan=None, supernet="192.168.0.0/16", domain_id=domain.id, ) vlan_name = "my-network" form = { "scope_id": scope.id, "vlan_name": vlan_name, "vlan_id": "", "address": "192.168.0.0/24", "first_ip": "192.168.0.11", "last_ip": "192.168.0.249", "gateway": "192.168.0.254", "domain_id": domain.id, "admin_only": False, } response = logged_admin_client.post("/network/networks/create", data=form) assert response.status_code == 302 # The network was created network = models.Network.query.filter_by(vlan_name=vlan_name).first() assert network is not None assert network.vlan_name == vlan_name assert network.address == form["address"] assert network.vlan_id is None def test_edit_network( logged_admin_client, domain_factory, network_scope_factory, network_factory ): domain = domain_factory(name="lab.example.org") scope = network_scope_factory( name="MyNetworks", first_vlan=100, last_vlan=200, supernet="192.168.0.0/16", domain_id=domain.id, ) vlan_name = "my-network" network = network_factory( vlan_name=vlan_name, domain=domain, scope=scope, vlan_id=100, address="192.168.0.0/24", first_ip="192.168.0.11", last_ip="192.168.0.249", gateway="192.168.0.254", admin_only=False, sensitive=False, ) new_first_ip = "192.168.0.10" form = { "vlan_name": vlan_name, "vlan_id": network.vlan_id, "address": network.address, "first_ip": new_first_ip, "last_ip": network.last_ip, "gateway": network.gateway, "domain_id": network.domain_id, "admin_only": True, "sensitive": True, } response = logged_admin_client.post( f"/network/networks/edit/{vlan_name}", data=form ) assert response.status_code == 302 # The network was updated network = models.Network.query.filter_by(vlan_name=vlan_name).first() assert network is not None assert network.vlan_name == vlan_name assert network.first_ip == new_first_ip assert network.admin_only is True assert network.sensitive is True def test_create_item_invalid_ics_id(logged_rw_client): ics_id = "AAA1100" form = {"ics_id": ics_id, "serial_number": "12345"} response = logged_rw_client.post( f"/inventory/items/create", data=form, follow_redirects=True ) assert response.status_code == 200 assert b"Register new item" in response.data assert b"The ICS id shall be composed of 3 letters and 3 digits" in response.data def test_create_item_with_stack_member( host_factory, device_type_factory, item_factory, logged_rw_client ): # Test for JIRA INFRA-1648 network_type = device_type_factory(name="NETWORK") host = host_factory(device_type=network_type) item1 = item_factory(ics_id="AAA001", host=host, stack_member=0) ics_id = "AAA042" form = { "ics_id": ics_id, "serial_number": "12345", "host_id": host.id, "stack_member": 1, } response = logged_rw_client.post(f"/inventory/items/create", data=form) assert response.status_code == 302 item2 = models.Item.query.filter_by(ics_id=ics_id).first() assert host.stack_members() == [item1, item2] def test_create_item_with_host_and_no_stack_member( host_factory, device_type_factory, item_factory, logged_rw_client ): network_type = device_type_factory(name="NETWORK") host = host_factory(device_type=network_type) ics_id = "AAA042" form = { "ics_id": ics_id, "serial_number": "12345", "host_id": host.id, "stack_member": "", } response = logged_rw_client.post(f"/inventory/items/create", data=form) assert response.status_code == 302 item = models.Item.query.filter_by(ics_id=ics_id).first() assert item.host == host assert item.stack_member is None def test_ansible_groups_no_recursive_dependency( ansible_group_factory, logged_admin_client ): group3 = ansible_group_factory() group2 = ansible_group_factory(children=[group3]) group1 = ansible_group_factory(children=[group2]) form = {"name": group3.name, "type": group3.type, "children": [group1.id]} response = logged_admin_client.post( f"/network/groups/edit/{group3.name}", data=form ) assert response.status_code == 200 assert b"creates a recursive dependency loop" in response.data def test_create_network_overlapping( network_scope_factory, network_factory, logged_admin_client ): scope = network_scope_factory( first_vlan=3800, last_vlan=4000, supernet="172.30.0.0/16" ) network_factory( vlan_name="network1", vlan_id=3800, address="172.30.0.0/23", first_ip="172.30.0.3", last_ip="172.30.1.240", scope=scope, ) form = { "vlan_name": "network2", "vlan_id": 3842, "scope_id": scope.id, "address": "172.30.1.0/24", "first_ip": "172.30.1.5", "last_ip": "172.30.1.245", "gateway": "172.30.1.248", "domain_id": scope.domain_id, } response = logged_admin_client.post("/network/networks/create", data=form) assert response.status_code == 200 assert b"172.30.1.0/24 overlaps network1 (172.30.0.0/23)" in response.data def test_create_network_scope_overlapping(network_scope_factory, logged_admin_client): scope1 = network_scope_factory( name="scope1", first_vlan=3800, last_vlan=4000, supernet="172.30.0.0/16" ) form = { "name": "scope2", "first_vlan": 200, "last_vlan": 500, "supernet": "172.30.200.0/22", "domain_id": scope1.domain_id, } response = logged_admin_client.post("/network/scopes/create", data=form) assert response.status_code == 200 assert b"172.30.200.0/22 overlaps scope1 (172.30.0.0/16)" in response.data def test_view_network_restriction(client, network_scope_factory, network_factory): scope = network_scope_factory(name="ProdNetworks", supernet="192.168.0.0/16") network = network_factory( address="192.168.1.0/24", first_ip="192.168.1.10", last_ip="192.168.1.250", scope=scope, ) # user_lab doesn't have the permissions to see that network login(client, "user_lab", "userlab") response = client.get(f"/network/networks/view/{network}") assert response.status_code == 403 logout(client) # Success with user_prod user login(client, "user_prod", "userprod") response = client.get(f"/network/networks/view/{network}") assert response.status_code == 200