Skip to content

Commit

Permalink
Merge pull request #10 from yuvipanda/feat/basic-unit-tests
Browse files Browse the repository at this point in the history
Add unit tests + CI + code coverage
  • Loading branch information
Zsailer authored Jul 9, 2019
2 parents 71f3ad6 + a0e2022 commit 2826838
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 45 deletions.
43 changes: 43 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
version: 2
jobs:
build:
docker:
- image: circleci/python:3.5
working_directory: ~/repo

steps:
- checkout

- restore_cache:
keys:
- v1-dependencies-{{ checksum "dev-requirements.txt" }}-{{ checksum "setup.py" }}
# fallback to using the latest cache if no exact match is found
- v1-dependencies-

- run:
name: install dependencies
command: |
python3 -m venv venv
. venv/bin/activate
pip install -r dev-requirements.txt
pip install -e .
- save_cache:
paths:
- ./venv
key: v1-dependencies-{{ checksum "dev-requirements.txt" }}-{{ checksum "setup.py" }}

- run:
name: run tests
command: |
. venv/bin/activate
# Have CircleCI display pretty test result output
mkdir test-reports
py.test --cov=jupyter_telemetry --junitxml=test-reports/junit.xml tests/
# Upload coverage info to codecov
codecov
- store_test_results:
path: test-reports
- store_artifacts:
path: test-reports
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
# Telemetry

[![circleci](https://circleci.com/gh/jupyter/telemetry?style=shield)][https://circleci.com/gh/jupyter/telemetry]
[![codecov](https://codecov.io/gh/jupyter/telemetry/branch/master/graph/badge.svg)](https://codecov.io/gh/jupyter/telemetry)

Telemetry for Jupyter Applications and extensions.
3 changes: 3 additions & 0 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pytest
pytest-cov
codecov
42 changes: 0 additions & 42 deletions jupyter_telemetry/handler.py

This file was deleted.

5 changes: 2 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
license = 'BSD',
platforms = "Linux, Mac OS X, Windows",
keywords = ['Jupyter', 'JupyterLab'],
python_requires = '>=3.6',
python_requires = '>=3.5',
classifiers = [
'Intended Audience :: Developers',
'Intended Audience :: System Administrators',
Expand All @@ -26,7 +26,6 @@
install_requires=[
'jsonschema',
'python-json-logger',
'traitlets',
'notebook',
'traitlets'
],
)
148 changes: 148 additions & 0 deletions tests/test_register_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
from contextlib import redirect_stderr
import json
import jsonschema
import logging
import pytest
import io

from jupyter_telemetry.eventlog import EventLog


def test_register_invalid_schema():
"""
Invalid JSON Schemas should fail registration
"""
el = EventLog()
with pytest.raises(jsonschema.SchemaError):
el.register_schema({
# Totally invalid
'properties': True
})

def test_missing_required_properties():
"""
id and $version are required properties in our schemas.
They aren't required by JSON Schema itself
"""
el = EventLog()
with pytest.raises(ValueError):
el.register_schema({
'properties': {}
})

with pytest.raises(ValueError):
el.register_schema({
'$id': 'something',
'$version': 1, # This should been 'version'
})

def test_reserved_properties():
"""
User schemas can't have properties starting with __
These are reserved
"""
el = EventLog()
with pytest.raises(ValueError):
el.register_schema({
'$id': 'test/test',
'version': 1,
'properties': {
'__fail__': {
'type': 'string'
},
},
})

def test_record_event():
"""
Simple test for emitting valid events
"""
schema = {
'$id': 'test/test',
'version': 1,
'properties': {
'something': {
'type': 'string'
},
},
}

output = io.StringIO()
handler = logging.StreamHandler(output)
el = EventLog(handlers_maker=lambda el: [handler])
el.register_schema(schema)
el.allowed_schemas = ['test/test']

el.record_event('test/test', 1, {
'something': 'blah',
})
handler.flush()

event_capsule = json.loads(output.getvalue())

assert '__timestamp__' in event_capsule
# Remove timestamp from capsule when checking equality, since it is gonna vary
del event_capsule['__timestamp__']
assert event_capsule == {
'__schema__': 'test/test',
'__version__': 1,
'something': 'blah'
}


def test_allowed_schemas():
"""
Events should be emitted only if their schemas are allowed
"""
schema = {
'$id': 'test/test',
'version': 1,
'properties': {
'something': {
'type': 'string'
},
},
}

output = io.StringIO()
handler = logging.StreamHandler(output)
el = EventLog(handlers_maker=lambda el: [handler])
# Just register schema, but do not mark it as allowed
el.register_schema(schema)

el.record_event('test/test', 1, {
'something': 'blah',
})
handler.flush()


assert output.getvalue() == ''

def test_record_event_badschema():
"""
Fail fast when an event doesn't conform to its schema
"""
schema = {
'$id': 'test/test',
'version': 1,
'properties': {
'something': {
'type': 'string'
},
'status': {
'enum': ['success', 'failure']
}
}
}

el = EventLog(handlers_maker=lambda el: [logging.NullHandler()])
el.register_schema(schema)
el.allowed_schemas = ['test/test']

with pytest.raises(jsonschema.ValidationError):
el.record_event('test/test', 1, {
'something': 'blah',
'status': 'not-in-enum'
})

0 comments on commit 2826838

Please sign in to comment.