예제 #1
0
def configure():
    """Configure HIL"""
    config_testsuite()
    config_merge({
        'auth': {
            'require_authentication': 'False',
        },
        'extensions': {
            'hil.ext.auth.null': None,
            'hil.ext.auth.mock': '',
            'hil.ext.switches.mock': '',
            'hil.ext.obm.ipmi': '',
            'hil.ext.obm.mock': '',
            'hil.ext.network_allocators.null': None,
            'hil.ext.network_allocators.vlan_pool': '',
        },
        'hil.ext.network_allocators.vlan_pool': {
            'vlans': '40-80',
        },
        'maintenance': {
            'maintenance_project': 'maintenance',
            # Keystone url acts as dummy for posting
            'url': 'http://127.0.0.1:9999/test/'
        }
    })
    config.load_extensions()
예제 #2
0
파일: port_revert.py 프로젝트: CCI-MOC/hil
    def setUp(self):
        from hil.ext.switches.mock import LOCAL_STATE
        self.LOCAL_STATE = LOCAL_STATE
        fail_on_log_warnings()

        # Configure HIL:
        config_testsuite()
        config_merge({
            'extensions': {
                'hil.ext.switches.mock': '',
                'hil.ext.network_allocators.null': None,
                'hil.ext.network_allocators.vlan_pool': '',
            },
            'hil.ext.network_allocators.vlan_pool': {
                'vlans': '100-200',
            },
        })
        config.load_extensions()

        newDB()  # Initialize the db schema
        initial_db()  # Populate the db with objects

        # Sanity check the start state:
        assert self.LOCAL_STATE['stock_switch_0']['free_port_0'] == {}

        self.request_context = app.test_request_context()
        self.request_context.push()
예제 #3
0
파일: deferred.py 프로젝트: mikelyy/hil
def configure():
    """Configure HIL.

    The tests in this module require two separate sessions, so if the
    configuration specifies an in-memory sqlite database, we use a
    temporary file instead.
    """
    config_testsuite()

    additional_config = {
        'extensions': {
            'hil.ext.obm.mock': ''
            }
        }

    # if we are using sqlite's in memory db, then change uri to a db on disk
    uri = config.cfg.get('database', 'uri')
    if uri == 'sqlite:///:memory:':
        with tempfile.NamedTemporaryFile() as temp_db:
            uri = 'sqlite:///' + temp_db.name
            additional_config['database'] = {'uri': uri}
            config_merge(additional_config)
            config.load_extensions()
            yield
    else:
        config_merge(additional_config)
        config.load_extensions()
        yield
예제 #4
0
    def setUp(self):
        from hil.ext.switches.mock import LOCAL_STATE
        self.LOCAL_STATE = LOCAL_STATE
        fail_on_log_warnings()

        # Configure HIL:
        config_testsuite()
        config_merge({
            'extensions': {
                'hil.ext.switches.mock': '',
                'hil.ext.obm.ipmi': '',
                'hil.ext.obm.mock': '',
                'hil.ext.network_allocators.null': None,
                'hil.ext.network_allocators.vlan_pool': '',
            },
            'hil.ext.network_allocators.vlan_pool': {
                'vlans': '100-200',
            },
        })
        config.load_extensions()

        newDB()  # Initialize the db schema
        initial_db()  # Populate the db with objects

        # Sanity check the start state:
        assert self.LOCAL_STATE['stock_switch_0']['free_port_0'] == {}

        self.request_context = app.test_request_context()
        self.request_context.push()
예제 #5
0
def configure():
    """Configure HIL"""
    config_testsuite()
    config_merge({
        'auth': {
            'require_authentication': 'False',
        },
        'extensions': {
            'hil.ext.switches.mock': '',
            'hil.ext.obm.mock': '',
            'hil.ext.network_allocators.null': None,
            'hil.ext.network_allocators.vlan_pool': '',
        },
        'hil.ext.network_allocators.vlan_pool': {
            'vlans': '1001-1040',
        },
        'devel': {
            # Disable dry_run, so we can talk to obmd. Note: We register
            # several "real" switches in this module, but never actually
            # preform any "real" network operations on them, so a proper
            # switch setup is still not necessary.
            'dry_run': None,
        },
    })
    config.load_extensions()
예제 #6
0
파일: stress.py 프로젝트: SahilTikale/hil
def configure():
    """Configure HIL"""
    config_testsuite()
    config_merge(
            {'extensions': {'hil.ext.obm.ipmi': '', }, })

    config.load_extensions()
