def test_CompilationHandler_compile__unexpected_exception_handling_upload_path_undeclared(
            self):
        handler = NonAbstractCompilationHandler(self.mock_language,
                                                self.mock_root_upload_path)

        mock_request = {
            "base_url": "http://127.0.0.1:8080",
            "path": "/api/test/compile/method",
            "data": {
                "code": (self.c_source_code_snippet_hello_c, ".././hello.c"),
                "compilation_options": '{}',
            },
        }

        with self.assertLogs(app.logger, level="INFO") as logs_list:
            with app.test_request_context(**mock_request):
                response, response_status = handler.compile(
                    request.files["code"],
                    request.form["compilation_options"],
                    store=True)

        self.assertEqual(response_status, 500)
        self.assertEqual(response.headers.get("Content-Type"),
                         "application/json")
        self.assertEqual(
            response.response[0],
            b"{\"message\":\"Internal Unexpected Error\",\"type\":\"UnexpectedException\"}\n"
        )

        root_upload_path_list = os.listdir(self.mock_root_upload_path)
        self.assertEqual(
            root_upload_path_list, [],
            msg="Path {path} is not empty: {root_upload_path_list}".format(
                path=self.mock_root_upload_path,
                root_upload_path_list=root_upload_path_list))

        test_all_files = file_model.SourceCodeFile.get_all_files()
        self.assertEqual(
            test_all_files, [],
            msg="Table sourcecodefiles in DB is not empty: {files}".format(
                files=test_all_files))

        self.assertEqual(
            len(logs_list.output),
            3,
            msg="There are expected exactly 3 log messages: {logs_list}".
            format(logs_list=logs_list))
        self.assertIn("ERROR:", logs_list.output[0])
        self.assertIn("Unexpected error occured during compile()",
                      logs_list.output[0])
        self.assertIn("WARNING:", logs_list.output[1])
        self.assertIn("Asserting that no orphaned directory is created...",
                      logs_list.output[1])
        self.assertIn("INFO:", logs_list.output[2])
        self.assertIn("No orphaned directory is created", logs_list.output[2])
    def test_authentication_authentication_required__authorization_header_missing(
            self):
        with app.test_request_context():
            response = authentication.Authentication.authentication_required(
                self.dummy_function)(1)

            self.assertEqual(response._status, "401 UNAUTHORIZED")
            self.assertEqual(response.headers.get("Content-Type"),
                             "application/json")
            self.assertEqual(
                response.headers.get("WWW-Authenticate"),
                "Bearer realm=\"Access to user specific resources\"")
            self.assertEqual(
                response.response[0],
                b'{"message":"Authorization Header is missing","type":"AuthorizationViolation"}\n'
            )
    def test_authentication_authentication_required__authorized(self):
        mock_request_authorization_valid_token = {
            "headers": {
                "Authorization": "Bearer " + self.token_valid
            },
        }

        with app.test_request_context(
                **mock_request_authorization_valid_token):
            result = authentication.Authentication.authentication_required(
                self.dummy_function)(1)

            self.assertEqual(
                result,
                "Real parameter is 1 but dummy_function always returns 42")
            self.assertEqual(g.user, {"id": self.decoded_token_valid})
    def test_authentication_authentication_required__incorrect_shema(self):
        mock_request = {"headers": {"Authorization": "string_1 string_2"}}

        with app.test_request_context(**mock_request):
            response = authentication.Authentication.authentication_required(
                self.dummy_function)(1)

            self.assertEqual(response._status, "401 UNAUTHORIZED")
            self.assertEqual(response.headers.get("Content-Type"),
                             "application/json")
            self.assertEqual(
                response.headers.get("WWW-Authenticate"),
                "Bearer realm=\"Access to user specific resources\"")
            self.assertEqual(
                response.response[0],
                '{"message":"Authorization Schema string_1 is incorrect","type":"AuthorizationSchemaViolation"}\n'
                .encode("utf-8"))
    def test_CompilationHandler_compile__invalid_compilation_options(self):
        handler = MockedCompilationHandlerWStdout(self.mock_language,
                                                  self.mock_root_upload_path)
        compilation_options_json_list = [
            'key: rue',
            '{',
            '{key: value}',
            '{"key": "value}',
            '{"key": v"alue}',
            '{"key": True}',
            '{"key": }',
        ]

        for compilation_options_json in compilation_options_json_list:
            mock_request = {
                "base_url": "http://127.0.0.1:8080",
                "path": "/api/test/compile/method",
                "data": {
                    "code": (self.c_source_code_snippet_hello_c, "hello.c"),
                    "compilation_options": compilation_options_json,
                },
            }

            with self.assertLogs(app.logger, level="INFO") as logs_list:
                with app.test_request_context(**mock_request):
                    response, response_status = handler.compile(
                        request.files["code"],
                        request.form["compilation_options"])

            self.assertEqual(response_status, 400)
            self.assertEqual(response.headers.get("Content-Type"),
                             "application/json")
            self.assertEqual(
                response.response[0],
                b"{\"message\":\"Bad JSON Format Error\",\"type\":\"JSONParseError\"}\n"
            )

            self.assertEqual(
                len(logs_list.output),
                1,
                msg="There are expected exactly 1 log messages: {logs_list}".
                format(logs_list=logs_list))
            self.assertIn("INFO:", logs_list.output[0])
            self.assertIn(
                "An error occured while loading incorrect compilation options json",
                logs_list.output[0])
    def test_authentication_authentication_required__invalid_token(self):
        mock_request = {
            "headers": {
                "Authorization": "Bearer " + self.token_invalid
            }
        }

        with app.test_request_context(**mock_request):
            response = authentication.Authentication.authentication_required(
                self.dummy_function)(1)

            self.assertEqual(response._status, "401 UNAUTHORIZED")
            self.assertEqual(response.headers.get("Content-Type"),
                             "application/json")
            self.assertEqual(
                response.headers.get("WWW-Authenticate"),
                "Bearer realm=\"Access to user specific resources\"")
            self.assertEqual(
                response.response[0],
                '{{"message":"{payload}","type":"AuthorizationJWTViolation"}}\n'
                .format(payload=self.decoded_token_invalid).encode("utf-8"))
    def test_authentication_authentication_required__authorization_header_malformed(
            self):
        malformed_authorization_header_list = [
            "",
            self.token_valid,
            "random_string",
            "Bearer",
            "Bearer" + self.token_valid,
            "Bearer  ",
            "Bearer string_1 ",
            "Bearer string_1 string_2",
            "Bearer " + self.token_valid + " ",
            "Bearer " + self.token_valid + " " + self.token_valid,
            "Bearer Bearer Bearer",
        ]

        for malformed_authorization_header in malformed_authorization_header_list:
            mock_request = {
                "headers": {
                    "Authorization": malformed_authorization_header
                }
            }

            with app.test_request_context(**mock_request):
                response = authentication.Authentication.authentication_required(
                    self.dummy_function)(1)

                self.assertEqual(response._status, "401 UNAUTHORIZED")
                self.assertEqual(response.headers.get("Content-Type"),
                                 "application/json")
                self.assertEqual(
                    response.headers.get("WWW-Authenticate"),
                    "Bearer realm=\"Access to user specific resources\"")
                self.assertEqual(
                    response.response[0],
                    '{{"message":"Authorization Header {header} is incorrect","type":"AuthorizationViolation"}}\n'
                    .format(
                        header=malformed_authorization_header).encode("utf-8"))
    def test_debug_request(self):
        mock_request = {
            "base_url": "https://127.0.0.1:8080",
            "path": "/api/test/debug_message",
            "method": "POST",
            "headers": {
                "Origin": "http://localhost:3535"
            },
            "data": {
                "code": (io.BytesIO(b'this is some dummy test content'), 'test.txt'),
                "compilation_options": '{"optimization_level": "O2", "iso_standard": "gnu11", "suppress_warnings": true, "output_filename": "-----hello"}'
            },
        }
        with app.test_request_context(**mock_request):
            debug_request_msg = common.debug_request(request)

        self.assertIn("<Request 'https://127.0.0.1:8080/api/test/debug_message' [POST]>", debug_request_msg)
        self.assertIn("Host: 127.0.0.1:8080", debug_request_msg)
        self.assertIn("Content-Type: multipart/form-data; boundary=", debug_request_msg)
        self.assertIn("Origin: http://localhost:3535", debug_request_msg)
        self.assertIn("ImmutableMultiDict([('code', <FileStorage: 'test.txt' ('text/plain')>)])", debug_request_msg)
        self.assertIn("ImmutableMultiDict([('compilation_options', '{\"optimization_level\": \"O2\", \"iso_standard\": \"gnu11\", \"suppress_warnings\": true, \"output_filename\": \"-----hello\"}')])", debug_request_msg)
        self.assertIn("None", debug_request_msg)
    def test_CompilationHandler_compile__subpath_exists(self):
        handler = MockedCompilationHandlerWStdout(self.mock_language,
                                                  self.mock_root_upload_path)

        existing_path = handler._format_full_file_path("unknown",
                                                       "mock_subpath")
        os.makedirs(existing_path)

        mock_request = {
            "base_url": "http://127.0.0.1:8080",
            "path": "/api/test/compile/method",
            "data": {
                "code": (self.c_source_code_snippet_hello_c, "hello.c"),
                "compilation_options": '{}',
            },
        }

        with self.assertLogs(app.logger, level="INFO") as logs_list:
            with app.test_request_context(**mock_request):
                response, response_status = handler.compile(
                    request.files["code"], request.form["compilation_options"])

        self.assertEqual(response_status, 400)
        self.assertEqual(response.headers.get("Content-Type"),
                         "application/json")
        self.assertEqual(
            response.response[0],
            b"{\"message\":\"The uploaded file already exists\",\"type\":\"FileExistsError\"}\n"
        )

        self.assertEqual(
            len(logs_list.output),
            1,
            msg="There are expected exactly 1 log messages: {logs_list}".
            format(logs_list=logs_list))
        self.assertIn("ERROR:", logs_list.output[0])
        self.assertIn("Path exists: " + existing_path, logs_list.output[0])
    def test_authentication_authentication_required__expired_token(self):
        mock_request = {
            "headers": {
                "Authorization": "Bearer " + self.token_expired
            }
        }

        with app.test_request_context(**mock_request):
            # Sleep is needed to make sure that the token is expired.
            # The token is instantly expired thus 1 second is enough.
            time.sleep(1)
            response = authentication.Authentication.authentication_required(
                self.dummy_function)(1)

            self.assertEqual(response._status, "401 UNAUTHORIZED")
            self.assertEqual(response.headers.get("Content-Type"),
                             "application/json")
            self.assertEqual(
                response.headers.get("WWW-Authenticate"),
                "Bearer realm=\"Access to user specific resources\"")
            self.assertEqual(
                response.response[0],
                '{{"message":"{payload}","type":"AuthorizationJWTViolation"}}\n'
                .format(payload=self.decoded_token_expired).encode("utf-8"))
    def test_CompilationHandler_compile__unexpected_exception_handling_upload_path_created(
            self):
        handler = NonAbstractCompilationHandler(self.mock_language,
                                                self.mock_root_upload_path)

        mock_request = {
            "base_url": "http://127.0.0.1:8080",
            "path": "/api/test/compile/method",
            "data": {
                "code": (self.c_source_code_snippet_hello_c, ".././hello.c"),
                "compilation_options": '{}',
            },
        }

        with self.assertLogs(app.logger, level="INFO") as logs_list:
            with app.test_request_context(**mock_request):
                response, response_status = handler.compile(
                    request.files["code"], request.form["compilation_options"])

        self.assertEqual(response_status, 500)
        self.assertEqual(response.headers.get("Content-Type"),
                         "application/json")
        self.assertEqual(
            response.response[0],
            b"{\"message\":\"Internal Unexpected Error\",\"type\":\"UnexpectedException\"}\n"
        )

        root_upload_path_list = os.listdir(self.mock_root_upload_path)
        self.assertEqual(
            root_upload_path_list, ["unknown"],
            msg=
            "Path {path} does not contain only the unknown folder: {root_upload_path_list}"
            .format(path=self.mock_root_upload_path,
                    root_upload_path_list=root_upload_path_list))

        unknown_directory = self.mock_root_upload_path + "/unknown"
        unknown_directory_list = os.listdir(unknown_directory)
        self.assertEqual(
            unknown_directory_list, ["e17"],
            msg=
            "Path {path} does not contain only the e17 file directory: {entry_list}"
            .format(path=unknown_directory, entry_list=unknown_directory_list))

        unknown_directory_level_1 = unknown_directory + "/e17"
        unknown_directory_level_1_list = os.listdir(unknown_directory_level_1)
        self.assertEqual(unknown_directory_level_1_list, [],
                         msg="Path {path} is not empty: {entry_list}".format(
                             path=unknown_directory_level_1,
                             entry_list=unknown_directory_level_1_list))

        test_all_files = file_model.SourceCodeFile.get_all_files()
        self.assertEqual(
            test_all_files, [],
            msg="Table sourcecodefiles in DB is not empty: {files}".format(
                files=test_all_files))

        self.assertEqual(
            len(logs_list.output),
            5,
            msg="There are expected exactly 5 log messages: {logs_list}".
            format(logs_list=logs_list))
        self.assertIn("INFO:", logs_list.output[0])
        self.assertIn("Path generated: ", logs_list.output[0])
        generated_path = logs_list.output[0].split(" ")[2]
        self.assertIn("ERROR:", logs_list.output[1])
        self.assertIn("Unexpected error occured during compile()",
                      logs_list.output[1])
        self.assertIn("WARNING:", logs_list.output[2])
        self.assertIn("Asserting that no orphaned directory is created...",
                      logs_list.output[2])
        self.assertIn("WARNING:", logs_list.output[3])
        self.assertIn(
            "Detected orphaned directory: {path}".format(path=generated_path),
            logs_list.output[3])
        self.assertIn("INFO:", logs_list.output[4])
        self.assertIn(
            "Orphaned directory deleted: {path}".format(path=generated_path),
            logs_list.output[4])
    def test_CompilationHandler_compile__store_erroneous_command(self):
        handler = MockedCompilationHandlerWStderr(self.mock_language,
                                                  self.mock_root_upload_path)

        mock_request = {
            "base_url": "http://127.0.0.1:8080",
            "path": "/api/test/compile/method",
            "data": {
                "code":
                (self.c_source_code_snippet_hello_c, ".././-h../ello.c"),
                "compilation_options": '{}',
            },
        }

        with self.assertLogs(app.logger, level="INFO") as logs_list:
            with app.test_request_context(**mock_request):
                g.user = {"id": self.user_info["id"]}
                response = handler.compile(request.files["code"],
                                           request.form["compilation_options"],
                                           store=True)

        self.assertEqual(response._status, "400 BAD REQUEST")
        self.assertEqual(response.headers.get("Content-Type"),
                         "application/zip")
        self.assertEqual(response.headers.get("Content-Disposition"),
                         "attachment; filename=results.zip")

        root_upload_path_list = os.listdir(self.mock_root_upload_path)
        self.assertEqual(
            root_upload_path_list, [str(self.user_info["id"])],
            msg=
            "Path {path} does not contain only the {user_id} folder: {root_upload_path_list}"
            .format(path=self.mock_root_upload_path,
                    user_id=self.user_info["id"],
                    root_upload_path_list=root_upload_path_list))

        user_directory = self.mock_root_upload_path + "/" + str(
            self.user_info["id"])
        user_directory_list = os.listdir(user_directory)
        self.assertEqual(
            user_directory_list, ["ath"],
            msg=
            "Path {path} does not contain only the ath file directory: {entry_list}"
            .format(path=user_directory, entry_list=user_directory_list))

        user_directory_level_1 = user_directory + "/ath"
        user_directory_level_1_list = os.listdir(user_directory_level_1)
        self.assertEqual(
            user_directory_level_1_list, ["mock_subpath"],
            msg=
            "Path {path} does not contain only the mock_subpath file directory: {entry_list}"
            .format(path=user_directory_level_1,
                    entry_list=user_directory_level_1_list))

        uploaded_file_directory = user_directory_level_1 + "/mock_subpath"
        uploaded_file_directory_list = sorted(
            os.listdir(uploaded_file_directory))
        self.assertEqual(
            uploaded_file_directory_list,
            ["-h.._ello.c", "results.zip", "stderr.txt"],
            msg="Path {path} does not contain exactly 3 files: {entry_list}".
            format(path=uploaded_file_directory,
                   entry_list=uploaded_file_directory_list))

        self.assertTrue(
            filecmp.cmp(uploaded_file_directory + "/-h.._ello.c",
                        self.c_source_code_snippet_hello_c))

        with open(uploaded_file_directory + "/stderr.txt", "r") as stderr_file:
            self.assertEqual(
                stderr_file.read(),
                "ls: cannot access 'non-existing-path': No such file or directory\n\n"
            )

        with ZipFile(file=uploaded_file_directory + "/results.zip",
                     mode="r") as file_system_zip:
            self.assertIsNone(file_system_zip.testzip())
            self.assertEqual(file_system_zip.namelist(), ["stderr.txt"])
            file_system_zip_infolist = file_system_zip.infolist()
            self.assertEqual(
                os.stat(uploaded_file_directory + "/stderr.txt").st_size,
                file_system_zip_infolist[0].file_size)

            with ZipFile(response.response.file, 'r') as response_zip:
                self.assertIsNone(response_zip.testzip())
                self.assertEqual(response_zip.namelist(), ["stderr.txt"])
                response_zip_infolist = response_zip.infolist()

                self.assertEqual(
                    file_system_zip_infolist[0].file_size,
                    response_zip_infolist[0].file_size,
                    msg=
                    "STDERR files do not have the same size inside the two zip files"
                )

        test_all_files = file_model.SourceCodeFile.get_all_files()
        self.assertEqual(
            len(test_all_files),
            1,
            msg=
            "Table sourcecodefiles in DB does not contain exactly one file: {files}"
            .format(files=test_all_files))

        test_file = test_all_files[0]
        self.assertEqual(test_file.user_id, self.user_info["id"])
        self.assertEqual(test_file.name, "-h.._ello.c")
        self.assertEqual(test_file.directory, "mock_subpath")
        self.assertEqual(test_file.compilation_options,
                         ["mock_option_1", "mock_option_2"])
        self.assertEqual(test_file.language, self.mock_language)
        self.assertEqual(test_file.status, "Erroneous")

        self.assertEqual(
            len(logs_list.output),
            3,
            msg="There are expected exactly 3 log messages: {logs_list}".
            format(logs_list=logs_list))
        self.assertIn("INFO:", logs_list.output[0])
        self.assertIn(
            "Path generated: {path}".format(path=uploaded_file_directory),
            logs_list.output[0])
        self.assertIn("INFO:", logs_list.output[1])
        self.assertIn(
            "Compilation return code in path {path}: 2".format(
                path=uploaded_file_directory), logs_list.output[1])
        self.assertIn("INFO:", logs_list.output[2])
        self.assertIn(
            "File in path {path} is saved in DB".format(
                path=uploaded_file_directory), logs_list.output[2])
    def test_CompilationHandler_compile__with_stdout_and_stderr(self):
        handler = MockedCompilationHandlerWStdoutWStderr(
            self.mock_language, self.mock_root_upload_path)

        mock_request = {
            "base_url": "http://127.0.0.1:8080",
            "path": "/api/test/compile/method",
            "data": {
                "code": (self.c_source_code_snippet_hello_c, "hello.c"),
                "compilation_options": '{}',
            },
        }

        with self.assertLogs(app.logger, level="INFO") as logs_list:
            with app.test_request_context(**mock_request):
                response = handler.compile(request.files["code"],
                                           request.form["compilation_options"])

        self.assertEqual(response._status, "400 BAD REQUEST")
        self.assertEqual(response.headers.get("Content-Type"),
                         "application/zip")
        self.assertEqual(response.headers.get("Content-Disposition"),
                         "attachment; filename=results.zip")

        root_upload_path_list = os.listdir(self.mock_root_upload_path)
        self.assertEqual(
            root_upload_path_list, ["unknown"],
            msg=
            "Path {path} does not contain only the unknown folder: {root_upload_path_list}"
            .format(path=self.mock_root_upload_path,
                    root_upload_path_list=root_upload_path_list))

        unknown_directory = self.mock_root_upload_path + "/unknown"
        unknown_directory_list = os.listdir(unknown_directory)
        self.assertEqual(
            unknown_directory_list, ["ath"],
            msg=
            "Path {path} does not contain only the ath file directory: {entry_list}"
            .format(path=unknown_directory, entry_list=unknown_directory_list))

        unknown_directory_level_1 = unknown_directory + "/ath"
        unknown_directory_level_1_list = os.listdir(unknown_directory_level_1)
        self.assertEqual(
            unknown_directory_level_1_list, ["mock_subpath"],
            msg=
            "Path {path} does not contain only the mock_subpath file directory: {entry_list}"
            .format(path=unknown_directory_level_1,
                    entry_list=unknown_directory_level_1_list))

        uploaded_file_directory = unknown_directory_level_1 + "/mock_subpath"
        uploaded_file_directory_list = sorted(
            os.listdir(uploaded_file_directory))
        self.assertEqual(
            uploaded_file_directory_list,
            ["hello.c", "results.zip", "stderr.txt", "stdout.txt"],
            msg="Path {path} does not contain exactly 4 files: {entry_list}".
            format(path=uploaded_file_directory,
                   entry_list=uploaded_file_directory_list))

        self.assertTrue(
            filecmp.cmp(uploaded_file_directory + "/hello.c",
                        self.c_source_code_snippet_hello_c))

        with open(uploaded_file_directory + "/stdout.txt", "r") as stdout_file:
            self.assertEqual(stdout_file.read(),
                             CURRENT_TEST_FILE_PATH + "\n\n")

        with open(uploaded_file_directory + "/stderr.txt", "r") as stderr_file:
            self.assertEqual(
                stderr_file.read(),
                "ls: cannot access 'non-existing-path': No such file or directory\n\n"
            )

        with ZipFile(file=uploaded_file_directory + "/results.zip",
                     mode="r") as file_system_zip:
            self.assertIsNone(file_system_zip.testzip())
            self.assertEqual(file_system_zip.namelist(),
                             ["stdout.txt", "stderr.txt"])
            file_system_zip_infolist = file_system_zip.infolist()
            self.assertEqual(
                os.stat(uploaded_file_directory + "/stdout.txt").st_size,
                file_system_zip_infolist[0].file_size)
            self.assertEqual(
                os.stat(uploaded_file_directory + "/stderr.txt").st_size,
                file_system_zip_infolist[1].file_size)

            with ZipFile(response.response.file, 'r') as response_zip:
                self.assertIsNone(response_zip.testzip())
                self.assertEqual(response_zip.namelist(),
                                 ["stdout.txt", "stderr.txt"])
                response_zip_infolist = response_zip.infolist()

                self.assertEqual(
                    file_system_zip_infolist[0].file_size,
                    response_zip_infolist[0].file_size,
                    msg=
                    "STDOUT files do not have the same size inside the two zip files"
                )
                self.assertEqual(
                    file_system_zip_infolist[1].file_size,
                    response_zip_infolist[1].file_size,
                    msg=
                    "STDERR files do not have the same size inside the two zip files"
                )

        test_all_files = file_model.SourceCodeFile.get_all_files()
        self.assertEqual(
            test_all_files, [],
            msg="Table sourcecodefiles in DB is not empty: {files}".format(
                files=test_all_files))

        self.assertEqual(
            len(logs_list.output),
            2,
            msg="There are expected exactly 2 log messages: {logs_list}".
            format(logs_list=logs_list))
        self.assertIn("INFO:", logs_list.output[0])
        self.assertIn(
            "Path generated: {path}".format(path=uploaded_file_directory),
            logs_list.output[0])
        self.assertIn("INFO:", logs_list.output[1])
        self.assertIn(
            "Compilation return code in path {path}: 2".format(
                path=uploaded_file_directory), logs_list.output[1])