Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

compatibility Test coverage #1057

Open
wants to merge 19 commits into
base: mainline
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
949b741
Test coverage
adityabharadwaj198 Nov 29, 2024
3a0ad93
Most tests run
adityabharadwaj198 Dec 2, 2024
c4eda2b
Added one assertion statement
adityabharadwaj198 Dec 2, 2024
bab9337
Made tests work
adityabharadwaj198 Dec 3, 2024
a834c9f
Removed docker_manager.py for now
adityabharadwaj198 Dec 3, 2024
44d37f9
Fixed exception handling and changed log level
adityabharadwaj198 Dec 3, 2024
4d6f2ae
Fixed exception handling and changed log level
adityabharadwaj198 Dec 3, 2024
fb07372
Merge remote-tracking branch 'origin/aditya/comp-test-coverage' into …
adityabharadwaj198 Dec 3, 2024
4c6cb9f
Moved all docker related logic to a seperate docker class & started u…
adityabharadwaj198 Dec 3, 2024
5b5eea6
Removed docker related logic which was using command line
adityabharadwaj198 Dec 3, 2024
9921576
removing cleanup_containers() & cleanup_volumes() method
adityabharadwaj198 Dec 6, 2024
64047cf
Addressing comments
adityabharadwaj198 Dec 11, 2024
6cd7885
Adding some more tests acc to post 2.0.0 API evolution
adityabharadwaj198 Dec 18, 2024
4bc2084
Fixing full_test_run for Rollback. Do I need to fix it for bw-comp also?
adityabharadwaj198 Dec 20, 2024
f2e5068
More tests to increase coverage. Contains all of data types for creat…
adityabharadwaj198 Dec 20, 2024
c95be2c
More tests + fix some issues with test
adityabharadwaj198 Dec 24, 2024
f84825d
Updating changed folder name for compatibility_tests, and adding a re…
adityabharadwaj198 Dec 24, 2024
b940b01
Fixing some test failures
adityabharadwaj198 Dec 24, 2024
cf68c99
Fixing some more test failures
adityabharadwaj198 Dec 26, 2024
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
743 changes: 0 additions & 743 deletions tests/backwards_compatibility_tests/compatibility_test_runner.py

This file was deleted.

4 changes: 0 additions & 4 deletions tests/backwards_compatibility_tests/requirements.txt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import pytest
from tests.compatibility_tests.base_test_case.base_compatibility_test import BaseCompatibilityTestCase

@pytest.mark.marqo_version('2.0.0')
class TestAddDocuments(BaseCompatibilityTestCase):
structured_index_name = "test_add_doc_api_structured_index"
unstructured_index_name = "test_add_doc_api_unstructured_index"

indexes_to_test_on = [{
"indexName": structured_index_name,
"type": "structured",
"model": "sentence-transformers/all-MiniLM-L6-v2",
"normalizeEmbeddings": False,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-normalized indexes need to be covered, but are unusual. If covering one, we should cover normalized

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

"allFields": [
{"name": "Title", "type": "text"},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You get the best coverage if you have all data types. That does mean you will need extra tests as some types were added in later versions. This comment applies to both index types.

{"name": "Description", "type": "text"},
{"name": "Genre", "type": "text"},
],
"tensorFields": ["Title", "Description", "Genre"],
},
{
"indexName": unstructured_index_name,
"type": "unstructured",
"model": "sentence-transformers/all-MiniLM-L6-v2",
"normalizeEmbeddings": False,
}]

text_docs = [{
"Title": "The Travels of Marco Polo",
"Description": "A 13th-century travelogue describing the travels of Polo",
"Genre": "History",
"_id": "article_602"
},
{
"Title": "Extravehicular Mobility Unit (EMU)",
"Description": "The EMU is a spacesuit that provides environmental protection",
"_id": "article_591",
"Genre": "Science"
}]
@classmethod
def tearDownClass(cls) -> None:
cls.indexes_to_delete = [index['indexName'] for index in cls.indexes_to_test_on]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could also do this in setupclass, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am using setupClass in prepare mode to create Marqo client and do other basic setup. I don't want to delete any indexes in prepare mode, I only want to delete an index after it has been thoroughly tested which happens after Test mode run finishes, so I've added it in tearDownClass() which will directly be called after a test run (executed by Test mode) finishes

