Skip to main content

pyFuncTest

The framework for functional testing of microservices

Functional сapabilities:

  1. Build a container from git repository
  2. Create, start and stop containers
  3. Send and receive messages from Kafka, RabbitMQ
  4. Write and read data from mySQL, MariaDB, PostgreSQL
  5. Write and read files from FTP, MinIO

Additional:

  1. You can create folders before running tests for FTP, MinIO
  2. You can migrate structure and data before running tests for databases
  3. You can replace configuration and other files inside container before work
  4. You can run docker services in a specific sequence before running tests

Table of Contents

Install

pip3 install pyfunctest

Upgrade

pip3 install --upgrade pyfunctest

How it works

Settings of modules

The main module is FMods. Its constructor has three parameters: path to settings, path to template folder and verbose. The example of structure settings: https://github.com/Lunkov/pyfunctest/tree/master/data/mods

The example commands for tests

import unittest

class TestServices(unittest.TestCase):

  def setUp(self):
    # New object of settings of modules
    self.fm = FMods("mods/", "tmp/", True)

    # Read settings
    self.fm.scan()

    # Run all containers
    self.fm.startAll()

  def testReceiveMessage(self):
    # New object of RabbitMQ Client
    rabbitmq = self.fm.newRabbitMQ('rabbitmq')

    # Create routes
    queue = 'log3'
    exchange = 'log3'
    routing_key = ''
    exchange_type = 'fanout'	
    self.assertTrue(rabbitmq.createRoute(exchange, exchange_type, routing_key, queue))

    # Send message
    self.assertTrue(rabbitmq.send(exchange, routing_key, 'message 1'))    

    # New object of PostgreSQL Client
    pg = self.fm.newPostgre('pg')

    # Check structure of database
    self.assertEqual(pg.getTableList(), [('public', 'messages')])

    # Get and check data from table
    self.assertEqual(pg.getData('select * from public.messages'), [(1, 'message 1')])

  
  def tearDown(self):
    # Stop all containers
    self.fm.stopAll()

if __name__ == '__main__':
  unittest.main()

Docker

Build container

Example file .yaml

name: srv-report
actions:
  - build

git:
  src: "https://github.com/Lunkov/srv-report.git"
  branch: master

docker:
  name: srv-report-test
  src: srv-report-test

  dockerfile: Dockerfile
  buildpath: .

Commands for tests

# New object of settings of modules
fm = FMods("mods/", "tmp/", True)

# Read settings
fm.scan()

# Get module
srvDocker = fm.newDocker('srv-report')

# Container must have status: not found
self.assertTrue(srvDocker.statusWaiting('not found'))

# Build container
self.assertTrue(srvDocker.build())

# Run container
self.assertTrue(srvDocker.run())

Start container

Example file .yaml

name: nginx
order: 10
actions:
  - run

docker:
  name: nginx-test
  src: nginx
  ports:
    - "3010:81"

  env:
    - NGINX_PORT: 81
  
  volumes:
    - "data/mods/nginx/html/:/usr/share/nginx/html:ro"
    - "data/mods/nginx/test.conf:/etc/nginx/conf.d/default.conf"

Commands for tests

# New object of settings of modules
fm = FMods("mods/", "tmp/", True)

# Read settings
fm.scan()

# Get module
srvNginx = fm.newDocker('nginx')

# Run container
self.assertTrue(srvNginx.run())

# Container must have status: running
self.assertEqual(srvNginx.status(), 'running')

Start compose

Example file .yaml

name: kafka
order: 1
actions:
  - run
  - init

docker:
  name: kafka_kafka-test_1
  compose: docker-compose.yml

  network: test-net

  init:
    create_channels:
      - channel-test
      - channel1-test
      - channel2-test

kafka:
  url_inside: "localhost:9092"
  url_outside: "localhost:9094"
  id_group: main

Commands for tests

# New object of settings of modules
fm = FMods("mods/", "tmp/", True)

# Read settings
fm.scan()

# Get module
srvDocker = fm.newDocker('kafka') # Docker Compose

# Run container
self.assertTrue(srvDocker.startCompose())

# Container must have status: running
self.assertEqual(srvDocker.status(), 'running')

