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

Added tests for api requests #78

Merged
merged 3 commits into from
May 30, 2024
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Changed
=======
- Updated python environment installation from 3.9 to 3.11
- Updated test dependencies
- Added versioning to API requests

Added
=====
Expand Down
10 changes: 5 additions & 5 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,31 +80,31 @@ def handle_packet_in(self, event):
if not isinstance(ethernet, int):
self.tracing.queue_probe_packet(event, ethernet, in_port, switch)

@rest("/trace", methods=["PUT"])
@rest("/v1/trace", methods=["PUT"])
@validate_openapi(spec)
def run_trace(self, request: Request) -> JSONResponse:
"""Submit a trace request."""
body = get_json_or_400(request, self.controller.loop)
return JSONResponse(self.tracing.rest_new_trace(body))

@rest("/trace", methods=["GET"])
@rest("/v1/trace", methods=["GET"])
def get_results(self, _request: Request) -> JSONResponse:
"""List all traces performed so far."""
return JSONResponse(self.tracing.rest_list_results())

@rest("/trace/{trace_id}", methods=["GET"])
@rest("/v1/trace/{trace_id}", methods=["GET"])
def get_result(self, request: Request) -> JSONResponse:
"""List All Traces performed since the Napp loaded."""
trace_id = request.path_params["trace_id"]
return JSONResponse(self.tracing.rest_get_result(trace_id))

@rest("/stats", methods=["GET"])
@rest("/v1/stats", methods=["GET"])
def get_stats(self, _request: Request) -> JSONResponse:
"""Get statistics."""
return JSONResponse(self.tracing.rest_list_stats())