super().tearDownClass()

@classmethod
def setUpClass(cls) -> None:
super().setUpClass()

def prepare(self):
self.logger.info(f"Creating indexes {self.indexes_to_test_on} in test case: {self.__class__.__name__}")
self.create_indexes(self.indexes_to_test_on)

try:
self.logger.debug(f'Feeding documents to {self.indexes_to_test_on}')
for index in self.indexes_to_test_on:
if index.get("type") is not None and index.get('type') == 'structured':
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem with the way this is written is if the test fails for one index type, it doesn't run for the other. You need either subtests (if you can make that work here) or separate tests.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Subtests alone won't work here, because they just can be a wrapper above assertionErrors. Any other types of exceptions / errors and the subtest will fail and make the whole test fail. So I'm now using a try catch block + a subtest. Try catch block will be useful for any generic errors where as assertion errors can be logged by subtests

self.client.index(index_name = index['indexName']).add_documents(documents = self.text_docs)
else:
self.client.index(index_name = index['indexName']).add_documents(documents = self.text_docs,
tensor_fields = ["Description", "Genre", "Title"])

self.logger.debug(f"Finished running prepare method for test case: {self.__class__.__name__}")
except Exception as e:
raise e

all_results = {}

for index in self.indexes_to_test_on:
index_name = index['indexName']
all_results[index_name] = {}

for doc in self.text_docs:
doc_id = doc['_id']
try:
all_results[index_name][doc_id] = self.client.index(index_name).get_document(doc_id)
except Exception as e:
self.logger.error(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we fail here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No point in failing a prepare mode test. Even if we fail here - when we run test mode we will not have the context of which prepare mode tests failed.

f"Exception when getting documents with id: {doc_id} from index: {index_name}",
exc_info=True)

self.save_results_to_file(all_results)

def test_add_doc(self):
self.logger.info(f"Running test_add_doc on {self.__class__.__name__}")
stored_results = self.load_results_from_file()
for index in self.indexes_to_test_on:
index_name = index['indexName']

for doc in self.text_docs:
doc_id = doc['_id']
try:
expected_doc = stored_results[index_name][doc_id]
except KeyError as e:
self.logger.error(f"The key {doc_id} doesn't exist in the stored results. Skipping the test for this document.")
adityabharadwaj198 marked this conversation as resolved.
Show resolved Hide resolved
continue
self.logger.debug(f"Printing expected doc {expected_doc}")
actual_doc = self.client.index(index_name).get_document(doc_id)
self.logger.debug(f"Printing actual doc {expected_doc}")

self.assertEqual(expected_doc, actual_doc)
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import logging
from abc import abstractmethod, ABC
from pathlib import Path
from marqo_test import MarqoTestCase
from tests.compatibility_tests.base_test_case.marqo_test import MarqoTestCase


class BaseCompatibilityTestCase(MarqoTestCase, ABC):
Expand Down Expand Up @@ -40,6 +40,8 @@ def tearDownClass(cls) -> None:
cls.delete_indexes(cls.indexes_to_delete)
cls.logger.debug(f"Deleting indexes {cls.indexes_to_delete}")

cls.delete_file()

@classmethod
def save_results_to_file(cls, results):
"""Save results to a JSON file."""
Expand All @@ -61,8 +63,11 @@ def load_results_from_file(cls):
def delete_file(cls):
"""Delete the results file."""
filepath = cls.get_results_file_path()
filepath.unlink()
cls.logger.debug(f"Results file deleted: {filepath}")
if filepath.exists():
filepath.unlink()
cls.logger.debug(f"Results file deleted: {filepath}")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if debug log level is excessive here. Do you think we will ever run this in debug mode? Is there a risk if we logged these at info level (i.e. print them all the time)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can run it in debug mode if debugging locally. If these are logged at info level then it would make the logs too verbose and it'd be difficult to find valuable information

else:
cls.logger.debug(f"Not deleting, as the results file was never created in the first place.")

@abstractmethod
def prepare(self):
Expand Down
Loading
Loading