diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..3473c47 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,54 @@ + +language: python +dist: bionic +# python: +# - '3.6' +# - '3.7' +# nodejs: +# - 10.0.0 +# os: osx +# command to run tests +cache: pip +env: + global: + - MOZ_HEADLESS=1 +addons: + firefox: "78.0.1" +sudo: required +services: + - xvfb +branches: + only: + - master + - react +before_install: + - sudo apt-get install xvfb + - wget https://github.com/mozilla/geckodriver/releases/download/v0.26.0/geckodriver-v0.26.0-linux64.tar.gz + # - mkdir geckodriver + # - tar -xzf geckodriver-v0.26.0-macos.tar.gz -C geckodriver + # - export PATH=$PATH:$PWD/geckodriver + - sudo tar -xzf geckodriver-v0.26.0-linux64.tar.gz -C /usr/bin + - sudo chmod a+x /usr/bin/geckodriver + # - export DISPLAY=:99.0 + # - sh -e /etc/init.d/xvfb start + # - sleep 5 # give xvfb some time to start +install: + - "pip install -r requirements.txt" + - npm install selenium-webdriver@^3.0.0 + - curl -o- -L https://yarnpkg.com/install.sh | bash + - node --version + - jupyter --version + - jlpm install + - jlpm run build + - jupyter labextension install + + +script: + - JUPYTER_TOKEN=secret jupyter-notebook & + - jupyter labextension list + - jupyter lab --port=8845 --NotebookApp.token='' & + - export PATH=$(pwd)/tests:$PATH + - sleep 30 + - pytest + +# JUPYTER_TOKEN=secret jupyter lab --port=8845 --NotebookApp.token='' & \ No newline at end of file diff --git a/infinite.txt b/infinite.txt new file mode 100644 index 0000000..f3a3bbd --- /dev/null +++ b/infinite.txt @@ -0,0 +1,6 @@ +#!/bin/sh +#SBATCH -C haswell +while [ ! -f /global/ul/n/labanyam/stop] +do + sleep 3000 +done \ No newline at end of file diff --git a/jupyterlab_slurm/slurm.py b/jupyterlab_slurm/slurm.py index 5ee0c80..27897c7 100755 --- a/jupyterlab_slurm/slurm.py +++ b/jupyterlab_slurm/slurm.py @@ -16,6 +16,7 @@ class ShellExecutionHandler(IPythonHandler): async def run_command(self, command, stdin=None, cwd=None): + print(command) commands = shlex.split(command) process = await asyncio.create_subprocess_exec(*commands, stdout=asyncio.subprocess.PIPE, @@ -101,9 +102,12 @@ async def post(self): # Have two options to specify SLURM script in the request body: either with a path to the script, or with the script's text contents if inputType: if inputType == 'path': + print(self.request.body) + print(self.request.headers['Content-Type'] == 'application/json') if self.request.headers['Content-Type'] == 'application/json': script_path = json.loads(self.request.body)["input"] else: + print("shouldn't be here") script_path = self.get_body_argument('input') try: stdout, stderr, returncode = await self.run_command(sbatch_command + script_path, cwd=outputDir) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..5040219 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +jupyter +jupyterlab>2.0.0 +selenium +pytest diff --git a/sq_output.txt b/sq_output.txt new file mode 100644 index 0000000..dd3825e --- /dev/null +++ b/sq_output.txt @@ -0,0 +1 @@ +JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON) diff --git a/squeue b/squeue new file mode 100755 index 0000000..4b604f3 --- /dev/null +++ b/squeue @@ -0,0 +1,3 @@ +#!/bin/sh +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +cat $DIR/sq_output.txt \ No newline at end of file diff --git a/tests/sbatch b/tests/sbatch new file mode 100755 index 0000000..ca29678 --- /dev/null +++ b/tests/sbatch @@ -0,0 +1,2 @@ +#!/bin/sh +echo "Success: Submitted batch job 33241147" diff --git a/tests/scancel b/tests/scancel new file mode 100755 index 0000000..754da39 --- /dev/null +++ b/tests/scancel @@ -0,0 +1,2 @@ +#!/bin/sh +echo "Success: scancel 33241147" \ No newline at end of file diff --git a/tests/scontrol b/tests/scontrol new file mode 100755 index 0000000..2d79e08 --- /dev/null +++ b/tests/scontrol @@ -0,0 +1,2 @@ +#!/bin/sh +echo "Success: scontrol hold 33241147" \ No newline at end of file diff --git a/tests/squeue b/tests/squeue new file mode 100755 index 0000000..e9d4f2a --- /dev/null +++ b/tests/squeue @@ -0,0 +1,3 @@ +#!/bin/sh +echo " 33241147 debug_hsw infinite labanyam R 2:25 1 nid01172" + \ No newline at end of file diff --git a/tests/test-api.py b/tests/test-api.py new file mode 100644 index 0000000..87b6f6c --- /dev/null +++ b/tests/test-api.py @@ -0,0 +1,53 @@ +#http://localhost:8845/ +import requests +import pytest +import asyncio +import json +import os +from http.client import HTTPConnection +from urllib.parse import quote +from tornado.websocket import websocket_connect + + +PORT = os.getenv('TEST_PORT', 8845) +TOKEN = os.getenv('JUPYTER_TOKEN', 'secret') + + +def test_sbatch(): + r = requests.post('http://localhost:8845/sbatch?inputType=contents&outputDir=%2Ftmp&token='+TOKEN, data = '{"input":"#!/bin/sh"}', headers={"content-type": "application/json"} ) + assert r.status_code == 200 + + fail_r = requests.post('http://localhost:8845/sbatch?inputType=contents&outputDir=%2Ftmp&token='+TOKEN, headers={"content-type": "application/json"} ) + assert fail_r.status_code != 200 + +def test_squeue(): + jobID = [] + r = requests.get('http://localhost:8845/squeue?userOnly=true&token='+ TOKEN) + assert r.status_code == 200 + assert len(r.json()['data'][0]) == 8 + + fail_r = requests.get('http://localhost:8845/squeue&token='+ TOKEN) + print(fail_r.text) + assert fail_r.status_code != 200 + + +def test_scontrol(): + r = requests.patch('http://localhost:8845/scontrol/hold?token='+ TOKEN, data = json.dumps({ "jobID": '33241147' }), headers={"content-type": "application/json"}) + assert r.status_code == 200 + assert ("Success: scontrol hold") in r.json()['responseMessage'] + + fail_r = requests.patch('http://localhost:8845/scontrol/hold?token='+ TOKEN, headers={"content-type": "application/json"}) + assert fail_r.status_code != 200 + + +def test_scancel(): + r = requests.delete('http://localhost:8845/scancel?token=' + TOKEN, data = json.dumps({ "jobID": '33241147' }), headers={"content-type": "application/json"}) + assert r.status_code == 200 + assert ("Success: scancel") in r.json()['responseMessage'] + + fail_r = requests.delete('http://localhost:8845/scancel?token=' + TOKEN, data = json.dumps({ "jobID": '33241147' })) + assert fail_r.status_code != 200 + +if __name__ == '__main__': + test_sbatch() + test_squeue() \ No newline at end of file diff --git a/tests/test_slurm.py b/tests/test_slurm.py new file mode 100644 index 0000000..6e5f904 --- /dev/null +++ b/tests/test_slurm.py @@ -0,0 +1,114 @@ +import pytest +import time +import json +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.webdriver.common.action_chains import ActionChains +from selenium.webdriver.support import expected_conditions +from selenium.webdriver.support.wait import WebDriverWait +from selenium.webdriver.common.keys import Keys +from selenium.webdriver.common.desired_capabilities import DesiredCapabilities +from selenium.common.exceptions import NoSuchElementException + +class TestAddfavs(): + def setup_method(self, method): + self.driver = webdriver.Firefox() + self.vars = {} + + def teardown_method(self, method): + self.driver.quit() + + # def test_slurmcard(self): + # #import pdb; pdb.set_trace() + + # self.driver.get("http://localhost:8845/lab") + # self.driver.implicitly_wait(40) + # self.driver.maximize_window() + # self.driver.implicitly_wait(40) + + # #card_text = self.driver.find_element(By.XPATH, "/html/body/div/div[3]/div[2]/div[3]/div[3]/div[2]/div/div/div[5]/div[2]/div") + # #assert card_text.text == "Slurm Queue" + + # slurm_card = self.driver.find_elements_by_class_name('jp-NerscLaunchIcon') + # #slurm_card = self.driver.find_element_by_css_selector(".jp-NerscLaunchIcon.jp-Launcher-icon") + # #assert slurm_card.text == "Slurm Queue" + # self.driver.implicitly_wait(40) + # #self.driver.execute_script("return arguments[0].scrollIntoView(0, document.documentElement.scrollHeight-10);", slurm_card) + # #self.driver.implicitly_wait(20) + # #actions.click(slurm_card[1]).perform() + # actions = ActionChains(self.driver) + # actions.click(slurm_card[1]).perform() + # #actions.click(slurm_card).perform() + # #actions = ActionChains(self.driver) + # #actions.move_to_element(slurm_launcher).perform() + # #actions = ActionChains(self.driver) + # #actions.click(slurm_launcher).perform() + # self.driver.implicitly_wait(40) + + # # try: + # # jobid_text = self.driver.find_element(By.XPATH, "//*[contains(text(),'JOBID')]") + # # assert jobid_text.text == "JOBID" + + # # partition_text = self.driver.find_element(By.XPATH, "//*[contains(text(),'PARTITION')]") + # # assert partition_text.text == "PARTITION" + + # # close_tab = self.driver.find_element(By.XPATH, "/html/body/div/div[3]/div[2]/div[3]/div[2]/ul/li[2]/div[3]") + # # actions = ActionChains(self.driver) + # # actions.click(close_tab).perform() + # # except NoSuchElementException: + # # print('No slurm elements found') + + # # jobid_text = self.driver.find_element(By.XPATH, "//h2[contains(text(),'HPC Tools')]") + # # assert jobid_text.text == "HPC Tools" + + # jobid_text = self.driver.find_element(By.XPATH, "//th[contains(text(),'JOBID')]") + # assert jobid_text.text == "JOBID" + + # partition_text = self.driver.find_element(By.XPATH, "//th[contains(text(),'PARTITION')]") + # assert partition_text.text == "PARTITION" + + # #close_tab = self.driver.find_element(By.XPATH, "/html/body/div/div[3]/div[2]/div[3]/div[2]/ul/li[2]/div[3]") + # #close_tab = self.driver.find_element(By.XPATH, "/html/body/div/div[3]/div[2]/div[3]/div[2]/ul/li/div[3]") + # close_tab = self.driver.find_element(By.XPATH, "/html/body/div/div[3]/div[2]/div[3]/div[2]/ul/li/div[3]") + + # actions = ActionChains(self.driver) + # actions.click(close_tab).perform() + + def test_slurmcommands(self): + #import pdb; pdb.set_trace() + + self.driver.get("http://localhost:8845/lab") + self.driver.implicitly_wait(40) + self.driver.maximize_window() + self.driver.implicitly_wait(40) + + console = self.driver.find_element(By.XPATH, '//*[@data-id="command-palette"]') + self.driver.implicitly_wait(30) + actions = ActionChains(self.driver) + actions.click(console).perform() + self.driver.implicitly_wait(40) + + slurm_launcher = self.driver.find_element(By.XPATH, "//div[contains(text(),'Slurm Queue')]") + self.driver.implicitly_wait(20) + self.driver.execute_script("return arguments[0].scrollIntoView(0, document.documentElement.scrollHeight-10);", slurm_launcher) + #actions.move_to_element(slurm_launcher).perform() + self.driver.implicitly_wait(60) + actions = ActionChains(self.driver) + actions.click(slurm_launcher).perform() + + self.driver.implicitly_wait(40) + jobid_text = self.driver.find_element(By.XPATH, "//th[contains(text(),'JOBID')]") + assert jobid_text.text == "JOBID" + + partition_text = self.driver.find_element(By.XPATH, "//th[contains(text(),'PARTITION')]") + assert partition_text.text == "PARTITION" + + self.driver.implicitly_wait(40) + + + +if __name__ == '__main__': + setup_method() + #test_slurmcard() + test_slurmcommands() + teardown_method() \ No newline at end of file