0

I have been trying to get my django testing working for an API I am building. I am newer to Python and have been stuck on this for a little while.

Some quick facts:

  • I am using 2 databases - A postgresql database for my users and a mongo database for everything else.
  • I am using TastyPie, Django-MongoDB-Engine, Djangotoolbox, Django-Non-rel, Pymongo and psycopg2
  • I have successfully connected to the databases. When I save an auth_user from the shell it saves to the sql database and the models from my app save to the mongoDB

I have to integrate this with another API so was limited to what my options were for databases and libraries.

My big problem is with testing - I can't get it to work.

When I try to run Django's tests with ./manage.py test, I keep getting this error:

pymongo.errors.OperationFailure: command SON([('authenticate', 1), ('user', u'test'), ('nonce', u'blahblah'), ('key', u'blahblah')]) failed: auth fails

After extensive search, I am still not sure what it is. I know that obviously something is trying to authenticate with my MongoDB and then its not allowing it. I dont mind using this DB to test as it is a testing DB anyways.

Please help! My configuration and error messages are below.


I set up the database settings to include both databases, as so:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'main_db',
        'USER': os.environ['RDS_USERNAME'],
        'PASSWORD': os.environ['RDS_PASSWORD'],
        'HOST': os.environ['RDS_HOSTNAME'],
        'PORT': os.environ['RDS_PORT'],
    },
    'mongo': {
        'ENGINE': 'django_mongodb_engine',
        'NAME': 'mongo_db',
        'USER': os.environ['MONGO_USERNAME'],
        'PASSWORD': os.environ['MONGO_PASSWORD'],
        'HOST': os.environ['MONGO_HOSTNAME'],
        'PORT': os.environ['MONGO_PORT'],
    }
}

DATABASE_ROUTERS = ['myproject.database_router.AuthRouter']

As you can see, I created my own custom router:

sql_databases = ['admin', 'auth', 'contenttypes', 'tastypie'
                 'sessions', 'messages', 'staticfiles']


class AuthRouter(object):
    """
    A router to control all database operations on models in the
    auth application.
    """
    def db_for_read(self, model, **hints):
        """
        Attempts to read auth models go to auth_db.
        """
        if model._meta.app_label in sql_databases:
            return 'default'
        return 'mongo'

    def db_for_write(self, model, **hints):
        """
        Attempts to write auth models go to auth_db.
        """
        if model._meta.app_label in sql_databases:
            return 'default'
        return 'mongo'

    def allow_relation(self, obj1, obj2, **hints):
        """
        Allow relations only if model does includes auth app.
        """
        if obj1._meta.app_label in sql_databases or \
           obj2._meta.app_label in sql_databases:
                return True
        return False

    def allow_migrate(self, db, model):
        """
        Make sure the auth app only appears in the 'auth_db'
        database.
        """
        if db == 'default':
            return model._meta.app_label in sql_databases
        elif model._meta.app_label in sql_databases:
            return False
        return False

The full trace is here:

Traceback (most recent call last):
File "./manage.py", line 10, in <module>
  execute_from_command_line(sys.argv)
File "myproject/djenv/lib/python2.7/site-packages/django/core/management/__init__.py", line 399, in execute_from_command_line
  utility.execute()
File "myproject/djenv/lib/python2.7/site-packages/django/core/management/__init__.py", line 392, in execute
  self.fetch_command(subcommand).run_from_argv(self.argv)
File "myproject/djenv/lib/python2.7/site-packages/django/core/management/commands/test.py", line 50, in run_from_argv
  super(Command, self).run_from_argv(argv)
File "myproject/djenv/lib/python2.7/site-packages/django/core/management/base.py", line 242, in run_from_argv
  self.execute(*args, **options.__dict__)
File "myproject/djenv/lib/python2.7/site-packages/django/core/management/commands/test.py", line 71, in execute
  super(Command, self).execute(*args, **options)
File "myproject/djenv/lib/python2.7/site-packages/django/core/management/base.py", line 285, in execute
  output = self.handle(*args, **options)
File "myproject/djenv/lib/python2.7/site-packages/django/core/management/commands/test.py", line 88, in handle
  failures = test_runner.run_tests(test_labels)