예제 #7
0
def test_db_eq(filename, make_objects, extra_config):
    """Migrating from a snapshot should create the same objects as a new db.

    `make_objects` is a function that, when run against the latest version
        of a schema, will create some set of objects.
    `filename` is the name of an sql dump of a previous database, whose
        contents were created with the then-current version of `make_objects`.
    `extra_config` specifies modifications to the hil.cfg under which the
        test is run. this is passed to `config_merge`.

    The test does the following:

        * Restore the database snapshot and run the migration scripts to update
          its contents to the current schema.
        * Create a fresh database according to the current schema, and execute
          `make_objects`.
        * Compare the two resulting databases. The test passes if and only if
          they are the same.
    """

    config_merge(extra_config)
    load_extensions()
    server.register_drivers()
    server.validate_state()

    def run_fn(f):
        """Run the function f and return a representation of its db."""

        # We can't just do db.drop_all(), since db's metadata won't
        # necessarily reflect the contents of the database. If there are
        # tables it doesn't know about, it may raise an exception.
        with app.app_context():
            drop_tables()
            f()

        return get_db_state()

    upgraded = run_fn(lambda: load_dump(filename))
    fresh = run_fn(lambda: fresh_create(make_objects))
    drop_tables()

    def censor_nondeterminism(string):
        """Censor parts of the output whose values are non-deterministic.

        Certain objects (currently just uuids) are generated
        non-deterministically, and will thus be different between databases
        even if everything is working. This function censors the relevant
        parts of `string`, so that they don't cause the tests to fail.
        """
        hex_re = r'[0-9a-f]'
        uuid_re = hex_re * 8 + ('-' + hex_re * 4) * 3 + '-' + hex_re * 12
        return re.sub(uuid_re, '<<UUID>>', string)

    differ = difflib.Differ()
    upgraded = censor_nondeterminism(pformat(upgraded)).split('\n')
    fresh = censor_nondeterminism(pformat(fresh)).split('\n')

    assert upgraded == fresh, ("Databases are different!\n\n" +
                               pformat(list(differ.compare(upgraded, fresh))))
예제 #8
0
def configure():
    """Set up the HIL configureation."""
    config_testsuite()
    config_merge({
        'devel': {
            'dry_run': None,
        },
    })
    config.load_extensions()
예제 #9
0
파일: mock.py 프로젝트: jethrosun/hil
def configure():
    config_testsuite()
    config_merge({
        'extensions': {
            'hil.ext.auth.mock': '',
            'hil.ext.auth.null': None,
        },
    })
    config.load_extensions()
예제 #10
0
파일: mock.py 프로젝트: CCI-MOC/hil
def configure():
    """Configure HIL"""
    config_testsuite()
    config_merge({
        'extensions': {
            'hil.ext.auth.mock': '',
            'hil.ext.auth.null': None,
        },
    })
    config.load_extensions()
예제 #11
0
def configure():
    """Configure HIL"""
    config_testsuite()
    config_merge({
        'extensions': {
            'hil.ext.obm.ipmi': '',
        },
    })

    config.load_extensions()
예제 #12
0
def configure():
    """Set up the HIL configureation."""
    config_testsuite()
    config_merge({
        'extensions': {
            'hil.ext.obm.mock': '',
        },
        'devel': {
            'dry_run': None,
        },
    })
    config.load_extensions()
예제 #13
0
파일: vlan_pool.py 프로젝트: jethrosun/hil
def configure():
    config_testsuite()
    config_merge({
        'extensions': {
            'hil.ext.network_allocators.null': None,
            'hil.ext.network_allocators.vlan_pool': ''
        },
        'hil.ext.network_allocators.vlan_pool': {
            'vlans': '100-104, 300, 702',  # Arbitrary list
        },
    })
    load_extensions()
예제 #14
0
파일: brocade.py 프로젝트: RobinKaul/hil
def configure():
    """Configure HIL"""
    config_testsuite()
    config_merge({
        'extensions': {
            'hil.ext.network_allocators.null': None,
            'hil.ext.network_allocators.vlan_pool': '',
        },
        'hil.ext.network_allocators.vlan_pool': {
            'vlans': '100-105',
        },
    })
    config.load_extensions()
예제 #15
0
파일: hil_auth.py 프로젝트: jethrosun/hil
def configure():
    config_testsuite()
    config_merge({
        'extensions': {
            'hil.ext.auth.mock': '',

            # This extension is enabled by default in the tests, so we need to
            # disable it explicitly:
            'hil.ext.auth.null': None,
            'hil.ext.switches.mock': '',
        },
    })
    config.load_extensions()
