-
Notifications
You must be signed in to change notification settings - Fork 809
Honor database assignment from router #1450
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
Merged
dopry
merged 18 commits into
django-oauth:master
from
shaleh:honor-database-assigment-from-router
Sep 5, 2024
Merged
Changes from 15 commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
def5a2b
Improve multiple database support.
shaleh 14821ba
changelog entry and authors update
shaleh 6043725
PR review response.
shaleh 73a0406
move migration
shaleh 7a64859
update migration
shaleh 0c6feae
use django checks system
shaleh a2b273e
drop misconfigured db check. Let's find a better way.
shaleh 90b2ff3
run checks
shaleh 7637a49
maybe a better test definition
shaleh 08f5021
listing tests was breaking things
shaleh dbddebf
No more magic.
shaleh 8072cc7
Oops. Debugger.
shaleh 86b2519
Use retrieven_current_databases in django_db marked tests.
shaleh ae4c4e6
Updates.
shaleh ceaebc9
fix typo
n2ygk f78ba9b
Merge branch 'master' into honor-database-assigment-from-router
n2ygk 4de971a
Merge branch 'master' into honor-database-assigment-from-router
shaleh 20b1ae9
Merge branch 'master' into honor-database-assigment-from-router
n2ygk File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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,28 @@ | ||
from django.apps import apps | ||
from django.core import checks | ||
from django.db import router | ||
|
||
from .settings import oauth2_settings | ||
|
||
|
||
@checks.register(checks.Tags.database) | ||
def validate_token_configuration(app_configs, **kwargs): | ||
databases = set( | ||
router.db_for_write(apps.get_model(model)) | ||
for model in ( | ||
oauth2_settings.ACCESS_TOKEN_MODEL, | ||
oauth2_settings.ID_TOKEN_MODEL, | ||
oauth2_settings.REFRESH_TOKEN_MODEL, | ||
) | ||
) | ||
|
||
# This is highly unlikely, but let's warn people just in case it does. | ||
# If the tokens were allowed to be in different databases this would require all | ||
# writes to have a transaction around each database. Instead, let's enforce that | ||
# they all live together in one database. | ||
# The tokens are not required to live in the default database provided the Django | ||
# routers know the correct database for them. | ||
if len(databases) > 1: | ||
return [checks.Error("The token models are expected to be stored in the same database.")] | ||
|
||
return [] |
This file contains hidden or 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 hidden or 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 hidden or 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,33 @@ | ||
from django.conf import settings | ||
from django.test import TestCase as DjangoTestCase | ||
from django.test import TransactionTestCase as DjangoTransactionTestCase | ||
|
||
|
||
# The multiple database scenario setup for these tests purposefully defines 'default' as | ||
# an empty database in order to catch any assumptions in this package about database names | ||
# and in particular to ensure there is no assumption that 'default' is a valid database. | ||
# | ||
# When there are multiple databases defined, Django tests will not work unless they are | ||
# told which database(s) to work with. | ||
|
||
|
||
def retrieve_current_databases(): | ||
if len(settings.DATABASES) > 1: | ||
return [name for name in settings.DATABASES if name != "default"] | ||
else: | ||
return ["default"] | ||
|
||
|
||
class OAuth2ProviderBase: | ||
@classmethod | ||
def setUpClass(cls): | ||
cls.databases = retrieve_current_databases() | ||
super().setUpClass() | ||
|
||
|
||
class OAuth2ProviderTestCase(OAuth2ProviderBase, DjangoTestCase): | ||
"""Place holder to allow overriding behaviors.""" | ||
|
||
|
||
class OAuth2ProviderTransactionTestCase(OAuth2ProviderBase, DjangoTransactionTestCase): | ||
"""Place holder to allow overriding behaviors.""" |
This file contains hidden or 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,76 @@ | ||
apps_in_beta = {"some_other_app", "this_one_too"} | ||
|
||
# These are bare minimum routers to fake the scenario where there is actually a | ||
# decision around where an application's models might live. | ||
|
||
|
||
class AlphaRouter: | ||
# alpha is where the core Django models are stored including user. To keep things | ||
# simple this is where the oauth2 provider models are stored as well because they | ||
# have a foreign key to User. | ||
|
||
def db_for_read(self, model, **hints): | ||
if model._meta.app_label not in apps_in_beta: | ||
return "alpha" | ||
return None | ||
|
||
def db_for_write(self, model, **hints): | ||
if model._meta.app_label not in apps_in_beta: | ||
return "alpha" | ||
return None | ||
|
||
def allow_relation(self, obj1, obj2, **hints): | ||
if obj1._state.db == "alpha" and obj2._state.db == "alpha": | ||
return True | ||
return None | ||
|
||
def allow_migrate(self, db, app_label, model_name=None, **hints): | ||
if app_label not in apps_in_beta: | ||
return db == "alpha" | ||
return None | ||
|
||
|
||
class BetaRouter: | ||
def db_for_read(self, model, **hints): | ||
if model._meta.app_label in apps_in_beta: | ||
return "beta" | ||
return None | ||
|
||
def db_for_write(self, model, **hints): | ||
if model._meta.app_label in apps_in_beta: | ||
return "beta" | ||
return None | ||
|
||
def allow_relation(self, obj1, obj2, **hints): | ||
if obj1._state.db == "beta" and obj2._state.db == "beta": | ||
return True | ||
return None | ||
|
||
def allow_migrate(self, db, app_label, model_name=None, **hints): | ||
if app_label in apps_in_beta: | ||
return db == "beta" | ||
|
||
|
||
class CrossDatabaseRouter: | ||
# alpha is where the core Django models are stored including user. To keep things | ||
# simple this is where the oauth2 provider models are stored as well because they | ||
# have a foreign key to User. | ||
def db_for_read(self, model, **hints): | ||
if model._meta.model_name == "accesstoken": | ||
return "beta" | ||
return None | ||
|
||
def db_for_write(self, model, **hints): | ||
if model._meta.model_name == "accesstoken": | ||
return "beta" | ||
return None | ||
|
||
def allow_relation(self, obj1, obj2, **hints): | ||
if obj1._state.db == "beta" and obj2._state.db == "beta": | ||
return True | ||
return None | ||
|
||
def allow_migrate(self, db, app_label, model_name=None, **hints): | ||
if model_name == "accesstoken": | ||
return db == "beta" | ||
return None |
This file contains hidden or 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,34 @@ | ||
# Generated by Django 3.2.25 on 2024-08-08 22:47 | ||
|
||
from django.conf import settings | ||
from django.db import migrations, models | ||
import django.db.models.deletion | ||
import uuid | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
migrations.swappable_dependency(settings.OAUTH2_PROVIDER_APPLICATION_MODEL), | ||
migrations.swappable_dependency(settings.AUTH_USER_MODEL), | ||
('tests', '0006_basetestapplication_token_family'), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name='LocalIDToken', | ||
fields=[ | ||
('id', models.BigAutoField(primary_key=True, serialize=False)), | ||
('jti', models.UUIDField(default=uuid.uuid4, editable=False, unique=True, verbose_name='JWT Token ID')), | ||
('expires', models.DateTimeField()), | ||
('scope', models.TextField(blank=True)), | ||
('created', models.DateTimeField(auto_now_add=True)), | ||
('updated', models.DateTimeField(auto_now=True)), | ||
('application', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.OAUTH2_PROVIDER_APPLICATION_MODEL)), | ||
('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='tests_localidtoken', to=settings.AUTH_USER_MODEL)), | ||
], | ||
options={ | ||
'abstract': False, | ||
}, | ||
), | ||
] |
This file contains hidden or 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 hidden or 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,19 @@ | ||
# Import the test settings and then override DATABASES. | ||
|
||
from .settings import * # noqa: F401, F403 | ||
|
||
|
||
DATABASES = { | ||
"alpha": { | ||
"ENGINE": "django.db.backends.sqlite3", | ||
"NAME": ":memory:", | ||
}, | ||
"beta": { | ||
"ENGINE": "django.db.backends.sqlite3", | ||
"NAME": ":memory:", | ||
}, | ||
# As https://docs.djangoproject.com/en/4.2/topics/db/multi-db/#defining-your-databases | ||
# indicates, it is ok to have no default database. | ||
"default": {}, | ||
} | ||
DATABASE_ROUTERS = ["tests.db_router.AlphaRouter", "tests.db_router.BetaRouter"] |
This file contains hidden or 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,8 @@ | ||
from .multi_db_settings import * # noqa: F401, F403 | ||
|
||
|
||
OAUTH2_PROVIDER = { | ||
# The other two tokens will be in alpha. This will cause a failure when the | ||
# app's ready method is called. | ||
"ID_TOKEN_MODEL": "tests.LocalIDToken", | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.