2022-06-17 10:33:13 +00:00
|
|
|
# Copyright © 2022 Aravinth Manivannan <realaravinth@batsense.net>
|
|
|
|
#
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU Affero General Public License as
|
|
|
|
# published by the Free Software Foundation, either version 3 of the
|
|
|
|
# License, or (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU Affero General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
from django.contrib.auth import get_user_model
|
|
|
|
from django.utils.http import urlencode
|
|
|
|
from django.urls import reverse
|
|
|
|
from django.test import TestCase, Client, override_settings
|
|
|
|
from django.conf import settings
|
2022-06-17 15:03:48 +00:00
|
|
|
from django.db.utils import IntegrityError
|
|
|
|
|
2022-06-19 15:53:38 +00:00
|
|
|
from accounts.tests import login_util, register_util
|
2022-06-19 15:31:12 +00:00
|
|
|
|
2022-06-19 15:53:38 +00:00
|
|
|
from .models import InstanceConfiguration, Instance
|
2022-06-17 17:58:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
def create_configurations(t: TestCase):
|
|
|
|
t.instance_config = [
|
2022-06-17 18:32:18 +00:00
|
|
|
InstanceConfiguration(name="Personal", rent=5.0, ram=0.5, cpu=1, storage=25),
|
|
|
|
InstanceConfiguration(name="Enthusiast", rent=10.0, ram=2, cpu=2, storage=50),
|
|
|
|
InstanceConfiguration(
|
|
|
|
name="Small Business", rent=20.0, ram=8, cpu=4, storage=64
|
|
|
|
),
|
|
|
|
InstanceConfiguration(
|
|
|
|
name="Enterprise", rent=100.0, ram=64, cpu=24, storage=1024
|
|
|
|
),
|
2022-06-17 17:58:51 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
for instance in t.instance_config:
|
|
|
|
instance.save()
|
|
|
|
print(f"[*][init] Instance {instance.name} is saved")
|
|
|
|
t.assertEqual(
|
|
|
|
InstanceConfiguration.objects.filter(name=instance.name).exists(), True
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2022-06-17 10:33:13 +00:00
|
|
|
class DashHome(TestCase):
|
|
|
|
"""
|
|
|
|
Tests create new app view
|
|
|
|
"""
|
|
|
|
|
|
|
|
def setUp(self):
|
2022-06-17 17:58:51 +00:00
|
|
|
register_util(t=self, username="dashboard_home_user")
|
2022-06-17 10:33:13 +00:00
|
|
|
|
|
|
|
def test_dash_is_protected(self):
|
|
|
|
"""
|
|
|
|
Tests if dashboard template renders
|
|
|
|
"""
|
|
|
|
resp = self.client.get(reverse("dash.home"))
|
|
|
|
self.assertEqual(resp.status_code, 302)
|
|
|
|
|
2022-06-17 11:29:20 +00:00
|
|
|
# default LOGIN redirect URI that is used by @login_required decorator is
|
2022-06-17 10:33:13 +00:00
|
|
|
# /accounts/login. There's a redirection endpoint at /accounts/login/ that
|
|
|
|
# will redirect user to /login. Hence the /accounts prefix
|
2022-06-17 11:29:20 +00:00
|
|
|
redirect_login_uri = (
|
|
|
|
f"/accounts{reverse('accounts.login')}?next={reverse('dash.home')}"
|
|
|
|
)
|
2022-06-17 10:33:13 +00:00
|
|
|
self.assertEqual(resp.headers["location"], redirect_login_uri)
|
|
|
|
|
|
|
|
def test_dash_home_renders(self):
|
|
|
|
"""
|
|
|
|
Tests if login template renders
|
|
|
|
"""
|
|
|
|
c = Client()
|
|
|
|
|
|
|
|
# username login works
|
2022-06-17 17:58:51 +00:00
|
|
|
login_util(t=self, c=c, redirect_to="accounts.home")
|
2022-06-17 10:33:13 +00:00
|
|
|
|
|
|
|
# email login works
|
2022-06-17 11:29:20 +00:00
|
|
|
resp = c.get(reverse("dash.home"))
|
2022-06-17 10:33:13 +00:00
|
|
|
self.assertEqual(resp.status_code, 200)
|
|
|
|
self.assertEqual(b"Billing" in resp.content, True)
|
|
|
|
self.assertEqual(b"Support" in resp.content, True)
|
|
|
|
self.assertEqual(b"Logout" in resp.content, True)
|
2022-06-17 15:03:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
class InstancesConfig(TestCase):
|
|
|
|
"""
|
|
|
|
Tests InstancesConfig model
|
|
|
|
"""
|
|
|
|
|
|
|
|
def test_unique_constraint(self):
|
|
|
|
"""
|
|
|
|
Test configuration uniqueness
|
|
|
|
"""
|
|
|
|
config1 = InstanceConfiguration(
|
2022-06-17 18:32:18 +00:00
|
|
|
name="test config 1", rent=5.0, ram=0.5, cpu=1, storage=0.5
|
2022-06-17 15:03:48 +00:00
|
|
|
)
|
|
|
|
config1.save()
|
|
|
|
config2 = InstanceConfiguration(
|
2022-06-17 18:32:18 +00:00
|
|
|
name="test config 2", rent=5.0, ram=0.5, cpu=2, storage=0.5
|
2022-06-17 15:03:48 +00:00
|
|
|
)
|
|
|
|
config2.save()
|
|
|
|
with self.assertRaises(IntegrityError):
|
|
|
|
config3 = InstanceConfiguration(
|
2022-06-17 18:32:18 +00:00
|
|
|
name="test config 3", rent=5.0, ram=0.5, cpu=1, storage=0.5
|
2022-06-17 15:03:48 +00:00
|
|
|
)
|
|
|
|
config3.save()
|
2022-06-17 17:58:51 +00:00
|
|
|
|
2022-06-18 08:22:52 +00:00
|
|
|
def test_default_configuration_is_loaded(self):
|
|
|
|
"""
|
|
|
|
Expects InstancesConfig titled "s1-2", "s1-4" and "s1-8"
|
|
|
|
|
|
|
|
ref: https://gitea.hostea.org/Hostea/july-mvp/issues/10#issuecomment-639
|
|
|
|
"""
|
|
|
|
self.assertEqual(
|
|
|
|
InstanceConfiguration.objects.filter(
|
|
|
|
name="s1-2", rent=10, ram=2, cpu=1, storage=10
|
|
|
|
).exists(),
|
|
|
|
True,
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
InstanceConfiguration.objects.filter(
|
|
|
|
name="s1-4", rent=20, ram=4, cpu=1, storage=20
|
|
|
|
).exists(),
|
|
|
|
True,
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
InstanceConfiguration.objects.filter(
|
|
|
|
name="s1-8", rent=40, ram=8, cpu=2, storage=40
|
|
|
|
).exists(),
|
|
|
|
True,
|
|
|
|
)
|
|
|
|
|
2022-06-17 17:58:51 +00:00
|
|
|
|
|
|
|
class CreateInstance(TestCase):
|
|
|
|
def setUp(self):
|
|
|
|
register_util(t=self, username="createinstance_user")
|
|
|
|
create_configurations(t=self)
|
|
|
|
|
|
|
|
def test_create_instance_renders(self):
|
|
|
|
c = Client()
|
|
|
|
login_util(self, c, "accounts.home")
|
|
|
|
urls = [(reverse("dash.instances.new"), "Instance Configuration")]
|
|
|
|
for (url, test) in urls:
|
|
|
|
print(f"[*] Testing URI: {url}")
|
|
|
|
resp = c.get(url)
|
|
|
|
self.assertEqual(resp.status_code, 200)
|
|
|
|
self.assertEqual(b"Billing" in resp.content, True)
|
|
|
|
self.assertEqual(b"Support" in resp.content, True)
|
|
|
|
self.assertEqual(b"Logout" in resp.content, True)
|
|
|
|
self.assertEqual(str.encode(test) in resp.content, True)
|
|
|
|
|
2022-06-18 16:42:07 +00:00
|
|
|
# create instance
|
2022-06-17 17:58:51 +00:00
|
|
|
payload = {
|
|
|
|
"name": "test_create_instance_renders",
|
|
|
|
"configuration": self.instance_config[0].name,
|
|
|
|
}
|
|
|
|
|
|
|
|
self.assertEqual(Instance.objects.filter(name=payload["name"]).exists(), False)
|
|
|
|
|
|
|
|
resp = c.post(reverse("dash.instances.new"), payload)
|
|
|
|
self.assertEqual(resp.status_code, 302)
|
|
|
|
self.assertEqual(resp.headers["location"], reverse("dash.home"))
|
|
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
Instance.objects.filter(
|
|
|
|
name=payload["name"],
|
|
|
|
owned_by=self.user,
|
|
|
|
configuration_id=self.instance_config[0],
|
|
|
|
).exists(),
|
|
|
|
True,
|
|
|
|
)
|
2022-06-18 16:42:07 +00:00
|
|
|
instance = Instance.objects.get(name=payload["name"], owned_by=self.user)
|
2022-06-17 17:58:51 +00:00
|
|
|
|
2022-06-18 16:42:07 +00:00
|
|
|
# try to create instance with duplicate name
|
2022-06-17 17:58:51 +00:00
|
|
|
resp = c.post(reverse("dash.instances.new"), payload)
|
|
|
|
self.assertEqual(resp.status_code, 400)
|
|
|
|
self.assertEqual(b"Instance name exists" in resp.content, True)
|
|
|
|
|
2022-06-18 16:42:07 +00:00
|
|
|
# try to create instance with a VM configuration that doesn't exist
|
2022-06-17 17:58:51 +00:00
|
|
|
payload = {
|
|
|
|
"name": f"2{payload['name']}",
|
|
|
|
"configuration": f"2{payload['name']}",
|
|
|
|
}
|
|
|
|
resp = c.post(reverse("dash.instances.new"), payload)
|
|
|
|
self.assertEqual(resp.status_code, 400)
|
|
|
|
self.assertEqual(b"Configuration doesn" in resp.content, True)
|
2022-06-18 16:42:07 +00:00
|
|
|
|
|
|
|
# list instances
|
|
|
|
resp = c.get(reverse("dash.instances.list"))
|
|
|
|
self.assertEqual(resp.status_code, 200)
|
|
|
|
self.assertEqual(str.encode(instance.name) in resp.content, True)
|
|
|
|
|
|
|
|
# view instance details
|
|
|
|
resp = c.get(reverse("dash.instances.view", args=(instance.name,)))
|
|
|
|
self.assertEqual(resp.status_code, 200)
|
|
|
|
self.assertEqual(str.encode(instance.name) in resp.content, True)
|
|
|
|
|
|
|
|
# delete instance details
|
|
|
|
delete_uri = reverse("dash.instances.delete", args=(instance.name,))
|
|
|
|
|
|
|
|
## will ask for sudo confirmation
|
|
|
|
resp = c.get(delete_uri)
|
|
|
|
self.assertEqual(resp.status_code, 302)
|
|
|
|
ctx = {"next": delete_uri}
|
|
|
|
self.assertEqual(
|
|
|
|
resp.headers["location"], f"{reverse('accounts.sudo')}?{urlencode(ctx)}"
|
|
|
|
)
|
|
|
|
|
|
|
|
## give sudo confirmation
|
|
|
|
payload = {"password": self.password, "next": ctx["next"]}
|
|
|
|
resp = c.post(reverse("accounts.sudo"), payload)
|
|
|
|
self.assertEqual(resp.status_code, 302)
|
|
|
|
self.assertEqual(resp.headers["location"], ctx["next"])
|
|
|
|
|
|
|
|
resp = c.get(delete_uri)
|
|
|
|
self.assertEqual(resp.status_code, 200)
|
|
|
|
self.assertEqual(
|
|
|
|
str.encode(f"to delete VM {instance.name}") in resp.content, True
|
|
|
|
)
|
|
|
|
|
|
|
|
resp = c.post(delete_uri)
|
|
|
|
self.assertEqual(resp.status_code, 302)
|
|
|
|
self.assertEqual(resp.headers["location"], reverse("dash.home"))
|
|
|
|
self.assertEqual(
|
|
|
|
Instance.objects.filter(
|
|
|
|
name=instance.name,
|
|
|
|
owned_by=self.user,
|
|
|
|
configuration_id=self.instance_config[0],
|
|
|
|
).exists(),
|
|
|
|
False,
|
|
|
|
)
|