Skip to content
This repository has been archived by the owner on Sep 7, 2024. It is now read-only.

Commit

Permalink
test: python general test (#127)
Browse files Browse the repository at this point in the history
  • Loading branch information
kehiy authored Jul 15, 2024
1 parent 0c90cd3 commit 7f95dc8
Show file tree
Hide file tree
Showing 7 changed files with 317 additions and 4 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@ cmd/config.yaml
/client
log.ttrace
build/

# python cache files
test/__pycache__
8 changes: 5 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Contributing

Thank you for considering contributing to go-TimeTraceDB!
Thank you for considering contributing to TimeTrace!
Please read these guidelines before submitting a pull request or opening an issue.

## Code guidelines

We strive to maintain clean, readable, and maintainable code in go-TimeTraceDB.
We strive to maintain clean, readable, and maintainable code in TimeTrace.
Please follow these guidelines when contributing code to the project:

- Code should follow the [Effective Go](https://golang.org/doc/effective_go.html) guidelines.
Expand All @@ -24,6 +24,8 @@ The following commands are available in the Makefile:
- `make check` runs various checks on the code, including formatting and linting.
- `make test` runs the tests to ensure that all functionality is working as intended.

All golang and [python](./test/README.md) must be passed.

## Commit guidelines

Please follow these guidelines when committing changes to go-TimeTraceDB:
Expand Down Expand Up @@ -55,4 +57,4 @@ Please read it before contributing to the project.

---

Thank you for your contributions to go-TimeTraceDB!
Thank you for your contributions to TimeTrace!
2 changes: 1 addition & 1 deletion doc/TQL/TQL.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Time trace is using a query language called TQL. Here is documentation and speci
| CNTS * | returns count of sets | |
| CNTSS * | returns count of subsets | set-name |
| CNTE * | returns count of elements | set-name - subset-name |
| CLN * | cleans all database sets (the sets themselves) | set-name - subset-name |
| CLN * | cleans all database sets (the sets themselves) | |
| CLNS * | cleans all sub-sets of a set | set-name |
| CLNSS * | cleans all elements of a subset | set-name - subset-name |
| DRPS * | drops a set | set-name |
Expand Down
Empty file removed test/.keep
Empty file.
42 changes: 42 additions & 0 deletions test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Tests

This directory contains a set of python scripts for testing time-trace database. Each change or pull request must pass this test otherwise it won't be merged.

## Checklist

Here is a list of different tests which must be added here and their status:

| Test | Status |
| -------- | ------- |
| Normal test ||
| Concurrent test | ⚒️ |

## Test writing guide

All of test must be in form of functions. The functions name must start with keyword `test` and finish with the result of test such as `ok`, `ssnf`, `snf`, `invalid` and so on.

Example of function name:

Correct: `test_new_sub_set_ok`
Incorrect: `new_sub_set_test`
Incorrect: `new_subset_test`
Incorrect: `test_new_sub_set`

> [!NOTE]
> Consider following python naming convention and code style.
Each function must have description such as:
```python
"""
Connecting to database and creating a session.
Testing: CON TQL command
Error: null
"""
```

The first line(s) are description of test. The testing part describes what exactly the function is testing. And the error describe which kind of error the tets must return, if it was an OK test, you can use null as its value.

Since in we use a connection a server with once instance, consider that sometimes order of commands can affect the result of test so make sure you do them in correct order and restart database each time. For example you can't clean a set when you dropped it!

> [!IMPORTANT]
> Codes in this directory are not about benchmark, these are only for testing functionality of project, for benchmark please check benchmark directory.
256 changes: 256 additions & 0 deletions test/normal_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
import socket
import time
import utils
import random

#! GET method is not tested here now.
# TODO: writing test for method GET.
# TODO: adding test bad cases such as invalid set/subset name.
# TODO: popping items from global variables while dropping or cleaning them(?)
# TODO: adding python tests to github workflows.

st = time.time()

#? Global variables
sub_set_names = []
set_names = []
elements_value = []

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server_address = ('localhost', 7070) #! You can change port and host for testing.
sock.connect(server_address)

def test_connect_ok():
"""
Connecting to database and creating a session.
Testing: CON TQL command
Error: null
"""
query = "CON root super_secret_password" #! Considers you config is default.
response = utils.make_query(query, sock)

assert response == "OK", f"\033[91mCan't connect to server with default info, received: {response}, expected: OK\033[0m"

print(f"\033[32mReceived response: {response}, Connection test Passed.\033[32m")

def test_ping_ok():
"""
Ping the database to check session health.
Testing: PING TQL command
Error: null
"""
response = utils.make_query("PING", sock)

assert response == "PONG", f"\033[91mCan't ping the database, received: {response}, expected: PONG\033[0m"

print(f"\033[32mReceived response: {response}, we are connected!\033[32m")

def test_new_set_ok():
"""
Creating random sets.
Testing: SET TQL command
Error: null
"""
for i in range(10):
set_names.append(utils.get_random_string_name(i+2))

query = f"SET {set_names[i]}"
response = utils.make_query(query, sock)

assert response == "OK", f"\033[91mCan't create set: {set_names[i]}, received: {response}, expected: OK\033[0m"

print(f"\033[32mReceived response: {response}, {len(set_names)} sets created successfully.\nSets: {set_names}\033[32m")

def test_new_sub_set_ok():
"""
Creating random subsets for sets.
Testing: SSET command
Error: null
"""
for s in set_names:
for i in range(7):
sub_set_names.append(utils.get_random_string_name(i+2))

query = f"SSET {s} {sub_set_names[i]}"
response = utils.make_query(query, sock)

assert response == "OK", f"\033[91mCan't create subset: {sub_set_names[i]} in set {s}, received: {response}, expected: OK\033[0m"

print(f"\033[32mReceived response: {response}, {len(sub_set_names)} subsets created successfully.\nSubsets: {sub_set_names}\033[32m")

def test_push_element_ok():
"""
Pushing randomly generated elements in all created subsets.
Testing: PUSH TQL command
Error: null
"""
set_index = 0

for s in set_names:
for i in range(7):
for _ in range(1_000):
element_value = utils.get_random_string_name(i+8)
elements_value.append(element_value)

element_time = int(time.mktime(time.gmtime()))
query = f"PUSH {s} {sub_set_names[i]} {element_value} {element_time}"
response = utils.make_query(query, sock)

assert response == "OK", f"\033[91mCan't push element with value of: {elements_value[i]} and time of: {element_time}, received: {response}, expected: OK\033[0m"

set_index += 7

#? Change `elements_value[:10]` to get more or less elements.
print(f"\033[32mReceived response: {response}, {len(elements_value)} elements pushed successfully.\nElements: {elements_value[:10]}\033[32m")

def test_count_sets_ok():
"""
Counting all sets.
Testing: CNTS TQL command
Error: null
"""
response = utils.make_query("CNTS", sock)

assert response == str(len(set_names)), f"\033[91mCan't count sets, received: {response}, expected: {len(set_names)}\033[0m"

print(f"\033[32mReceived response: {response}, sets number counted successfully.\033[32m")

def test_count_sub_sets_ok():
"""
Counting all subsets.
Testing: CNTSS TQL command
Error: null
"""
sub_sets_count = 0

for s in set_names:
query = f"CNTSS {s}"
response = utils.make_query(query, sock)

sub_sets_count += int(response)

assert sub_sets_count == len(sub_set_names), f"\033[91mCan't count subsets, received: {sub_sets_count}, expected: {len(sub_set_names)}\033[0m"

print(f"\033[32mReceived response: {sub_sets_count}, subsets counted successfully.\033[32m")

def test_count_elements_ok():
"""
Counting all elements in all subsets.
Testing: CNTE TQL command
Error: null
"""
set_index = 0
elements_count = 0

for s in set_names:
for i in range(7):
query = f"CNTE {s} {sub_set_names[i]}"
response = utils.make_query(query, sock)

elements_count += int(response)

set_index += 7

assert elements_count == len(elements_value), f"\033[91mCan't count elements, received: {elements_count}, expected: {len(elements_value)}\033[0m"

print(f"\033[32mReceived response: {elements_count}, elements counted successfully.\033[32m")

def test_clean_sub_sets_elements_ok():
"""
Cleaning all elements in all subsets.
Testing: CLNSS TQL command
Error: null
"""
set_index = 0

for s in set_names:
for i in range(7):
query = f"CLNSS {s} {sub_set_names[i]}"
response = utils.make_query(query, sock)

assert response == "OK", f"\033[91mCan't clean subset: {sub_set_names[i]} of set {s}, received: {response}, expected: OK\033[0m"

set_index += 7

print(f"\033[32mReceived response: {response}, subset elements cleaned successfully.\033[32m")

def test_drop_sub_sets_ok():
"""
Dropping all subsets.
Testing: DRPSS TQL command
Error: null
"""
set_index = 0

for s in set_names:
for i in range(7):
query = f"DRPSS {s} {sub_set_names[i]}"
response = utils.make_query(query, sock)

assert response == "OK", f"\033[91mCan't drop subset: {sub_set_names[i]} from set: {s}, received: {response}, expected: OK\033[0m"

set_index += 7

print(f"\033[32mReceived response: {response}, subsets dropped successfully.\033[32m")

def test_clean_sub_sets_ok():
"""
Cleaning all subsets in all sets.
Testing: CLNS TQL command
Error: null
"""
for s in set_names:
query = f"CLNS {s}"
response = utils.make_query(query, sock)

assert response == "OK", f"\033[91mCan't clean set: {s}, received: {response}, expected: OK\033[0m"

print(f"\033[32mReceived response: {response}, sets cleaned successfully.\033[32m")

def test_drop_sets_ok():
"""
Dropping all sets.
Testing: DRPS TQL command
Error: null
"""
for s in set_names:
query = f"DRPS {s}"
response = utils.make_query(query, sock)

assert response == "OK", f"\033[91mCan't drop set: {s}, received: {response}, expected: OK\033[0m"

print(f"\033[32mReceived response: {response}, sets dropped successfully.\033[32m")

def test_clean_sets_ok():
"""
Cleaning all sets.
Testing: CLN TQL command
Error: null
"""
response = utils.make_query("CLN", sock)

assert response == "OK", f"\033[91mCan't clean sets, received: {response}, expected: OK\033[0m"

print(f"\033[32mReceived response: {response},sets cleaned successfully.\033[32m")


def main():
test_connect_ok()
test_ping_ok()
test_new_set_ok()
test_new_sub_set_ok()
test_push_element_ok()
test_count_sets_ok()
test_count_sub_sets_ok()
test_count_elements_ok()
test_clean_sub_sets_elements_ok()
test_drop_sub_sets_ok()
test_clean_sub_sets_ok()
test_drop_sets_ok()
test_clean_sets_ok()

if __name__ == "__main__":
main()
sock.close()
print('\033[34mAll tests successfully passed in:\033[34m', time.time() - st, 'seconds')
10 changes: 10 additions & 0 deletions test/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import random
import string
import socket

def get_random_string_name(length: int) -> str:
return ''.join(random.choice(string.ascii_lowercase) for i in range(length))

def make_query(query: str, sock: socket.socket) -> str:
sock.sendall(query.encode())
return sock.recv(1024).decode()

0 comments on commit 7f95dc8

Please sign in to comment.