diff --git a/.gitignore b/.gitignore
index ab0bd1145..24d8a83c9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -47,6 +47,9 @@ coverage.xml
# Django stuff:
*.log
+# celery
+tests/celerybeat*
+
# Sphinx documentation
docs/_build/
@@ -55,6 +58,7 @@ target/
# editors
*.komodoproject
+.vscode
# other
*.DS_Store*
@@ -63,9 +67,5 @@ target/
local_settings.py
*.db
*.tar.gz
-
-# celery
-tests/celerybeat*
-
-# editor
-.vscode
+Pipfile
+Pipfile.lock
diff --git a/.travis.yml b/.travis.yml
index f74c28874..dfb0eda2b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -39,7 +39,11 @@ before_install:
install:
- pip install -e .
- # temporary: remove when openwisp-notifications is released
+ # TODO: removed when openwisp-controller 0.8.0 is released
+ - pip install -U https://github.com/openwisp/openwisp-controller/tarball/master
+ # TODO: removed when openwisp-users 0.3.0 is released
+ - pip install -U https://github.com/openwisp/openwisp-users/tarball/master
+ # TODO: remove when openwisp-notifications 0.1 is released
- pip install -U https://github.com/openwisp/openwisp-notifications/tarball/master
script:
diff --git a/README.rst b/README.rst
index d6a62a153..dd7b7d6ea 100644
--- a/README.rst
+++ b/README.rst
@@ -793,7 +793,7 @@ For ``check`` app,
from openwisp_monitoring.check.admin import CheckAdmin as BaseCheckAdmin
from swapper import load_model
- Check = load_model('Check')
+ Check = load_model('check', 'Check')
admin.site.unregister(Check)
@@ -808,7 +808,9 @@ For ``device_monitoring`` app,
from django.contrib import admin
from openwisp_monitoring.device_monitoring.admin import DeviceAdmin as BaseDeviceAdmin
- from openwisp_controller.config.models import Device
+ from swapper import load_model
+
+ Device = load_model('config', 'Device')
admin.site.unregister(Device)
diff --git a/openwisp_monitoring/check/apps.py b/openwisp_monitoring/check/apps.py
index 4bffb7915..479d9640d 100644
--- a/openwisp_monitoring/check/apps.py
+++ b/openwisp_monitoring/check/apps.py
@@ -1,8 +1,24 @@
from django.apps import AppConfig
+from django.db.models.signals import post_save
from django.utils.translation import ugettext_lazy as _
+from openwisp_monitoring.check import settings as app_settings
+from swapper import load_model
class CheckConfig(AppConfig):
name = 'openwisp_monitoring.check'
label = 'check'
verbose_name = _('Network Monitoring Checks')
+
+ def ready(self):
+ self._connect_signals()
+
+ def _connect_signals(self):
+ if app_settings.AUTO_PING:
+ from .base.models import auto_ping_receiver
+
+ post_save.connect(
+ auto_ping_receiver,
+ sender=load_model('config', 'Device'),
+ dispatch_uid='auto_ping',
+ )
diff --git a/openwisp_monitoring/check/base/models.py b/openwisp_monitoring/check/base/models.py
index 0c4a42ceb..428a1f87b 100644
--- a/openwisp_monitoring/check/base/models.py
+++ b/openwisp_monitoring/check/base/models.py
@@ -2,15 +2,14 @@
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
-from django.db import models
-from django.db.models.signals import post_save
+from django.db import models, transaction
from django.utils.functional import cached_property
from django.utils.module_loading import import_string
from django.utils.translation import gettext_lazy as _
from jsonfield import JSONField
from openwisp_monitoring.check import settings as app_settings
+from openwisp_monitoring.check.tasks import auto_create_ping
-from openwisp_controller.config.models import Device
from openwisp_utils.base import TimeStampedEditableModel
@@ -75,26 +74,20 @@ def perform_check(self, store=True):
return self.check_instance.check(store=True)
-if app_settings.AUTO_PING:
- from django.db import transaction
- from django.dispatch import receiver
- from openwisp_monitoring.check.tasks import auto_create_ping
-
- @receiver(post_save, sender=Device, dispatch_uid='auto_ping')
- def auto_ping_receiver(sender, instance, created, **kwargs):
- """
- Implements OPENWISP_MONITORING_AUTO_PING
- The creation step is executed in the background
- """
- # we need to skip this otherwise this task will be executed
- # every time the configuration is requested via checksum
- if not created:
- return
- with transaction.atomic():
- transaction.on_commit(
- lambda: auto_create_ping.delay(
- model=sender.__name__.lower(),
- app_label=sender._meta.app_label,
- object_id=str(instance.pk),
- )
+def auto_ping_receiver(sender, instance, created, **kwargs):
+ """
+ Implements OPENWISP_MONITORING_AUTO_PING
+ The creation step is executed in the background
+ """
+ # we need to skip this otherwise this task will be executed
+ # every time the configuration is requested via checksum
+ if not created:
+ return
+ with transaction.atomic():
+ transaction.on_commit(
+ lambda: auto_create_ping.delay(
+ model=sender.__name__.lower(),
+ app_label=sender._meta.app_label,
+ object_id=str(instance.pk),
)
+ )
diff --git a/openwisp_monitoring/check/classes/base.py b/openwisp_monitoring/check/classes/base.py
index f2d7c4d0f..4251887f7 100644
--- a/openwisp_monitoring/check/classes/base.py
+++ b/openwisp_monitoring/check/classes/base.py
@@ -2,10 +2,9 @@
from django.core.exceptions import ValidationError
from swapper import load_model
-from openwisp_controller.config.models import Device
-
Check = load_model('check', 'Check')
Metric = load_model('monitoring', 'Metric')
+Device = load_model('config', 'Device')
class BaseCheck(object):
diff --git a/openwisp_monitoring/check/tasks.py b/openwisp_monitoring/check/tasks.py
index 6d14d799b..ac77f26a5 100644
--- a/openwisp_monitoring/check/tasks.py
+++ b/openwisp_monitoring/check/tasks.py
@@ -37,7 +37,8 @@ def perform_check(uuid):
@shared_task
def auto_create_ping(model, app_label, object_id):
"""
- Called by openwisp_monitoring.check.models.auto_ping_receiver
+ Called by django signal (dispatch_uid: auto_ping)
+ registered in check app's apps.py file.
"""
Check = load_model('check', 'Check')
ping_path = 'openwisp_monitoring.check.classes.Ping'
diff --git a/openwisp_monitoring/device/admin.py b/openwisp_monitoring/device/admin.py
index 083661f15..55e7b4adc 100644
--- a/openwisp_monitoring/device/admin.py
+++ b/openwisp_monitoring/device/admin.py
@@ -8,7 +8,6 @@
from swapper import load_model
from openwisp_controller.config.admin import DeviceAdmin as BaseDeviceAdmin
-from openwisp_controller.config.models import Device
from ..monitoring.admin import MetricAdmin
from . import settings as app_settings
@@ -16,9 +15,12 @@
DeviceData = load_model('device_monitoring', 'DeviceData')
DeviceMonitoring = load_model('device_monitoring', 'DeviceMonitoring')
Chart = load_model('monitoring', 'Chart')
+Device = load_model('config', 'Device')
class DeviceAdmin(BaseDeviceAdmin):
+ change_form_template = 'admin/config/device/change_form.html'
+
def get_extra_context(self, pk=None):
ctx = super().get_extra_context(pk)
if pk:
diff --git a/openwisp_monitoring/device/api/views.py b/openwisp_monitoring/device/api/views.py
index dc11cbcd2..e154300e6 100644
--- a/openwisp_monitoring/device/api/views.py
+++ b/openwisp_monitoring/device/api/views.py
@@ -17,8 +17,6 @@
from rest_framework.response import Response
from swapper import load_model
-from openwisp_controller.config.models import Device
-
from ... import settings as monitoring_settings
from ...monitoring.exceptions import InvalidChartConfigException
from ..schema import schema
@@ -29,6 +27,7 @@
Chart = load_model('monitoring', 'Chart')
Metric = load_model('monitoring', 'Metric')
AlertSettings = load_model('monitoring', 'AlertSettings')
+Device = load_model('config', 'Device')
DeviceData = load_model('device_monitoring', 'DeviceData')
diff --git a/openwisp_monitoring/device/apps.py b/openwisp_monitoring/device/apps.py
index 02e4fa8d2..8745a1363 100644
--- a/openwisp_monitoring/device/apps.py
+++ b/openwisp_monitoring/device/apps.py
@@ -2,11 +2,13 @@
from django.core.cache import cache
from django.db.models.signals import post_delete, post_save
from django.utils.translation import gettext_lazy as _
-from django_netjsonconfig.signals import checksum_requested
from openwisp_notifications.signals import notify
from openwisp_notifications.types import register_notification_type
from swapper import load_model
+from openwisp_controller.config.signals import checksum_requested
+from openwisp_controller.connection.signals import is_working_changed
+
from . import settings as app_settings
from .signals import device_metrics_received, health_status_changed
from .utils import get_device_recovery_cache_key, manage_short_retention_policy
@@ -25,7 +27,7 @@ def ready(self):
self.device_recovery_detection()
def connect_device_signals(self):
- from openwisp_controller.config.models import Device
+ Device = load_model('config', 'Device')
post_save.connect(
self.device_post_save_receiver,
@@ -56,8 +58,7 @@ def device_recovery_detection(self):
if not app_settings.DEVICE_RECOVERY_DETECTION:
return
- from openwisp_controller.config.models import Device
-
+ Device = load_model('config', 'Device')
DeviceData = load_model('device_monitoring', 'DeviceData')
DeviceMonitoring = load_model('device_monitoring', 'DeviceMonitoring')
health_status_changed.connect(
@@ -96,13 +97,10 @@ def trigger_device_recovery_checks(cls, instance, **kwargs):
trigger_device_checks.delay(pk=instance.pk)
@classmethod
- def connect_is_working_changed(self):
- from openwisp_controller.connection.models import DeviceConnection
- from openwisp_controller.connection.signals import is_working_changed
-
+ def connect_is_working_changed(cls):
is_working_changed.connect(
- self.is_working_changed_receiver,
- sender=DeviceConnection,
+ cls.is_working_changed_receiver,
+ sender=load_model('connection', 'DeviceConnection'),
dispatch_uid='is_working_changed_monitoring',
)
diff --git a/openwisp_monitoring/device/base/models.py b/openwisp_monitoring/device/base/models.py
index c8694091f..0b7cc7387 100644
--- a/openwisp_monitoring/device/base/models.py
+++ b/openwisp_monitoring/device/base/models.py
@@ -3,6 +3,7 @@
from collections import OrderedDict
from datetime import datetime
+import swapper
from cache_memoize import cache_memoize
from dateutil.relativedelta import relativedelta
from django.core.exceptions import ValidationError
@@ -45,7 +46,7 @@ class AbstractDeviceData(object):
def __init__(self, *args, **kwargs):
self.data = kwargs.pop('data', None)
- return super().__init__(*args, **kwargs)
+ super().__init__(*args, **kwargs)
@property
def data_user_friendly(self):
@@ -182,7 +183,9 @@ def json(self, *args, **kwargs):
class AbstractDeviceMonitoring(TimeStampedEditableModel):
device = models.OneToOneField(
- 'config.Device', on_delete=models.CASCADE, related_name='monitoring'
+ swapper.get_model_name('config', 'Device'),
+ on_delete=models.CASCADE,
+ related_name='monitoring',
)
STATUS = Choices(
('unknown', _(app_settings.HEALTH_STATUS_LABELS['unknown'])),
diff --git a/openwisp_monitoring/device/migrations/0001_initial.py b/openwisp_monitoring/device/migrations/0001_initial.py
index 302775cf3..2f9383e6c 100644
--- a/openwisp_monitoring/device/migrations/0001_initial.py
+++ b/openwisp_monitoring/device/migrations/0001_initial.py
@@ -24,6 +24,6 @@ class Migration(migrations.Migration):
'device_monitoring', 'DeviceData'
),
},
- bases=('config.device',),
+ bases=(swapper.get_model_name('config', 'Device'),),
),
]
diff --git a/openwisp_monitoring/device/migrations/0002_devicemonitoring.py b/openwisp_monitoring/device/migrations/0002_devicemonitoring.py
index 6728124d2..b8ecd4b4e 100644
--- a/openwisp_monitoring/device/migrations/0002_devicemonitoring.py
+++ b/openwisp_monitoring/device/migrations/0002_devicemonitoring.py
@@ -86,7 +86,7 @@ class Migration(migrations.Migration):
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
related_name='monitoring',
- to='config.Device',
+ to=swapper.get_model_name('config', 'Device'),
),
),
],
diff --git a/openwisp_monitoring/device/models.py b/openwisp_monitoring/device/models.py
index 2b7480cdf..6929bc79f 100644
--- a/openwisp_monitoring/device/models.py
+++ b/openwisp_monitoring/device/models.py
@@ -1,12 +1,12 @@
from django.contrib.contenttypes.fields import GenericRelation
from swapper import get_model_name, swappable_setting
-from openwisp_controller.config.models import Device
+from openwisp_controller.config.models import Device as BaseDevice
from .base.models import AbstractDeviceData, AbstractDeviceMonitoring
-class DeviceData(AbstractDeviceData, Device):
+class DeviceData(AbstractDeviceData, BaseDevice):
checks = GenericRelation(get_model_name('check', 'Check'))
metrics = GenericRelation(get_model_name('monitoring', 'Metric'))
diff --git a/openwisp_monitoring/device/tests/__init__.py b/openwisp_monitoring/device/tests/__init__.py
index 474bb581b..a34e9dfa1 100644
--- a/openwisp_monitoring/device/tests/__init__.py
+++ b/openwisp_monitoring/device/tests/__init__.py
@@ -5,8 +5,7 @@
from django.urls import reverse
from swapper import load_model
-from openwisp_controller.config.models import Config, Device
-from openwisp_controller.config.tests import CreateConfigTemplateMixin
+from openwisp_controller.config.tests.utils import CreateConfigTemplateMixin
from ...monitoring.tests import TestMonitoringMixin
from ..utils import manage_short_retention_policy
@@ -14,6 +13,8 @@
Metric = load_model('monitoring', 'Metric')
DeviceData = load_model('device_monitoring', 'DeviceData')
Chart = load_model('monitoring', 'Chart')
+Config = load_model('config', 'Config')
+Device = load_model('config', 'Device')
class TestDeviceMonitoringMixin(CreateConfigTemplateMixin, TestMonitoringMixin):
diff --git a/openwisp_monitoring/device/tests/test_admin.py b/openwisp_monitoring/device/tests/test_admin.py
index 306ce260b..2464f86f6 100644
--- a/openwisp_monitoring/device/tests/test_admin.py
+++ b/openwisp_monitoring/device/tests/test_admin.py
@@ -7,6 +7,7 @@
Chart = load_model('monitoring', 'Chart')
Metric = load_model('monitoring', 'Metric')
DeviceData = load_model('device_monitoring', 'DeviceData')
+User = get_user_model()
class TestAdmin(DeviceMonitoringTestCase):
@@ -15,7 +16,6 @@ class TestAdmin(DeviceMonitoringTestCase):
"""
def _login_admin(self):
- User = get_user_model()
u = User.objects.create_superuser('admin', 'admin', 'test@test.com')
self.client.force_login(u)
diff --git a/openwisp_monitoring/device/tests/test_api.py b/openwisp_monitoring/device/tests/test_api.py
index 5444019e7..16ce489f8 100644
--- a/openwisp_monitoring/device/tests/test_api.py
+++ b/openwisp_monitoring/device/tests/test_api.py
@@ -367,12 +367,12 @@ def test_invalid_chart_config(self):
d = self._create_device(organization=self._create_org())
m = self._create_object_metric(name='test_metric', content_object=d)
c = self._create_chart(metric=m, test_data=None)
+ c.configuration = 'invalid'
+ c.save()
with redirect_stderr(StringIO()) as stderr:
- c.configuration = 'invalid'
- c.save()
- r = self.client.get(self._url(d.pk.hex, d.key))
+ response = self.client.get(self._url(d.pk.hex, d.key))
self.assertIn('InvalidChartConfigException', stderr.getvalue())
- self.assertEqual(r.status_code, 200)
+ self.assertEqual(response.status_code, 200)
def test_available_memory(self):
o = self._create_org()
diff --git a/openwisp_monitoring/device/tests/test_device_notifications.py b/openwisp_monitoring/device/tests/test_device_notifications.py
index 7723ae90a..f4f80991f 100644
--- a/openwisp_monitoring/device/tests/test_device_notifications.py
+++ b/openwisp_monitoring/device/tests/test_device_notifications.py
@@ -2,11 +2,11 @@
from django.utils.html import strip_tags
from swapper import load_model
-from openwisp_controller.connection.models import Credentials, DeviceConnection
-
from .test_models import BaseTestCase
Notification = load_model('openwisp_notifications', 'Notification')
+Credentials = load_model('connection', 'Credentials')
+DeviceConnection = load_model('connection', 'DeviceConnection')
class TestDeviceNotifications(BaseTestCase):
@@ -26,7 +26,7 @@ def _generic_notification_test(
n = Notification.objects.first()
email = mail.outbox.pop()
- html_message, content_type = email.alternatives.pop()
+ html_message, _ = email.alternatives.pop()
self.assertEqual(n.type, exp_type)
self.assertEqual(n.level, exp_level)
self.assertEqual(n.verb, exp_verb)
@@ -45,7 +45,7 @@ def _generic_notification_test(
self.assertIn(n.message, html_message)
self.assertIn(
f''
- 'For further information see "device: test-device".',
+ 'For further information see "device: default.test.device".',
html_message,
)
diff --git a/openwisp_monitoring/device/tests/test_models.py b/openwisp_monitoring/device/tests/test_models.py
index c672dbcef..3d7613f00 100644
--- a/openwisp_monitoring/device/tests/test_models.py
+++ b/openwisp_monitoring/device/tests/test_models.py
@@ -6,7 +6,6 @@
from openwisp_notifications.signals import notify
from swapper import load_model
-from openwisp_controller.connection.models import Credentials, DeviceConnection
from openwisp_utils.tests import catch_signal
from ..signals import health_status_changed
@@ -15,6 +14,8 @@
Check = load_model('check', 'Check')
DeviceMonitoring = load_model('device_monitoring', 'DeviceMonitoring')
DeviceData = load_model('device_monitoring', 'DeviceData')
+DeviceConnection = load_model('connection', 'DeviceConnection')
+Credentials = load_model('connection', 'Credentials')
class BaseTestCase(DeviceMonitoringTestCase):
diff --git a/openwisp_monitoring/monitoring/migrations/0001_initial.py b/openwisp_monitoring/monitoring/migrations/0001_initial.py
index b228f7956..bdec50c2f 100644
--- a/openwisp_monitoring/monitoring/migrations/0001_initial.py
+++ b/openwisp_monitoring/monitoring/migrations/0001_initial.py
@@ -232,7 +232,7 @@ class Migration(migrations.Migration):
'metric',
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
- to='monitoring.Metric',
+ to=swapper.get_model_name('monitoring', 'Metric'),
),
),
],
@@ -245,7 +245,8 @@ class Migration(migrations.Migration):
model_name='graph',
name='metric',
field=models.ForeignKey(
- on_delete=django.db.models.deletion.CASCADE, to='monitoring.Metric'
+ on_delete=django.db.models.deletion.CASCADE,
+ to=swapper.get_model_name('monitoring', 'Metric'),
),
),
migrations.AlterUniqueTogether(
diff --git a/openwisp_monitoring/monitoring/tests/test_monitoring_notifications.py b/openwisp_monitoring/monitoring/tests/test_monitoring_notifications.py
index 1a932cbbc..677ff1da0 100644
--- a/openwisp_monitoring/monitoring/tests/test_monitoring_notifications.py
+++ b/openwisp_monitoring/monitoring/tests/test_monitoring_notifications.py
@@ -6,13 +6,14 @@
from django.utils.html import strip_tags
from swapper import load_model
-from openwisp_controller.config.models import Config, Device
-from openwisp_users.models import OrganizationUser
-
from ...device.tests import DeviceMonitoringTestCase
Metric = load_model('monitoring', 'Metric')
Notification = load_model('openwisp_notifications', 'Notification')
+Device = load_model('config', 'Device')
+Config = load_model('config', 'Config')
+OrganizationUser = load_model('openwisp_users', 'OrganizationUser')
+
notification_queryset = Notification.objects.order_by('timestamp')
start_time = timezone.now()
ten_minutes_ago = start_time - timedelta(minutes=10)
@@ -331,7 +332,7 @@ def test_email_notification(self):
self.assertIn(n.message, html_message)
self.assertIn(
f''
- 'For further information see "device: test-device".',
+ 'For further information see "device: default.test.device".',
html_message,
)
@@ -347,7 +348,7 @@ def test_email_notification(self):
self.assertIn(n.message, html_message)
self.assertIn(
f''
- 'For further information see "device: test-device".',
+ 'For further information see "device: default.test.device".',
html_message,
)
diff --git a/setup.cfg b/setup.cfg
index 7aae69b3b..f308e9d79 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -14,7 +14,7 @@ max-line-length = 110
ignore = W605, W503, W504
[isort]
-known_third_party = django, django_x509, django_netjsonconfig
+known_third_party = django, django_x509
known_first_party = openwisp_users, openwisp_utils, openwisp_controller
line_length=88
default_section=THIRDPARTY
diff --git a/tests/openwisp2/sample_device_monitoring/migrations/0001_initial.py b/tests/openwisp2/sample_device_monitoring/migrations/0001_initial.py
index a59c3d4b7..c99871893 100644
--- a/tests/openwisp2/sample_device_monitoring/migrations/0001_initial.py
+++ b/tests/openwisp2/sample_device_monitoring/migrations/0001_initial.py
@@ -6,6 +6,7 @@
import model_utils.fields
import openwisp_monitoring.device.base.models
import uuid
+import swapper
class Migration(migrations.Migration):
@@ -23,7 +24,7 @@ class Migration(migrations.Migration):
options={'proxy': True, 'indexes': [], 'constraints': [],},
bases=(
openwisp_monitoring.device.base.models.AbstractDeviceData,
- 'config.device',
+ swapper.get_model_name('config', 'Device'),
),
),
migrations.CreateModel(
@@ -76,7 +77,7 @@ class Migration(migrations.Migration):
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
related_name='monitoring',
- to='config.Device',
+ to=swapper.get_model_name('config', 'Device'),
),
),
(
diff --git a/tests/openwisp2/sample_device_monitoring/models.py b/tests/openwisp2/sample_device_monitoring/models.py
index 37cc6986c..a6541afa7 100644
--- a/tests/openwisp2/sample_device_monitoring/models.py
+++ b/tests/openwisp2/sample_device_monitoring/models.py
@@ -6,10 +6,10 @@
)
from swapper import get_model_name
-from openwisp_controller.config.models import Device
+from openwisp_controller.config.models import Device as BaseDevice
-class DeviceData(AbstractDeviceData, Device):
+class DeviceData(AbstractDeviceData, BaseDevice):
checks = GenericRelation(get_model_name('check', 'Check'))
metrics = GenericRelation(get_model_name('monitoring', 'Metric'))
diff --git a/tests/openwisp2/sample_monitoring/migrations/0001_initial.py b/tests/openwisp2/sample_monitoring/migrations/0001_initial.py
index 004fc62b9..1155f89db 100644
--- a/tests/openwisp2/sample_monitoring/migrations/0001_initial.py
+++ b/tests/openwisp2/sample_monitoring/migrations/0001_initial.py
@@ -6,6 +6,7 @@
import django.utils.timezone
import model_utils.fields
import uuid
+import swapper
from openwisp_monitoring.monitoring.charts import get_chart_configuration_choices
@@ -131,7 +132,7 @@ class Migration(migrations.Migration):
'metric',
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
- to='sample_monitoring.Metric',
+ to=swapper.get_model_name('monitoring', 'Metric'),
),
),
],
@@ -177,7 +178,7 @@ class Migration(migrations.Migration):
'metric',
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
- to='sample_monitoring.Metric',
+ to=swapper.get_model_name('monitoring', 'Metric'),
),
),
],
diff --git a/tests/openwisp2/settings.py b/tests/openwisp2/settings.py
index 140af031e..25dbde11b 100644
--- a/tests/openwisp2/settings.py
+++ b/tests/openwisp2/settings.py
@@ -71,7 +71,6 @@
]
EXTENDED_APPS = [
- 'django_netjsonconfig',
'django_x509',
'django_loci',
]