Skip to content
Snippets Groups Projects
tests.py 65.6 KiB
Newer Older
"""Unit tests for testing the application functionality."""
# TODO: TEST BLINKER, GUNICORN, PSYCOPG2-BINARY AND COVERAGE IMPORTS
import copy
import logging
import ntpath
import os
from collections import OrderedDict
from threading import Thread
from unittest.mock import patch, MagicMock, mock_open
from zipfile import ZipFile

import rapidjson as json
import re
import shutil
import string
import sys
import time
import unittest
from multiprocessing import Process
from unittest import TestLoader
from datetime import datetime
from typing import Dict, List, Tuple, Type

from conllu import TokenList
from flask import Flask
from flask.testing import FlaskClient
from gensim.models import Word2Vec
from lxml import etree
from networkx import MultiDiGraph, Graph
from requests import HTTPError
from sqlalchemy.exc import OperationalError
from sqlalchemy.orm import session
from werkzeug.exceptions import NotFound
from werkzeug.wrappers import Response

import csm
import mcserver
from csm.app import create_csm_app
from mcserver.app import create_app, db, start_updater, full_init
from mcserver.app.api.exerciseAPI import map_exercise_data_to_database
from mcserver.app.api.vectorNetworkAPI import add_edges, get_concept_network
from mcserver.app.models import Corpus, UpdateInfo, ResourceType, Exercise, FileType, ExerciseType, ExerciseData, \
    NodeMC, LinkMC, GraphData, Phenomenon, CustomCorpus, AnnisResponse, Solution, DownloadableFile, Language, \
    VocabularyCorpus, SolutionElement, TextComplexityMeasure, FrequencyAnalysis, CitationLevel, FrequencyItem, \
    LearningResult, TextComplexity, Dependency, PartOfSpeech, Category, Choice, Actor, XapiStatement
from mcserver.app.services import AnnotationService, CorpusService, FileService, CustomCorpusService, DatabaseService, \
    XMLservice, TextService
from mcserver.config import TestingConfig, Config
from mocks import Mocks, MockResponse, MockW2V


