Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .github/tests-browser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: test

channels:
- conda-forge
- nodefaults

dependencies:
# browser deps
- firefox >=78,<79
- geckodriver
- nodejs >=12,<13
- pandoc
# rest of python deps
- pip
- setuptools
- wheel
78 changes: 78 additions & 0 deletions .github/workflows/tests-browser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Browser Tests

on:
push:
branches: [master]
pull_request:
branches: [master]

env:
JUPYTER_TEST_BROWSER: firefox
MOZ_HEADLESS: 1

jobs:
build:
runs-on: ${{ matrix.os }}-latest
strategy:
fail-fast: false
matrix:
os: [ubuntu, macos, windows]
python-version: ['3.6', '3.8', '3.9']
defaults:
run:
shell: bash -l {0}
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Cache conda
uses: actions/cache@v1
with:
path: ~/conda_pkgs_dir
key:
${{ runner.os }}-conda-${{ matrix.python-version }}-${{ hashFiles('.github/tests-browser.yml') }}
restore-keys: |
${{ runner.os }}-conda-${{ matrix.python-version }}-
- name: Install Browser Test Dependencies
uses: conda-incubator/setup-miniconda@v2
with:
python-version: ${{ matrix.python-version }}
environment-file: .github/tests-browser.yml
- if: ${{ matrix.os == 'windows' }}
name: Install windows conda dependencies
run: conda install -c conda-forge -c msys2 -c nodefaults pywin32
- name: List conda packages
run: |
conda list --explicit
- name: Get pip cache dir
id: pip-cache
run: |
echo "::set-output name=dir::$(pip cache dir)"
- name: Cache pip
uses: actions/cache@v1
with:
path: ${{ steps.pip-cache.outputs.dir }}
key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('setup.py') }}
restore-keys: |
${{ runner.os }}-pip-${{ matrix.python-version }}-
${{ runner.os }}-pip-
- name: Build static assets
run: |
python setup.py build
- name: Install the Python dependencies
run: |
pip install -e .[test] codecov
- name: List installed packages
run: |
pip freeze
pip check
- name: Run selenium tests
timeout-minutes: 30
run: |
py.test -sv notebook/tests/selenium ${{ matrix.selenium-pytest-args }}
- name: Install npm dependencies
run: |
npm install -g [email protected] [email protected]
- name: Run legacy js tests
timeout-minutes: 30
run: |
python -m notebook.jstest
66 changes: 66 additions & 0 deletions .github/workflows/tests-python.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: Python Tests

on:
push:
branches: [master]
pull_request:
branches: [master]

jobs:
build:
runs-on: ${{ matrix.os }}-latest
strategy:
fail-fast: false
matrix:
os: [ubuntu, macos, windows]
python-version: ['3.6', '3.7', '3.8', '3.9', 'pypy3']
exclude:
- os: windows
python-version: pypy3
include:
# TODO: remove if fixed https://github.com/spyder-ide/pywinpty/issues/134
- os: windows
python-version: '3.9'
pytest-args: --ignore notebook/terminal
- python-version: pypy3
pytest-args: -k "not culling"
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Install Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
architecture: 'x64'
- name: Upgrade packaging dependencies
run: |
pip install --upgrade pip setuptools wheel --user
- name: Get pip cache dir
id: pip-cache
run: |
echo "::set-output name=dir::$(pip cache dir)"
- name: Cache pip
uses: actions/cache@v1
with:
path: ${{ steps.pip-cache.outputs.dir }}
key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('setup.py') }}
restore-keys: |
${{ runner.os }}-pip-${{ matrix.python-version }}-
${{ runner.os }}-pip-
- uses: actions/setup-node@v1
with:
node-version: '12'
- name: Build static assets
run: |
python setup.py build
- name: Install the Python dependencies
run: |
pip install -e .[test] codecov
- name: List installed packages
run: |
pip freeze
pip check
- name: Run the tests
timeout-minutes: 30
run: |
pytest -vv notebook --cov notebook --ignore notebook/tests/selenium --cov-branch --cov-report term-missing:skip-covered --durations 10 ${{ matrix.pytest-args }}
8 changes: 4 additions & 4 deletions notebook/auth/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,13 @@ def hashed_password(self):

def passwd_check(self, a, b):
return passwd_check(a, b)

def post(self):
typed_password = self.get_argument('password', default=u'')
new_password = self.get_argument('new_password', default=u'')



if self.get_login_available(self.settings):
if self.passwd_check(self.hashed_password, typed_password) and not new_password:
self.set_login_cookie(self, uuid.uuid4().hex)
Expand Down Expand Up @@ -112,7 +112,7 @@ def set_login_cookie(cls, handler, user_id=None):
handler.set_secure_cookie(handler.cookie_name, user_id, **cookie_options)
return user_id

