def test_copy_config():
    old_sdk_key = "OLD_SDK_KEY"
    new_sdk_key = "NEW_SDK_KEY"

    old_config = Config(sdk_key=old_sdk_key, stream=False)

    assert old_config.sdk_key is old_sdk_key
    assert old_config.stream is False

    new_config = old_config.copy_with_new_sdk_key(new_sdk_key)
    assert new_config.sdk_key is new_sdk_key
    assert new_config.stream is False
Beispiel #2
0
def test_can_use_https_proxy_via_environment_var(monkeypatch):
    with start_server() as server:
        monkeypatch.setenv('https_proxy', server.uri)
        config = Config(sdk_key='sdk-key',
                        events_uri='https://not-real',
                        diagnostic_opt_out=True)
        _verify_https_proxy_is_used(server, config)
Beispiel #3
0
def test_does_not_block_on_full_inbox():
    config = Config(
        events_max_pending=1
    )  # this sets the size of both the inbox and the outbox to 1
    ep_inbox_holder = [None]
    ep_inbox = None

    def dispatcher_factory(inbox, config, http, diag):
        ep_inbox_holder[
            0] = inbox  # it's an array because otherwise it's hard for a closure to modify a variable
        return None  # the dispatcher object itself doesn't matter, we only manipulate the inbox

    def event_consumer():
        while True:
            message = ep_inbox.get(block=True)
            if message.type == 'stop':
                message.param.set()
                return

    def start_consuming_events():
        Thread(target=event_consumer).start()

    with DefaultEventProcessor(config, mock_http, dispatcher_factory) as ep:
        ep_inbox = ep_inbox_holder[0]
        event1 = {'kind': 'custom', 'key': 'event1', 'user': user}
        event2 = {'kind': 'custom', 'key': 'event2', 'user': user}
        ep.send_event(event1)
        ep.send_event(event2)  # this event should be dropped - inbox is full
        message1 = ep_inbox.get(block=False)
        had_no_more = ep_inbox.empty()
        start_consuming_events()
        assert message1.param == event1
        assert had_no_more
 def __init__(self, **kwargs):
     if not 'diagnostic_opt_out' in kwargs:
         kwargs['diagnostic_opt_out'] = True
     if not 'sdk_key' in kwargs:
         kwargs['sdk_key'] = 'SDK_KEY'
     config = Config(**kwargs)
     diagnostic_accumulator = _DiagnosticAccumulator(create_diagnostic_id(config))
     DefaultEventProcessor.__init__(self, config, mock_http, diagnostic_accumulator = diagnostic_accumulator)
def test_sdk_key_is_sent():
    setup_processor(Config(sdk_key = 'SDK_KEY'))

    ep.send_event({ 'kind': 'identify', 'user': user })
    ep.flush()
    ep._wait_until_inactive()

    assert mock_http.request_headers.get('Authorization') is 'SDK_KEY'
Beispiel #6
0
def test_general_connection_error_does_not_cause_immediate_failure(
        ignore_mock):
    mock_requester.exception = Exception("bad")
    start_time = time.time()
    setup_processor(Config("SDK_KEY"))
    ready.wait(0.3)
    assert not pp.initialized()
    assert mock_requester.request_count >= 2
Beispiel #7
0
def get_ld_client():
    #if this was an app in prod, keey would go in secret file
    #hard-coding as a shortcut for now! 
    if "ld_client" not in g:
        ldclient.set_config(Config("sdk-6d5668a8-bca4-43e8-a4ed-aae8b501be6c"))
        g.ld_client = ldclient.get()

    return g.ld_client
def test_create_diagnostic_id():
    test_config = Config(sdk_key="SDK_KEY", http=HTTPConfig())
    diag_id = create_diagnostic_id(test_config)
    assert len(diag_id) == 2
    uid = diag_id['diagnosticId']
    # Will throw if invalid UUID4
    uuid.UUID('urn:uuid:' + uid)
    assert diag_id['sdkKeySuffix'] == 'DK_KEY'
def test_get_one_flag_returns_data():
    with start_server() as server:
        config = Config(sdk_key='sdk-key', base_uri=server.uri)
        fr = FeatureRequesterImpl(config)
        key = 'flag1'
        flag_data = {'key': key}
        server.setup_json_response('/sdk/latest-flags/' + key, flag_data)
        result = fr.get_one(FEATURES, key)
        assert result == flag_data
