Skip to content

Commit

Permalink
Split tests to separate functions
Browse files Browse the repository at this point in the history
  • Loading branch information
ljodal committed Feb 10, 2023
1 parent b03a4df commit cbf4adf
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 85 deletions.
58 changes: 57 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,63 @@ jobs:
## Checks
### Add index
### Adding a non-nullable field
Adding a non-nullable field is not entirely straight forward. This is the case
even if you set a default value, because Django does not use default values at
the database level. This means that the previous version running when you roll
out the field will not provide a value when writing to the table. Because of
this you should add always add new fields as nullable first. You should also
make sure any code that writes to the table is updated to also provide a value
for the new field (either through defaults or by explicity updating code that
writes to the models). Once that has been rolled out you can make a second
deploy, which first backfills old rows and then makes the field non-nullable.
#### First deploy
```python
class Migration(migrations.Migration):
...
operations = [
migrations.AddField(
model_name="order",
name="number",
field=models.PositiveBigIntegerField(null=True),
),
]
```
#### Second deploy
First backfill data in one migration:
```python
class Migration(migrations.Migration):
...
operations = [
migrations.RunSQL(
"update tests_order set number=1 where number is null",
migrations.RunSQL.noop,
),
]
```
Then make the field non-nullable
```python
class Migration(migrations.Migration):
...
operations = [
migrations.AlterField(
model_name="order",
name="number",
field=models.PositiveBigIntegerField(),
),
]
```
### Adding indexes
Checks if the migration contains an `AddIndex` operation and suggests using
`AddIndexConcurrently` instead. This is safer as it doesn't take a lock on the
Expand Down
146 changes: 62 additions & 84 deletions tests/test_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,90 +43,68 @@ class Migration(migrations.Migration):
return set(run_checks(migration=Migration(name="0001_foo", app_label="foo")))


@pytest.mark.parametrize(
("operations", "warnings"),
(
(
[
AddIndex(model_name="foo", index=Index(fields=["foo"], name="foo")),
],
{USE_ADD_INDEX_CONCURRENTLY},
),
(
[
AddField(model_name="foo", name="bar", field=IntegerField(null=True)),
AddIndex(model_name="foo", index=Index(fields=["foo"], name="foo")),
],
{USE_ADD_INDEX_CONCURRENTLY, ADD_INDEX_IN_SEPARATE_MIGRATION},
),
(
[
AddField(model_name="foo", name="bar", field=IntegerField(null=True)),
],
set(),
),
(
[
AddField(model_name="foo", name="bar", field=IntegerField()),
],
{ADDING_NON_NULLABLE_FIELD},
),
(
[
RemoveField(model_name="foo", name="bar"),
],
{REMOVING_FIELD},
),
(
[
RenameModel(old_name="foo", new_name="bar"),
],
{RENAMING_MODEL},
),
(
[
RenameField(model_name="foo", old_name="bar", new_name="baz"),
],
{RENAMING_FIELD},
),
(
[
AddField(model_name="foo", name="bar", field=IntegerField(null=True)),
RunSQL("select 1", RunSQL.noop),
],
{SCHEMA_AND_DATA_CHANGES},
),
(
[
AddField(model_name="foo", name="bar", field=IntegerField(null=True)),
AddField(model_name="baz", name="bar", field=IntegerField(null=True)),
],
{ALTERING_MULTIPLE_MODELS},
),
(
[
AddField(
model_name="foo", name="bar", field=PositiveIntegerField(null=True)
),
],
{ADDING_FIELD_WITH_CHECK},
),
),
ids=(
"use-add-index-concurrently",
"add-index-separately",
"safe-add-nullable-field",
"adding-non-nullable-field",
"removing-field",
"renaming-model",
"renaming-field",
"schema-and-data-changes",
"altering-multiple-models",
"adding-field-with-check",
),
)
def test_checks(operations: list[Operation], warnings: set[Warning]) -> None:
assert check_migration(*operations) == warnings
def test_add_index() -> None:
operation = AddIndex(model_name="foo", index=Index(fields=["foo"], name="foo"))
assert check_migration(operation) == {USE_ADD_INDEX_CONCURRENTLY}


def test_add_index_separately() -> None:
operations = [
AddField(model_name="foo", name="bar", field=IntegerField(null=True)),
AddIndex(model_name="foo", index=Index(fields=["foo"], name="foo")),
]
assert check_migration(*operations) == {
USE_ADD_INDEX_CONCURRENTLY,
ADD_INDEX_IN_SEPARATE_MIGRATION,
}


def test_add_nullable_field() -> None:
operation = AddField(model_name="foo", name="bar", field=IntegerField(null=True))
assert not check_migration(operation)


def test_add_non_nullable_field() -> None:
operation = AddField(model_name="foo", name="bar", field=IntegerField())
assert check_migration(operation) == {ADDING_NON_NULLABLE_FIELD}


def test_remove_field() -> None:
operation = RemoveField(model_name="foo", name="bar")
assert check_migration(operation) == {REMOVING_FIELD}


def test_remove_model() -> None:
operation = RenameModel(old_name="foo", new_name="bar")
assert check_migration(operation) == {RENAMING_MODEL}


def test_rename_field() -> None:
operation = RenameField(model_name="foo", old_name="bar", new_name="baz")
assert check_migration(operation) == {RENAMING_FIELD}


def test_schema_and_data_changes() -> None:
operations = [
AddField(model_name="foo", name="bar", field=IntegerField(null=True)),
RunSQL("select 1", RunSQL.noop),
]
assert check_migration(*operations) == {SCHEMA_AND_DATA_CHANGES}


def test_alter_multiple_models() -> None:
operations = [
AddField(model_name="foo", name="bar", field=IntegerField(null=True)),
AddField(model_name="baz", name="bar", field=IntegerField(null=True)),
]
assert check_migration(*operations) == {ALTERING_MULTIPLE_MODELS}


def test_add_field_with_check() -> None:
operation = AddField(
model_name="foo", name="bar", field=PositiveIntegerField(null=True)
)
assert check_migration(operation) == {ADDING_FIELD_WITH_CHECK}


def test_add_constraint() -> None:
Expand Down

0 comments on commit cbf4adf

Please sign in to comment.