예제 #1
0
def test_put_infra_config_ok(
        zk, client, infra_info, test_application_name, test_application_token,
        test_redis, last_audit_log, mocker,
        scope_type, scope_name,
        exception_on_recording_downstream):
    major_application_name = test_application_name

    logger = mocker.patch(
        'huskar_api.api.middlewares.logger.logger', autospec=True)

    exit_scope_name = scope_name.replace('altb1', 'alta1')
    infra_info.set_by_name('r100010', scope_type, exit_scope_name, {
        'url': 'redis://localhost:6543'})
    infra_info.save()

    url = 'sam+redis://%s/overall.alta' % test_redis
    r = client.put(
        '/api/infra-config/%s/redis/r100010' % test_application_name,
        query_string={'scope_type': scope_type, 'scope_name': scope_name},
        data=json.dumps({'url': url}),
        headers={'Authorization': test_application_token,
                 'Content-Type': 'application/json'})
    assert_response_ok(r)
    assert r.json['data'] == {'infra_config': [
        {'scope_type': scope_type, 'scope_name': exit_scope_name,
         'value': {'url': 'redis://localhost:6543'}},
        {'scope_type': scope_type, 'scope_name': scope_name,
         'value': {'url': url}},
    ]}
    request_args = json.loads(logger.mock_calls[0][1][-6])
    assert 'url' not in request_args

    InfraDownstream.flush_cache_by_application(test_redis)
    ds = InfraDownstream.get_multi_by_application(test_redis)
    if exception_on_recording_downstream:
        assert len(ds) == 0
    else:
        assert len(ds) == 1
        assert ds[0].user_application_name == major_application_name
        assert ds[0].user_infra_type == 'redis'
        assert ds[0].user_infra_name == 'r100010'

    audit_log = last_audit_log()
    assert audit_log and audit_log.action_name == 'UPDATE_INFRA_CONFIG'
    assert audit_log.action_json['application_name'] == major_application_name
    assert audit_log.action_json['infra_type'] == 'redis'
    assert audit_log.action_json['infra_name'] == 'r100010'
    assert audit_log.action_json['scope_type'] == scope_type
    assert audit_log.action_json['scope_name'] == scope_name
    assert audit_log.action_json['data']['new'] == {'url': url}
    assert audit_log.action_json['data']['old'] is None

    url = 'sam+redis://%s/overall.alta1' % test_redis
    r = client.put(
        '/api/infra-config/%s/redis/r100010' % test_application_name,
        query_string={'scope_type': scope_type, 'scope_name': scope_name},
        data=json.dumps({'url': url}),
        headers={'Authorization': test_application_token,
                 'Content-Type': 'application/json'})
    assert_response_ok(r)
예제 #2
0
def test_bind(db):
    InfraDownstream.bind('base.foo', 'redis', 'mycache', 'idcs', 'alta1',
                         'url', 'redis.foo')
    InfraDownstream.bind('base.bar', 'redis', 'mycache', 'idcs', 'alta1',
                         'url', 'redis.foo')
    InfraDownstream.bind('base.bar', 'redis', 'mycache', 'idcs', 'altb1',
                         'url', 'redis.foo')
    InfraDownstream.bind('base.bar', 'redis', u'缓存', 'idcs', 'alta1', 'url',
                         'redis.foo')
    result = list_infra_downstream_by_application_name(db, 'redis.foo')
    assert len(result) == 4
    assert result[0].user_application_name == 'base.foo'
    assert result[0].user_scope_name == 'alta1'
    assert result[1].user_application_name == 'base.bar'
    assert result[1].user_scope_name == 'alta1'
    assert result[2].user_application_name == 'base.bar'
    assert result[2].user_scope_name == 'altb1'
    assert result[3].user_application_name == 'base.bar'
    assert result[3].user_scope_name == 'alta1'
    assert result[3].user_infra_name == u'缓存'
    result = list_infra_downstream_by_application_name(db, 'redis.bar')
    assert len(result) == 0

    InfraDownstream.bind('base.bar', 'redis', 'mycache', 'idcs', 'alta1',
                         'url', 'redis.bar')
    result = list_infra_downstream_by_application_name(db, 'redis.foo')
    assert len(result) == 3
    assert result[0].user_application_name == 'base.foo'
    assert result[0].user_scope_name == 'alta1'
    assert result[1].user_application_name == 'base.bar'
    assert result[1].user_scope_name == 'altb1'
    result = list_infra_downstream_by_application_name(db, 'redis.bar')
    assert len(result) == 1
    assert result[0].user_application_name == 'base.bar'
    assert result[0].user_scope_name == 'alta1'
