From 19c43e270587213bc4804b7ef73d3fb64e4e9fdd Mon Sep 17 00:00:00 2001 From: Nadav Mordechai Date: Wed, 3 Sep 2025 11:17:31 +0300 Subject: [PATCH 1/4] Tests moved to pytest --- backend/Tests/API_Test.py | 98 ++++++++++++++++++++++++++++----- backend/Tests/Discovery_Test.py | 20 ++++--- 2 files changed, 95 insertions(+), 23 deletions(-) diff --git a/backend/Tests/API_Test.py b/backend/Tests/API_Test.py index b10abf9..677c603 100644 --- a/backend/Tests/API_Test.py +++ b/backend/Tests/API_Test.py @@ -1,5 +1,6 @@ import socket import time +import json IP = "127.0.0.1" PORT = 3391 @@ -8,6 +9,8 @@ BUFFER_SIZE = 1024 DISCOVERY_MESSAGE = "DISCOVER_LOCAL_HOMESERVER" +# approve testcase if API worked but context not found +DEFAULT_ALLOW_NOT_FOUND = True class bcolors: HEADER = '\033[95m' @@ -22,36 +25,99 @@ class bcolors: totalRunTime = 0.0 +def test_StartProcess(): + ans = ConnectToAPI('{"Path":"/api/process/start", "Type":"UPDATE", "Data":"Minecraft Server"}') + assert isAnswerSuccess(ans) + + +def test_GetProcesses(): + ans = ConnectToAPI('{"Path":"/api/processes", "Type":"GET", "Data":"Test"}') + assert isAnswerSuccess(ans) + + +def test_GetProcessStatus(): + ans = ConnectToAPI('{"Path":"/api/processes/status", "Type":"GET", "Data":"Test"}') + assert isAnswerSuccess(ans) + + +def test_LastLogs(): + ans = ConnectToAPI('{"Path":"/api/process/lastlogs", "Type":"GET", "Data":"Minecraft Server"}') + assert isAnswerSuccess(ans) + + +def test_LastErrors(): + ans = ConnectToAPI('{"Path":"/api/process/lasterrors", "Type":"GET", "Data":"Minecraft Server"}') + assert isAnswerSuccess(ans) + +def test_InvalidProcesses(): + ans = ConnectToAPI('{"Path":"/api/processes", "Type":"POST", "Data":"Invalid Data"}') + assert not isAnswerSuccess(ans, False) + +def test_InvalidPath(): + ans = ConnectToAPI('{"Path":"/api/fsdfasdf", "Type":"GET", "Data":"Invalid Data"}') + assert not isAnswerSuccess(ans, False) + +def test_InvalidType(): + ans = ConnectToAPI('{"Path":"/api/processes", "Type":"migga", "Data":"Invalid Data"}') + assert not isAnswerSuccess(ans, False) + +def test_StopProcess(): + ans = ConnectToAPI('{"Path":"/api/process/stop", "Type":"UPDATE", "Data":"Test"}') + assert isAnswerSuccess(ans) + +def test_ProcessInput(): + ans = ConnectToAPI('{"Path":"api/process/input", "Type":"POST", "Data":"{\\"ProcessTag\\": \\"Minecraft Server\\", \\"Input\\": \\"say hello API\\"}"}') + assert isAnswerSuccess(ans) + +def test_ProcessStop(): + ans = ConnectToAPI('{"Path":"/api/process/stop", "Type":"UPDATE", "Data":"Minecraft Server"}') + assert isAnswerSuccess(ans) + +def isAnswerSuccess(ans: json, Allow_not_found: bool = DEFAULT_ALLOW_NOT_FOUND) -> bool: + ''' + Getting the API answer and returning if the answer is status code is success +
ans: Server Answer +
Allow_not_found: Allowing the answer to be 404 if the API path found but context wasn't + ''' + # if the answer isn't unknown so the API worked but the data was not found + if (Allow_not_found and ans["StatusCode"] == 404): + if "unknown" not in ans["Data"]: + return True + + return ans["StatusCode"] < 300 + + +''' def main(): global totalRunTime print("Searching for server") print("=====================Starting API Tests=======================") - TestAPI('{"Path":"/api/process/start", "Type":"UPDATE", "Data":"Minecraft Server"}') - TestAPI('{"Path":"/api/processes", "Type":"GET", "Data":"Test"}') - TestAPI('{"Path":"/api/processes/status", "Type":"GET", "Data":"Test"}') - TestAPI('{"Path":"/api/process/lastlogs", "Type":"GET", "Data":"Minecraft Server"}') - TestAPI('{"Path":"/api/process/lasterrors", "Type":"GET", "Data":"Minecraft Server"}') - TestAPI('{"Path":"/api/processes", "Type":"POST", "Data":"Invalid Data"}') - TestAPI('{"Path":"/api/fsdfasdf", "Type":"GET", "Data":"Invalid Data"}') - TestAPI('{"Path":"/api/processes", "Type":"migga", "Data":"Invalid Data"}') - TestAPI('{"Path":"/api/process/stop", "Type":"UPDATE", "Data":"Test"}') + ConnectToAPI('{"Path":"/api/process/start", "Type":"UPDATE", "Data":"Minecraft Server"}') + ConnectToAPI('{"Path":"/api/processes", "Type":"GET", "Data":"Test"}') + ConnectToAPI('{"Path":"/api/processes/status", "Type":"GET", "Data":"Test"}') + ConnectToAPI('{"Path":"/api/process/lastlogs", "Type":"GET", "Data":"Minecraft Server"}') + ConnectToAPI('{"Path":"/api/process/lasterrors", "Type":"GET", "Data":"Minecraft Server"}') + ConnectToAPI('{"Path":"/api/fsdfasdf", "Type":"GET", "Data":"Invalid Data"}') + ConnectToAPI('{"Path":"/api/processes", "Type":"migga", "Data":"Invalid Data"}') + ConnectToAPI('{"Path":"/api/process/stop", "Type":"UPDATE", "Data":"Test"}') time.sleep(5) - TestAPI('{"Path":"api/process/input", "Type":"POST", "Data":"{\\"ProcessTag\\": \\"Minecraft Server\\", \\"Input\\": \\"say hello API\\"}"}') + ConnectToAPI('{"Path":"api/process/input", "Type":"POST", "Data":"{\\"ProcessTag\\": \\"Minecraft Server\\", \\"Input\\": \\"say hello API\\"}"}') time.sleep(10) - TestAPI('{"Path":"/api/process/stop", "Type":"UPDATE", "Data":"Minecraft Server"}') + ConnectToAPI('{"Path":"/api/process/stop", "Type":"UPDATE", "Data":"Minecraft Server"}') print(f"Execution time: {totalRunTime:.4f} seconds") +''' - -def TestAPI(message): +def ConnectToAPI(message): global totalRunTime print ("Testing API with message:", message) try: print("Trying to connect: " + str((IP, PORT)) ) with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.settimeout(2) s.connect((IP, PORT)) s.sendall(message.encode()) @@ -63,10 +129,12 @@ def TestAPI(message): print(f"{bcolors.OKCYAN}{bcolors.BOLD} Answer time: {(elapsed_time * 1000):.0f} ms{bcolors.ENDC}") except Exception as err: - print(f"{bcolors.FAIL} Failed to message API: {err} {bcolors.ENDC}") + raise Exception (f"Failed to message API: {err}") print("\n\n") + return json.loads(data.decode()) if __name__ == "__main__": - main() \ No newline at end of file + print("Pls use pytest") + exit(-1) \ No newline at end of file diff --git a/backend/Tests/Discovery_Test.py b/backend/Tests/Discovery_Test.py index 652befd..46c099e 100644 --- a/backend/Tests/Discovery_Test.py +++ b/backend/Tests/Discovery_Test.py @@ -1,5 +1,6 @@ import socket import time +import sys IP = "127.0.0.1" PORT = 3391 @@ -20,14 +21,16 @@ class bcolors: UNDERLINE = '\033[4m' -def main(): - if discover_server(): - print(f"{bcolors.OKGREEN} Server found {IP} {bcolors.ENDC}") +def eprint(*args, **kwargs): + ''' + printing error + ''' + print(*args, file=sys.stderr, **kwargs) - else: - print(f"{bcolors.FAIL} Failed to find server! {bcolors.ENDC}") - exit(1) +def test_Discovery(): + '''Testing if we able to discover the server''' + assert discover_server() def discover_server(timeout=5): global IP @@ -63,11 +66,12 @@ def discover_server(timeout=5): Succeeded = True except socket.timeout: - print("No server response received within timeout.") + raise TimeoutError("No server response received within time window.") finally: client_socket.close() return Succeeded if __name__ == "__main__": - main() \ No newline at end of file + print("Pls run pytest") + exit(-1) \ No newline at end of file From 66291a22b2859148f56f676c91f51f1fbf5906e4 Mon Sep 17 00:00:00 2001 From: Nadav Mordechai Date: Wed, 3 Sep 2025 12:00:08 +0300 Subject: [PATCH 2/4] Tests added to github workflow --- .github/workflows/dotnet.yml | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 2f37b95..7064c9a 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -69,16 +69,26 @@ jobs: uses: actions/setup-python@v5 with: python-version: '3.x' + + # Install Python dependencies + - name: Install dependencies + run: | + python -m pip install --upgrade pip + + - name: test with pytest + run: | + pip install pytest pytest-cov + pytest tests.py --doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html - # Run Python Discovery Test - - name: Run Discovery tests - working-directory: ./backend/Tests - run: python3 Discovery_Test.py + # # Run Python Discovery Test + # - name: Run Discovery tests + # working-directory: ./backend/Tests + # run: python3 Discovery_Test.py - # Run Python test script - - name: Run API tests - working-directory: ./backend/Tests - run: python3 API_Test.py + # # Run Python test script + # - name: Run API tests + # working-directory: ./backend/Tests + # run: python3 API_Test.py # Stop backend process after tests - name: Stop backend From 7c98405d4f9a3ed2c34545f7ff061f7063079415 Mon Sep 17 00:00:00 2001 From: Nadav Mordechai Date: Wed, 3 Sep 2025 12:03:50 +0300 Subject: [PATCH 3/4] workflow fix pytesting in the wrong directory --- .github/workflows/dotnet.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 7064c9a..c53c730 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -76,6 +76,7 @@ jobs: python -m pip install --upgrade pip - name: test with pytest + working-directory: ./backend/Tests run: | pip install pytest pytest-cov pytest tests.py --doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html From 0623b1221ae23e2ad3a9f7bf33a0bda6ed3bb4f5 Mon Sep 17 00:00:00 2001 From: Nadav Mordechai Date: Wed, 3 Sep 2025 12:11:03 +0300 Subject: [PATCH 4/4] Workflow fix Workflow pytest testing specific file instead of folder pytest cache added to gitignore --- .github/workflows/dotnet.yml | 2 +- .gitignore | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index c53c730..b11dcec 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -79,7 +79,7 @@ jobs: working-directory: ./backend/Tests run: | pip install pytest pytest-cov - pytest tests.py --doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html + pytest --doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html # # Run Python Discovery Test # - name: Run Discovery tests diff --git a/.gitignore b/.gitignore index 9b135ed..d872665 100644 --- a/.gitignore +++ b/.gitignore @@ -415,4 +415,7 @@ FodyWeavers.xsd *.msi *.msix *.msm -*.msp \ No newline at end of file +*.msp + +# pytest cache files +junit/ \ No newline at end of file