def test_user_is_filtered_in_custom_event():
    setup_processor(Config(inline_users_in_events = True, all_attributes_private = True))

    e = { 'kind': 'custom', 'key': 'eventkey', 'user': user, 'data': { 'thing': 'stuff '} }
    ep.send_event(e)

    output = flush_and_get_events()
    assert len(output) == 1
    check_custom_event(output[0], e, filtered_user)
def test_cannot_connect_with_selfsigned_cert_by_default():
    with start_secure_server() as server:
        server.for_path('/sdk/latest-all', poll_content())
        config = Config(sdk_key='sdk_key',
                        base_uri=server.uri,
                        stream=False,
                        send_events=False)
        with LDClient(config=config, start_wait=1.5) as client:
            assert not client.is_initialized()
Beispiel #12
0
def test_set_config():
    _reset_client()
    with start_server() as stream_server:
        with stream_content(make_put_event()) as stream_handler:
            try:
                stream_server.for_path('/all', stream_handler)

                ldclient.set_config(Config(sdk_key, offline=True))
                assert ldclient.get().is_offline() is True

                ldclient.set_config(Config(sdk_key, stream_uri = stream_server.uri, send_events = False))
                assert ldclient.get().is_offline() is False
                wait_until(ldclient.get().is_initialized, timeout=10)

                r = stream_server.await_request()
                assert r.headers['Authorization'] == sdk_key
            finally:
                _reset_client()
def test_custom_event_can_contain_inline_user():
    setup_processor(Config(inline_users_in_events = True))

    e = { 'kind': 'custom', 'key': 'eventkey', 'user': user, 'data': { 'thing': 'stuff '} }
    ep.send_event(e)

    output = flush_and_get_events()
    assert len(output) == 1
    check_custom_event(output[0], e, user)
def test_can_connect_with_selfsigned_cert_if_ssl_verify_is_false():
    with start_secure_server() as server:
        server.for_path('/sdk/latest-all', poll_content())
        config = Config(sdk_key='sdk_key',
                        base_uri=server.uri,
                        stream=False,
                        send_events=False,
                        verify_ssl=False)
        with LDClient(config=config) as client:
            assert client.is_initialized()
def test_custom_event_is_queued_with_user():
    setup_processor(Config())

    e = { 'kind': 'custom', 'key': 'eventkey', 'user': user, 'data': { 'thing': 'stuff '} }
    ep.send_event(e)

    output = flush_and_get_events()
    assert len(output) == 2
    check_index_event(output[0], e, user)
    check_custom_event(output[1], e, None)
def test_can_connect_with_selfsigned_cert_by_setting_ca_certs():
    with start_secure_server() as server:
        server.for_path('/sdk/latest-all', poll_content())
        config = Config(sdk_key='sdk_key',
                        base_uri=server.uri,
                        stream=False,
                        send_events=False,
                        http=HTTPConfig(ca_certs='./testing/selfsigned.pem'))
        with LDClient(config=config) as client:
            assert client.is_initialized()
def test_event_payload_id_is_sent():
    with DefaultEventProcessor(Config(sdk_key='SDK_KEY'), mock_http) as ep:
        ep.send_event({'kind': 'identify', 'user': user})
        ep.flush()
        ep._wait_until_inactive()

        headerVal = mock_http.request_headers.get('X-LaunchDarkly-Payload-ID')
        assert headerVal is not None
        # Throws on invalid UUID
        uuid.UUID(headerVal)
def test_nontracked_events_are_summarized():
    setup_processor(Config())

    e1 = {
        'kind': 'feature',
        'key': 'flagkey1',
        'version': 11,
        'user': user,
        'variation': 1,
        'value': 'value1',
        'default': 'default1',
        'trackEvents': False
    }
    e2 = {
        'kind': 'feature',
        'key': 'flagkey2',
        'version': 22,
        'user': user,
        'variation': 2,
        'value': 'value2',
        'default': 'default2',
        'trackEvents': False
    }
    ep.send_event(e1)
    ep.send_event(e2)

    output = flush_and_get_events()
    assert len(output) == 2
    check_index_event(output[0], e1, user)
    se = output[1]
    assert se['kind'] == 'summary'
    assert se['startDate'] == e1['creationDate']
    assert se['endDate'] == e2['creationDate']
    assert se['features'] == {
        'flagkey1': {
            'default':
            'default1',
            'counters': [{
                'version': 11,
                'variation': 1,
                'value': 'value1',
                'count': 1
            }]
        },
        'flagkey2': {
            'default':
            'default2',
            'counters': [{
                'version': 22,
                'variation': 2,
                'value': 'value2',
                'count': 1
            }]
        }
    }