예제 #16
0
파일: brocade.py 프로젝트: CCI-MOC/hil
def configure():
    """Configure HIL"""
    config_testsuite()
    config_merge({
        'extensions': {
            'hil.ext.network_allocators.null': None,
            'hil.ext.network_allocators.vlan_pool': '',
        },
        'hil.ext.network_allocators.vlan_pool': {
            'vlans': '100-105',
        },
    })
    config.load_extensions()
예제 #17
0
파일: hil_auth.py 프로젝트: shwsun/haas
def configure():
    config_testsuite()
    config_merge({
        'extensions': {
            'hil.ext.auth.mock': '',

            # This extension is enabled by default in the tests, so we need to
            # disable it explicitly:
            'hil.ext.auth.null': None,

            'hil.ext.switches.mock': '',
        },
    })
    config.load_extensions()
예제 #18
0
def database_authentication():
    """setup the config file for using database authentication.
    This fixture is only used by Test_user class"""
    config_testsuite()
    config_merge({
        'auth': {
            'require_authentication': 'False',
        },
        'extensions': {
            'hil.ext.auth.null': None,
            'hil.ext.auth.database': '',
        },
    })
    config.load_extensions()
예제 #19
0
def database_authentication():
    """setup the config file for using database authentication.
    This fixture is only used by Test_user class"""
    config_testsuite()
    config_merge({
        'auth': {
            'require_authentication': 'False',
        },
        'extensions': {
            'hil.ext.auth.null': None,
            'hil.ext.auth.database': '',
        },
    })
    config.load_extensions()
예제 #20
0
def test_load_extension():
    """Check that putting modules in [extensions] results in importing them."""
    config_set({
        'extensions': {
            # These modules are chosen because:
            #
            # 1. They are in the standard library, and cross-platform
            # 2. If you ever think you need to import these for use in
            #    HIL, I will judge you.
            'sndhdr': '',
            'colorsys': '',
            'email.mime.audio': '',
        },
    })
    config.load_extensions()
    for module in 'sndhdr', 'colorsys', 'email.mime.audio':
        assert module in sys.modules
예제 #21
0
파일: config.py 프로젝트: CCI-MOC/hil
def test_load_extension():
    """Check that putting modules in [extensions] results in importing them."""
    config_set({
        'extensions': {
            # These modules are chosen because:
            #
            # 1. They are in the standard library, and cross-platform
            # 2. If you ever think you need to import these for use in
            #    HIL, I will judge you.
            'sndhdr': '',
            'colorsys': '',
            'email.mime.audio': '',
        },
    })
    config.load_extensions()
    for module in 'sndhdr', 'colorsys', 'email.mime.audio':
        assert module in sys.modules
예제 #22
0
파일: database.py 프로젝트: shwsun/haas
def configure():
    config_testsuite()
    config_merge({
        'auth': {
            # The tests in this module are checking the specific authorization
            # requirements of the API calls. as such, we don't want things to
            # fail due to complete lack of authentication, where they should
            # fail later when the specific authorization checks we're testing
            # for happen.
            'require_authentication': 'False',
        },
        'extensions': {
            'hil.ext.auth.database': '',
            'hil.ext.auth.null': None,
        },
    })
    config.load_extensions()
예제 #23
0
def configure():
    config_testsuite()
    config_merge({
        'auth': {
            # The tests in this module are checking the specific authorization
            # requirements of the API calls. as such, we don't want things to
            # fail due to complete lack of authentication, where they should
            # fail later when the specific authorization checks we're testing
            # for happen.
            'require_authentication': 'False',
        },
        'extensions': {
            'hil.ext.auth.database': '',
            'hil.ext.auth.null': None,
        },
    })
    config.load_extensions()
예제 #24
0
def configure():
    """Configure HIL"""
    config_testsuite()
    config_merge({
        'auth': {
            'require_authentication': 'False',
        },
        'extensions': {
            'hil.ext.switches.mock': '',
            'hil.ext.obm.mock': '',
            'hil.ext.network_allocators.null': None,
            'hil.ext.network_allocators.vlan_pool': '',
        },
        'hil.ext.network_allocators.vlan_pool': {
            'vlans': '1001-1040',
        },
    })
    config.load_extensions()
