Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve node assignment coverage across building groups #807

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/meshapi/models/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,11 @@ def save(self, *args: Any, **kwargs: Any) -> None:
if self.install_number != original.install_number:
raise ValidationError("Install number is immutable")

if self._state.adding:
if not self.node:
if self.building.primary_node:
self.node = self.building.primary_node
elif self.building.nodes:
self.node = self.building.nodes.first()

super().save(*args, **kwargs)
74 changes: 73 additions & 1 deletion src/meshapi/tests/test_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from django.core.exceptions import ValidationError
from django.test import TestCase

from meshapi.models import Building, Install, Member
from meshapi.models import Building, Install, Member, Node
from meshapi.tests.sample_data import sample_building, sample_install, sample_member


Expand Down Expand Up @@ -43,6 +43,78 @@ def test_construct_install_no_id_yes_install_number(self):
self.assertIsNotNone(install2.id)
self.assertEqual(install2.install_number, 89)

def test_construct_install_building_has_node(self):
building_node = Node(status=Node.NodeStatus.ACTIVE, latitude=0, longitude=0)
building_node.save()

self.building_1.primary_node = building_node
self.building_1.save()

install = Install(**self.sample_install_copy, install_number=45)
install.save()

install.refresh_from_db()
self.assertEqual(install.node, building_node)

def test_construct_install_building_has_node_without_primary(self):
building_node = Node(status=Node.NodeStatus.ACTIVE, latitude=0, longitude=0)
building_node.save()

self.building_1.nodes.add(building_node)
self.building_1.save()

install = Install(**self.sample_install_copy, install_number=45)
install.save()

install.refresh_from_db()
self.assertEqual(install.node, building_node)

def test_remove_node_when_building_has_one(self):
building_node = Node(status=Node.NodeStatus.ACTIVE, latitude=0, longitude=0)
building_node.save()

self.building_1.primary_node = building_node
self.building_1.save()

install = Install(**self.sample_install_copy, install_number=45)
install.node = building_node
install.save()

install.refresh_from_db()
self.assertEqual(install.node, building_node)

install.node = None
install.save()

install.refresh_from_db()
self.assertEqual(install.node, None)

def test_set_install_to_different_to_building(self):
building1_node = Node(status=Node.NodeStatus.ACTIVE, latitude=0, longitude=0)
building2_node = Node(status=Node.NodeStatus.ACTIVE, latitude=0, longitude=0)
building1_node.save()
building2_node.save()

self.building_1.primary_node = building1_node
self.building_1.save()

building2 = Building(**sample_building)
building2.primary_node = building2_node
building2.save()

install = Install(**self.sample_install_copy, install_number=45)
install.node = building1_node
install.save()

install.refresh_from_db()
self.assertEqual(install.node, building1_node)

install.building = building2
install.save()

install.refresh_from_db()
self.assertEqual(install.node, building1_node)

def test_construct_install_yes_id_no_install_number(self):
install = Install(
id=uuid.UUID("23ef170c-f37d-44e3-aaac-93dae636c86e"),
Expand Down
154 changes: 151 additions & 3 deletions src/meshapi/tests/test_nn.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ def setUp(self):
self.admin_c.login(username="admin", password="admin_password")

# Create sample data
member_obj = Member(**sample_member)
member_obj.save()
self.member_obj = Member(**sample_member)
self.member_obj.save()

self.building = Building(**sample_building)
self.building.latitude = 4
Expand All @@ -42,7 +42,7 @@ def setUp(self):
inst["abandon_date"] = None

inst["building"] = self.building
inst["member"] = member_obj
inst["member"] = self.member_obj

self.install = Install(**inst)
self.install.install_number = 10001
Expand Down Expand Up @@ -109,6 +109,98 @@ def test_nn_valid_install_number(self):
f"nn incorrect for test_nn_valid_install_number. Should be {expected_nn}, but got {resp_nn}",
)

def test_nn_assign_set_all_installs_on_building_without_nns(self):
pre_existing_node = Node(status=Node.NodeStatus.ACTIVE, latitude=0, longitude=0, network_number=123)
pre_existing_node.save()

inst = sample_install.copy()
inst["status"] = Install.InstallStatus.REQUEST_RECEIVED
if inst["abandon_date"] == "":
inst["abandon_date"] = None

inst["building"] = self.building
inst["member"] = self.member_obj

install2 = Install(**inst)
install2.status = Install.InstallStatus.ACTIVE
install2.install_number = 10002
install2.node = pre_existing_node
install2.save()

install3 = Install(**inst)
install3.status = Install.InstallStatus.BLOCKED
install3.install_number = 10003
install3.save()

install4 = Install(**inst)
install4.status = Install.InstallStatus.CLOSED
install4.install_number = 10004
install4.save()

response = self.admin_c.post(
"/api/v1/nn-assign/",
{"install_number": self.install_number, "password": os.environ.get("NN_ASSIGN_PSK")},
content_type="application/json",
)