Beispiel #19
0
    def init_app(self, app):
        """Initialize the Feature Flag environment."""
        self.app = app
        self.sdk_key = app.config.get('LD_SDK_KEY')

        if app.env == 'production':
            config = Config(sdk_key=self.sdk_key, connect_timeout=5)
        else:
            factory = FileDataSource.factory(paths=['flags.json'],
                                             auto_update=True)
            config = Config(sdk_key=self.sdk_key,
                            update_processor_class=factory,
                            send_events=False)

        ldclient_set_config(config)
        client = ldclient_get()

        app.extensions['featureflags'] = client

        app.teardown_appcontext(self.teardown)
def test_can_connect_with_selfsigned_cert_if_disable_ssl_verification_is_true(
):
    with start_secure_server() as server:
        server.for_path('/sdk/latest-all', poll_content())
        config = Config(sdk_key='sdk_key',
                        base_uri=server.uri,
                        stream=False,
                        send_events=False,
                        http=HTTPConfig(disable_ssl_verification=True))
        with LDClient(config=config) as client:
            assert client.is_initialized()
def test_client_fails_to_start_in_streaming_mode_with_401_error():
    with start_server() as stream_server:
        stream_server.for_path('/all', BasicResponse(401))
        config = Config(sdk_key=sdk_key,
                        stream_uri=stream_server.uri,
                        send_events=False)

        with LDClient(config=config) as client:
            assert not client.is_initialized()
            assert client.variation(always_true_flag['key'], user,
                                    False) == False
def test_get_one_flag_sends_headers():
    with start_server() as server:
        config = Config(sdk_key='sdk-key', base_uri=server.uri)
        fr = FeatureRequesterImpl(config)
        key = 'flag1'
        flag_data = {'key': key}
        server.setup_json_response('/sdk/latest-flags/' + key, flag_data)
        fr.get_one(FEATURES, key)
        req = server.require_request()
        assert req.headers['Authorization'] == 'sdk-key'
        assert req.headers['User-Agent'] == 'PythonClient/' + VERSION
        assert req.headers.get('X-LaunchDarkly-Wrapper') is None
def test_get_one_flag_sends_wrapper_header_without_version():
    with start_server() as server:
        config = Config(sdk_key='sdk-key',
                        base_uri=server.uri,
                        wrapper_name='Flask')
        fr = FeatureRequesterImpl(config)
        key = 'flag1'
        flag_data = {'key': key}
        server.setup_json_response('/sdk/latest-flags/' + key, flag_data)
        fr.get_one(FEATURES, key)
        req = server.require_request()
        assert req.headers.get('X-LaunchDarkly-Wrapper') == 'Flask'
def test_evaluates_simplified_flag_with_client_as_expected():
    path = make_temp_file(all_properties_json)
    try:
        factory = Files.new_data_source(paths=path)
        client = LDClient(
            config=Config(update_processor_class=factory, send_events=False))
        value = client.variation('flag2', {'key': 'user'}, '')
        assert value == 'value2'
    finally:
        os.remove(path)
        if client is not None:
            client.close()
