feat: init
This commit is contained in:
222
test/model/features/test_restful_features.py
Normal file
222
test/model/features/test_restful_features.py
Normal file
@@ -0,0 +1,222 @@
|
||||
# Copyright (c) 2021-2025 The University of Texas Southwestern Medical Center.
|
||||
# All rights reserved.
|
||||
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted for academic and research use only
|
||||
# (subject to the limitations in the disclaimer below)
|
||||
# provided that the following conditions are met:
|
||||
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
|
||||
# * Neither the name of the copyright holders nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from this
|
||||
# software without specific prior written permission.
|
||||
|
||||
# NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
|
||||
# THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
# Standard Library Import
|
||||
import base64
|
||||
import unittest
|
||||
import json
|
||||
import logging
|
||||
from unittest.mock import patch, Mock, MagicMock
|
||||
from io import BytesIO
|
||||
|
||||
# Third Party Imports
|
||||
import numpy as np
|
||||
|
||||
# Local Imports
|
||||
from navigate.model.features.restful_features import (
|
||||
prepare_service,
|
||||
IlastikSegmentation,
|
||||
)
|
||||
|
||||
|
||||
class TestPrepareService(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.service_url = "http://example.com/ilastik"
|
||||
self.project_file = "path/to/project.ilp"
|
||||
self.expected_url = f"{self.service_url}/load?project={self.project_file}"
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
self.logger = logging.getLogger(
|
||||
"mymodule"
|
||||
) # Replace with the actual logger name used
|
||||
|
||||
@patch("navigate.model.features.restful_features.requests.get")
|
||||
def test_prepare_service_success(self, mock_get):
|
||||
expected_response = {"status": "success", "data": "segmentation data"}
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.content = json.dumps(expected_response)
|
||||
mock_get.return_value = mock_response
|
||||
|
||||
response = prepare_service(self.service_url, project_file=self.project_file)
|
||||
|
||||
self.assertEqual(response, expected_response)
|
||||
mock_get.assert_called_once_with(self.expected_url)
|
||||
|
||||
@patch("navigate.model.features.restful_features.requests.get")
|
||||
def test_prepare_service_failure(self, mock_get):
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 404
|
||||
mock_response.content = "Error"
|
||||
mock_get.return_value = mock_response
|
||||
|
||||
response = prepare_service(self.service_url, project_file=self.project_file)
|
||||
|
||||
self.assertIsNone(response)
|
||||
mock_get.assert_called_once_with(self.expected_url)
|
||||
|
||||
def test_prepare_service_non_ilastik_url(self):
|
||||
non_ilastik_url = "http://example.com/not_ilastik"
|
||||
response = prepare_service(non_ilastik_url, project_file=self.project_file)
|
||||
|
||||
self.assertIsNone(response)
|
||||
|
||||
|
||||
class TestIlastikSegmentation(unittest.TestCase):
|
||||
def setUp(self):
|
||||
# Set up a mock model object
|
||||
shape = (2048, 2048)
|
||||
self.mock_model = Mock()
|
||||
self.mock_model.configuration = {
|
||||
"rest_api_config": {"Ilastik": {"url": "http://example.com/ilastik"}},
|
||||
"experiment": {
|
||||
"MicroscopeState": {"microscope_name": "Nanoscale", "zoom": "1.0"},
|
||||
"CameraParameters": {
|
||||
"Nanoscale": {"x_pixels": "2048", "y_pixels": "2048"},
|
||||
},
|
||||
"StageParameters": {
|
||||
"x": "100",
|
||||
"y": "100",
|
||||
"z": "50",
|
||||
"theta": "0",
|
||||
"f": "1.0",
|
||||
},
|
||||
},
|
||||
"configuration": {
|
||||
"microscopes": {
|
||||
"Nanoscale": {"zoom": {"pixel_size": {"N/A": "1.0", "1.0": "1.0"}}}
|
||||
}
|
||||
},
|
||||
}
|
||||
self.mock_model.data_buffer = {
|
||||
0: np.random.randint(0, 65536, size=shape, dtype=np.uint16),
|
||||
1: np.random.randint(0, 65536, size=shape, dtype=np.uint16),
|
||||
}
|
||||
|
||||
self.mock_model.img_height = shape[0]
|
||||
self.mock_model.img_width = shape[1]
|
||||
self.mock_model.display_ilastik_segmentation = True
|
||||
self.mock_model.mark_ilastik_position = False
|
||||
self.mock_model.event_queue = MagicMock()
|
||||
self.mock_model.active_microscope_name = "Nanoscale"
|
||||
|
||||
self.ilastik_segmentation = IlastikSegmentation(self.mock_model)
|
||||
|
||||
@patch("requests.post")
|
||||
def test_data_func_success(self, mock_post):
|
||||
frame_ids = [0, 1]
|
||||
expected_json_data = {
|
||||
"dtype": "uint16",
|
||||
"shape": (self.mock_model.img_height, self.mock_model.img_width),
|
||||
"image": [
|
||||
base64.b64encode(self.mock_model.data_buffer[0]).decode("utf-8"),
|
||||
base64.b64encode(self.mock_model.data_buffer[1]).decode("utf-8"),
|
||||
],
|
||||
}
|
||||
|
||||
# Create a valid numpy array to simulate the response
|
||||
array_data = np.array([np.zeros((2048, 2048, 1), dtype=np.uint16)])
|
||||
buffer = BytesIO()
|
||||
np.savez(buffer, *array_data)
|
||||
buffer.seek(0)
|
||||
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.raw.read.return_value = buffer.read()
|
||||
mock_post.return_value = mock_response
|
||||
|
||||
self.ilastik_segmentation.data_func(frame_ids)
|
||||
|
||||
mock_post.assert_called_once_with(
|
||||
"http://example.com/ilastik/segmentation",
|
||||
json=expected_json_data,
|
||||
stream=True,
|
||||
)
|
||||
self.mock_model.event_queue.put.assert_called()
|
||||
|
||||
# Test with self.model.mark_ilastik_position set to True
|
||||
self.mock_model.mark_ilastik_position = True
|
||||
self.mock_model.event_queue.reset_mock()
|
||||
|
||||
self.mock_model.ilastik_target_labels = range(1)
|
||||
self.ilastik_segmentation.update_setting()
|
||||
self.ilastik_segmentation.data_func(frame_ids)
|
||||
assert self.mock_model.event_queue.put.call_count == 2
|
||||
# self.mock_model.event_queue.put.assert_called_with(("multiposition"))
|
||||
called_args, _ = self.mock_model.event_queue.put.call_args
|
||||
assert "multiposition" in called_args[0]
|
||||
|
||||
@patch("requests.post")
|
||||
def test_data_func_failure(self, mock_post):
|
||||
frame_ids = [0, 1]
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 404
|
||||
mock_response.content = "Error"
|
||||
mock_post.return_value = mock_response
|
||||
|
||||
with patch("builtins.print") as mocked_print:
|
||||
self.ilastik_segmentation.data_func(frame_ids)
|
||||
mocked_print.assert_called_once_with("There is something wrong!")
|
||||
|
||||
def test_update_setting(self):
|
||||
self.ilastik_segmentation.update_setting()
|
||||
|
||||
self.assertEqual(self.ilastik_segmentation.resolution, "Nanoscale")
|
||||
self.assertEqual(self.ilastik_segmentation.zoom, "1.0")
|
||||
self.assertEqual(self.ilastik_segmentation.pieces_num, 1)
|
||||
self.assertEqual(self.ilastik_segmentation.pieces_size, 2048)
|
||||
self.assertEqual(self.ilastik_segmentation.posistion_step_size, 2048)
|
||||
self.assertEqual(self.ilastik_segmentation.x_start, -924)
|
||||
self.assertEqual(self.ilastik_segmentation.y_start, -924)
|
||||
|
||||
def test_init_func_update_settings(self):
|
||||
with patch.object(
|
||||
self.ilastik_segmentation, "update_setting"
|
||||
) as mock_update_setting:
|
||||
self.ilastik_segmentation.resolution = "DifferentResolution"
|
||||
self.ilastik_segmentation.zoom = "DifferentZoom"
|
||||
self.ilastik_segmentation.init_func()
|
||||
mock_update_setting.assert_called_once()
|
||||
|
||||
def test_mark_position(self):
|
||||
mask = np.zeros((2048, 2048, 1), dtype=np.uint16)
|
||||
mask[0:1024, 0:1024, 0] = 1 # Mock some segmentation data
|
||||
self.mock_model.ilastik_target_labels = [1]
|
||||
|
||||
self.ilastik_segmentation.update_setting()
|
||||
self.ilastik_segmentation.mark_position(mask)
|
||||
|
||||
self.mock_model.event_queue.put.assert_called()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user