-
Notifications
You must be signed in to change notification settings - Fork 362
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Detailed logging using databases (#151)
* Adding initial dabase concept. * Initial passing of unit tests. * Refactored db call. Still WIP. * Fixed db name. * Updated DB path. * LogDB working locally but not updating from Docker container out. * Migrated DB inserts to Cover Agent. * Added documentation for DB. * Fixed UnitTestDB tests. * Fixed default DB creation. * Reverting test. * Resolved empty DB path assertion. * Added before/after tests into DB. * Fixed arg call for validate test.
- Loading branch information
1 parent
9634b99
commit e9f9467
Showing
16 changed files
with
1,704 additions
and
1,148 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
from datetime import datetime | ||
from sqlalchemy import create_engine, Column, Integer, String, Text, DateTime | ||
from sqlalchemy.ext.declarative import declarative_base | ||
from sqlalchemy.orm import sessionmaker, scoped_session, load_only | ||
from sqlalchemy.orm.exc import NoResultFound | ||
|
||
Base = declarative_base() | ||
|
||
class UnitTestGenerationAttempt(Base): | ||
__tablename__ = 'unit_test_generation_attempts' | ||
id = Column(Integer, primary_key=True) | ||
run_time = Column(DateTime, default=datetime.now) # Use local time | ||
status = Column(String) | ||
reason = Column(Text) | ||
exit_code = Column(Integer) | ||
stderr = Column(Text) | ||
stdout = Column(Text) | ||
test_code = Column(Text) | ||
imports = Column(Text) | ||
original_test_file = Column(Text) | ||
processed_test_file = Column(Text) | ||
|
||
class UnitTestDB: | ||
def __init__(self, db_connection_string): | ||
self.engine = create_engine(db_connection_string) | ||
Base.metadata.create_all(self.engine) | ||
self.Session = scoped_session(sessionmaker(bind=self.engine)) | ||
|
||
def insert_attempt(self, test_result: dict): | ||
with self.Session() as session: | ||
new_attempt = UnitTestGenerationAttempt( | ||
run_time=datetime.now(), # Use local time | ||
status=test_result.get("status"), | ||
reason=test_result.get("reason"), | ||
exit_code=test_result.get("exit_code"), | ||
stderr=test_result.get("stderr"), | ||
stdout=test_result.get("stdout"), | ||
test_code=test_result.get("test", {}).get("test_code", ""), | ||
imports=test_result.get("test", {}).get("new_imports_code", ""), | ||
original_test_file=test_result.get("original_test_file"), | ||
processed_test_file=test_result.get("processed_test_file"), | ||
) | ||
session.add(new_attempt) | ||
session.commit() | ||
return new_attempt.id | ||
|
||
def select_all_attempts(self): | ||
with self.Session() as session: | ||
return session.query(UnitTestGenerationAttempt).all() | ||
|
||
def select_attempt(self, attempt_id): | ||
with self.Session() as session: | ||
try: | ||
return session.query(UnitTestGenerationAttempt).filter_by(id=attempt_id).one() | ||
except NoResultFound: | ||
return None | ||
|
||
def select_attempt_in_range(self, start: datetime, end: datetime): | ||
with self.Session() as session: | ||
return session.query(UnitTestGenerationAttempt).filter( | ||
UnitTestGenerationAttempt.run_time >= start, | ||
UnitTestGenerationAttempt.run_time <= end | ||
).all() | ||
|
||
def select_attempt_flat(self, attempt_id): | ||
with self.Session() as session: | ||
try: | ||
result = session.query(UnitTestGenerationAttempt).filter_by(id=attempt_id).options( | ||
load_only( | ||
UnitTestGenerationAttempt.id, | ||
UnitTestGenerationAttempt.run_time, | ||
UnitTestGenerationAttempt.status, | ||
UnitTestGenerationAttempt.reason, | ||
UnitTestGenerationAttempt.exit_code, | ||
UnitTestGenerationAttempt.stderr, | ||
UnitTestGenerationAttempt.stdout, | ||
UnitTestGenerationAttempt.test_code, | ||
UnitTestGenerationAttempt.imports, | ||
UnitTestGenerationAttempt.original_test_file, | ||
UnitTestGenerationAttempt.processed_test_file, | ||
) | ||
).one().__dict__ | ||
return result | ||
except NoResultFound: | ||
return None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
0.1.48 | ||
0.1.49 |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# Using a Test Database with Cover Agent | ||
Note: This feature is still in beta | ||
|
||
## Requirements | ||
Currently, only SQLite is supported. [SQLite](https://www.sqlite.org/) uses a local `.db` file to write to and read from (versus a server based database). The long term goal is to use any type of database that is support by [SQLAlchemy](https://www.sqlalchemy.org/). | ||
|
||
You'll need to have SQLite installed in order to view the tables but to get started you can just create an empty `.db` file using the `touch` command. For example: | ||
``` | ||
touch run_tests.db | ||
``` | ||
|
||
## Running with an external DB | ||
You can run Cover Agent using the `--log-db-path` option. For example: | ||
``` | ||
cover-agent \ | ||
--source-file-path "templated_tests/python_fastapi/app.py" \ | ||
--test-file-path "templated_tests/python_fastapi/test_app.py" \ | ||
--code-coverage-report-path "templated_tests/python_fastapi/coverage.xml" \ | ||
--test-command "pytest --cov=. --cov-report=xml --cov-report=term" \ | ||
--test-command-dir "templated_tests/python_fastapi" \ | ||
--coverage-type "cobertura" \ | ||
--desired-coverage 70 \ | ||
--max-iterations 10 \ | ||
--log-db-path "run_tests.db" | ||
``` | ||
|
||
Cover Agent will create a table called `unit_test_generation_attempts` within the database. | ||
|
||
## Integration Tests | ||
You can run the integration test suite and pass in the local `.db` to each Docker container with the following (example) command at the root of this repository: | ||
``` | ||
LOG_DB_PATH="<full_path_to_root_folder>/run_tests.db" tests_integration/test_all.sh | ||
``` | ||
|
||
## Observing the test data | ||
You can look at the test results using an external database reader or the basic SQLite command line tool: | ||
``` | ||
sqlite3 run_tests.db | ||
``` | ||
|
||
Once in SQLite you can show the tables and observe that after running some tests a table called `unit_test_generation_attempts` has been created: | ||
``` | ||
sqlite> .tables | ||
unit_test_generation_attempts | ||
``` | ||
|
||
To get the definition of our table we can run: | ||
``` | ||
sqlite> PRAGMA table_info(unit_test_generation_attempts); | ||
0|id|INTEGER|1||1 | ||
1|run_time|DATETIME|0||0 | ||
2|status|VARCHAR|0||0 | ||
3|reason|TEXT|0||0 | ||
4|exit_code|INTEGER|0||0 | ||
5|stderr|TEXT|0||0 | ||
6|stdout|TEXT|0||0 | ||
7|test_code|TEXT|0||0 | ||
8|imports|TEXT|0||0 | ||
``` | ||
|
||
A simple `select * from unit_test_generation_attempts;` query will display all test results (which include formatted carriage returns). This may be a bit difficult to look at from the command line so using a GUI would probably serve you a bit better. | ||
|
||
You can also filter the results to show only failed tests, for example: | ||
``` | ||
sqlite> select * from unit_test_generation_attempts where status = "FAIL"; | ||
``` |
File renamed without changes.
Oops, something went wrong.