def test_diagnostic_accumulator():
    test_config = Config(sdk_key="SDK_KEY")
    diag_id = create_diagnostic_id(test_config)
    diag_accum = _DiagnosticAccumulator(diag_id)

    # Test default periodic event
    def_diag_event = diag_accum.create_event_and_reset(0, 0)
    assert len(def_diag_event) == 8
    assert def_diag_event['kind'] == 'diagnostic'
    assert def_diag_event['id'] == diag_id
    assert def_diag_event['creationDate'] == diag_accum.data_since_date
    assert def_diag_event['dataSinceDate']
    assert def_diag_event['droppedEvents'] == 0
    assert def_diag_event['deduplicatedUsers'] == 0
    assert def_diag_event['eventsInLastBatch'] == 0
    assert def_diag_event['streamInits'] == []

    # Verify converts to json without failure
    json.dumps(def_diag_event)

    # Test periodic event after recording values
    diag_accum.record_stream_init(100, 100, False)
    diag_accum.record_stream_init(300, 200, True)
    diag_accum.record_events_in_batch(10)
    diag_accum.record_events_in_batch(50)
    diag_event = diag_accum.create_event_and_reset(10, 15)
    assert len(diag_event) == 8
    assert diag_event['kind'] == 'diagnostic'
    assert diag_event['id'] == diag_id
    assert diag_event['creationDate'] == diag_accum.data_since_date
    assert diag_event['dataSinceDate'] == def_diag_event['creationDate']
    assert diag_event['droppedEvents'] == 10
    assert diag_event['deduplicatedUsers'] == 15
    assert diag_event['eventsInLastBatch'] == 50
    assert diag_event['streamInits'] == [{
        'timestamp': 100,
        'durationMillis': 100,
        'failed': False
    }, {
        'timestamp': 300,
        'durationMillis': 200,
        'failed': True
    }]
    json.dumps(diag_event)

    reset_diag_event = diag_accum.create_event_and_reset(0, 0)
    assert reset_diag_event['creationDate'] == diag_accum.data_since_date
    assert reset_diag_event['dataSinceDate'] == diag_event['creationDate']
    del reset_diag_event['creationDate']
    del def_diag_event['creationDate']
    del reset_diag_event['dataSinceDate']
    del def_diag_event['dataSinceDate']
    assert reset_diag_event == def_diag_event
def test_get_all_data_sends_headers():
    with start_server() as server:
        config = Config(sdk_key='sdk-key', base_uri=server.uri)
        fr = FeatureRequesterImpl(config)

        resp_data = {'flags': {}, 'segments': {}}
        server.for_path('/sdk/latest-all', JsonResponse(resp_data))

        fr.get_all_data()
        req = server.require_request()
        assert req.headers['Authorization'] == 'sdk-key'
        assert req.headers['User-Agent'] == 'PythonClient/' + VERSION
        assert req.headers.get('X-LaunchDarkly-Wrapper') is None
def test_index_event_is_still_generated_if_inline_users_is_true_but_feature_event_is_not_tracked():
    setup_processor(Config(inline_users_in_events = True))

    e = {
        'kind': 'feature', 'key': 'flagkey', 'version': 11, 'user': user,
        'variation': 1, 'value': 'value', 'default': 'default', 'trackEvents': False
    }
    ep.send_event(e)

    output = flush_and_get_events()
    assert len(output) == 2
    check_index_event(output[0], e, user)
    check_summary_event(output[1])
def verify_recoverable_http_error(status):
    setup_processor(Config(sdk_key = 'SDK_KEY'))

    mock_http.set_response_status(status)
    ep.send_event({ 'kind': 'identify', 'user': user })
    ep.flush()
    ep._wait_until_inactive()
    mock_http.reset()

    ep.send_event({ 'kind': 'identify', 'user': user })
    ep.flush()
    ep._wait_until_inactive()
    assert mock_http.request_data is not None
def test_feature_event_can_contain_inline_user():
    setup_processor(Config(inline_users_in_events = True))

    e = {
        'kind': 'feature', 'key': 'flagkey', 'version': 11, 'user': user,
        'variation': 1, 'value': 'value', 'default': 'default', 'trackEvents': True
    }
    ep.send_event(e)

    output = flush_and_get_events()
    assert len(output) == 2
    check_feature_event(output[0], e, False, user)
    check_summary_event(output[1])
def test_get_all_data_returns_data():
    with start_server() as server:
        config = Config(sdk_key='sdk-key', base_uri=server.uri)
        fr = FeatureRequesterImpl(config)

        flags = {'flag1': {'key': 'flag1'}}
        segments = {'segment1': {'key': 'segment1'}}
        resp_data = {'flags': flags, 'segments': segments}
        expected_data = {FEATURES: flags, SEGMENTS: segments}
        server.for_path('/sdk/latest-all', JsonResponse(resp_data))

        result = fr.get_all_data()
        assert result == expected_data
def test_get_all_data_sends_wrapper_header_without_version():
    with start_server() as server:
        config = Config(sdk_key='sdk-key',
                        base_uri=server.uri,
                        wrapper_name='Flask')
        fr = FeatureRequesterImpl(config)

        resp_data = {'flags': {}, 'segments': {}}
        server.for_path('/sdk/latest-all', JsonResponse(resp_data))

        fr.get_all_data()
        req = server.require_request()
        assert req.headers.get('X-LaunchDarkly-Wrapper') == 'Flask'