diff --git a/.github/workflows/test_civet.yml b/.github/workflows/test_civet.yml deleted file mode 100644 index b941328c..00000000 --- a/.github/workflows/test_civet.yml +++ /dev/null @@ -1,68 +0,0 @@ -name: CivetServer -# This workflow is triggered on pushes to the repository. -on: - push: - paths-ignore: - - 'docs/**' - - '.github/workflows/**' - - '!.github/workflows/test_civet.yml' - pull_request: - -defaults: - run: - shell: bash - -jobs: - # all: - # matrix: - # cfg: - # - { os: ubuntu, tag: 20.04, arch: debian} - # - { os: centos, tag: latest, arch: rhel} - # include: - # - cfg: {} - # - cfg: { os: ubuntu } - # deps - trickops-tests-ubuntu: - name: Unit Tests Ubuntu:20.04 - runs-on: ubuntu-20.04 - container: ubuntu:20.04 - steps: - - uses: actions/checkout@master - - name: install dependencies - run: | - export DEBIAN_FRONTEND=noninteractive && apt-get update && apt-get install -y git python3 python3-venv perl perl-modules-5.30 qtbase5-dev wget unzip g++ make flex bison - - name: create virtual environment - run: | - cd share/trick/pymods/trick/ - python3 -m venv .venv && source .venv/bin/activate && pip3 install -r requirements.txt - - name: run Python tests - run: | - cd share/trick/pymods/trick/ - source .venv/bin/activate - ./run_tests.py - - trickops-tests-centos8: - name: Unit Tests CentOS:latest - runs-on: ubuntu-20.04 - container: centos:latest - steps: - - uses: actions/checkout@master - - name: install dependencies - run: | - dnf install -y git python3-devel which perl perl-Digest-MD5 qt5-qtbase-devel bison clang flex make gcc gcc-c++ wget - - name: create virtual environment - run: | - cd share/trick/pymods/trick/ - python3 -m venv .venv && source .venv/bin/activate && pip3 install -r requirements.txt - - name: run Python tests - run: | - cd share/trick/pymods/trick/ - source .venv/bin/activate - ./run_tests.py - -# TODO: ExampleWorkflow.py is not included here because it needs a built Trick -# to function correctly and I don't want to duplicate the Trick build testing -# here to provide testing of what is essentially an example provided for -# documentation purposes. If we could leverage artifacts from a previous -# stage and/or stable containers where Trick is already pre-built, we should -# consider adding ExampleWorfklow.py to testing in this file. -Jordan 4/2021 diff --git a/.github/workflows/test_civet_linux.yml b/.github/workflows/test_civet_linux.yml new file mode 100644 index 00000000..9e2eb65a --- /dev/null +++ b/.github/workflows/test_civet_linux.yml @@ -0,0 +1,190 @@ +name: Civet_Linux + +on: + push: + paths-ignore: + - 'docs/**' + - '.github/workflows/**' + - '!.github/workflows/test_civet_linux.yml' + pull_request: + +jobs: + build: + strategy: + fail-fast: false + matrix: + cfg: +#-------- Operating Systems ---------------- + - { os: ubuntu, tag: 18.04, arch: debian } # EOL April 2023 + - { os: ubuntu, tag: 20.04, arch: debian } # EOL April 2025 + - { os: debian, tag: 10, arch: debian } # EOL 2024 + - { os: centos, tag: 7, arch: rhel } # EOL June 2024 + - { os: centos, tag: latest, arch: rhel } # 8 as of April 2020 + # - { os: fedora, tag: latest, arch: rhel } # 31 as of April 2020 + # - { os: fedora, tag: 33, arch: rhel } # feeling confident? + # - { os: fedora, tag: rawhide, arch: rhel } # for thrill-seekers only + +#-------- Defaults -------------------------- + include: + - cfg: {} + deps: >- + bison + clang + flex + git + llvm + make + maven + cmake + zip + install_gtest: echo gtest already installed + conf_pkg: echo package manager already configured + install_cmd: install -y +#-------- Debian-based Dependencies ---------------- + - cfg: { arch: debian } + pkg_mgr: apt-get + conf_pkg: apt-get update + arch_deps: >- + swig + curl + g++ + libx11-dev + libxml2-dev + libxt-dev + libmotif-common + libmotif-dev + python2.7-dev + zlib1g-dev + llvm-dev + libclang-dev + libudunits2-dev + libgtest-dev + python3 + python3-venv + python3-dev + install_gtest: cd /usr/src/gtest && cmake . && make && cp libgtest* /usr/lib/ +#-------- RHEL Dependencies ---------------- + - cfg: { arch: rhel } + arch_deps: >- + clang-devel + gcc + gcc-c++ + java-11-openjdk-devel + libxml2-devel + llvm-devel + llvm-static + ncurses-devel + openmotif + openmotif-devel + perl + perl-Digest-MD5 + udunits2 + udunits2-devel + which + zlib-devel + gtest-devel + python3-devel +#-------- Ubuntu Only Dependencies ---------------- + - cfg: { os: ubuntu } + os_deps: >- + openjdk-11-jdk +#-------- Debian OS Only Dependencies ---------------- + - cfg: { os: debian } + os_deps: >- + openjdk-11-jdk +#-------- CentOS Only Dependencies ---------------- + - cfg: { os: centos } + pkg_mgr: yum + conf_pkg: yum -y install epel-release && yum -y update + os_deps: >- + libX11-devel + libXt-devel +#-------- Fedora Only Dependencies ---------------- +# - cfg: { os: fedora } +# pkg_mgr: dnf +# os_deps: >- +# swig +# perl-Text-Balanced +# python-devel +# diffutils +#-------- Version Specific Dependencies ---------------- + - cfg: { os: ubuntu, tag: 20.04 } + conf_pkg: DEBIAN_FRONTEND=noninteractive && apt-get update && apt-get install -y tzdata + install_gtest: cd /usr/src/gtest && cmake . && make && cp lib/libgtest* /usr/lib/ + tag_deps: >- + python3.8-dev + - cfg: { os: centos, tag: 7 } + tag_deps: >- + swig3 + python-devel + - cfg: { os: centos, tag: latest } + pkg_mgr: dnf + conf_pkg: > + dnf -y install epel-release && + dnf -y update && + dnf install -y 'dnf-command(config-manager)' && + dnf config-manager --enable powertools + tag_deps: >- + swig + python3-devel diffutils +#-------- Job definition ---------------- + runs-on: ubuntu-18.04 + container: docker://${{matrix.cfg.os}}:${{matrix.cfg.tag}} + steps: + # - name: Set up Python ${{ matrix.python-version }} + # uses: actions/setup-python@v2 + # with: + # python-version: ${{ matrix.python-version }} + - name: Info + run: | + pwd + echo $TEST + echo workspace is $TRICK_HOME + echo files in workspace: + ls -la $TRICK_HOME + env: + TEST: Hello World! + TRICK_HOME: ${{ github.workspace }} + - name: Update Package Manager + run: ${{matrix.conf_pkg}} + - name: Install Dependencies + run: | + ${{matrix.pkg_mgr}} ${{matrix.install_cmd}} ${{matrix.deps}} ${{matrix.arch_deps}} ${{matrix.os_deps}} ${{matrix.tag_deps}} + - name: Install GTest + run: ${{matrix.install_gtest}} + - name: Checkout repository + uses: actions/checkout@master + - name: Info after checkout + run: | + pwd + echo $TEST + echo workspace is $TRICK_HOME + echo files in workspace: + ls -la $TRICK_HOME + env: + TEST: Hello World! + TRICK_HOME: ${{ github.workspace }} + - name: Create testing environment + run: | + cd share/trick/pymods/trick/ + python3 -m venv .venv && . .venv/bin/activate && pip3 install -r requirements.txt + - name: Build trick + run: | + export MAKEFLAGS=-j`nproc` + ./configure + make + # - name: Build Cannon Sim + # run: | + # cd trick_sims/Cannon/SIM_cannon_numeric + # ls -la + # $TRICK_HOME/bin/trick-CP + # ls -la + # env: + # TRICK_HOME: "${{ github.workspace }}" + - name: Run Civet Tests + run: | + cd share/trick/pymods/trick/ + . .venv/bin/activate + ./run_tests.py + env: + TRICK_HOME: "${{ github.workspace }}" diff --git a/.github/workflows/test_civet_macos.yml b/.github/workflows/test_civet_macos.yml new file mode 100644 index 00000000..cb525ff3 --- /dev/null +++ b/.github/workflows/test_civet_macos.yml @@ -0,0 +1,55 @@ +name: Civet_macOS + +on: + push: + paths-ignore: + - 'docs/**' + - '.github/workflows/**' + - '!.github/workflows/test_civet_macos.yml' + pull_request: + +jobs: + macOS: + runs-on: macos-latest + steps: + - name: Checkout repository + uses: actions/checkout@master + - name: Install python + run: | + brew install python + python3 -m ensurepip --upgrade + pip3 install virtualenv + python3 --version + pip3 --version + - name: Install gtest + run: | + wget https://github.com/google/googletest/archive/release-1.8.0.tar.gz + tar xzvf release-1.8.0.tar.gz + cd googletest-release-1.8.0/googletest + cmake . + make + make install + - name: Install dependencies + run: | + # sudo installer -pkg /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.15.pkg -target / + brew install --cask xquartz + brew install llvm@11 swig udunits openmotif maven + brew link llvm llvm@11 + - name: Create testing environment + run: | + cd share/trick/pymods/trick/ + python3 -m virtualenv .venv && . .venv/bin/activate && pip install -r requirements.txt + - name: Build Trick + run: | + export MAKEFLAGS=-j4 + ./configure + make + - name: Run Civet Tests + run: | + cd share/trick/pymods/trick/ + . .venv/bin/activate + ./run_tests.py + env: + TRICK_HOME: "${{ github.workspace }}" + + diff --git a/.github/workflows/test_linux.yml b/.github/workflows/test_linux.yml index f7f447dd..28491c5c 100644 --- a/.github/workflows/test_linux.yml +++ b/.github/workflows/test_linux.yml @@ -59,10 +59,6 @@ jobs: libclang-dev libudunits2-dev libgtest-dev - python3 - python3-venv - net-tools - netcat install_gtest: cd /usr/src/gtest && cmake . && make && cp libgtest* /usr/lib/ #-------- RHEL Dependencies ---------------- - cfg: { arch: rhel } @@ -84,9 +80,6 @@ jobs: which zlib-devel gtest-devel - python3-devel - net-tools - nc #-------- Ubuntu Only Dependencies ---------------- - cfg: { os: ubuntu } os_deps: >- @@ -134,20 +127,6 @@ jobs: runs-on: ubuntu-18.04 container: docker://${{matrix.cfg.os}}:${{matrix.cfg.tag}} steps: - # - name: Set up Python ${{ matrix.python-version }} - # uses: actions/setup-python@v2 - # with: - # python-version: ${{ matrix.python-version }} - - name: Info - run: | - pwd - echo $TEST - echo workspace is $TRICK_HOME - echo files in workspace: - ls -la $TRICK_HOME - env: - TEST: Hello World! - TRICK_HOME: ${{ github.workspace }} - name: Update Package Manager run: ${{matrix.conf_pkg}} - name: Install Dependencies @@ -157,41 +136,10 @@ jobs: run: ${{matrix.install_gtest}} - name: Checkout repository uses: actions/checkout@master - - name: Info after checkout - run: | - pwd - echo $TEST - echo workspace is $TRICK_HOME - echo files in workspace: - ls -la $TRICK_HOME - netstat -tulpan - whereis nc - env: - TEST: Hello World! - TRICK_HOME: ${{ github.workspace }} - - name: Create testing environment - run: | - cd share/trick/pymods/trick/ - python3 -m venv .venv && . .venv/bin/activate && pip3 install -r requirements.txt - name: Build trick run: | export MAKEFLAGS=-j`nproc` ./configure make - # - name: Build Cannon Sim - # run: | - # cd trick_sims/Cannon/SIM_cannon_numeric - # ls -la - # $TRICK_HOME/bin/trick-CP - # ls -la - # env: - # TRICK_HOME: "${{ github.workspace }}" - - name: Run Civet Tests - run: | - cd share/trick/pymods/trick/ - . .venv/bin/activate - ./run_tests.py - env: - TRICK_HOME: "${{ github.workspace }}" - name: Test - run: make test + run: make test \ No newline at end of file diff --git a/.gitignore b/.gitignore index aba79b40..0049e740 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,4 @@ trick-offline *sim_services_classes.resource civetweb_clone/ include/civet/ +.vscode/ diff --git a/Makefile b/Makefile index 31960177..1cfde427 100644 --- a/Makefile +++ b/Makefile @@ -237,16 +237,18 @@ CIVET_CLONE_DIR = civetweb_clone civetweb: ${TRICK_LIB_DIR}/libcivetweb.a $(MAKE) -C ${TRICK_HOME}/trick_source/web/CivetServer -${TRICK_LIB_DIR}/libcivetweb.a: ${CIVET_CLONE_DIR} | ${TRICK_LIB_DIR} +${TRICK_LIB_DIR}/libcivetweb.a: ${CIVET_CLONE_DIR} ${CIVET_CLONE_DIR}/libcivetweb.a | ${TRICK_LIB_DIR} cp ${CIVET_CLONE_DIR}/libcivetweb.a $(TRICK_LIB_DIR)/libcivetweb.a mkdir -p ${TRICK_HOME}/include/civet/ cp ${CIVET_CLONE_DIR}/include/civetweb.h ${TRICK_HOME}/include/civet/civetweb.h cp ${CIVET_CLONE_DIR}/include/CivetServer.h ${TRICK_HOME}/include/civet/CivetServer.h +${CIVET_CLONE_DIR}/libcivetweb.a: ${CIVET_CLONE_DIR} + cd ${CIVET_CLONE_DIR} && make lib WITH_CPP=1 WITH_WEBSOCKET=1 + ${CIVET_CLONE_DIR}: git clone https://github.com/civetweb/civetweb.git $@ cd $@ && git checkout tags/v1.14 - cd ${CIVET_CLONE_DIR} && make lib WITH_CPP=1 WITH_WEBSOCKET=1 #------------------------------------------------------------------------------- diff --git a/share/trick/pymods/trick/conftest.py b/share/trick/pymods/trick/conftest.py index c7bd6ff7..c94d68d8 100644 --- a/share/trick/pymods/trick/conftest.py +++ b/share/trick/pymods/trick/conftest.py @@ -72,16 +72,15 @@ trick.exec_set_freeze_command(True)""") # pause("Before find") # subprocess.run(cmd, shell=True) # pause("After find") - if not os.path.exists(os.path.join(pathToSim, "S_main_Linux_9.3_x86_64.exe")): - build_cmd = f"echo \"cd {pathToSim} && {params.get_trick_home()}/bin/trick-CP\" | /bin/bash" - print("....................Running:", build_cmd) - subprocess.run(build_cmd, shell=True) + build_cmd = f"echo \"cd {pathToSim} && {params.get_trick_home()}/bin/trick-CP\" | /bin/bash" + print("....................Running:", build_cmd) + subprocess.run(build_cmd, shell=True) # pause("After build before start") if params.get_start_sim(): - if not os.path.exists(os.path.join(pathToSim, "S_main_Linux_9.3_x86_64.exe")): + if not os.path.exists(os.path.join(pathToSim, params.get_sim_name())): raise RuntimeError(f"Sim executable does not exist in {pathToSim}. Build this sim before running this test.") - cmd = f'echo "cd {pathToSim} && ./S_main_Linux_9.3_x86_64.exe {os.path.join(params.get_input_folder(), params.get_test_input_file())} &" | /bin/bash' + cmd = f'echo "cd {pathToSim} && ./{params.get_sim_name()} {os.path.join(params.get_input_folder(), params.get_test_input_file())} &" | /bin/bash' print("....................Running:", cmd) subprocess.run(cmd, shell=True) diff --git a/share/trick/pymods/trick/requirements.txt b/share/trick/pymods/trick/requirements.txt index 8a159988..0cfe2244 100644 --- a/share/trick/pymods/trick/requirements.txt +++ b/share/trick/pymods/trick/requirements.txt @@ -1,4 +1,5 @@ -websockets==9.1 -pytest-asyncio==0.15.1 -pytest==6.2.4 -requests==2.26.0 +websockets +pytest-asyncio +pytest +requests +psutil diff --git a/share/trick/pymods/trick/tests/civet_server/test_http.py b/share/trick/pymods/trick/tests/civet_server/test_http.py index 3f5d042a..af5cb9db 100644 --- a/share/trick/pymods/trick/tests/civet_server/test_http.py +++ b/share/trick/pymods/trick/tests/civet_server/test_http.py @@ -18,15 +18,18 @@ path.append("../..") from utils import is_web_server_started, params def open_connections(numConnections): - processes = [] + sockets = [] for _ in range(numConnections): - processes.append(subprocess.Popen(f"nc -s 127.0.0.1 localhost {params.get_var_server_port()}".split())) #Connect to webserver to establish connections. + sockets.append(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) + sockets[-1].connect(("127.0.0.1", params.get_var_server_port())) sleep(1) #Wait for the connection to persist. - return processes + return sockets -def kill_processes(processes): - for p in processes: - p.kill() +def close_sockets(sockets): + for s in sockets: + port = s.getsockname()[1] + s.close() + # is_web_server_started(port, "") sleep(1) def get_vs_open_connections(): @@ -65,15 +68,15 @@ class TestWebserverHttp: assert res.json()["alloc_total"] == 48, "Expecting 48 memory allocations." def test_vs_connections(self): - processes = open_connections(1) + sockets = open_connections(1) webResponse=get_vs_open_connections() - kill_processes(processes) + close_sockets(sockets) assert webResponse.json()["variable_server_connections"][0]["connection"]["client_IP_address"] == "127.0.0.1" assert len(webResponse.json()["variable_server_connections"]) == 1 - processes = open_connections(50) + sockets = open_connections(50) webResponse=get_vs_open_connections() - kill_processes(processes) + close_sockets(sockets) assert webResponse.json()["variable_server_connections"][0]["connection"]["client_IP_address"] == "127.0.0.1" assert len(webResponse.json()["variable_server_connections"]) == 50, "Should be able to open more than 1 connection." #Todo: determine appropriate number of simultaneous connections to test diff --git a/share/trick/pymods/trick/utils.py b/share/trick/pymods/trick/utils.py index b7944b7a..0fa45cca 100644 --- a/share/trick/pymods/trick/utils.py +++ b/share/trick/pymods/trick/utils.py @@ -1,6 +1,7 @@ from time import sleep import subprocess import os +import psutil def pause(my_str = "no message."): print("Type exit to continue:" + my_str) @@ -28,6 +29,14 @@ class Params: self.__input_folder = "RUN_test" self.__test_input_file = f"tmp_input_for_test.py" + def get_sim_name(self): + sim_name = None + for file in os.listdir(self.get_path_to_sim()): + if file.startswith("S_main"): + sim_name = file + if sim_name == None: + raise RuntimeError(f"Did not find sim executable. Please make sure the sim in {self.get_path_to_sim()} is compiled.") + return sim_name def get_trick_home(self): return self.__trick_home def get_path_to_sim(self): @@ -76,14 +85,20 @@ class Params: params = Params() -def is_web_server_started(): - for _ in range(20): #Wait 2 seconds i.e 20 * .1 seconds, must wait for service to get to listening state. - cmd = f"echo \"netstat -tulpan | grep {params.get_port()}\" | /bin/bash" - p = subprocess.run(cmd, capture_output=True, shell=True) - print("runing........", cmd) - print(f"Checking for port output: {p.stdout}") - print(f"Error is: {p.stderr}") - sleep(.1) #We sleep to use less recourses - if "LISTEN" in p.stdout.decode(): - return True - return False +def is_web_server_started(port=params.get_port(), status_method="LISTEN"): + isConnectionOpen = False + try: + for _ in range(20): #Wait up to 2 seconds i.e 20 * .1 seconds, must wait for service to get to listening state. + for connection in psutil.net_connections(): + local_address = connection.laddr + if len(local_address) > 1 and local_address[1] == port and connection.status == status_method: + isConnectionOpen = True + break + if isConnectionOpen: + break + sleep(.1) #We sleep to use less recourses + except psutil.AccessDenied as e: + print("psutil.net_connections() requires root access on mac. Sleeping for 2 seconds instead.") + isConnectionOpen = True + sleep(2) + return isConnectionOpen