kopia lustrzana https://github.com/OpenDroneMap/WebODM
nodeodm API client testing, app views testing
rodzic
a0be8ae8ca
commit
aff4ab7314
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "nodeodm/external/node-OpenDroneMap"]
|
||||||
|
path = nodeodm/external/node-OpenDroneMap
|
||||||
|
url = https://github.com/pierotofy/node-OpenDroneMap
|
13
Dockerfile
13
Dockerfile
|
@ -17,3 +17,16 @@ RUN pip install --upgrade git+git://github.com/Yelp/swagger_spec_validator
|
||||||
|
|
||||||
# Add repository files
|
# Add repository files
|
||||||
ADD . /webodm/
|
ADD . /webodm/
|
||||||
|
|
||||||
|
RUN git submodule init
|
||||||
|
RUN git submodule update
|
||||||
|
|
||||||
|
# Install Node.js + npm requirements for testing node-OpenDroneMap
|
||||||
|
RUN curl --silent --location https://deb.nodesource.com/setup_6.x | sudo bash -
|
||||||
|
RUN apt-get install -y nodejs
|
||||||
|
|
||||||
|
WORKDIR /webodm/nodeodm/external/node-OpenDroneMap
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
WORKDIR /webodm
|
||||||
|
ENTRYPOINT ["python", "manage.py", "runserver"]
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h3>Processing Node</h3>
|
<h3>Processing Node</h3>
|
||||||
<table class="table table-bordered table-first-col-bold">
|
<table class="table table-bordered table-striped table-first-col-bold">
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% trans "Hostname" %}</td>
|
<td>{% trans "Hostname" %}</td>
|
||||||
<td>{{ processing_node.hostname }}</td>
|
<td>{{ processing_node.hostname }}</td>
|
||||||
|
|
44
app/tests.py
44
app/tests.py
|
@ -1,15 +1,14 @@
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
from django.contrib.auth.models import User, Group
|
from django.contrib.auth.models import User, Group
|
||||||
|
from django.contrib import messages
|
||||||
from django.test import Client
|
from django.test import Client
|
||||||
|
|
||||||
from .models import Project, Task
|
from .models import Project, Task
|
||||||
|
|
||||||
# Create your tests here.
|
class TestApp(TestCase):
|
||||||
|
|
||||||
class TestUser(TestCase):
|
fixtures = ['test_users', 'test_processingnodes', ]
|
||||||
|
|
||||||
fixtures = ['test_users', ]
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.credentials = {
|
self.credentials = {
|
||||||
|
@ -26,7 +25,7 @@ class TestUser(TestCase):
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_User_Login_Test(self):
|
def test_user_login(self):
|
||||||
c = Client()
|
c = Client()
|
||||||
# User points the browser to the landing page
|
# User points the browser to the landing page
|
||||||
res = c.post('/', follow=True)
|
res = c.post('/', follow=True)
|
||||||
|
@ -47,3 +46,38 @@ class TestUser(TestCase):
|
||||||
|
|
||||||
# and moves him at the dashboard
|
# and moves him at the dashboard
|
||||||
self.assertTemplateUsed(res, 'app/dashboard.html')
|
self.assertTemplateUsed(res, 'app/dashboard.html')
|
||||||
|
|
||||||
|
def test_views(self):
|
||||||
|
c = Client()
|
||||||
|
|
||||||
|
# Connecting to dashboard without auth redirects to /
|
||||||
|
res = c.get('/dashboard/', follow=True)
|
||||||
|
self.assertFalse(res.context['user'].is_authenticated)
|
||||||
|
self.assertRedirects(res, '/login/?next=/dashboard/')
|
||||||
|
|
||||||
|
res = c.get('/processingnode/1/', follow=True)
|
||||||
|
self.assertRedirects(res, '/login/?next=/processingnode/1/')
|
||||||
|
|
||||||
|
# Login
|
||||||
|
c.post('/login/', data=self.credentials, follow=True)
|
||||||
|
|
||||||
|
# We can access a processingnode view that exists
|
||||||
|
res = c.get('/processingnode/1/')
|
||||||
|
self.assertTrue(res.status_code == 200)
|
||||||
|
self.assertTemplateUsed(res, 'app/processing_node.html')
|
||||||
|
|
||||||
|
# We can access a processingnode that is offline
|
||||||
|
# (and there's a warning message when we do that)
|
||||||
|
res = c.get('/processingnode/2/')
|
||||||
|
self.assertTrue(res.status_code == 200)
|
||||||
|
self.assertTemplateUsed(res, 'app/processing_node.html')
|
||||||
|
|
||||||
|
message = list(res.context['messages'])[0]
|
||||||
|
self.assertEqual(message.tags, 'warning')
|
||||||
|
self.assertTrue("offline" in message.message)
|
||||||
|
|
||||||
|
res = c.get('/processingnode/9999/')
|
||||||
|
self.assertTrue(res.status_code == 404)
|
||||||
|
|
||||||
|
res = c.get('/processingnode/abc/')
|
||||||
|
self.assertTrue(res.status_code == 404)
|
||||||
|
|
|
@ -2,15 +2,17 @@ from django.shortcuts import render, redirect, get_object_or_404
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from nodeodm.models import ProcessingNode
|
from nodeodm.models import ProcessingNode
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
return redirect('dashboard' if request.user.is_authenticated()
|
return redirect('dashboard' if request.user.is_authenticated()
|
||||||
else 'login')
|
else 'login')
|
||||||
|
|
||||||
|
@login_required
|
||||||
def dashboard(request):
|
def dashboard(request):
|
||||||
return render(request, 'app/dashboard.html', {'title': 'Dashboard'})
|
return render(request, 'app/dashboard.html', {'title': 'Dashboard'})
|
||||||
|
|
||||||
|
@login_required
|
||||||
def processing_node(request, processing_node_id):
|
def processing_node(request, processing_node_id):
|
||||||
pn = get_object_or_404(ProcessingNode, pk=processing_node_id)
|
pn = get_object_or_404(ProcessingNode, pk=processing_node_id)
|
||||||
if not pn.update_node_info():
|
if not pn.update_node_info():
|
||||||
|
|
|
@ -17,7 +17,6 @@ class ApiClient:
|
||||||
try:
|
try:
|
||||||
self.client = SwaggerClient.from_url('http://{}:{}/swagger.json'.format(self.host, self.port))
|
self.client = SwaggerClient.from_url('http://{}:{}/swagger.json'.format(self.host, self.port))
|
||||||
except (ConnectionError, HTTPError) as err:
|
except (ConnectionError, HTTPError) as err:
|
||||||
print("{}:{} seems offline: {}".format(self.host, self.port, err))
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return func(self, *args, **kwargs)
|
return func(self, *args, **kwargs)
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit fdc55291525c03dbdf922724f1a4af8d1a89d2af
|
|
@ -0,0 +1,26 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"fields": {
|
||||||
|
"api_version": "",
|
||||||
|
"available_options": {},
|
||||||
|
"hostname": "localhost",
|
||||||
|
"last_refreshed": null,
|
||||||
|
"port": 11223,
|
||||||
|
"queue_count": 0
|
||||||
|
},
|
||||||
|
"model": "nodeodm.processingnode",
|
||||||
|
"pk": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fields": {
|
||||||
|
"api_version": "",
|
||||||
|
"available_options": {},
|
||||||
|
"hostname": "invalid-host",
|
||||||
|
"last_refreshed": null,
|
||||||
|
"port": 11223,
|
||||||
|
"queue_count": 0
|
||||||
|
},
|
||||||
|
"model": "nodeodm.processingnode",
|
||||||
|
"pk": 2
|
||||||
|
}
|
||||||
|
]
|
|
@ -1,3 +1,63 @@
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
from django.utils import six
|
||||||
|
import subprocess, time
|
||||||
|
from os import path
|
||||||
|
from .models import ProcessingNode
|
||||||
|
from .api_client import ApiClient
|
||||||
|
|
||||||
# Create your tests here.
|
current_dir = path.dirname(path.realpath(__file__))
|
||||||
|
|
||||||
|
|
||||||
|
class TestClientApi(TestCase):
|
||||||
|
fixtures = ['test_processingnodes', ]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super(TestClientApi, cls).setUpClass()
|
||||||
|
cls.node_odm = subprocess.Popen(['node', 'index.js', '--port', '11223', '--test'], shell=False, cwd=path.join(current_dir, "external", "node-OpenDroneMap"))
|
||||||
|
time.sleep(5) # Wait for the server to launch
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
super(TestClientApi, cls).tearDownClass()
|
||||||
|
cls.node_odm.terminate()
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.api_client = ApiClient("localhost", 11223)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_offline_api(self):
|
||||||
|
api = ApiClient("offline-host", 3000)
|
||||||
|
self.assertTrue(api.info() == None)
|
||||||
|
self.assertTrue(api.options() == None)
|
||||||
|
|
||||||
|
def test_info(self):
|
||||||
|
info = self.api_client.info()
|
||||||
|
self.assertTrue(isinstance(info['version'], six.string_types), "Found version string")
|
||||||
|
self.assertTrue(isinstance(info['taskQueueCount'], int), "Found task queue count")
|
||||||
|
|
||||||
|
def test_options(self):
|
||||||
|
options = self.api_client.options()
|
||||||
|
self.assertTrue(len(options) > 0, "Found options")
|
||||||
|
|
||||||
|
def test_online_processing_node(self):
|
||||||
|
online_node = ProcessingNode.objects.get(pk=1)
|
||||||
|
self.assertTrue(str(online_node) == "localhost:11223", "Formatting string works")
|
||||||
|
self.assertTrue(online_node.last_refreshed != 0, "Last refreshed not yet set")
|
||||||
|
self.assertTrue(len(online_node.available_options) == 0, "Available options not yet set")
|
||||||
|
self.assertTrue(online_node.api_version == "", "API version is not set")
|
||||||
|
|
||||||
|
self.assertTrue(online_node.update_node_info(), "Could update info")
|
||||||
|
self.assertTrue(online_node.last_refreshed != 0, "Last refreshed is set")
|
||||||
|
self.assertTrue(len(online_node.available_options) > 0, "Available options are set")
|
||||||
|
self.assertTrue(online_node.api_version != "", "API version is set")
|
||||||
|
|
||||||
|
self.assertTrue(isinstance(online_node.get_available_options_json(), six.string_types), "Available options json works")
|
||||||
|
|
||||||
|
def test_offline_processing_node(self):
|
||||||
|
offline_node = ProcessingNode.objects.get(pk=2)
|
||||||
|
self.assertFalse(offline_node.update_node_info(), "Could not update info (offline)")
|
||||||
|
self.assertTrue(offline_node.api_version == "", "API version is not set")
|
||||||
|
|
Ładowanie…
Reference in New Issue