@staticmethod
@rest("/settings", methods=["GET"])
@rest("/v1/settings", methods=["GET"])
def list_settings(_request: Request) -> JSONResponse:
"""List the SDNTrace settings

Expand Down
10 changes: 5 additions & 5 deletions openapi.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
openapi: '3.0.0'
info:
version: none
version: '1.0.0'
title: amlight/sdntrace
description: Create and look up OpenFlow path traces.
servers:
- url: /api/amlight/sdntrace
paths:
/trace:
/v1/trace:
get:
summary: List traces
description: Get all traces available from the database
Expand Down Expand Up @@ -49,7 +49,7 @@ paths:
'400':
description: Bad request.

/trace/{trace_id}:
/v1/trace/{trace_id}:
get:
summary: Get trace details
description: Request trace details by providing the trace_id
Expand All @@ -73,7 +73,7 @@ paths:
msg: # This property will show only error messages
type: string

/stats:
/v1/stats:
get:
summary: Get trace statistics
description: Request trace statistics details
Expand All @@ -86,7 +86,7 @@ paths:
schema:
$ref: '#/components/schemas/Statistics'

/settings:
/v1/settings:
get:
summary: Get settings
description: Request settings for sdntrace
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ class Test(TestCommand):

def run(self):
"""Run tests."""
cmd = f"python3 -m pytest tests/ {self.get_args()}"
cmd = f"python3 -m pytest tests/ --cov-report term-missing {self.get_args()}"
viniarck marked this conversation as resolved.
Show resolved Hide resolved
try:
check_call(cmd, shell=True)
except CalledProcessError as exc:
Expand All @@ -115,7 +115,7 @@ class TestCoverage(Test):

def run(self):
"""Run tests quietly and display coverage report."""
cmd = f"python3 -m pytest --cov=. tests/ {self.get_args()}"
cmd = f"python3 -m pytest --cov=. tests/ --cov-report term-missing {self.get_args()}"
try:
check_call(cmd, shell=True)
except CalledProcessError as exc:
Expand Down
144 changes: 140 additions & 4 deletions tests/unit/test_main.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
"""Module to test the main napp file."""

from unittest.mock import patch

from kytos.lib.helpers import get_controller_mock
import asyncio
from unittest.mock import patch, MagicMock
from napps.amlight.sdntrace import settings
from napps.amlight.sdntrace.tracing.trace_entries import TraceEntries
from kytos.lib.helpers import get_controller_mock, get_test_client


# pylint: disable=too-many-public-methods, too-many-lines
Expand All @@ -20,4 +22,138 @@ def setup_method(self):
# pylint: disable=import-outside-toplevel
from napps.amlight.sdntrace.main import Main

self.napp = Main(get_controller_mock())
Main.get_eline_controller = MagicMock()
self.controller = get_controller_mock()
self.napp = Main(self.controller)
self.api_client = get_test_client(self.controller, self.napp)
self.base_endpoint = "amlight/sdntrace/v1"

@patch(
"napps.amlight.sdntrace.tracing.trace_manager.TraceManager.avoid_duplicated_request"
)
@patch("napps.amlight.sdntrace.tracing.trace_manager.TraceManager.is_entry_valid")
@patch("napps.amlight.sdntrace.tracing.trace_manager.TraceManager.new_trace")
async def test_run_trace(self, mock_trace, mock_entry, mock_duplicate):
"""Test run_trace"""
self.napp.controller.loop = asyncio.get_running_loop()
payload = {
"trace": {
"switch": {"dpid": "00:00:00:00:00:00:00:01", "in_port": 1},
"eth": {"dl_vlan": 400, "dl_vlan_pcp": 4, "dl_type": 2048},
}
}
# Error not TraceEntries instance
mock_entry.return_value = "not_entry"
url = f"{self.base_endpoint}/trace"
response = await self.api_client.put(url, json=payload)
assert response.status_code == 200
actual_result = response.json()
expected_result = {"result": {"error": "not_entry"}}
assert actual_result == expected_result

# Error duplicated trace
mock_entry.return_value = TraceEntries()
mock_duplicate.return_value = True
url = f"{self.base_endpoint}/trace"
response = await self.api_client.put(url, json=payload)
assert response.status_code == 200
result = response.json()
assert result["result"]["error"] == "Duplicated Trace Request ignored"

# Success
mock_duplicate.return_value = False
trace_id = 9999
mock_trace.return_value = trace_id
url = f"{self.base_endpoint}/trace"
response = await self.api_client.put(url, json=payload)
assert response.status_code == 200
result = response.json()
assert result["result"]["trace_id"] == trace_id

@patch("napps.amlight.sdntrace.tracing.trace_manager.TraceManager.get_results")
async def test_get_results(self, mock_rest_results):
"""Test get_results"""
mock_rest_results.return_value = "mock_results"
url = f"{self.base_endpoint}/trace"
response = await self.api_client.get(url)
assert response.status_code == 200
result = response.json()
assert result == "mock_results"
assert mock_rest_results.call_count == 1

# pylint: disable=protected-access
async def test_get_result(self):
"""Test get_result"""
trace_id = "9999"

# Trace in process
self.napp.tracing._results_queue = {}
self.napp.tracing._running_traces = {int(trace_id): "mock"}
url = f"{self.base_endpoint}/trace/{trace_id}"
response = await self.api_client.get(url)
assert response.status_code == 200
result = response.json()
assert result == {"msg": "trace in process"}

# Trace pending
self.napp.tracing._running_traces = {}
self.napp.tracing._request_queue = {int(trace_id): "mock"}
url = f"{self.base_endpoint}/trace/{trace_id}"
response = await self.api_client.get(url)
assert response.status_code == 200
result = response.json()
assert result == {"msg": "trace pending"}

# Trace not found
self.napp.tracing._request_queue = {}
url = f"{self.base_endpoint}/trace/{int(trace_id)}"
response = await self.api_client.get(url)
assert response.status_code == 200
result = response.json()
assert result == {"msg": "unknown trace id"}

# Success
self.napp.tracing._results_queue = {int(trace_id): "success_mock"}
url = f"{self.base_endpoint}/trace/{trace_id}"
response = await self.api_client.get(url)
assert response.status_code == 200
result = response.json()
assert result == "success_mock"

# pylint: disable=protected-access
@patch("napps.amlight.sdntrace.tracing.trace_manager.new_thread")
async def test_get_stats(self, mock_thread):
"""Test get_stats"""
mock_thread.return_value = True
traces_n = 99
traces_running = {"mock": "request"}
queue_request = {"mock1": "trace1", "mock2": "trace2"}
queue_result = {"mock": "result"}
self.napp.tracing._total_traces_requested = traces_n
self.napp.tracing._running_traces = traces_running
self.napp.tracing._request_queue = queue_request
self.napp.tracing._results_queue = queue_result
url = f"{self.base_endpoint}/stats"
response = await self.api_client.get(url)
assert response.status_code == 200
actual_result = response.json()
expected_result = {
"number_of_requests": traces_n,
"number_of_running_traces": len(traces_running),
"number_of_pending_traces": len(queue_request),
"list_of_pending_traces": queue_result,
}
assert actual_result == expected_result

async def test_list_settings(self):
"""Test list_settings"""
url = f"{self.base_endpoint}/settings"
response = await self.api_client.get(url)
actual_result = response.json()
expected_result = {
"color_field": settings.COLOR_FIELD,
"color_value": settings.COLOR_VALUE,
"trace_interval": settings.TRACE_INTERVAL,
"parallel_traces": settings.PARALLEL_TRACES,
}
assert actual_result == expected_result
4 changes: 2 additions & 2 deletions ui/k-info-panel/show_trace_results.kytos
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
async: true,
dataType: "json",
type: "GET",
url: `${this.$kytos_server_api}amlight/sdntrace/trace/${this.traceId}`,
url: `${this.$kytos_server_api}amlight/sdntrace/v1/trace/${this.traceId}`,
success: function(response) {
self.trace_results = response.result;
self.updateId = response.request_id;
Expand All @@ -91,7 +91,7 @@
dataType: "json",
type: "GET",
contentType: "application/json",
url: this.$kytos_server_api + "amlight/sdntrace/trace",
url: this.$kytos_server_api + "amlight/sdntrace/v1/trace",
});

request.done(function(data) {
Expand Down
4 changes: 2 additions & 2 deletions ui/k-toolbar/main.kytos
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ module.exports = {
type: "PUT",
contentType: "application/json",
data: JSON.stringify(payload),
url: this.$kytos_server_api + "amlight/sdntrace/trace",
url: this.$kytos_server_api + "amlight/sdntrace/v1/trace",
});


Expand Down Expand Up @@ -164,7 +164,7 @@ module.exports = {
dataType: "json",
type: "GET",
contentType: "application/json",
url: this.$kytos_server_api + "amlight/sdntrace/trace",
url: this.$kytos_server_api + "amlight/sdntrace/v1/trace",
});

request.done(function(data) {
Expand Down