예제 #3
0
def test_get_multi_by_application(db):
    InfraDownstream.bindmany() \
        .bind('base.foo', 'redis', 'mycache', 'idcs', 'alta1', 'url',
              'redis.foo') \
        .bind('base.bar', 'redis', 'mycache', 'idcs', 'alta1', 'url',
              'redis.foo') \
        .bind('base.bar', 'redis', 'frog+1s', 'idcs', 'alta1', 'url',
              'redis.bar') \
        .bind('base.bar', 'redis', 'frog+1s', 'idcs', 'altb1', 'url',
              'redis.bar') \
        .commit()

    r = InfraDownstream.get_multi_by_application('redis.foo')
    assert len(r) == 2
    assert r[0].user_application_name == 'base.foo'
    assert r[0].user_infra_type == 'redis'
    assert r[0].user_infra_name == 'mycache'
    assert r[0].user_scope_name == 'alta1'
    assert r[1].user_application_name == 'base.bar'
    assert r[1].user_infra_type == 'redis'
    assert r[1].user_infra_name == 'mycache'
    assert r[1].user_scope_name == 'alta1'

    r = InfraDownstream.get_multi_by_application('redis.bar')
    assert len(r) == 2
    assert r[0].user_application_name == 'base.bar'
    assert r[0].user_infra_type == 'redis'
    assert r[0].user_infra_name == 'frog+1s'
    assert r[0].user_scope_name == 'alta1'
    assert r[1].user_application_name == 'base.bar'
    assert r[1].user_infra_type == 'redis'
    assert r[1].user_infra_name == 'frog+1s'
    assert r[1].user_scope_name == 'altb1'
예제 #4
0
    def post(self, infra_application_name):
        """Invalidates cache and shows downstream information of infra.

        The response is the same to the ``GET`` method.

        :param infra_application_name: The application name of infrastructure.
        :<header Authorization: Huskar Token (See :ref:`token`)
        :status 200: The result is in the response.
        """
        InfraDownstream.flush_cache_by_application(infra_application_name)
        return self.get(infra_application_name)
예제 #5
0
    def _update(self, application_name, request, infra_type, infra_name):
        check_application_auth(application_name, Authority.WRITE)
        check_infra_type(infra_type)

        scope_type = request.args['scope_type']
        scope_name = request.args['scope_name']
        check_scope(scope_type, scope_name)

        value = request.get_json()
        if not value or not isinstance(value, dict):
            abort(400, 'Unacceptable content type or content body')

        infra_info = InfraInfo(huskar_client.client, application_name,
                               infra_type)
        infra_info.load()
        old_value = infra_info.get_by_name(infra_name, scope_type, scope_name)

        yield application_name, infra_info, scope_type, scope_name, value

        infra_urls = infra_info.extract_urls(value)
        infra_application_names = extract_application_names(infra_urls)
        new_value = infra_info.get_by_name(infra_name, scope_type, scope_name)

        with audit_log(audit_log.types.UPDATE_INFRA_CONFIG,
                       application_name=application_name,
                       infra_type=infra_type,
                       infra_name=infra_name,
                       scope_type=scope_type,
                       scope_name=scope_name,
                       old_value=old_value,
                       new_value=new_value):
            for infra_application_name in infra_application_names:
                check_application(infra_application_name)

            infra_info.save()

            with suppress_exceptions('infra config updating'):
                infra_urls = infra_info.extract_urls(value, as_dict=True)
                infra_applications = extract_application_names(infra_urls)
                for field_name, infra_application_name in \
                        infra_applications.iteritems():
                    InfraDownstream.bind(application_name, infra_type,
                                         infra_name, scope_type, scope_name,
                                         field_name, infra_application_name)