code = 201
self.assertEqual(
code,
response.status_code,
f"status code incorrect for test_nn_valid_install_number. Should be {code}, but got {response.status_code}",
)

resp_nn = json.loads(response.content.decode("utf-8"))["network_number"]
expected_nn = 101
self.assertEqual(
expected_nn,
resp_nn,
f"nn incorrect for test_nn_valid_install_number. Should be {expected_nn}, but got {resp_nn}",
)

node_object = Node.objects.get(network_number=expected_nn)
self.assertEqual(node_object.status, Node.NodeStatus.PLANNED)
self.assertEqual(node_object.latitude, self.building.latitude)
self.assertEqual(node_object.longitude, self.building.longitude)
self.assertEqual(node_object.install_date, datetime.date.today())

self.install.refresh_from_db()
self.assertEqual(self.install.node, node_object)
self.assertEqual(self.install.status, Install.InstallStatus.PENDING)

install2.refresh_from_db()
self.assertEqual(install2.node, pre_existing_node)
self.assertEqual(install2.status, Install.InstallStatus.ACTIVE)

install3.refresh_from_db()
self.assertEqual(install3.node, node_object)
self.assertEqual(install3.status, Install.InstallStatus.BLOCKED)

install4.refresh_from_db()
self.assertEqual(install4.node, node_object)
self.assertEqual(install4.status, Install.InstallStatus.CLOSED)

# Now test to make sure that we get 200 for dupes
response = self.admin_c.post(
"/api/v1/nn-assign/",
{"install_number": self.install_number, "password": os.environ.get("NN_ASSIGN_PSK")},
content_type="application/json",
)

code = 200
self.assertEqual(
code,
response.status_code,
f"status code incorrect for test_nn_valid_install_number DUPLICATE. Should be {code}, but got {response.status_code}",
)

resp_nn = json.loads(response.content.decode("utf-8"))["network_number"]
self.assertEqual(
expected_nn,
resp_nn,
f"nn incorrect for test_nn_valid_install_number. Should be {expected_nn}, but got {resp_nn}",
)

def test_doesnt_change_the_status_of_active_nodes(self):
self.install.status = Install.InstallStatus.ACTIVE
self.install.save()
Expand Down Expand Up @@ -168,6 +260,62 @@ def test_building_already_has_nn(self):
self.assertEqual(self.install.status, Install.InstallStatus.PENDING)
self.assertEqual(node.status, Node.NodeStatus.ACTIVE)

def test_building_already_has_nn_but_another_install_is_missing_the_node(self):
node = Node(
network_number=9999,
status=Node.NodeStatus.ACTIVE,
type=Node.NodeType.STANDARD,
latitude=0,
longitude=0,
)
node.save()

self.building.primary_node = node
self.building.save()

inst = sample_install.copy()
inst["status"] = Install.InstallStatus.REQUEST_RECEIVED
if inst["abandon_date"] == "":
inst["abandon_date"] = None

inst["building"] = self.building
inst["member"] = self.member_obj

install2 = Install(**inst)
install2.status = Install.InstallStatus.PENDING
install2.install_number = 10002
install2.save()

response = self.admin_c.post(
"/api/v1/nn-assign/",
{"install_number": self.install_number, "password": os.environ.get("NN_ASSIGN_PSK")},
content_type="application/json",
)

code = 201
self.assertEqual(
code,
response.status_code,
f"status code incorrect for test_nn_valid_install_number. Should be {code}, but got {response.status_code}",
)

resp_nn = json.loads(response.content.decode("utf-8"))["network_number"]
expected_nn = 9999
self.assertEqual(
expected_nn,
resp_nn,
f"nn incorrect for test_nn_valid_install_number. Should be {expected_nn}, but got {resp_nn}",
)

self.install.refresh_from_db()
self.assertEqual(self.install.node, node)
self.assertEqual(self.install.status, Install.InstallStatus.PENDING)
self.assertEqual(node.status, Node.NodeStatus.ACTIVE)

install2.refresh_from_db()
self.assertEqual(install2.node, node)
self.assertEqual(install2.status, Install.InstallStatus.PENDING)

def test_node_already_exists_no_nn(self):
node = Node(
status=Node.NodeStatus.PLANNED,
Expand Down
8 changes: 8 additions & 0 deletions src/meshapi/views/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,12 @@ def network_number_assignment(request: Request) -> Response:
nn_install.status = Install.InstallStatus.PENDING
dirty = True

other_building_installs = [install for install in nn_building.installs.all() if install != nn_install]
for install in other_building_installs:
if install.node is None:
dirty = True
install.node = nn_install.node

# If nothing was changed by this request, return a 200 instead of a 201
if not dirty:
message = f"This Install Number ({r.install_number}) already has a "
Expand All @@ -601,6 +607,8 @@ def network_number_assignment(request: Request) -> Response:
nn_install.node.save()
nn_building.save()
nn_install.save()
for install in other_building_installs:
install.save()
except IntegrityError:
logging.exception("NN Request failed. Could not save node number.")
return Response(
Expand Down
Loading