auth_header_pat = re.compile('token\s+(.+)', re.IGNORECASE)
auth_header_pat = re.compile(r'token\s+(.+)', re.IGNORECASE)

@classmethod
def get_token(cls, handler):
Expand Down Expand Up @@ -197,7 +197,7 @@ def get_user(cls, handler):
@classmethod
def get_user_token(cls, handler):
"""Identify the user based on a token in the URL or Authorization header

Returns:
- uuid if authenticated
- None if not
Expand Down
40 changes: 25 additions & 15 deletions notebook/jstest.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ def popen_wait(p, timeout):
return p.wait(timeout)

NOTEBOOK_SHUTDOWN_TIMEOUT = 10
SKIP_JS_GROUPS = [
# doesn't appear to do anything
"mockextension",
# has its own test entrypoint
"selenium"
]

have = {}
have['casperjs'] = bool(which('casperjs'))
Expand Down Expand Up @@ -60,7 +66,7 @@ def run(self):
self.buffer.write(chunk)
if self.echo:
sys.stdout.write(bytes_to_str(chunk))

os.close(self.readfd)
os.close(self.writefd)

Expand Down Expand Up @@ -110,7 +116,7 @@ def __init__(self):

def setup(self):
"""Create temporary directories etc.

This is only called when we know the test group will be run. Things
created here may be cleaned up by self.cleanup().
"""
Expand Down Expand Up @@ -138,11 +144,11 @@ def wait(self):

def print_extra_info(self):
"""Print extra information about this test run.

If we're running in parallel and showing the concise view, this is only
called if the test group fails. Otherwise, it's called before the test
group is started.

The base implementation does nothing, but it can be overridden by
subclasses.
"""
Expand Down Expand Up @@ -189,11 +195,15 @@ def all_js_groups():
import glob
test_dir = get_js_test_dir()
all_subdirs = glob.glob(test_dir + '[!_]*/')
return [os.path.relpath(x, test_dir) for x in all_subdirs]
return [
os.path.relpath(x, test_dir)
for x in all_subdirs
if os.path.relpath(x, test_dir) not in SKIP_JS_GROUPS
]

class JSController(TestController):
"""Run CasperJS tests """

requirements = ['casperjs']

def __init__(self, section, xunit=True, engine='phantomjs', url=None):
Expand All @@ -206,11 +216,11 @@ def __init__(self, section, xunit=True, engine='phantomjs', url=None):
# run with a base URL that would be escaped,
# to test that we don't double-escape URLs
self.base_url = '/a@b/'
self.slimer_failure = re.compile('^FAIL.*', flags=re.MULTILINE)
self.slimer_failure = re.compile(r'^FAIL.*', flags=re.MULTILINE)
js_test_dir = get_js_test_dir()
includes = '--includes=' + os.path.join(js_test_dir,'util.js')
test_cases = os.path.join(js_test_dir, self.section)
self.cmd = ['casperjs', 'test', includes, test_cases, '--engine=%s' % self.engine]
self.cmd = [shutil.which('casperjs'), 'test', includes, test_cases, '--engine=%s' % self.engine]

def setup(self):
self.ipydir = TemporaryDirectory()
Expand Down Expand Up @@ -317,7 +327,7 @@ def _init_server(self):
'nbserver-%i.json' % self.server.pid
)
self._wait_for_server()

def _wait_for_server(self):
"""Wait 30 seconds for the notebook server to start"""
for i in range(300):
Expand All @@ -336,14 +346,14 @@ def _wait_for_server(self):
print("Notebook server-info file never arrived: %s" % self.server_info_file,
file=sys.stderr
)

def _failed_to_start(self):
"""Notebook server exited prematurely"""
captured = self.stream_capturer.get_buffer().decode('utf-8', 'replace')
print("Notebook failed to start: ", file=sys.stderr)
print(self.server_command)
print(captured, file=sys.stderr)

def _load_server_info(self):
"""Notebook server started, load connection info from JSON"""
with open(self.server_info_file) as f:
Expand Down Expand Up @@ -377,7 +387,7 @@ def cleanup(self):
print("Notebook server still running (%s)" % self.server_info_file,
file=sys.stderr
)

self.stream_capturer.halt()
TestController.cleanup(self)

Expand All @@ -399,11 +409,11 @@ def prepare_controllers(options):

def do_run(controller, buffer_output=True):
"""Setup and run a test controller.

If buffer_output is True, no output is displayed, to avoid it appearing
interleaved. In this case, the caller is responsible for displaying test
output on failure.