예제 #6
0
    def delete(self, application_name, infra_type, infra_name):
        """Deletes the infrastructure configuration in specified application.

        :param application_name: The application which uses infrastructure.
        :param infra_type: ``database``, ``redis`` or ``amqp``.
        :param infra_name: The unique code-reference name of infrastructure.
        :query scope_type: ``idcs`` or ``clusters``.
        :query scope_name: The ezone id or clsuter name.
        :<header Authorization: Huskar Token (See :ref:`token`)
        :status 200: The same as ``GET``.
        """
        check_application_auth(application_name, Authority.WRITE)
        check_infra_type(infra_type)

        scope_type = request.args['scope_type']
        scope_name = request.args['scope_name']
        check_scope(scope_type, scope_name)

        infra_info = InfraInfo(huskar_client.client, application_name,
                               infra_type)
        infra_info.load()
        old_value = infra_info.get_by_name(infra_name, scope_type, scope_name)
        infra_info.delete_by_name(infra_name, scope_type, scope_name)
        with audit_log(audit_log.types.DELETE_INFRA_CONFIG,
                       application_name=application_name,
                       infra_type=infra_type,
                       infra_name=infra_name,
                       scope_type=scope_type,
                       scope_name=scope_name,
                       old_value=old_value,
                       new_value=None):
            infra_info.save()

        with suppress_exceptions('infra config deletion'):
            old_urls = infra_info.extract_urls(old_value or {}, as_dict=True)
            for field_name in frozenset(extract_application_names(old_urls)):
                InfraDownstream.unbind(application_name, infra_type,
                                       infra_name, scope_type, scope_name,
                                       field_name)

        infra_config = infra_info.list_by_infra_name(infra_name)
        return api_response({'infra_config': dump_infra_config(infra_config)})
예제 #7
0
def test_unbind_stale(db):
    m1 = InfraDownstream.bindmany() \
        .bind('base.foo', 'redis', 'mycache', 'idcs', 'alta1', 'url',
              'redis.foo') \
        .bind('base.bar', 'redis', 'mycache', 'idcs', 'alta1', 'url',
              'redis.foo') \
        .commit()
    result = list_infra_downstream_by_application_name(db, 'redis.foo')
    assert len(result) == 2

    m2 = InfraDownstream.bindmany() \
        .bind('base.foo', 'redis', 'mycache', 'idcs', 'alta1', 'url',
              'redis.foo') \
        .unbind_stale() \
        .commit()
    result = list_infra_downstream_by_application_name(db, 'redis.foo')
    assert len(result) == 1
    assert result[0].user_application_name == 'base.foo'
    assert result[0].version == m2._timestamp
    assert result[0].version > m1._timestamp
예제 #8
0
파일: infra.py 프로젝트: zhoudaqing/huskar
def collect_infra_config():
    logger.info('Looking up application list')
    application_list = Application.get_all()
    builder = InfraDownstream.bindmany()
    client = huskar_client.client

    for application in application_list:
        application_name = application.application_name
        logger.info('Collecting %s', application_name)
        iterator = _collect_infra_upstream(client, application_name)
        iterator = _bind_infra_upstream(builder, iterator, application_name)
        for upstream in iterator:
            logger.info('Recorded %r', upstream)
            InfraDownstream.flush_cache_by_application(
                upstream.infra_application_name)
        builder.commit()
        logger.info('Committed %s', application_name)

    logger.info('Deleting stale records')
    builder.unbind_stale().commit()
    logger.info('Done')
