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

[RHINENG-1284] Tests are failing in test_api_assignment_rules_create.py #1440

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

jpramos123
Copy link
Contributor

Overview

This PR is being created to address RHINENG-1284.

The issue was in the Model, that was not creating the correct constrains.
Pytest uses the Models directly, and do not run the migration scrips to create the tables.

PR Checklist

  • Keep PR title short, ideally under 72 characters
  • Descriptive comments provided in complex code blocks
  • Tests: validate optimal/expected output
  • Tests: validate exceptions and failure scenarios
  • Tests: edge cases
  • Recovers or fails gracefully during potential resource outages (e.g. DB, Kafka)
  • Uses type hinting, if convenient
  • Documentation, if this PR changes the way other services interact with host inventory
  • Links to related PRs

Secure Coding Practices Documentation Reference

You can find documentation on this checklist here.

Secure Coding Checklist

  • Input Validation
  • Output Encoding
  • Authentication and Password Management
  • Session Management
  • Access Control
  • Cryptographic Practices
  • Error Handling and Logging
  • Data Protection
  • Communication Security
  • System Configuration
  • Database Security
  • File Management
  • Memory Management
  • General Coding Practices

@jpramos123 jpramos123 requested a review from a team as a code owner July 28, 2023 21:11
@jpramos123 jpramos123 force-pushed the RHINENG-1284 branch 2 times, most recently from df92987 to 36204de Compare July 31, 2023 13:58
@jpramos123 jpramos123 requested a review from thearifismail July 31, 2023 16:46
Comment on lines +110 to +111
def _db_get_assignment_rule(ar_id, group_id):
return AssignmentRule.query.get((ar_id, group_id))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why is this necessary? Isn't the assignment rule ID unique?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It led to a issue with multiple primary keys, and was not able to fetch the data using only the ID.
See the error below:

sqlalchemy.exc.InvalidRequestError: Incorrect number of values in identifier to formulate primary key for query.get(); primary key columns are 'assignment_rules.id','assignment_rules.group_id'

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah... so then my follow-up question is, why do we need the primary key to consist of both the ID and group ID, when the ID should already be unique and non-nullable?
If we make the primary key the combination of those two columns, we technically open up the possibility to having duplicate values for ID (as long as group_id is different)

Copy link
Contributor Author

@jpramos123 jpramos123 Aug 1, 2023

Choose a reason for hiding this comment

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

We do not hehe.

But it was initially created this way:
https://github.com/RedHatInsights/insights-host-inventory/pull/1377/files#diff-6b8bcd51a947a9eb1db19cd9157a27b5bea41a8191cca8ad7b2ee297b0a3e9f7R28

In this case, we can create a new migration to remove the constraint from this column. As we are already making sure group_id is unique: https://github.com/RedHatInsights/insights-host-inventory/pull/1418/files#diff-be43a8e7819671e5eca91faed55b391bf96c0a0149d54a213c8fe3bf3163447a

Thoughts?

Copy link
Contributor

Choose a reason for hiding this comment

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

We have an idxassrulesorgid which should work to make org_id unique, but maybe what we needed was a unique constraint.

op.create_index("idxassrulesorgid", "assignment_rules", ["org_id"])

Copy link
Collaborator

Choose a reason for hiding this comment

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

Personally, I don't think it makes sense for the table's primary key to be a combination of unique IDs. If we already have an id field, that should be the primary key; otherwise it adds unnecessary complexity because you need both the assignment rule ID and its group ID in order to fetch the record, right?

tests/test_api_assignment_rules_create.py Outdated Show resolved Hide resolved
@@ -38,10 +38,10 @@ def test_get_assignment_rule_by_name(db_create_assignment_rule, db_create_group,


def test_get_assignment_rule_with_bad_name(db_create_assignment_rule, db_create_group, api_get):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not an issue with your changes, but am I missing the point of this test? It doesn't appear to be testing any scenario related to having a bad name (and both responses return 200)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In this case, it validates that 3 rules were created, make an api call with a name that will not be in the list, and validate the return is an empty list.

We do not trigger an error when fetching rules that are not in the DB

@thearifismail Can you add more context here?

Thanks

Copy link
Contributor

Choose a reason for hiding this comment

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

from what I read, the query.filter function doesn't return an error if no results were found

@jpramos123 jpramos123 requested a review from kruai August 1, 2023 14:20
@FabriciaDinizRH
Copy link
Contributor

/retest

@@ -524,7 +528,7 @@ def update(self, input_ar):
account = db.Column(db.String(10))
name = db.Column(db.String(255), nullable=False)
description = db.Column(db.String(255))
group_id = db.Column(UUID(as_uuid=True), ForeignKey("groups.id"))
group_id = db.Column(UUID(as_uuid=True), ForeignKey("groups.id"), primary_key=True)
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can remove it from the model.py file and create a new migration to remove this constraint from the column, or we can add it as this PR suggests and it will be aligned with the DB modeling we have today.

Copy link
Contributor

Choose a reason for hiding this comment

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

@jpramos123 I was checking the migration files and since this change doesn't break the tests we can leave it as it is.

@@ -38,10 +38,10 @@ def test_get_assignment_rule_by_name(db_create_assignment_rule, db_create_group,


def test_get_assignment_rule_with_bad_name(db_create_assignment_rule, db_create_group, api_get):
Copy link
Contributor

Choose a reason for hiding this comment

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

from what I read, the query.filter function doesn't return an error if no results were found

Comment on lines +110 to +111
def _db_get_assignment_rule(ar_id, group_id):
return AssignmentRule.query.get((ar_id, group_id))
Copy link
Contributor

Choose a reason for hiding this comment

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

We have an idxassrulesorgid which should work to make org_id unique, but maybe what we needed was a unique constraint.

op.create_index("idxassrulesorgid", "assignment_rules", ["org_id"])

@jpramos123
Copy link
Contributor Author

@FabriciaDinizRH Indexes are used to enhance queries performances, making the data easily available!
See: https://www.postgresql.org/docs/current/indexes.html

@roliveri
Copy link
Contributor

I have a question, but it's not specific to the issue addressed by this PR. It's more specific to the test scenario that uncovered this issue.

In the ticket, it says the problem can be reproduced by running 2 separate test cases in the given order:

1. pytest tests/test_api_assignment_rules_create.py::test_create_assignemnt_rule_same_name
2. pytest tests/test_api_assignment_rules_create.py::test_create_assignemnt_rule_same_group

What concerns me here is the fact that not only can the artifacts of running a test case affect the subsequent test cases, it can also have such impact across separate pytest runs. I always had the impression that each test case should be insulated from the others. In fact, in other projects I worked on, we used to randomize the test run order to ensure that was the case.

Is that accurate?

I guess in this case it's a good thing because it helped expose this issue. But overall, I think this is undesirable.

@thearifismail
Copy link
Contributor

Yes tests should be insulated and not rely on which test ran before and after. That said, pytest uses scope for sharing fixtures. Possible values for scope are function, class, module, package, or session.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants