Repository: ansible/awx
File: awx/main/tests/functional/test_migrations.py (Python)

Code before:
        """
        # 1. Apply migrations up to the point *before* the 0202_squashed_deletions migration.
        # This simulates the state where the problematic CredentialType might exist.
        # We use 0201_create_managed_creds as the direct predecessor.
        old_state = migrator.apply_tested_migration(('main', '0201_create_managed_creds'))

        # Get the CredentialType model from the historical state.
        CredentialType = old_state.apps.get_model('main', 'CredentialType')

        CredentialType.objects.create(
            name='Legacy GitHub App Credential',
            kind='github_app',  # The old, problematic 'kind' value
            namespace='github_app',  # The namespace that causes the KeyError in the registry lookup
            managed=True,
            created=timezone.now(),
            modified=timezone.now(),
        )

        new_state = migrator.apply_tested_migration(('main', '0202_squashed_deletions'))

        out = io.StringIO()
        err = io.StringIO()

        try:
            # The `--noinput` flag is essential for non-interactive testing.
            call_command('createsuperuser', username='testadmin', email='test@example.com', noinput=True, stdout=out, stderr=err)
            test_successful = True
        except Exception as e:
            # If any exception occurs, print it to stderr for debugging and mark test as failed.
            sys.stderr.write(f"createsuperuser failed with an unexpected exception: {e}\n")
            sys.stderr.write(f"stdout from createsuperuser: {out.getvalue()}\n")
            sys.stderr.write(f"stderr from createsuperuser: {err.getvalue()}\n")
            test_successful = False

        assert test_successful, "createsuperuser should run without an exception after the CredentialType kind update."

        User = new_state.apps.get_model('auth', 'User')  # Get User model from the new state
        assert User.objects.filter(username='testadmin').exists(), "Superuser 'testadmin' should be successfully created."

        # Verify that the CredentialType with the old 'kind' no longer exists
        # and the 'kind' has been updated to the new value.
        CredentialType = new_state.apps.get_model('main', 'CredentialType')  # Get CredentialType model from the new state
        assert not CredentialType.objects.filter(
            kind='github_app'
        ).exists(), "CredentialType with old 'github_app' kind should no longer exist after migration."
        assert CredentialType.objects.filter(
            kind='github_app_lookup', name='Legacy GitHub App Credential'
        ).exists(), "CredentialType should be updated to 'github_app_lookup'."


Review comment (bug):
IMO, the error on superuser creation was extremely secondary to the original issue. And the credential plugin loading is likely mocked in tests anyway, I don't trust that you would have reproduced the bug here without the fix.

I would say, just focus on detecting that the credential had its `kind` field renamed. You do this later in the test. I wouldn't bother with this stuff here, which creates a lot of overhead and is probably going to bug-out.

Code after:
        # We use 0201_create_managed_creds as the direct predecessor.
        old_state = migrator.apply_tested_migration(('main', '0201_create_managed_creds'))

        # Get the CredentialType model from the historical state.
        CredentialType = old_state.apps.get_model('main', 'CredentialType')

        # Create a CredentialType with the old, problematic 'kind' value
        CredentialType.objects.create(
            name='Legacy GitHub App Credential',
            kind='github_app',  # The old, problematic 'kind' value
            namespace='github_app',  # The namespace that causes the KeyError in the registry lookup
            managed=True,
            created=timezone.now(),
            modified=timezone.now(),
        )

        # Apply the migration that includes the fix (0202_squashed_deletions).
        new_state = migrator.apply_tested_migration(('main', '0202_squashed_deletions'))

        # Verify that the CredentialType with the old 'kind' no longer exists
        # and the 'kind' has been updated to the new value.
        CredentialType = new_state.apps.get_model('main', 'CredentialType')  # Get CredentialType model from the new state

        # Assertion 1: The CredentialType with the old 'github_app' kind should no longer exist.
        assert not CredentialType.objects.filter(
            kind='github_app'
        ).exists(), "CredentialType with old 'github_app' kind should no longer exist after migration."

        # Assertion 2: The CredentialType should now exist with the new 'github_app_lookup' kind
        # and retain its original name.
        assert CredentialType.objects.filter(
            kind='github_app_lookup', name='Legacy GitHub App Credential'
        ).exists(), "CredentialType should be updated to 'github_app_lookup' and retain its name."