예제 #9
0
def test_bind_various_scopes_and_fields(db):
    InfraDownstream.bindmany() \
        .bind('base.foo', 'database', 'mydb', 'idcs', 'alta1', 'master',
              'dal.test.master') \
        .bind('base.foo', 'database', 'mydb', 'idcs', 'alta1', 'slave',
              'dal.test.auto') \
        .bind('base.foo', 'database', 'mydb', 'clusters', 'sandbox', 'master',
              'dal.sandbox.master') \
        .bind('base.foo', 'database', 'mydb', 'clusters', 'sandbox', 'slave',
              'dal.sandbox.auto') \
        .bind('base.foo', 'database', 'mydb', 'idcs', 'altb1', 'master',
              'dal.test.master') \
        .bind('base.foo', 'database', 'mydb', 'idcs', 'altb1', 'slave',
              'dal.test.auto') \
        .commit()

    r = InfraDownstream.get_multi_by_application('dal.test.master')
    assert len(r) == 2
    assert r[0].user_application_name == 'base.foo'
    assert r[0].user_infra_type == 'database'
    assert r[0].user_infra_name == 'mydb'
    assert r[0].user_scope_pair == ('idcs', 'alta1')
    assert r[0].user_field_name == 'master'
    assert r[1].user_application_name == 'base.foo'
    assert r[1].user_infra_type == 'database'
    assert r[1].user_infra_name == 'mydb'
    assert r[1].user_scope_pair == ('idcs', 'altb1')
    assert r[1].user_field_name == 'master'

    r = InfraDownstream.get_multi_by_application('dal.test.auto')
    assert len(r) == 2
    assert r[0].user_application_name == 'base.foo'
    assert r[0].user_infra_type == 'database'
    assert r[0].user_infra_name == 'mydb'
    assert r[0].user_scope_pair == ('idcs', 'alta1')
    assert r[0].user_field_name == 'slave'
    assert r[1].user_application_name == 'base.foo'
    assert r[1].user_infra_type == 'database'
    assert r[1].user_infra_name == 'mydb'
    assert r[1].user_scope_pair == ('idcs', 'altb1')
    assert r[1].user_field_name == 'slave'

    r = InfraDownstream.get_multi_by_application('dal.sandbox.master')
    assert len(r) == 1
    assert r[0].user_application_name == 'base.foo'
    assert r[0].user_infra_type == 'database'
    assert r[0].user_infra_name == 'mydb'
    assert r[0].user_scope_pair == ('clusters', 'sandbox')
    assert r[0].user_field_name == 'master'

    r = InfraDownstream.get_multi_by_application('dal.sandbox.auto')
    assert len(r) == 1
    assert r[0].user_application_name == 'base.foo'
    assert r[0].user_infra_type == 'database'
    assert r[0].user_infra_name == 'mydb'
    assert r[0].user_scope_pair == ('clusters', 'sandbox')
    assert r[0].user_field_name == 'slave'
예제 #10
0
def test_unbind(db):
    InfraDownstream.bind('base.foo', 'redis', 'mycache', 'idcs', 'alta1',
                         'url', 'redis.foo')
    InfraDownstream.bind('base.foo', 'redis', 'mycache', 'idcs', 'altb1',
                         'url', 'redis.foo')
    InfraDownstream.bind('base.bar', 'redis', 'mycache', 'idcs', 'alta1',
                         'url', 'redis.foo')
    result = list_infra_downstream_by_application_name(db, 'redis.foo')
    assert len(result) == 3

    InfraDownstream.unbind('base.bar', 'redis', 'mycache', 'idcs', 'alta1',
                           'url')
    result = list_infra_downstream_by_application_name(db, 'redis.foo')
    assert len(result) == 2
    assert result[0].user_application_name == 'base.foo'
    assert result[0].user_scope_name == 'alta1'
    assert result[1].user_application_name == 'base.foo'
    assert result[1].user_scope_name == 'altb1'
