Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
116 changes: 116 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Byte-compiled / optimized / DLL files
__pycache__/
.pytest_cache/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
include/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
pip-selfcheck.json
bin/

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# IPython Notebook
.ipynb_checkpoints

# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# dotenv
.env

# virtualenv
venv/
ENV/
*_venv/

# Spyder project settings
.spyderproject

# Rope project settings
.ropeproject

# idea
.idea/

# miscellaneous files
log/
.DS_Store
baseline_coverage/
.docker_config/
reports/

# intellij
*.iml

# vs code
*.vscode

# Pact files
.pacts/

# SonarQube
.scannerwork/
34 changes: 34 additions & 0 deletions INSTALL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@


# Shorter URL Application
This application contains the APIs for translate long URLs in short URLs.

## Getting Started
#### First make sure you run this code in a virtual environment:

* pip (or conda) package manager are required
`python3 -m venv shorter_venv`
`source shorter_venv/bin/activate`


#### Now to get the app running:

1. Create a build `./build.sh`
2. Start the local dev server `./server.sh`
3. Check that the app is running: http://localhost:5000/shorter/healthcheck/
4. For Unit test execute `pytest`
5. For Feature test execute `behave`


## Database

### Applying Changes
Alembic is in implementation process

###TODO:

* Complete UT for all APIs
* Change SQL DB for some NON-SQL DB
* Dockerize
* Add log
* Test date object properly
20 changes: 20 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env bash

echo "Installing Requirements"
pip install -r requirements.txt

echo "Auto-formatting code"
#black .

echo "Running Unit Tests"
if ! pytest; then
echo "One or more unit tests failed"
exit 1
fi

echo "Running System Tests"
if ! behave; then
echo "One or more system tests failed"
exit 1
fi
echo "Build Done!"
Empty file added features/__init__.py
Empty file.
92 changes: 92 additions & 0 deletions features/api.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
Feature: Test Shorter API

Scenario: Healthcheck
When I test healthcheck
Then I get status code 200
And the value of Service is OK

Scenario: Get a short URL list
When I get a valid short URL with a valid code
Then I get status code 200


Scenario: Create a short URL
When I post a valid short URL with a valid code
Then I get status code 201
And the code is correct


Scenario: Create a short URL without code
When I post a valid short URL without code
Then I get status code 201
And the code is correct


Scenario: Invalid URL
When I post an invalid URL
Then I get status code 400
And the value of Error is ERROR_INVALID_URL


Scenario: Missing URL
When I post a missing URL
Then I get status code 400
And the value of Error is ERROR_URL_IS_REQUIRED


Scenario: Invalid code
When I post an invalid code
Then I get status code 400
And the value of Error is ERROR_INVALID_CODE


Scenario: Duplicated code
When I post a valid short URL with a valid code
Then I get status code 201
And the code is correct
When I post a valid short URL with the same valid code
Then I get status code 409
And the value of Error is ERROR_DUPLICATED_CODE


Scenario: Get code
When I post a valid short URL with a valid code and URL http://url.com
Then I get status code 201
And the code is correct
When I get the same valid code
Then I get status code 302
And the value for location header is http://url.com


Scenario: Get invalid code
When I get an invalid code
Then I get status code 404
And the value of Error is ERROR_CODE_NOT_FOUND


Scenario: Get code stats
When I post a valid short URL with a valid code and URL http://url.com
Then I get status code 201
And the code is correct
When I get the same valid code
Then I get status code 302
And the value for location header is http://url.com

When I get the same valid code
Then I get status code 302
And the value for location header is http://url.com

When I get the same valid code
Then I get status code 302
And the value for location header is http://url.com

When I get code stats
Then the value of created_at is a_valid_date
Then the value of last_usage is a_valid_date
Then the value of usage_count is 3


Scenario: Get an invalid code for stats
When I get invalid code stats
Then I get status code 404
And the value of Error is ERROR_CODE_NOT_FOUND
25 changes: 25 additions & 0 deletions features/environment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import os
import tempfile
from behave import fixture, use_fixture

from shorter_app.app import create_app
from shorter_app.database import init_db
from shorter_app.config import TestConfig


@fixture
def shorter_client(context, *args, **kwargs):
app = create_app(TestConfig)
context.db, app.config["DATABASE"] = tempfile.mkstemp()
app.testing = True
context.client = app.test_client()
with app.app_context():
init_db()
yield context.client
# -- CLEANUP:
os.close(context.db)
os.unlink(app.config["DATABASE"])


def before_feature(context, feature):
use_fixture(shorter_client, context)
Empty file added features/steps/__init__.py
Empty file.
Loading