Skip to content

Commit

Permalink
Merge d83aa72 into 44aa6c8
Browse files Browse the repository at this point in the history
  • Loading branch information
0golovatyi committed Feb 22, 2019
2 parents 44aa6c8 + d83aa72 commit fb0f4b8
Show file tree
Hide file tree
Showing 21 changed files with 523 additions and 90 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG
Expand Up @@ -3,6 +3,14 @@
This file list notable changes for TabPy project releases.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## v0.4

### Improvements

- Added basic access authentication (all methods except /info)
- Increased unit tests coverage
- Travis CI for merge requests: unit tests executed, code style checking

## v0.3.2

### Breaking changes
Expand Down
40 changes: 34 additions & 6 deletions CONTRIBUTING.md
Expand Up @@ -5,10 +5,10 @@
- [Environment Setup](#environment-setup)
- [Prerequisites](#prerequisites)
- [Windows Specific Steps](#windows-specific-steps)
- [Mac Specific Steps](#mac-specific-steps)
- [Linux and Mac Specific Steps](#linux-and-mac-specific-steps)
- [Documentation Updates](#documentation-updates)
- [Versioning](#versioning)
- [TabPy with Swagger](#tabpy-with-swagger)
- [Code styling](#code-styling)

<!-- tocstop -->

Expand Down Expand Up @@ -54,6 +54,20 @@ To run the unit test suite:
python tests\runtests.py
```

Alternatively you can run unit tests to collect code coverage data. First
install `pytest`:

```sh
pip install pytest
```

And then run `pytest` either for server or tools test, or even combined:

```sh
pytest tabpy-server/server_tests/ --cov=tabpy-server/tabpy_server
pytest tabpy-tools/tools_tests/ --cov=tabpy-tools/tabpy_tools --cov-append
```

## Linux and Mac Specific Steps

If you have downloaded Tabpy and would like to manually install Tabpy Server
Expand Down Expand Up @@ -100,13 +114,27 @@ file where modifications were made:

```sh
pip install pycodestyle
pycodestyle <file.py>
```

And then run it for file where modifications were made, e.g.:

```sh
pycodestyle tabpy-server/server_tests/test_pwd_file.py
```

For reported errors and warnings either fix them manually or auto-format files with
`autopep8`:
`autopep8`.

To install `autopep8` run the next command:

```sh
pip install autopep8
autopep8 -i <file.py>
```
```

And then you can run the tool for a file. In the example below `-i`
option tells `autopep8` to update the file. Without the option it
outputs formated code to console.

```sh
autopep8 -i tabpy-server/server_tests/test_pwd_file.py
```
2 changes: 1 addition & 1 deletion VERSION
@@ -1 +1 @@
0.3.2
0.4
4 changes: 0 additions & 4 deletions tabpy-server/server_tests/__init__.py
@@ -1,4 +0,0 @@
import logging

# Keep test cases logging quiet
logging.basicConfig(level=logging.CRITICAL + 1)
111 changes: 111 additions & 0 deletions tabpy-server/server_tests/test_endpoint_handler.py
@@ -0,0 +1,111 @@
import base64
import hashlib
import os
import tempfile
import unittest

from argparse import Namespace
from tabpy_server.app.app import TabPyApp
from tabpy_server.handlers.endpoint_handler import EndpointHandler
from tornado.testing import AsyncHTTPTestCase
from unittest.mock import patch


class TestEndpointHandlerWithAuth(AsyncHTTPTestCase):
@classmethod
def setUpClass(cls):
cls.patcher = patch(
'tabpy_server.app.TabPyApp._parse_cli_arguments',
return_value=Namespace(
config=None))
cls.patcher.start()

prefix = '__TestEndpointHandlerWithAuth_'
# create password file
cls.pwd_file = tempfile.NamedTemporaryFile(
mode='w+t', prefix=prefix, suffix='.txt', delete=False)
cls.pwd_file.write('username {}'.format(
hashlib.sha3_256('password'.encode('utf-8')).hexdigest()))
cls.pwd_file.close()

# create state.ini dir and file
cls.state_dir = tempfile.mkdtemp(prefix=prefix)
cls.state_file = open(os.path.join(cls.state_dir, 'state.ini'), 'w+')
cls.state_file.write('[Service Info]\n'
'Name = TabPy Serve\n'
'Description = \n'
'Creation Time = 0\n'
'Access-Control-Allow-Origin = \n'
'Access-Control-Allow-Headers = \n'
'Access-Control-Allow-Methods = \n'
'\n'
'[Query Objects Service Versions]\n'
'\n'
'[Query Objects Docstrings]\n'
'\n'
'[Meta]\n'
'Revision Number = 1\n')
cls.state_file.close()

# create config file
cls.config_file = tempfile.NamedTemporaryFile(
mode='w+t', prefix=prefix, suffix='.conf', delete=False)
cls.config_file.write(
'[TabPy]\n'
'TABPY_PWD_FILE = {}\n'
'TABPY_STATE_PATH = {}'.format(
cls.pwd_file.name,
cls.state_dir))
cls.config_file.close()

@classmethod
def tearDownClass(cls):
cls.patcher.stop()
os.remove(cls.pwd_file.name)
os.remove(cls.state_file.name)
os.remove(cls.config_file.name)
os.rmdir(cls.state_dir)

def get_app(self):
self.app = TabPyApp(self.config_file.name)
return self.app._create_tornado_web_app()

def test_no_creds_required_auth_fails(self):
response = self.fetch('/endpoints/anything')
self.assertEqual(401, response.code)

def test_invalid_creds_fails(self):
response = self.fetch(
'/endpoints/anything',
method='GET',
headers={
'Authorization': 'Basic {}'.
format(
base64.b64encode('user:wrong_password'.encode('utf-8')).
decode('utf-8'))
})
self.assertEqual(401, response.code)

def test_valid_creds_pass(self):
response = self.fetch(
'/endpoints/',
method='GET',
headers={
'Authorization': 'Basic {}'.
format(
base64.b64encode('username:password'.encode('utf-8')).
decode('utf-8'))
})
self.assertEqual(200, response.code)

def test_valid_creds_unknown_endpoint_fails(self):
response = self.fetch(
'/endpoints/unknown_endpoint',
method='GET',
headers={
'Authorization': 'Basic {}'.
format(
base64.b64encode('username:password'.encode('utf-8')).
decode('utf-8'))
})
self.assertEqual(404, response.code)
99 changes: 99 additions & 0 deletions tabpy-server/server_tests/test_endpoints_handler.py
@@ -0,0 +1,99 @@
import base64
import hashlib
import os
import tempfile
import unittest

from argparse import Namespace
from tabpy_server.app.app import TabPyApp
from tabpy_server.handlers.endpoints_handler import EndpointsHandler
from tornado.testing import AsyncHTTPTestCase
from unittest.mock import patch


class TestEndpointsHandlerWithAuth(AsyncHTTPTestCase):
@classmethod
def setUpClass(cls):
cls.patcher = patch(
'tabpy_server.app.TabPyApp._parse_cli_arguments',
return_value=Namespace(
config=None))
cls.patcher.start()

prefix = '__TestEndpointsHandlerWithAuth_'
# create password file
cls.pwd_file = tempfile.NamedTemporaryFile(
mode='w+t', prefix=prefix, suffix='.txt', delete=False)
cls.pwd_file.write('username {}'.format(
hashlib.sha3_256('password'.encode('utf-8')).hexdigest()))
cls.pwd_file.close()

# create state.ini dir and file
cls.state_dir = tempfile.mkdtemp(prefix=prefix)
cls.state_file = open(os.path.join(cls.state_dir, 'state.ini'), 'w+')
cls.state_file.write('[Service Info]\n'
'Name = TabPy Serve\n'
'Description = \n'
'Creation Time = 0\n'
'Access-Control-Allow-Origin = \n'
'Access-Control-Allow-Headers = \n'
'Access-Control-Allow-Methods = \n'
'\n'
'[Query Objects Service Versions]\n'
'\n'
'[Query Objects Docstrings]\n'
'\n'
'[Meta]\n'
'Revision Number = 1\n')
cls.state_file.close()

# create config file
cls.config_file = tempfile.NamedTemporaryFile(
mode='w+t', prefix=prefix, suffix='.conf', delete=False)
cls.config_file.write(
'[TabPy]\n'
'TABPY_PWD_FILE = {}\n'
'TABPY_STATE_PATH = {}'.format(
cls.pwd_file.name,
cls.state_dir))
cls.config_file.close()

@classmethod
def tearDownClass(cls):
cls.patcher.stop()
os.remove(cls.pwd_file.name)
os.remove(cls.state_file.name)
os.remove(cls.config_file.name)
os.rmdir(cls.state_dir)

def get_app(self):
self.app = TabPyApp(self.config_file.name)
return self.app._create_tornado_web_app()

def test_no_creds_required_auth_fails(self):
response = self.fetch('/endpoints')
self.assertEqual(401, response.code)

def test_invalid_creds_fails(self):
response = self.fetch(
'/endpoints',
method='GET',
headers={
'Authorization': 'Basic {}'.
format(
base64.b64encode('user:wrong_password'.encode('utf-8')).
decode('utf-8'))
})
self.assertEqual(401, response.code)

def test_valid_creds_pass(self):
response = self.fetch(
'/endpoints',
method='GET',
headers={
'Authorization': 'Basic {}'.
format(
base64.b64encode('username:password'.encode('utf-8')).
decode('utf-8'))
})
self.assertEqual(200, response.code)

0 comments on commit fb0f4b8

Please sign in to comment.