예제 #25
0
def configure():
    """Configure HIL"""
    config_testsuite()
    config_merge({
        'auth': {
            'require_authentication': 'True',
        },
        'extensions': {
            'hil.ext.auth.null': '',
            'hil.ext.switches.dellnos9': '',
            'hil.ext.network_allocators.null': None,
            'hil.ext.network_allocators.vlan_pool': '',
        },
        'hil.ext.network_allocators.vlan_pool': {
            'vlans': '40-80',
        },
    })
    config.load_extensions()
예제 #26
0
파일: dellnos9.py 프로젝트: CCI-MOC/hil
def configure():
    """Configure HIL"""
    config_testsuite()
    config_merge({
        'auth': {
            'require_authentication': 'True',
        },
        'extensions': {
            'hil.ext.auth.null': '',
            'hil.ext.switches.dellnos9': '',
            'hil.ext.network_allocators.null': None,
            'hil.ext.network_allocators.vlan_pool': '',
        },
        'hil.ext.network_allocators.vlan_pool': {
            'vlans': '40-80',
        },
    })
    config.load_extensions()
예제 #27
0
def configure():
    """Configure HIL"""
    config_testsuite()
    config_merge({
        'auth': {
            'require_authentication': 'True',
        },
        'extensions': {
            'hil.ext.switches.brocade': '',
            'hil.ext.switches.dell': '',
        },
        'hil.ext.switches.brocade': {
            'save': 'True'
        },
        'hil.ext.switches.dell': {
            'save': 'False'
        }
    })
    config.load_extensions()
예제 #28
0
파일: keystone.py 프로젝트: vsemp/hil
def configure():
    """Fixture which setups up hil.cfg, and loads extensions and such."""
    tc.config_testsuite()
    tc.config_merge({
        'extensions': {
            'hil.ext.auth.null': None,
            'hil.ext.auth.keystone': '',
        },
        'hil.ext.auth.keystone': {
            'auth_url': 'http://127.0.0.1:35357/v3',
            'auth_protocol': 'http',
            'username': '******',
            'password': '******',
            'project_name': 'admin',
            'admin_user': '******',
            'admin_password': '******',
        },
    })
    # the keystone client library actually bombs out if we don't configure
    # logging:
    config.configure_logging()
    config.load_extensions()
예제 #29
0
파일: keystone.py 프로젝트: CCI-MOC/hil
def configure():
    """Fixture which setups up hil.cfg, and loads extensions and such."""
    tc.config_testsuite()
    tc.config_merge({
        'extensions': {
            'hil.ext.auth.null': None,
            'hil.ext.auth.keystone': '',
        },
        'hil.ext.auth.keystone': {
            'auth_url': 'http://127.0.0.1:35357/v3',
            'auth_protocol': 'http',
            'username': '******',
            'password': '******',
            'project_name': 'admin',
            'admin_user': '******',
            'admin_password': '******',
        },
    })
    # the keystone client library actually bombs out if we don't configure
    # logging:
    config.configure_logging()
    config.load_extensions()
예제 #30
0
def configure():
    config_testsuite()
    config_merge({
        'auth': {
            'require_authentication': 'False',
        },
        'extensions': {
            'hil.ext.auth.null': None,
            'hil.ext.auth.database': '',
            'hil.ext.switches.mock': '',
            'hil.ext.switches.nexus': '',
            'hil.ext.switches.dell': '',
            'hil.ext.switches.brocade': '',
            'hil.ext.obm.mock': '',
            'hil.ext.obm.ipmi': '',
            'hil.ext.network_allocators.null': None,
            'hil.ext.network_allocators.vlan_pool': '',
        },
        'hil.ext.network_allocators.vlan_pool': {
            'vlans': '1001-1040',
        },
    })
    config.load_extensions()
예제 #31
0
파일: client.py 프로젝트: SahilTikale/hil
def configure():
    """Configure HIL"""
    config_testsuite()
    config_merge({
        'auth': {
            'require_authentication': 'False',
        },
        'extensions': {
            'hil.ext.auth.null': None,
            'hil.ext.auth.database': '',
            'hil.ext.switches.mock': '',
            'hil.ext.switches.nexus': '',
            'hil.ext.switches.dell': '',
            'hil.ext.switches.brocade': '',
            'hil.ext.obm.mock': '',
            'hil.ext.network_allocators.null': None,
            'hil.ext.network_allocators.vlan_pool': '',
        },
        'hil.ext.network_allocators.vlan_pool': {
            'vlans': '1001-1040',
        },
    })
    config.load_extensions()