예제 #11
0
    def get(self, infra_application_name):
        """Shows downstream information of infrastructure.

        The response looks like::

            [{
              "user_application_name": "base.foo",
              "user_infra_type": "database",
              "user_infra_name": "db-1",
              "version": 1000001,
              "updated_at": "... (ISO formatted datetime)",
              "created_at": "... (ISO formatted datetime)"
            }]

        :param infra_application_name: The application name of infrastructure.
        :<header Authorization: Huskar Token (See :ref:`token`)
        :status 200: The result is in the response.
        """
        r = InfraDownstream.get_multi_by_application(infra_application_name)
        data = infra_downstream_schema.dump(r, many=True).data
        return api_response({'downstream': data})
예제 #12
0
def test_bindmany(db):
    m = InfraDownstream.bindmany() \
        .bind('base.foo', 'redis', 'mycache', 'idcs', 'alta1', 'url',
              'redis.foo') \
        .bind('base.bar', 'redis', 'mycache', 'idcs', 'alta1', 'url',
              'redis.foo') \
        .commit()
    result = list_infra_downstream_by_application_name(db, 'redis.foo')
    assert len(result) == 2
    assert result[0].user_application_name == 'base.foo'
    assert result[1].user_application_name == 'base.bar'
    result = list_infra_downstream_by_application_name(db, 'redis.bar')
    assert len(result) == 0

    m.bindmany() \
        .bind('base.bar', 'redis', 'mycache', 'idcs', 'alta1', 'url',
              'redis.bar') \
        .commit()
    result = list_infra_downstream_by_application_name(db, 'redis.foo')
    assert len(result) == 1
    assert result[0].user_application_name == 'base.foo'
    result = list_infra_downstream_by_application_name(db, 'redis.bar')
    assert len(result) == 1
    assert result[0].user_application_name == 'base.bar'
예제 #13
0
def test_delete_infra_config_ok(
        client, db, infra_info, test_application_name, test_application_token,
        last_audit_log):
    major_application_name = test_application_name
    infra_info.set_by_name('r100010', 'idcs', 'alta1', {
        'url': 'sam+redis://redis.100010/overall.alta1'})
    infra_info.set_by_name('r100010', 'idcs', 'altb1', {
        'url': 'sam+redis://redis.100010/overall.altb1'})
    infra_info.save()

    InfraDownstream.bindmany() \
        .bind(major_application_name, 'redis', 'r100010', 'idcs', 'alta1',
              'url', 'redis.100010') \
        .bind(major_application_name, 'redis', 'r100010', 'idcs', 'altb1',
              'url', 'redis.100010') \
        .commit()

    InfraDownstream.flush_cache_by_application('redis.100010')
    ds = InfraDownstream.get_multi_by_application('redis.100010')
    assert len(ds) == 2

    r = client.delete(
        '/api/infra-config/%s/redis/r100010' % test_application_name,
        query_string={'scope_type': 'idcs', 'scope_name': 'altb1'},
        headers={'Authorization': test_application_token})
    assert_response_ok(r)
    assert r.json['data'] == {'infra_config': [
        {'scope_type': 'idcs', 'scope_name': 'alta1',
         'value': {'url': 'sam+redis://redis.100010/overall.alta1'}},
    ]}

    InfraDownstream.flush_cache_by_application('redis.100010')
    ds = InfraDownstream.get_multi_by_application('redis.100010')
    assert len(ds) == 1
    assert ds[0].user_application_name == major_application_name
    assert ds[0].user_infra_type == 'redis'
    assert ds[0].user_infra_name == 'r100010'

    r = client.delete(
        '/api/infra-config/%s/redis/r100010' % test_application_name,
        query_string={'scope_type': 'idcs', 'scope_name': 'alta1'},
        headers={'Authorization': test_application_token})
    assert_response_ok(r)
    assert r.json['data'] == {'infra_config': []}

    InfraDownstream.flush_cache_by_application('redis.100010')
    ds = InfraDownstream.get_multi_by_application('redis.100010')
    assert len(ds) == 0

    audit_log = last_audit_log()
    assert audit_log and audit_log.action_name == 'DELETE_INFRA_CONFIG'
    assert audit_log.action_json['application_name'] == major_application_name
    assert audit_log.action_json['infra_type'] == 'redis'
    assert audit_log.action_json['infra_name'] == 'r100010'
    assert audit_log.action_json['scope_type'] == 'idcs'
    assert audit_log.action_json['scope_name'] == 'alta1'
    assert audit_log.action_json['data']['new'] is None
    assert audit_log.action_json['data']['old'] == {
        'url': 'sam+redis://redis.100010/overall.alta1'}