# Stop container
self.assertTrue(srvDocker.stopCompose())

FTP

Settings

Example file .yaml

name: ftp
order: 5
actions:
  - run

docker:
  name: ftp-test
  src: teezily/ftpd
  ports:
    - "3021:21"
    - "35000-35004:35000-35004"

  patch:
    - start-ftp: /
  env:
    - FTP_USER: user
    - FTP_PASSWORD: pwd
    - PASV_MIN_PORT: 35000
    - PASV_MAX_PORT: 35004

ftp:
  user: user
  password: pwd
  port: 3021
  init:
    # You can create folders before running tests
    create_folders:
      - folder-test/folder-test1
      - folder-test/folder-test2
      - folder-test1

Testing

# New object of FTP Client
ftp = fm.newFTP('ftp')

# Check structure of folder
self.assertEqual(ftp.getDirList(), ['incoming'])

# Upload file
self.assertTrue(ftp.uploadFile('folder-test', 'test.txt', 'data/files/test.txt'))

# Compare local and remote files 
self.assertTrue(ftp.compareFiles('folder-test', 'test.txt', 'data/files/test.txt'))

Minio

Settings

Example file .yaml

name: minio
order: 6
actions:
  - run
  - init

docker:
  name: minio-test
  src: minio/minio
  ports:
    - "3010:9000"

  run_command: "server /data"


s3:
  access_key: minioadmin
  secret_key: minioadmin
  port: 3010
  init:
    # You can create folders before running tests
    create_folders:
      - "bucket-test:folder000"
      - "bucket-test2:folder1/folder1"

Testing

# New object of Minio Client
minio = fm.newMinIO('minio')

# Check structure of basket
self.assertEqual(minio.getBasketsList(), ['bucket-test'])

# Upload file
self.assertTrue(minio.uploadFile('bucket-test', 'test.txt', 'data/files/test.txt'))

# Compare local and remote files 
self.assertTrue(minio.compareFiles('bucket-test', 'test.txt', 'data/files/test.txt'))

MySQL

Settings

Example file .yaml

name: mysql
order: 2
actions:
  - run
  - migrate

docker:
  name: mysql-test
  src: mariadb

  ports:
    - "17436:3306"

  # You can replace configuration file inside container before work
  patch: 
    - 50-server.cnf: /etc/mysql/mariadb.conf.d/

  env:
    - MYSQL_ROOT_PASSWORD: pwd
    - MYSQL_USER: user
    - MYSQL_PASSWORD: pwd
    - MYSQL_DATABASE: test-db
    - ALLOW_EMPTY_PASSWORD: yes

db:
  name: test-db
  user: root
  password: pwd
  port: 17436

# You can migrate your data before tests
migrate:
  command: "--path=/migrations/ --database=\"mysql://root:pwd@tcp(mysql-test:3306)/test-db\" up"
  path: migrations
  timeout_before_migrate: 10

Testing

Commands for tests

# New object of mySQL Client
msql = fm.newMySQL('mysql')

# Check structure of database
self.assertEqual(msql.getTableList(), ['article', 'article2', 'article3'])

# Create table
self.assertTrue(msql.loadSQL('data/mysql/create_tables.sql'))

# Insert Data
self.assertTrue(msql.loadSQL('data/mysql/insert.sql'))

# Get and check data from table
self.assertEqual(msql.getData('select * from article'), ((1, 'article 1', 'description'),))

PostgreSQL

Settings

Example file .yaml

name: pg
actions:
  - run
  - migrate

docker:

  name: pg-test
  src: postgres:alpine
  ports:
    - "17432:5432"
  env:
    - POSTGRES_PASSWORD: pwd
    - POSTGRES_USER: user
    - POSTGRES_DB: test-db

db:
  name: test-db
  user: user
  password: pwd
  port: 17432

migrate:
  command: --path=/migrations/ --database="postgres://user:pwd@pg-test:5432/test-db?sslmode=disable" up
  path: migrate
  timeout_before_migrate: 5

Testing

# New object of PostgreSQL Client
pg = fm.newPostgre('pg')

# Check structure of database
self.assertEqual(pg.getTableList(), [('public', 'article'), ('public', 'article2'), ('public', 'article3')])