Returns
-------
controller : TestController
Expand Down Expand Up @@ -468,7 +478,7 @@ def _add(name, value):

def run_jstestall(options):
"""Run the entire Javascript test suite.

This function constructs TestControllers and runs them in subprocesses.

Parameters
Expand Down
12 changes: 6 additions & 6 deletions notebook/templates/tree.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,17 @@
<button title="{% trans %}Duplicate selected{% endtrans %}" aria-label="{% trans %}Duplicate selected{% endtrans %}" class="duplicate-button btn btn-default btn-xs" aria-describedby="tooltip1">{% trans %}Duplicate{% endtrans %} </button>
<div role="tooltip" id="tooltip1" >{% trans %}Duplicate selected{% endtrans %}</div>
<button title="{% trans %}Rename selected{% endtrans %}" aria-label="{% trans %}Rename selected{% endtrans %}" class="rename-button btn btn-default btn-xs" aria-describedby="tooltip2">{% trans %}Rename{% endtrans %}</button>
<div role="tooltip" id="tooltip2" >{% trans %}Rename selected{% endtrans %}</div>
<div role="tooltip" id="tooltip2" >{% trans %}Rename selected{% endtrans %}</div>
<button title="{% trans %}Move selected{% endtrans %}" aria-label="{% trans %}Move selected{% endtrans %}" class="move-button btn btn-default btn-xs" aria-describedby="tooltip3">{% trans %}Move{% endtrans %}</button>
<div role="tooltip" id="tooltip3" >{% trans %}Move selected{% endtrans %}</div>
<div role="tooltip" id="tooltip3" >{% trans %}Move selected{% endtrans %}</div>
<button title="{% trans %}Download selected{% endtrans %}" aria-label="{% trans %}Download selected{% endtrans %}" class="download-button btn btn-default btn-xs" aria-describedby="tooltip4">{% trans %}Download{% endtrans %}</button>
<div role="tooltip" id="tooltip4" >{% trans %}Download selected{% endtrans %}</div>
<button title="{% trans %}Shutdown selected notebook(s){% endtrans %}" aria-label="{% trans %}Shutdown selected notebook(s){% endtrans %}" class="shutdown-button btn btn-default btn-xs btn-warning" aria-describedby="tooltip5">{% trans %}Shutdown{% endtrans %}</button>
<div role="tooltip" id="tooltip5" >{% trans %}Shutdown selected notebook(s){% endtrans %}</div>
<div role="tooltip" id="tooltip5" >{% trans %}Shutdown selected notebook(s){% endtrans %}</div>
<button title="{% trans %}View selected{% endtrans %}" aria-label="{% trans %}View selected{% endtrans %}" class="view-button btn btn-default btn-xs" aria-describedby="tooltip6">{% trans %}View{% endtrans %}</button>
<div role="tooltip" id="tooltip6" >{% trans %}View selected{% endtrans %}</div>
<div role="tooltip" id="tooltip6" >{% trans %}View selected{% endtrans %}</div>
<button title="{% trans %}Edit selected{% endtrans %}" aria-label="{% trans %}Edit selected{% endtrans %}" class="edit-button btn btn-default btn-xs" aria-describedby="tooltip7">{% trans %}Edit{% endtrans %}</button>
<div role="tooltip" id="tooltip7" >{% trans %}Edit selected{% endtrans %}</div>
<div role="tooltip" id="tooltip7" >{% trans %}Edit selected{% endtrans %}</div>
<button title="{% trans %}Delete selected{% endtrans %}" aria-label="{% trans %}Delete selected{% endtrans %}" class="delete-button btn btn-default btn-xs btn-danger" aria-describedby="tooltip8">
<i class="fa fa-trash"></i>
</button>
Expand Down Expand Up @@ -216,7 +216,7 @@
{% block script %}
{{super()}}
<script type="text/javascript">
('#element').tooltip('enable')
$('#element').tooltip('enable');
</script>

<script src="{{ static_url("tree/js/main.min.js") }}" type="text/javascript" charset="utf-8"></script>
Expand Down
11 changes: 8 additions & 3 deletions notebook/tests/selenium/conftest.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import time
import json
import nbformat
from nbformat.v4 import new_notebook, new_code_cell
Expand Down Expand Up @@ -66,9 +67,13 @@ def notebook_server():
print("Notebook server info:", info)
yield info

# Shut the server down
requests.post(urljoin(info['url'], 'api/shutdown'),
headers={'Authorization': 'token '+info['token']})
# Shut the server down
requests.post(urljoin(info['url'], 'api/shutdown'),
headers={'Authorization': 'token '+info['token']})

while proc.returncode is None:
proc.wait()
time.sleep(5)


def make_sauce_driver():
Expand Down
Loading