예제 #14
0
def test_get_infra_downstream(client, test_token):
    InfraDownstream.bindmany() \
        .bind('base.foo', 'redis', 'cache-1', 'idcs', 'alta1', 'url',
              'redis.100010') \
        .bind('base.foo', 'redis', 'cache-1', 'idcs', 'altb1', 'url',
              'redis.100010') \
        .bind('base.bar', 'redis', 'cache-1', 'idcs', 'alta1', 'url',
              'redis.100010') \
        .bind('base.bar', 'redis', 'cache-2', 'idcs', 'alta1', 'url',
              'redis.100011') \
        .commit()

    r = client.get('/api/infra-config-downstream/redis.100010',
                   headers={'Authorization': test_token})
    assert_response_ok(r)
    downstream = r.json['data']['downstream']
    assert len(downstream) == 3
    assert downstream[0]['user_application_name'] == 'base.foo'
    assert downstream[0]['user_infra_type'] == 'redis'
    assert downstream[0]['user_infra_name'] == 'cache-1'
    assert downstream[0]['user_scope_pair'] == {
        'type': 'idcs',
        'name': 'alta1'
    }
    assert downstream[0]['user_field_name'] == 'url'
    assert downstream[1]['user_application_name'] == 'base.foo'
    assert downstream[1]['user_infra_type'] == 'redis'
    assert downstream[1]['user_infra_name'] == 'cache-1'
    assert downstream[1]['user_scope_pair'] == {
        'type': 'idcs',
        'name': 'altb1'
    }
    assert downstream[1]['user_field_name'] == 'url'
    assert downstream[2]['user_application_name'] == 'base.bar'
    assert downstream[2]['user_infra_type'] == 'redis'
    assert downstream[2]['user_infra_name'] == 'cache-1'
    assert downstream[2]['user_scope_pair'] == {
        'type': 'idcs',
        'name': 'alta1'
    }
    assert downstream[2]['user_field_name'] == 'url'

    r = client.get('/api/infra-config-downstream/redis.100011',
                   headers={'Authorization': test_token})
    assert_response_ok(r)
    downstream = r.json['data']['downstream']
    assert len(downstream) == 1
    assert downstream[0]['user_application_name'] == 'base.bar'
    assert downstream[0]['user_infra_type'] == 'redis'
    assert downstream[0]['user_infra_name'] == 'cache-2'
    assert downstream[0]['user_scope_pair'] == {
        'type': 'idcs',
        'name': 'alta1'
    }
    assert downstream[0]['user_field_name'] == 'url'

    InfraDownstream.bind('base.baz', 'redis', 'cache-1', 'idcs', 'alta1',
                         'url', 'redis.100011')
    InfraDownstream.unbind('base.bar', 'redis', 'cache-2', 'idcs', 'alta1',
                           'url')

    # Stale data
    r = client.get('/api/infra-config-downstream/redis.100011',
                   headers={'Authorization': test_token})
    assert_response_ok(r)
    downstream = r.json['data']['downstream']
    assert len(downstream) == 1
    assert downstream[0]['user_application_name'] == 'base.bar'
    assert downstream[0]['user_infra_name'] == 'cache-2'
    assert downstream[0]['user_scope_pair'] == {
        'type': 'idcs',
        'name': 'alta1'
    }
    assert downstream[0]['user_field_name'] == 'url'

    # Fresh data
    r = client.post('/api/infra-config-downstream/redis.100011',
                    headers={'Authorization': test_token})
    assert_response_ok(r)
    downstream = r.json['data']['downstream']
    assert len(downstream) == 1
    assert downstream[0]['user_application_name'] == 'base.baz'
    assert downstream[0]['user_infra_name'] == 'cache-1'
    assert downstream[0]['user_scope_pair'] == {
        'type': 'idcs',
        'name': 'alta1'
    }
    assert downstream[0]['user_field_name'] == 'url'
