def setup_database_for_testing(testcase, with_storage=False, force_rebuild=False): """ Called when a testcase has started using the database, indicating that the database should be setup (if not already) and a savepoint created. """ # Sanity check to make sure we're not killing our prod db if not IS_TESTING_REAL_DATABASE and not isinstance(db.obj, SqliteDatabase): raise RuntimeError("Attempted to wipe production database!") if not db_initialized_for_testing.is_set() or force_rebuild: logger.debug("Setting up DB for testing.") # Setup the database. if os.environ.get("SKIP_DB_SCHEMA", "") != "true": wipe_database() initialize_database() populate_database(with_storage=with_storage) models_missing_data = find_models_missing_data() if models_missing_data: raise RuntimeError("%s models are missing data: %s", len(models_missing_data), models_missing_data) # Enable foreign key constraints. if not IS_TESTING_REAL_DATABASE: db.obj.execute_sql("PRAGMA foreign_keys = ON;") db_initialized_for_testing.set() # Initialize caches. Repository.kind.get_id("image") # Create a savepoint for the testcase. testcases[testcase] = {} testcases[testcase]["transaction"] = db.transaction() testcases[testcase]["transaction"].__enter__() testcases[testcase]["savepoint"] = db.savepoint() testcases[testcase]["savepoint"].__enter__()
def initialized_db(appconfig): """ Configures the database for the database found in the appconfig. """ under_test_real_database = bool(os.environ.get("TEST_DATABASE_URI")) # Configure the database. configure(appconfig) # Initialize caches. model._basequery._lookup_team_roles() model._basequery.get_public_repo_visibility() model.log.get_log_entry_kinds() if not under_test_real_database: # Make absolutely sure foreign key constraints are on. db.obj.execute_sql("PRAGMA foreign_keys = ON;") db.obj.execute_sql('PRAGMA encoding="UTF-8";') assert db.obj.execute_sql("PRAGMA foreign_keys;").fetchone()[0] == 1 assert db.obj.execute_sql("PRAGMA encoding;").fetchone()[0] == "UTF-8" # If under a test *real* database, setup a savepoint. if under_test_real_database: with db.transaction(): test_savepoint = db.savepoint() test_savepoint.__enter__() yield # Run the test. try: test_savepoint.rollback() test_savepoint.__exit__(None, None, None) except InternalError: # If postgres fails with an exception (like IntegrityError) mid-transaction, it terminates # it immediately, so when we go to remove the savepoint, it complains. We can safely ignore # this case. pass else: if os.environ.get("DISALLOW_AUTO_JOINS", "false").lower() == "true": # Patch get_rel_instance to fail if we try to load any non-joined foreign key. This will allow # us to catch missing joins when running tests. def get_rel_instance(self, instance): value = instance.__data__.get(self.name) if value is not None or self.name in instance.__rel__: if self.name not in instance.__rel__: # NOTE: We only raise an exception if this auto-lookup occurs from non-testing code. # Testing code can be a bit inefficient. lookup_allowed = False try: outerframes = inspect.getouterframes( inspect.currentframe()) except IndexError: # Happens due to a bug in Jinja. outerframes = [] for allowed_auto_join in ALLOWED_AUTO_JOINS: if lookup_allowed: break if (len(outerframes) >= allowed_auto_join.frame_start_index + CALLER_FRAMES_OFFSET): found_match = True for index, pattern_prefix in enumerate( allowed_auto_join.pattern_prefixes): frame_info = outerframes[ index + CALLER_FRAMES_OFFSET] if not frame_info[ FRAME_NAME_INDEX].startswith( pattern_prefix): found_match = False break if found_match: lookup_allowed = True break if not lookup_allowed: raise Exception( "Missing join on instance `%s` for field `%s`", instance, self.name) obj = self.rel_model.get(self.field.rel_field == value) instance.__rel__[self.name] = obj return instance.__rel__[self.name] elif not self.field.null: raise self.rel_model.DoesNotExist return value with patch("peewee.ForeignKeyAccessor.get_rel_instance", get_rel_instance): yield else: yield