예제 #32
0
def configure(tmpdir):
    """Set up HIL configuration.

    This creates a hil.cfg in tmpdir, and loads it. The file needs to be
    written out separately , since we invoke other commands that read it,
    besides the test process.
    """
    cfg = '\n'.join([
        "[extensions]",
        "hil.ext.network_allocators.null =",
        "hil.ext.auth.null =",
        "hil.ext.obm.ipmi = ",
        "[devel]",
        "dry_run = True",
        "[headnode]",
        "base_imgs = base-headnode, img1, img2, img3, img4",
        "[database]",
        "uri = sqlite:///" + tmpdir + "/hil.db",
    ])
    with open(tmpdir + '/hil.cfg', 'w') as f:
        f.write(cfg)
    config.load(tmpdir + '/hil.cfg')
    config.configure_logging()
    config.load_extensions()
예제 #33
0
def configure():
    """Configure HIL"""
    config_testsuite()
    config_merge({
        'auth': {
            'require_authentication': 'False',
        },
        'extensions': {
            'hil.ext.auth.null': None,
            'hil.ext.auth.mock': '',
            'hil.ext.switches.mock': '',
            'hil.ext.network_allocators.null': None,
            'hil.ext.network_allocators.vlan_pool': '',
        },
        'hil.ext.network_allocators.vlan_pool': {
            'vlans': '40-80',
        },
        'maintenance': {
            'maintenance_project': 'maintenance',
            # Keystone url acts as dummy for posting
            'url': 'http://127.0.0.1:9999/test/'
        }
    })
    config.load_extensions()
예제 #34
0
def configure():
    """Configure HIL"""
    config_testsuite()
    config_merge({
        'auth': {
            'require_authentication': 'False',
        },
        'extensions': {
            'hil.ext.switches.mock': '',
            'hil.ext.network_allocators.null': None,
            'hil.ext.network_allocators.vlan_pool': '',
        },
        'hil.ext.network_allocators.vlan_pool': {
            'vlans': '1001-1040',
        },
        'devel': {
            # Disable dry_run, so we can talk to obmd. Note: We register
            # several "real" switches in this module, but never actually
            # preform any "real" network operations on them, so a proper
            # switch setup is still not necessary.
            'dry_run': None,
        },
    })
    config.load_extensions()
예제 #35
0
파일: config.py 프로젝트: CCI-MOC/hil
def test_validate_config():
    """Test validing a HIL config file."""
    config_testsuite()
    config_merge({
        'general': {
            'log_level': 'debug',
        },
        'auth': {
            'require_authentication': 'True',
        },
        'headnode': {
            'trunk_nic': 'eth0',
            'libvirt_endpoint': 'qemu:///system',
        },
        'client': {
            'endpoint': 'http://127.0.0.1:5000',
        },
        'maintenance': {
            'maintenance_project': 'maintenance',
            'url': 'http://test.xyz',
            'shutdown': '',
        },
        'extensions': {
            'hil.ext.switches.dell': '',
            'hil.ext.switches.dellnos9': '',
            'hil.ext.switches.brocade': '',
            'hil.ext.switches.n3000': '',
            'hil.ext.switches.nexus': '',
            'hil.ext.auth.null': None,
            'hil.ext.auth.keystone': '',
            'hil.ext.network_allocators.null': None,
            'hil.ext.network_allocators.vlan_pool': '',
        },
        'hil.ext.network_allocators.vlan_pool': {
            'vlans': '12, 13-20, 100-200',
        },
        'hil.ext.switches.dell': {
            'save': 'True',
        },
        'hil.ext.switches.dellnos9': {
            'save': 'False',
        },
        'hil.ext.switches.brocade': {
            'save': 'True',
        },
        'hil.ext.switches.n3000': {
            'save': 'False',
        },
        'hil.ext.switches.nexus': {
            'save': 'True',
        },
        'hil.ext.auth.keystone': {
            'auth_url': 'https://website:35357/v3',
            'auth_protocol': 'http',
            'username': '******',
            'password': '******',
            'project_name': 'project',
            'admin_user': '******',
            'admin_password': '******',
        }
    })
    config.load_extensions()
    config.validate_config()
예제 #36
0
def configure():
    """Fixture to load the HIL config."""
    config_testsuite()
    config.load_extensions()
예제 #37
0
파일: model.py 프로젝트: SahilTikale/hil
def configure():
    """Configure HIL."""
    config_testsuite()
    config.load_extensions()
예제 #38
0
파일: ipmi.py 프로젝트: razaaliraza/hil
def configure():
    """Configure HIL"""
    config_testsuite()
    config.load_extensions()
