Skip to content

DSmolke/Flota

Repository files navigation

logo

Flota - microservices

The Fleet is an application designed for managing corporate fleets. Its purpose is to optimize the processes of repairs, insurance, inspections, and vehicle rentals.

Python Flask React Gunicorn Nginx Docker MySQL AWS Selenium


Navigation:

DEV Stories | Microservices | How to use | Features | How to install & test

Read in different languages: plPL gbEN



2024-02-0210-15-08-ezgif com-video-to-gif-converter



DEV Stories


Migrations

At first, my convention was to use a regular alembic to create a global migration for the entire project. This was a suboptimal solution that didn't naturally separate migrations for each of the microservices. That's why I decided to use flask-migrate in each microservice.

Tests

I conducted them following the guidelines from the documentation - https://flask.palletsprojects.com/en/3.0.x/testing/. For their execution, I used a separate test database. During their execution, I made an effort to clear table rows before each test iteration.

Cors

At the beginning of development I decided to store CORS policies for any URL with suffix '/*' in separate package inside of 'configuration.py' module. Although this implementation gives more separation between domains of configuration my call is to store it directly in app context, because it gives more compact code. Also storing policies in .env file looks like a 'overkill' to me.

Coverage and Sphinx Documentation

Once coverage and sphinx docs are generated, they need to be deployed on separate as GitHub pages, and then removed from main repository to avoid messing up with 'Languages' highlights of repository. Here is example before and after:

image image

pipenv vs poetry

At this particular project I decided to use pipenv over poetry as it seems to be more stable and up-to-date tool for virtual environments.

Loading env variables redundancy

By reviewing code we can see that when it comes to loading environment variables I use python-dotenv package. Because every env file has '.env' filename, theoretically there is no need for using dotenv as pipenv loads those variables by default whenever their path is parallel with Pipfile. But dotenv will definitely will pay off then different naming conventions will see a daylight. Like 'test.env', 'serviceX.env', so I prefer to use this external package.

Making API Routes more orthogonal

Creating routes for the "repairs" microservice, I began to wonder if I could introduce an implementation of connecting resources to the API that would be as orthogonal as possible to the application context in which configuration takes place. Orthogonality is the abstraction of a state in which changes in one element of the system do not affect its other elements. The approach I had developed so far was simple. Create a resource, import it into the configuration space, and finally add it to the existing API.

image image

However, I often had to repeat this procedure for several resources. According to the principle of orthogonality, a change in one module should not necessitate changes outside of it. That's why I created the "RepairEndpointsMapper", where I define the resources I want to attach to the API on the fly.

image

The API itself is passed when the class is called. This way, the procedure transforms into: Assign the resource along with the path to the mapper, import the mapper, pass the API, and call the "init_endpoints" method. Now, if we want to add a resource, we simply add it to the mapper.

image

image

Using selenium in a console environment of a Docker container

Automatic settings of a sample Chrome web driver in selenium force us to install the Chromium engine in our environment and to use an output device, such as our monitor. However, in order to commercially create automation systems, we need to adapt to working in a Debian environment without extensions emulating a monitor.

Using the example of the cepik microservice, which verifies whether our car has valid insurance and inspection, I will demonstrate how I configured selenium objects to work in a Docker container.

1. Installing Google Chrome in a container with Debian

In the Dockerfile of our microservice, we invoke commands to install the stable version of Google Chrome.

image

2. Adding arguments to the selenium.webdriver.chrome.options.Options object to enable the proper functioning of the Selenium driver

In my code, I created a ChromeOptionsBuilder, which provides all the necessary options that we need to add to the object.

image

--no-sandbox allows avoiding issues with session creation.

image

--no-screen disables the need for a screen.

--disable-dev-shm-usage changes the cache location from shm to tmp, providing greater flexibility if multiple objects are working on shm.

image

The final creation of a driver that works correctly in a Docker container, considering the implementation of the options builder, looks as follows:

image

Where to mock?

When creating unittests, attention should be paid to where to mock functions. For example, if I'm creating a module a.py containing the function get_roberts_name, mocking should focus on that function.

def get_roberts_name() -> str:
    return 'Robert'

Now we create module b.py, which will be importing get_roberts_name

from a import get_roberts_name

def top_customer() -> str:
    return get_roberts_name()

Assuming we want to test top_customer, but we don't want to depend on get_roberts_name

THE CORRECT PLACE OF MOCKING get_roberts_name IS b.py AND NOT a.py

βœ… diff at line 5

import pytest
from b import top_customer

def test_top_customer(mocker) -> None:
    mocker.patch('b.get_roberts_name', side_effect=lambda *args, **kwargs: 'Adam')
    assert top_customer() == 'Adam' # True

β›” diff at line 5

import pytest
from b import top_customer

def test_top_customer(mocker) -> None:
    mocker.patch('a.get_roberts_name', side_effect=lambda *args, **kwargs: 'Adam')
    assert top_customer() == 'Adam' # False


Microservices


microservice wiki coverage
api-gateway
cars link link
mots link link
insurances link link
repairs link link
aws-resources
cepik link link
external-resources-factory
drivers link link
notifications
scheduler


How to use


Deployed app πŸš€ SOON



Features


Functionality State Demo
CRUD Operations on Car βœ…
Authorization βœ…
Registration βœ…
Authentication via Email βœ…
CRUD Operations on Mot βœ…
CRUD Operations on Insurance βœ…
Storing static resources in Amazon S3 βœ…
Managing cars repairs βœ…
Validating MOT and Insurance using historia.pojazdu.gov βœ…
Generating full car history reports using historia.pojazdu.gov βœ…
Loading Cars, Mots, Insurances data from existing sources βœ…
CRUD Operations on Driver βœ…
Notifying Driver about expiring Mot and Insurance βœ…
Scheduling system notifications βœ…
UI πŸ› οΈ

βœ… done πŸ› οΈ in progress πŸ”œ planned



How to install & test


What is needed πŸ€”

βœ”οΈ Docker βœ”οΈ NodeJS βœ”οΈ Python 3.11 βœ”οΈ Current .env files - tutorial


Clone repository and enter it's directory 🧐

    git clone https://github.com/DSmolke/Flota.git
    cd Flota

Add current .env files into required directories 🧐

    ......

Run docker-compose to create containers 🧐

    docker-compose up -d --build

Find cars container id, migrate tables using flask_migrate 🧐

    docker ps
    docker exec -it <CONTAINER-ID> bash
    cd app
    pipenv run flask --app "create_app:main" db upgrade head

Run tests 🧐

    cd ..
    pipenv run pytest

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published