# Create table
self.assertTrue(pg.loadSQL('data/postgre/create_table.sql'))

# Insert Data
self.assertTrue(pg.loadSQL('data/postgre/insert.sql'))

# Get and check data from table
self.assertEqual(pg.getData('select * from public.article'), [(1, 'article 1', 'description', None)])

RabbitMQ

Settings

Example file .yaml

name: rabbitmq
actions:
  - run
  - init

docker:
  name: rabbitmq-test
  src: rabbitmq:management-alpine
  ports:
    - "5672:5672"
    - "15672:15672"
  env:
    - RABBITMQ_DEFAULT_USER: user
    - RABBITMQ_DEFAULT_PASS: pwd
    - RABBITMQ_DEFAULT_VHOST: /


rabbitmq:
  url: "amqp://user:pwd@localhost:5672/"
  user: user
  password: pwd
  init:
    # You can create channels before running tests
    create_channels:
      - "log3:fanout::log3"
      - "log1:fanout::log1"

Testing

# New object of RabbitMQ Client
rabbitmq = fm.newRabbitMQ('rabbitmq')

# Create routes
self.assertTrue(rabbitmq.createRoute(exchange, exchange_type, routing_key, queue))

# Send message
self.assertTrue(rabbitmq.send(exchange, routing_key, 'message 1'))

# Recieve message
msg, ok = rabbitmq.receive(queue)
self.assertTrue(ok)
self.assertEqual(msg, 'message 1')

# Send file
self.assertTrue(rabbitmq.sendFile(exchange, routing_key, 'data/files/test.txt'))

# Recieve and compare file
self.assertTrue(rabbitmq.receiveAndCompareFile(queue, 'data/files/test.txt'))

Kafka

Settings

Example file .yaml

name: kafka
order: 1
actions:
  - run
  - init

docker:
  name: kafka_kafka-test_1
  compose: docker-compose.yml

  network: test-net

  init:
    # You can create channels before running tests
    create_channels:
      - channel-test
      - channel1-test
      - channel2-test

kafka:
  url_inside: "localhost:9092"
  url_outside: "localhost:9094"
  id_group: main

Testing

# New object of Kafka Client
kafka = fm.newKafka('kafka')

# Send message
self.assertTrue(kafka.send(channel, 'message 1'))

# Recieve message
msg, ok = kafka.receive(channel)
self.assertTrue(ok)
self.assertEqual(msg, 'message 1')

# Send file
self.assertTrue(kafka.sendFile(channel, 'data/files/test.txt'))

# Recieve and compare file
self.assertTrue(kafka.receiveAndCompareFile(channel, 'data/files/test.txt'))

Metadata

Release files for pyfunctest 0.0.6

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pyfunctest 0.0.6
File Size Uploaded Provenance
pyfunctest-0.0.6.tar.gz 17.5 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for pyfunctest 0.0.6
File Interpreter ABI Platform
pyfunctest-0.0.6-py3-none-any.whl Python 3 none any Details

Total release size: 42.7 kB

Release files / pyfunctest-0.0.6.tar.gz

Download URL pyfunctest-0.0.6.tar.gz
Size 17.5 kB
Tags Source
SHA-256 checksum
How to use checksums
291acc56f8c7aac07860ed7ce92877705022abea69c8a73b64394157953f8de9
BLAKE2b-256 checksum
How to use checksums
0ac56ce93be8993e93558105e8d3023eef280d22426af9a80b4f4d2d5e91e0bc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.4.2 importlib_metadata/4.6.4 pkginfo/1.7.1 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.60.0 CPython/3.8.10

Release files / pyfunctest-0.0.6-py3-none-any.whl

Download URL pyfunctest-0.0.6-py3-none-any.whl
Size 25.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5891b8ad4b94916a8467b0fbfceb57c8ec71ad3c8d68892fb7c90f84e2ee682a
BLAKE2b-256 checksum
How to use checksums
66101be4de0c023c5dde0189d69eb2c878466d64a85dd0ce90ae71d1a51a570c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.4.2 importlib_metadata/4.6.4 pkginfo/1.7.1 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.60.0 CPython/3.8.10

Security for pyfunctest 0.0.6

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.0.6 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page