예제 #39
0
def configure():
    config_testsuite()
    config.load_extensions()
예제 #40
0
파일: headnodes.py 프로젝트: shwsun/haas
def configure():
    config_testsuite()
    config.load_extensions()
예제 #41
0
def configure():
    """Set up the HIL config."""
    config_testsuite()
    config.configure_logging()
    config.load_extensions()
예제 #42
0
def configure():
    config_testsuite()
    config.configure_logging()
    config.load_extensions()
예제 #43
0
def test_validate_config():
    """Test validing a HIL config file."""
    config_testsuite()
    config_merge({
        'general': {
            'log_level': 'debug',
        },
        'auth': {
            'require_authentication': 'True',
        },
        'headnode': {
            'trunk_nic': 'eth0',
            'libvirt_endpoint': 'qemu:///system',
        },
        'client': {
            'endpoint': 'http://127.0.0.1:5000',
        },
        'maintenance': {
            'maintenance_project': 'maintenance',
            'url': 'http://test.xyz',
            'shutdown': '',
        },
        'extensions': {
            'hil.ext.switches.dell': '',
            'hil.ext.switches.dellnos9': '',
            'hil.ext.switches.brocade': '',
            'hil.ext.switches.n3000': '',
            'hil.ext.switches.nexus': '',
            'hil.ext.auth.null': None,
            'hil.ext.auth.keystone': '',
            'hil.ext.network_allocators.null': None,
            'hil.ext.network_allocators.vlan_pool': '',
        },
        'hil.ext.network_allocators.vlan_pool': {
            'vlans': '12, 13-20, 100-200',
        },
        'hil.ext.switches.dell': {
            'save': 'True',
        },
        'hil.ext.switches.dellnos9': {
            'save': 'False',
        },
        'hil.ext.switches.brocade': {
            'save': 'True',
        },
        'hil.ext.switches.n3000': {
            'save': 'False',
        },
        'hil.ext.switches.nexus': {
            'save': 'True',
        },
        'hil.ext.auth.keystone': {
            'auth_url': 'https://website:35357/v3',
            'auth_protocol': 'http',
            'username': '******',
            'password': '******',
            'project_name': 'project',
            'admin_user': '******',
            'admin_password': '******',
        }
    })
    config.load_extensions()
    config.validate_config()
예제 #44
0
파일: migrations.py 프로젝트: shwsun/haas
def test_db_eq(filename, make_objects, extra_config):
    """Migrating from a snapshot should create the same objects as a new db.

    `make_objects` is a function that, when run against the latest version
        of a schema, will create some set of objects.
    `filename` is the name of an sql dump of a previous database, whose
        contents were created with the then-current version of `make_objects`.
    `extra_config` specifies modifications to the hil.cfg under which the
        test is run. this is passed to `config_merge`.

    The test does the following:

        * Restore the database snapshot and run the migration scripts to update
          its contents to the current schema.
        * Create a fresh database according to the current schema, and execute
          `make_objects`.
        * Compare the two resulting databases. The test passes if and only if
          they are the same.
    """

    config_merge(extra_config)
    load_extensions()
    server.register_drivers()
    server.validate_state()

    def run_fn(f):
        """Run the function f and return a representation of its db."""

        # We can't just do db.drop_all(), since db's metadata won't
        # necessarily reflect the contents of the database. If there are
        # tables it doesn't know about, it may raise an exception.
        with app.app_context():
            drop_tables()
            f()

        return get_db_state()

    upgraded = run_fn(lambda: load_dump(filename))
    fresh = run_fn(lambda: fresh_create(make_objects))
    drop_tables()

    def censor_nondeterminism(string):
        """Censor parts of the output whose values are non-deterministic.

        Certain objects (currently just uuids) are generated
        non-deterministically, and will thus be different between databases
        even if everything is working. This function censors the relevant
        parts of `string`, so that they don't cause the tests to fail.
        """
        hex_re = r'[0-9a-f]'
        uuid_re = hex_re * 8 + ('-' + hex_re * 4) * 3 + '-' + hex_re * 12
        return re.sub(uuid_re, '<<UUID>>', string)

    differ = difflib.Differ()
    upgraded = censor_nondeterminism(pformat(upgraded)).split('\n')
    fresh = censor_nondeterminism(pformat(fresh)).split('\n')

    assert upgraded == fresh, (
        "Databases are different!\n\n" +
        pformat(list(differ.compare(upgraded, fresh)))
    )