예제 #15
0
def test_collect_infra_config(zk, db, faker, test_team):
    prefix = faker.uuid4()[:8]
    for x in 'foo', 'bar':
        x = '%s_%s' % (prefix, x)
        Application.create(x, test_team.id)
        InfraDownstream.bindmany()\
            .bind(x, 'database', 'stale-db', 'idcs', 'altb1', 'master',
                  'dal.foo.master') \
            .bind(x, 'database', 'stale-db', 'idcs', 'altb1', 'slave',
                  'dal.foo.auto') \
            .bind(x, 'redis', 'stale-cache', 'idcs', 'altb1', 'url',
                  'redis.foo') \
            .commit()
        mysql_url = {
            'master': 'sam+mysql://root:[email protected]/%s_db' % x,
            'slave': 'sam+mysql://root:[email protected]/%s_db' % x}
        redis_url = {'url': 'sam+redis://redis.foo'}
        infra_info = InfraInfo(zk, x, 'database')
        infra_info.load()
        infra_info.set_by_name('db', 'idcs', 'altb1', mysql_url)
        infra_info.save()
        infra_info = InfraInfo(zk, x, 'redis')
        infra_info.load()
        infra_info.set_by_name('cache', 'idcs', 'altb1', redis_url)
        infra_info.save()

    InfraDownstream.flush_cache_by_application('dal.foo.auto')
    ds = InfraDownstream.get_multi_by_application('dal.foo.auto')
    assert all(d.user_infra_name == 'stale-db' for d in ds)

    InfraDownstream.flush_cache_by_application('redis.auto')
    ds = InfraDownstream.get_multi_by_application('redis.foo')
    assert all(d.user_infra_name == 'stale-cache' for d in ds)

    list(_collect_infra_upstream(zk, u'error\u00a0'))

    collect_infra_config()

    InfraDownstream.flush_cache_by_application('dal.foo.auto')
    ds = InfraDownstream.get_multi_by_application('dal.foo.auto')
    assert len(ds) == 2
    assert ds[0].user_application_name == '%s_foo' % prefix
    assert ds[0].user_infra_type == 'database'
    assert ds[0].user_infra_name == 'db'
    assert ds[0].user_scope_pair == ('idcs', 'altb1')
    assert ds[0].user_field_name == 'slave'
    assert ds[1].user_application_name == '%s_bar' % prefix
    assert ds[1].user_infra_type == 'database'
    assert ds[1].user_infra_name == 'db'
    assert ds[1].user_scope_pair == ('idcs', 'altb1')
    assert ds[1].user_field_name == 'slave'

    InfraDownstream.flush_cache_by_application('redis.auto')
    ds = InfraDownstream.get_multi_by_application('redis.foo')
    assert len(ds) == 2
    assert ds[0].user_application_name == '%s_foo' % prefix
    assert ds[0].user_infra_type == 'redis'
    assert ds[0].user_infra_name == 'cache'
    assert ds[0].user_scope_pair == ('idcs', 'altb1')
    assert ds[0].user_field_name == 'url'
    assert ds[1].user_application_name == '%s_bar' % prefix
    assert ds[1].user_infra_type == 'redis'
    assert ds[1].user_infra_name == 'cache'
    assert ds[1].user_scope_pair == ('idcs', 'altb1')
    assert ds[1].user_field_name == 'url'