File "myproject/djenv/lib/python2.7/site-packages/django/test/runner.py", line 145, in run_tests
  old_config = self.setup_databases()
File "myproject/djenv/lib/python2.7/site-packages/django/test/runner.py", line 107, in setup_databases
  return setup_databases(self.verbosity, self.interactive, **kwargs)
File "myproject/djenv/lib/python2.7/site-packages/django/test/runner.py", line 279, in setup_databases
  verbosity, autoclobber=not interactive)
File "myproject/djenv/lib/python2.7/site-packages/django_mongodb_engine/creation.py", line 196, in create_test_db
  self.connection._reconnect()
File "myproject/djenv/lib/python2.7/site-packages/django_mongodb_engine/base.py", line 279, in _reconnect
  self._connect()
File "myproject/djenv/lib/python2.7/site-packages/django_mongodb_engine/base.py", line 268, in _connect
  if not self.database.authenticate(user, password):
File "myproject/djenv/lib/python2.7/site-packages/pymongo/database.py", line 891, in authenticate
  self.connection._cache_credentials(self.name, credentials)
File "myproject/djenv/lib/python2.7/site-packages/pymongo/mongo_client.py", line 459, in _cache_credentials
  auth.authenticate(credentials, sock_info, self.__simple_command)
File "myproject/djenv/lib/python2.7/site-packages/pymongo/auth.py", line 243, in authenticate
  auth_func(credentials[1:], sock_info, cmd_func)
File "myproject/djenv/lib/python2.7/site-packages/pymongo/auth.py", line 222, in _authenticate_mongo_cr
  cmd_func(sock_info, source, query)
File "myproject/djenv/lib/python2.7/site-packages/pymongo/mongo_client.py", line 690, in __simple_command
  helpers._check_command_response(response, None, msg)
File "myproject/djenv/lib/python2.7/site-packages/pymongo/helpers.py", line 178, in _check_command_response
  raise OperationFailure(msg % errmsg, code, response)
pymongo.errors.OperationFailure: command SON([('authenticate', 1), ('user', u'test'), ('nonce', u'blahblah'), ('key', u'blahblah')]) failed: auth fails

Any help is appreciated!

user2498045
  • 141
  • 1
  • 5

1 Answers1

0

Wanted to give a update on how I fixed this - I thought it was a read/write issue (with the auth fails issue), but it was not.

  1. If you see this error, its an authentication issue - Either your username, password, database name or collection name is incorrect.

    pymongo.errors.OperationFailure: command SON([('authenticate', 1), ('user', u'test'), ('nonce', 
    u'blahblah'), ('key', u'blahblah')]) failed: auth fails
    
  2. Django when setting up a test database adds 'test_' to the beginning of the database name. So my main database, called maindb is then created as 'test_maindb'.

    You can see info regarding this at: Test Databases and Django

  3. Ensure that you can write to a separate database that is named as your database name with 'test_' appended to the name.

    Also - an alternative solution is to define test database setting in your database settings. This can be done by appending 'TEST_' to any of the database attributes. An example inlcudes:

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql_psycopg2',
            'NAME': 'maindb',
            'USER': os.environ['RDS_USERNAME'],
            'PASSWORD': os.environ['RDS_PASSWORD'],
            'HOST': os.environ['RDS_HOSTNAME'],
            'PORT': os.environ['RDS_PORT'],
            'TEST_NAME': 'my_test_sql',
            'TEST_USER': 'test_sql_user',
            'TEST_PASSWORD': 'password'
        },
        'mongo': {
            'ENGINE': 'django_mongodb_engine',
            'NAME': 'mongodb',
            'USER': os.environ['MONGO_USERNAME'],
            'PASSWORD': os.environ['MONGO_PASSWORD'],
            'HOST': os.environ['MONGO_HOSTNAME'],
            'PORT': os.environ['MONGO_PORT'],
            'TEST_NAME': 'my_test_mongodb',
            'TEST_USER': 'test_mongo_user',
            'TEST_PASSWORD': 'password'
        }
    }
    

Hope it helps! And please give feedback if you see anything additional

user2498045
  • 141
  • 1
  • 5