class McTestCase(unittest.TestCase):
    """The test suite for the main application."""

    def mocked_requests_get(*args, **kwargs):
        if TestingConfig.SIMULATE_CORPUS_NOT_FOUND:
            return MockResponse(json.dumps(AnnisResponse().__dict__))
        elif TestingConfig.SIMULATE_HTTP_ERROR:
            raise HTTPError
        elif TestingConfig.SIMULATE_EMPTY_GRAPH:
            graph_data_raw: dict = dict(Mocks.annis_response_dict["graph_data_raw"])
            graph_data_raw["nodes"] = []
            return MockResponse(json.dumps(graph_data_raw))
        url: str = args[0]
        if url == Config.CTS_API_BASE_URL:
            if kwargs['params']['request'] == 'GetCapabilities':
                return MockResponse(Mocks.cts_capabilities_xml)
            return MockResponse(Mocks.cts_reff_xml)
        elif url.endswith(Config.SERVER_URI_CSM_SUBGRAPH):
            return MockResponse(json.dumps(Mocks.annis_response_dict))
        else:
            gd: GraphData = AnnotationService.map_graph_data(Mocks.annis_response_dict["graph_data_raw"])
            return MockResponse(json.dumps(gd.serialize()))

    def mocked_requests_post(*args, **kwargs):
        url: str = args[0]
        if url.endswith(Config.SERVER_URI_TEXT_COMPLEXITY):
            return MockResponse(Mocks.text_complexity_json_string)
        else:
            ed1: ExerciseData = AnnotationService.map_graph_data_to_exercise(
                Mocks.annis_response_dict["graph_data_raw"],
                "", [Solution(target=SolutionElement(
                    salt_id='salt:/urn:custom:latinLit:proiel.pal-agr.lat:1.1.1/doc1#sent159692tok1'))])
            ed2: ExerciseData = AnnotationService.map_graph_data_to_exercise(
                Mocks.annis_response_dict["graph_data_raw"],
                "", [Solution(target=SolutionElement(
                    salt_id='salt:/urn:custom:latinLit:proiel.pal-agr.lat:1.1.1/doc1#sent159695tok10'))])
            ed2.graph.nodes = ed2.graph.nodes[42:]
            return MockResponse(json.dumps([ed1.serialize(), ed2.serialize()]))

    def setUp(self):
        """Initializes the testing environment."""
        self.start_time = time.time()
        if os.path.exists(Config.GRAPH_DATABASE_DIR):
            shutil.rmtree(Config.GRAPH_DATABASE_DIR)
        patcher = patch.object(TextService, "init_stop_words_latin")
        self.addCleanup(patcher.stop)
        patcher.start()
        self.app: Flask = create_app(TestingConfig)
        self.app.logger.setLevel(logging.CRITICAL)
        self.assertIsInstance(self.app, Flask)
        self.app_context = self.app.app_context()
        self.app_context.push()
        self.app.testing = True
        self.client: FlaskClient = self.app.test_client()
        self.assertIsInstance(self.client, FlaskClient)
        UpdateInfo.query.delete()
        Corpus.query.delete()

    def tearDown(self):
        """Finishes testing by removing the traces."""
        db.session.remove()
        db.drop_all()
        self.app_context.pop()
        print("{0}: {1} seconds".format(self.id(), "%.2f" % (time.time() - self.start_time)))

    @staticmethod
    def add_corpus(corpus: Corpus):
        """ Adds a corpus to the database. """
        db.session.add(corpus)
        UpdateInfo.query.delete()
        ui_cts: UpdateInfo = UpdateInfo(resource_type=ResourceType.cts_data, last_modified_time=datetime.utcnow())
        db.session.add(ui_cts)
        db.session.commit()

    @staticmethod
    def clear_folder(folder_path: str):
        """ Deletes every file in a folder. """
        for f in [x for x in os.listdir(folder_path) if x != ".gitignore"]:
            os.remove(os.path.join(folder_path, f))

    def test_api_corpus_delete(self):
        """ Deletes a single corpus. """
        response: Response = self.client.delete(Mocks.corpora[0].uri)
        self.assertEqual(response.status_code, 404)
        McTestCase.add_corpus(Mocks.corpora[0])
        response = self.client.delete(Mocks.corpora[0].uri)
        data_json: dict = json.loads(response.get_data())
        self.assertEqual(data_json, {"result": True})
        Corpus.query.delete()
        UpdateInfo.query.delete()
        # dirty hack so we can reuse it in other tests
        session.make_transient(Mocks.corpora[0])

    def test_api_corpus_get(self):
        """ Gets information about a single corpus. """
        response: Response = self.client.get(Mocks.corpora[0].uri)
        self.assertEqual(response.status_code, 404)
        McTestCase.add_corpus(Mocks.corpora[0])
        response: Response = self.client.get(Mocks.corpora[0].uri)
        data_json: dict = json.loads(response.get_data())
        actual_corpus: Corpus = Corpus(json_dict=data_json["corpus"])
        self.assertEqual(actual_corpus, Mocks.corpora[0])
        Corpus.query.delete()
        UpdateInfo.query.delete()
        # dirty hack so we can reuse it in other tests
        session.make_transient(Mocks.corpora[0])

    def test_api_corpus_list_get(self):
        """Adds multiple texts to the database and queries them all."""

        class MockFilterBy:
            def __init__(self, do_raise: bool = False, ui: UpdateInfo = None):
                self.do_raise: bool = do_raise
                self.ui: UpdateInfo = ui

            def first(self):
                if self.do_raise:
                    raise OperationalError("error", [], "")
                else:
                    return self.ui

        def expect_result(self: McTestCase, mock: MagicMock, do_raise: bool, lut: str, result: object,
                          lmt: datetime = datetime.utcnow()):
            ui: UpdateInfo = UpdateInfo(resource_type=ResourceType.cts_data, last_modified_time=lmt)
            mfb: MockFilterBy = MockFilterBy(do_raise, ui)
            mock.query.filter_by.return_value = mfb
            response: Response = self.client.get(TestingConfig.SERVER_URI_CORPORA,
                                                 query_string=dict(last_update_time=lut))
            data_json = json.loads(response.get_data())
            if data_json:
                data_json = [Corpus(json_dict=x) for x in data_json["corpora"]]
            self.assertEqual(data_json, result)

        with patch.object(mcserver.app.api.corpusListAPI, "UpdateInfo") as mock_update_info:
            expect_result(self, mock_update_info, True, "0", None)
            expect_result(self, mock_update_info, False, str(int(datetime.utcnow().timestamp() * 1000)), None,
                          datetime.fromtimestamp(0))
            db.session.add_all(Mocks.corpora)
            db.session.commit()
            expect_result(self, mock_update_info, False, "0", Mocks.corpora, datetime.fromtimestamp(time.time()))
        Corpus.query.delete()
        UpdateInfo.query.delete()
        # dirty hack so we can reuse it in other tests
        session.make_transient(Mocks.corpora[0])

    def test_api_corpus_put(self):
        """ Changes information about a single corpus. """
        response: Response = self.client.put(Mocks.corpora[0].uri)
        self.assertEqual(response.status_code, 404)
        McTestCase.add_corpus(Mocks.corpora[0])
        old_title: str = Mocks.corpora[0].title
        new_title: str = "new_title"
        response: Response = self.client.put(Mocks.corpora[0].uri, data=dict(title=new_title))
        data_json: dict = json.loads(response.get_data())
        new_corpus: Corpus = Corpus(json_dict=data_json["corpus"])
        self.assertEqual(new_corpus.title, Mocks.corpora[0].title)
        Mocks.corpora[0].title = old_title
        Corpus.query.delete()
        UpdateInfo.query.delete()
        # dirty hack so we can reuse it in other tests
        session.make_transient(Mocks.corpora[0])

    def test_api_exercise_get(self):
        """ Retrieves an existing exercise by its exercise ID. """
        response: Response = self.client.get(Config.SERVER_URI_EXERCISE, query_string=dict(eid=""))
        self.assertEqual(response.status_code, 404)
        old_urn: str = Mocks.exercise.urn
        Mocks.exercise.urn = ""
        db.session.add(Mocks.exercise)
        db.session.commit()
        with patch.object(CorpusService, "get_corpus", side_effect=[AnnisResponse(), Mocks.annis_response]):
            response = self.client.get(Config.SERVER_URI_EXERCISE, query_string=dict(eid=Mocks.exercise.eid))
            self.assertEqual(response.status_code, 404)
            Mocks.exercise.urn = old_urn
            db.session.commit()
            response = self.client.get(Config.SERVER_URI_EXERCISE, query_string=dict(eid=Mocks.exercise.eid))
            graph_dict: dict = json.loads(response.data.decode("utf-8"))
            ar: AnnisResponse = AnnisResponse(json_dict=graph_dict)
            self.assertEqual(len(ar.nodes), 52)
            Exercise.query.delete()
            session.make_transient(Mocks.exercise)
            self.app_context.push()

    def test_api_exercise_list_get(self):
        """ Retrieves a list of available exercises. """
        ui_exercises: UpdateInfo = UpdateInfo(resource_type=ResourceType.exercise_list,
                                              last_modified_time=datetime.fromtimestamp(1))
        db.session.add(ui_exercises)
        db.session.commit()
        args: dict = dict(lang="fr", last_update_time=int(time.time()))
        response: Response = self.client.get(TestingConfig.SERVER_URI_EXERCISE_LIST, query_string=args)
        self.assertEqual(json.loads(response.get_data()), [])
        args["last_update_time"] = 0
        db.session.add(Mocks.exercise)
        db.session.commit()
        response = self.client.get(TestingConfig.SERVER_URI_EXERCISE_LIST, query_string=args)
        exercises: List[Exercise] = [Exercise(json_dict=x) for x in json.loads(response.get_data())]  # .decode("utf-8")
        self.assertEqual(len(exercises), 1)
        args = dict(lang=Language.English.value, vocabulary=VocabularyCorpus.agldt.name, frequency_upper_bound=500)
        response = self.client.get(TestingConfig.SERVER_URI_EXERCISE_LIST, query_string=args)
        exercises: List[dict] = json.loads(response.get_data())  # .decode("utf-8")
        self.assertTrue(exercises[0]["matching_degree"])
        Exercise.query.delete()
        session.make_transient(Mocks.exercise)

    def test_api_file_get(self):
        """Gets an existing exercise"""
        ui_file: UpdateInfo = UpdateInfo(resource_type=ResourceType.file_api_clean,
                                         last_modified_time=datetime.fromtimestamp(1))
        db.session.add(ui_file)
        db.session.commit()
        # create a fake old file, to be deleted on the next GET request
        FileService.create_tmp_file(FileType.xml, "old")
        args: dict = dict(type=FileType.xml.value, id=Mocks.exercise.eid, solution_indices="[0]")
        response: Response = self.client.get(TestingConfig.SERVER_URI_FILE, query_string=args)
        self.assertEqual(response.status_code, 404)
        file_path: str = os.path.join(Config.TMP_DIRECTORY, Mocks.exercise.eid + "." + FileType.xml.value)
        file_content: str = "<xml></xml>"
        with open(file_path, "w+") as f:
            f.write(file_content)
        ui_file.last_modified_time = datetime.utcnow()
        db.session.commit()
        del ui_file
        response = self.client.get(TestingConfig.SERVER_URI_FILE, query_string=args)
        os.remove(file_path)
        self.assertEqual(response.data.decode("utf-8"), file_content)
        # add the mapped exercise to the database
        db.session.add(Mocks.exercise)
        db.session.commit()
        args["type"] = FileType.pdf.value
        response = self.client.get(TestingConfig.SERVER_URI_FILE, query_string=args)
        # the PDFs are not deterministically reproducible because the creation date etc. is written into them
        self.assertTrue(response.data.startswith(Mocks.exercise_pdf))
        Exercise.query.delete()
        session.make_transient(Mocks.exercise)

    def test_api_file_post(self):
        """ Posts exercise data to be saved temporarily or permanently on the server, e.g. for downloading. """
        learning_result: str = Mocks.xapi_json_string
        data_dict: dict = dict(learning_result=learning_result)
        self.client.post(TestingConfig.SERVER_URI_FILE, headers=Mocks.headers_form_data, data=data_dict)
        lrs: List[LearningResult] = LearningResult.query.all()
        self.assertEqual(len(lrs), 1)
        data_dict: dict = dict(file_type=FileType.xml.name, urn=Mocks.urn_custom, html_content="<html></html>")
        response: Response = self.client.post(TestingConfig.SERVER_URI_FILE, headers=Mocks.headers_form_data,
                                              data=data_dict)
        file_name = json.loads(response.data.decode("utf-8"))
        self.assertTrue(file_name.endswith(".xml"))
        os.remove(os.path.join(Config.TMP_DIRECTORY, file_name))
        LearningResult.query.delete()

    def test_api_frequency_get(self):
        """ Requests a frequency analysis for a given URN. """
        with patch.object(mcserver.app.services.corpusService.requests, "get", return_value=MockResponse(
                json.dumps([FrequencyItem(values=[], phenomena=[], count=[]).serialize()]))):
            response: Response = self.client.get(TestingConfig.SERVER_URI_FREQUENCY,
                                                 query_string=dict(urn=Mocks.urn_custom))
            result_list: List[dict] = json.loads(response.data.decode("utf-8"))
            fa: FrequencyAnalysis = FrequencyAnalysis(json_list=result_list)
            self.assertEqual(len(fa), 1)

    def test_api_h5p_get(self):
        """ Requests a H5P JSON file for a given exercise. """
        args: dict = dict(eid=Mocks.exercise.eid, lang=Language.English.value, solution_indices="[0]")
        response: Response = self.client.get(TestingConfig.SERVER_URI_H5P, query_string=args)
        self.assertEqual(response.status_code, 404)
        db.session.add(Mocks.exercise)
        db.session.commit()
        response = self.client.get(TestingConfig.SERVER_URI_H5P, query_string=args)
        self.assertIn(Mocks.h5p_json_cloze[1:-1], response.data.decode("utf-8"))
        Mocks.exercise.exercise_type = ExerciseType.kwic.value
        db.session.commit()
        response = self.client.get(TestingConfig.SERVER_URI_H5P, query_string=args)
        self.assertEqual(response.status_code, 422)
        Mocks.exercise.exercise_type = ExerciseType.matching.value
        db.session.commit()
        response = self.client.get(TestingConfig.SERVER_URI_H5P, query_string=args)
        self.assertIn(Mocks.h5p_json_matching[1:-1], response.data.decode("utf-8"))
        Mocks.exercise.exercise_type = ExerciseType.cloze.value
        args["lang"] = "fr"
        response = self.client.get(TestingConfig.SERVER_URI_H5P, query_string=args)
        self.assertIn(Mocks.h5p_json_cloze[1:-1], response.data.decode("utf-8"))
        Exercise.query.delete()
        session.make_transient(Mocks.exercise)

    @patch('mcserver.app.api.kwicAPI.requests.post', side_effect=mocked_requests_post)
    def test_api_kwic_post(self, mock_post: MagicMock):
        """ Posts an AQL query to create a KWIC visualization in SVG format. """
        data_dict: dict = dict(search_values=Mocks.exercise.search_values, urn=Mocks.urn_custom)
        response: Response = self.client.post(TestingConfig.SERVER_URI_KWIC, headers=Mocks.headers_form_data,
                                              data=data_dict)
        self.assertTrue(response.data.startswith(Mocks.kwic_svg))

    def test_api_not_found(self):
        """Checks the 404 response in case of an invalid API query URL."""
        with self.assertRaises(NotFound):
            self.client.get("/")

    @patch('mcserver.app.services.textComplexityService.requests.post', side_effect=mocked_requests_post)
    @patch('mcserver.app.services.corpusService.requests.get', side_effect=mocked_requests_get)
    def test_api_raw_text_get(self, mock_post_tcs: MagicMock, mock_get_cs: MagicMock):
        """ Retrieves the raw text for a given URN. """
        TestingConfig.SIMULATE_CORPUS_NOT_FOUND = True
        response: Response = self.client.get(TestingConfig.SERVER_URI_RAW_TEXT, query_string=dict(urn=Mocks.urn_custom))
        self.assertEqual(response.status_code, 404)
        TestingConfig.SIMULATE_CORPUS_NOT_FOUND = False
        response = self.client.get(TestingConfig.SERVER_URI_RAW_TEXT, query_string=dict(urn=Mocks.urn_custom))
        self.assertEqual(len(json.loads(response.data.decode("utf-8"))["nodes"]), 52)
        TestingConfig.SIMULATE_EMPTY_GRAPH = True
        response = self.client.get(TestingConfig.SERVER_URI_RAW_TEXT, query_string=dict(urn=Mocks.urn_custom))
        self.assertEqual(response.status_code, 404)
        TestingConfig.SIMULATE_EMPTY_GRAPH = False

Konstantin Schulz's avatar
Konstantin Schulz committed
    def test_api_static_exercises_get(self):
        """ Retrieves static exercises from the frontend and publishes deep URLs for each one of them. """
        exercises: List[Tuple[str, str, str]] = [
            (Config.H5P_FILL_BLANKS,) + Mocks.h5p_json_fill_blanks_1,
            (Config.H5P_FILL_BLANKS,) + Mocks.h5p_json_fill_blanks_3,
            (Config.H5P_FILL_BLANKS,) + Mocks.h5p_json_fill_blanks_4,
            (Config.H5P_FILL_BLANKS,) + Mocks.h5p_json_fill_blanks_13,
            (Config.H5P_DRAG_TEXT, "1_en", Mocks.h5p_json_cloze),
            (Config.H5P_MULTI_CHOICE, "1_en", Mocks.h5p_json_multi_choice),
            (Config.H5P_MULTI_CHOICE, "2_en", Mocks.h5p_json_multi_choice_2),
            (Config.H5P_MULTI_CHOICE,) + Mocks.h5p_json_multi_choice_9,
            (Config.H5P_VOC_LIST, "1_en", Mocks.h5p_json_voc_list)]
        paths: List[str] = []
        for exercise in exercises:
            file_name: str = exercise[1] + ".json"
            file_path: str = os.path.join(Config.TMP_DIRECTORY, exercise[0], "content", file_name)
            os.makedirs(os.path.split(file_path)[0], exist_ok=True)
            json.dump(json.loads(exercise[2]), open(file_path, "w+"))
            paths.append(file_path)
        with ZipFile(TestingConfig.STATIC_EXERCISES_ZIP_FILE_PATH, "w") as z:
            for path in paths:
                z.write(path)
        for exercise in exercises:
            shutil.rmtree(os.path.join(Config.TMP_DIRECTORY, exercise[0]), ignore_errors=True)
        zip_content: bytes = open(TestingConfig.STATIC_EXERCISES_ZIP_FILE_PATH, "rb").read()
        with patch.object(mcserver.app.api.staticExercisesAPI.requests, "get",
                          side_effect=[MockResponse("{}", ok=False), MockResponse("{}", content=zip_content)]):
            with patch.object(AnnotationService, "get_udpipe", return_value=Mocks.static_exercises_udpipe_string):
                response = self.client.get(TestingConfig.SERVER_URI_STATIC_EXERCISES)
                self.assertEqual(response.status_code, 503)
                response: Response = self.client.get(TestingConfig.SERVER_URI_STATIC_EXERCISES)
                os.remove(TestingConfig.STATIC_EXERCISES_ZIP_FILE_PATH)
                self.assertGreater(len(response.data.decode("utf-8")), 1900)

    @patch('mcserver.app.services.corpusService.requests.get', side_effect=mocked_requests_get)
    def test_api_subgraph_get(self, mock_get: MagicMock):
        """ Retrieves subgraph data for a given URN. """
        ar: AnnisResponse = CorpusService.get_subgraph(Mocks.urn_custom, 'tok="quarum"', 0, 0, False)
        self.assertEqual(len(ar.solutions), 3)

    @patch('mcserver.app.services.corpusService.requests.get', side_effect=mocked_requests_get)
    @patch('mcserver.app.services.textComplexityService.requests.post', side_effect=mocked_requests_post)
    def test_api_text_complexity_get(self, mock_get: MagicMock, mock_post: MagicMock):
        """ Calculates text complexity measures for a given URN. """
        args: dict = dict(urn=Mocks.urn_custom, measure=TextComplexityMeasure.all.name)
        response: Response = self.client.get(TestingConfig.SERVER_URI_TEXT_COMPLEXITY, query_string=args)
        self.assertEqual(response.data.decode("utf-8"), Mocks.text_complexity_json_string)
        args["measure"] = "n_w"
        response = self.client.get(TestingConfig.SERVER_URI_TEXT_COMPLEXITY, query_string=args)
        self.assertEqual(json.loads(response.data.decode("utf-8"))["n_w"], 52)

    @patch('MyCapytain.retrievers.cts5.requests.get', side_effect=mocked_requests_get)
    def test_api_valid_reff_get(self, mock_get: MagicMock):  #
        """ Retrieves possible citations for a given URN. """
        args: dict = dict(urn=Mocks.urn_custom[:-14])
        response: Response = self.client.get(TestingConfig.SERVER_URI_VALID_REFF, query_string=args)
        self.assertEqual(len(json.loads(response.data.decode("utf-8"))), 3)
        McTestCase.clear_folder(Config.REFF_CACHE_DIRECTORY)
        args["urn"] = f"{Mocks.urn_custom[:-13]}4"
        response = self.client.get(TestingConfig.SERVER_URI_VALID_REFF, query_string=args)
        self.assertEqual(response.status_code, 404)
        McTestCase.clear_folder(Config.REFF_CACHE_DIRECTORY)
        args["urn"] = f"{Mocks.urn_custom[:-13]}abc"
        response = self.client.get(TestingConfig.SERVER_URI_VALID_REFF, query_string=args)
        self.assertEqual(response.status_code, 400)
        McTestCase.clear_folder(Config.REFF_CACHE_DIRECTORY)
        TestingConfig.SIMULATE_HTTP_ERROR = True
        self.assertEqual(len(CorpusService.get_standard_corpus_reff(Mocks.urn[:-8])), 0)
        TestingConfig.SIMULATE_HTTP_ERROR = False
        reff: List[str] = CorpusService.get_standard_corpus_reff(Mocks.urn[:-8])
        self.assertEqual(len(reff), 7)

    def test_api_vector_network_get(self):
        """ Builds a network of semantically similar vectors for a given list of words. """
        with patch.object(mcserver.app.api.vectorNetworkAPI, "add_edges", side_effect=Mocks.mock_add_eges):
            with patch.object(mcserver.app.api.vectorNetworkAPI.Word2Vec, "load", return_value=MockW2V()):
                args: dict = dict(search_regex='ueritas', nearest_neighbor_count=150, min_count=6)
                response: Response = self.client.get(TestingConfig.SERVER_URI_VECTOR_NETWORK, query_string=args)
                svg_string: str = json.loads(response.data.decode("utf-8"))
                self.assertGreater(len(svg_string), 6500)

    def test_api_vector_network_post(self):
        """ Returns contexts that are semantically similar to a given query. """
        mock_data: str = "This is a sentence.\nAnd here is yet another one.\n"
        with patch("mcserver.app.api.vectorNetworkAPI.open", mock_open(read_data=mock_data)):
            with patch.object(mcserver.app.api.vectorNetworkAPI.Word2Vec, "load", return_value=MockW2V()):
                data_dict: dict = dict(search_regex='uera', nearest_neighbor_count=10)
                response: Response = self.client.post(TestingConfig.SERVER_URI_VECTOR_NETWORK,
                                                      headers=Mocks.headers_form_data, data=data_dict)
                self.assertEqual(len(json.loads(response.data.decode("utf-8"))), 2)

    @patch('mcserver.app.services.corpusService.requests.get', side_effect=mocked_requests_get)
    @patch('mcserver.app.services.textComplexityService.requests.post', side_effect=mocked_requests_post)
    def test_api_vocabulary_get(self, mock_get: MagicMock, mock_post: MagicMock):
        """ Calculates lexical overlap between a text (specified by URN) and a static vocabulary. """
        args: dict = dict(query_urn=Mocks.urn_custom, show_oov=True, vocabulary=VocabularyCorpus.agldt.name,
                          frequency_upper_bound=500)
        response: Response = self.client.get(TestingConfig.SERVER_URI_VOCABULARY, query_string=args)
        ar: AnnisResponse = AnnisResponse(json_dict=json.loads(response.data.decode("utf-8")))
        self.assertTrue(NodeMC(json_dict=ar.nodes[3]).is_oov)
        args["show_oov"] = False
        args["frequency_upper_bound"] = 6000
        response = self.client.get(TestingConfig.SERVER_URI_VOCABULARY, query_string=args)
        self.assertEqual(json.loads(response.data.decode("utf-8"))[0]["matching_degree"], 90.9090909090909)

    def test_app_init(self):
        """Creates a CSM app in testing mode."""
        CorpusService.init_graphannis_logging()
        log_path: str = os.path.join(os.getcwd(), Config.GRAPHANNIS_LOG_PATH)
        self.assertTrue(os.path.exists(log_path))
        os.remove(log_path)
        with patch.object(sys, 'argv', Mocks.test_args):
            app: Flask = csm.get_app()
            self.assertIsInstance(app, Flask)
            self.assertTrue(app.config["TESTING"])
            UpdateInfo.query.delete()
            app = mcserver.get_app()
            self.assertIsInstance(app, Flask)
            self.assertTrue(app.config["TESTING"])
        self.app_context.push()
        Corpus.query.delete()

    def test_create_app(self):
        """Creates a new Flask application and configures it. Initializes the application and the database."""
        with patch.object(sys, "argv", [None, None, Config.FLASK_MIGRATE]):
            with patch.object(mcserver.app, "init_app_common", return_value=Flask(__name__)):
                cfg: Type[Config] = TestingConfig
                old_uri: str = cfg.SQLALCHEMY_DATABASE_URI
                create_app(cfg)
                self.assertEqual(cfg.SQLALCHEMY_DATABASE_URI, Config.DATABASE_URL_LOCAL)
Loading
Loading full blame...