def test_can_use_https_proxy_via_config():
    with start_server() as server:
        config = Config(sdk_key='sdk-key',
                        events_uri='https://not-real',
                        http_proxy=server.uri,
                        diagnostic_opt_out=True)
        _verify_https_proxy_is_used(server, config)
def test_reconnects_if_stream_is_broken():
    store = InMemoryFeatureStore()
    ready = Event()
    flagv1 = {'key': 'flagkey', 'version': 1}
    flagv2 = {'key': 'flagkey', 'version': 2}

    with start_server() as server:
        with stream_content(make_put_event([flagv1])) as stream1:
            with stream_content(make_put_event([flagv2])) as stream2:
                config = Config(sdk_key='sdk-key',
                                stream_uri=server.uri,
                                initial_reconnect_delay=brief_delay)
                server.for_path('/all', SequentialHandler(stream1, stream2))

                with StreamingUpdateProcessor(config, store, ready,
                                              None) as sp:
                    sp.start()
                    server.await_request
                    ready.wait(start_wait)
                    assert sp.initialized()
                    expect_item(store, FEATURES, flagv1)

                    stream1.close()
                    server.await_request
                    expect_update(store, FEATURES, flagv2)
def test_receives_patch_events():
    store = InMemoryFeatureStore()
    ready = Event()
    flagv1 = {'key': 'flagkey', 'version': 1}
    flagv2 = {'key': 'flagkey', 'version': 2}
    segmentv1 = {'key': 'segkey', 'version': 1}
    segmentv2 = {'key': 'segkey', 'version': 1}

    with start_server() as server:
        with stream_content(make_put_event([flagv1], [segmentv1])) as stream:
            config = Config(sdk_key='sdk-key', stream_uri=server.uri)
            server.for_path('/all', stream)

            with StreamingUpdateProcessor(config, store, ready, None) as sp:
                sp.start()
                ready.wait(start_wait)
                assert sp.initialized()
                expect_item(store, FEATURES, flagv1)
                expect_item(store, SEGMENTS, segmentv1)

                stream.push(make_patch_event(FEATURES, flagv2))
                expect_update(store, FEATURES, flagv2)

                stream.push(make_patch_event(SEGMENTS, segmentv2))
                expect_update(store, SEGMENTS, segmentv2)
def test_get_one_flag_throws_on_error():
    with start_server() as server:
        config = Config(sdk_key='sdk-key', base_uri=server.uri)
        fr = FeatureRequesterImpl(config)
        with pytest.raises(UnsuccessfulResponseException) as e:
            fr.get_one(FEATURES, 'didnt-set-up-a-response-for-this-flag')
        assert e.value.status == 404
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)
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_client_sends_diagnostics():
    with start_server() as poll_server:
        with start_server() as events_server:
            poll_server.for_path('/sdk/latest-all',
                                 poll_content([always_true_flag]))
            events_server.for_path('/diagnostic', BasicResponse(202))

            config = Config(sdk_key=sdk_key,
                            base_uri=poll_server.uri,
                            events_uri=events_server.uri,
                            stream=False)
            with LDClient(config=config) as client:
                assert client.is_initialized()

                r = events_server.await_request()
                assert r.headers['Authorization'] == sdk_key
                data = json.loads(r.body)
                assert data['kind'] == 'diagnostic-init'
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_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'
def test_client_sends_event_without_diagnostics():
    with start_server() as poll_server:
        with start_server() as events_server:
            poll_server.for_path('/sdk/latest-all',
                                 poll_content([always_true_flag]))
            events_server.for_path('/bulk', BasicResponse(202))

            config = Config(sdk_key=sdk_key,
                            base_uri=poll_server.uri,
                            events_uri=events_server.uri,
                            stream=False,
                            diagnostic_opt_out=True)
            with LDClient(config=config) as client:
                assert client.is_initialized()
                client.identify(user)
                client.flush()

                r = events_server.await_request()
                assert r.headers['Authorization'] == sdk_key
                data = json.loads(r.body)
                assert len(data) == 1
                assert data[0]['kind'] == 'identify'
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
Beispiel #15
0
def test_set_sdk_key_before_init():
    _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, stream_uri = stream_server.uri, send_events = False))
                wait_until(ldclient.get().is_initialized, timeout=10)

                r = stream_server.await_request()
                assert r.headers['Authorization'] == sdk_key
            finally:
                _reset_client()
Beispiel #16
0
def test_sends_headers():
    store = InMemoryFeatureStore()
    ready = Event()

    with start_server() as server:
        config = Config(sdk_key='sdk-key', stream_uri=server.uri)
        server.setup_response('/all', 200, fake_event, response_headers)

        with StreamingUpdateProcessor(config, None, store, ready, None) as sp:
            sp.start()
            req = server.await_request()
            assert req.headers.get('Authorization') == 'sdk-key'
            assert req.headers.get('User-Agent') == 'PythonClient/' + VERSION
            assert req.headers.get('X-LaunchDarkly-Wrapper') is None
Beispiel #17
0
def test_uses_stream_uri():
    store = InMemoryFeatureStore()
    ready = Event()

    with start_server() as server:
        config = Config(sdk_key='sdk-key', stream_uri=server.uri)
        server.setup_response('/all', 200, fake_event, response_headers)

        with StreamingUpdateProcessor(config, None, store, ready, None) as sp:
            sp.start()
            req = server.await_request()
            assert req.method == 'GET'
            ready.wait(1)
            assert sp.initialized()
Beispiel #18
0
def test_sends_wrapper_header_without_version():
    store = InMemoryFeatureStore()
    ready = Event()

    with start_server() as server:
        config = Config(sdk_key='sdk-key',
                        stream_uri=server.uri,
                        wrapper_name='Flask')
        server.setup_response('/all', 200, fake_event, response_headers)

        with StreamingUpdateProcessor(config, None, store, ready, None) as sp:
            sp.start()
            req = server.await_request()
            assert req.headers.get('X-LaunchDarkly-Wrapper') == 'Flask'
def do_proxy_tests(action, action_method, monkeypatch):
    # We'll test each permutation of use_env_vars, secure, and use_auth, except that if secure is
    # true then we'll only test with use_auth=false because we don't have a way to test proxy
    # authorization over HTTPS (even though we believe it works).
    for (use_env_vars, secure, use_auth) in [(False, False, False),
                                             (False, False, True),
                                             (False, True, False),
                                             (True, False, False),
                                             (True, False, True),
                                             (True, True, False)]:
        test_desc = "%s, %s, %s" % (
            "using env vars" if use_env_vars else "using Config", "secure"
            if secure else "insecure", "with auth" if use_auth else "no auth")
        with start_server() as server:
            proxy_uri = server.uri.replace(
                'http://', 'http://*****:*****@') if use_auth else server.uri
            target_uri = 'https://not-real' if secure else 'http://not-real'
            if use_env_vars:
                monkeypatch.setenv('https_proxy' if secure else 'http_proxy',
                                   proxy_uri)
            config = Config(sdk_key='sdk_key',
                            base_uri=target_uri,
                            events_uri=target_uri,
                            stream_uri=target_uri,
                            http=HTTPConfig(http_proxy=proxy_uri),
                            diagnostic_opt_out=True)
            try:
                action(server, config, secure)
            except:
                print("test action failed (%s)" % test_desc)
                raise
            # For an insecure proxy request, our stub server behaves enough like the real thing to satisfy the
            # HTTP client, so we should be able to see the request go through. Note that the URI path will
            # actually be an absolute URI for a proxy request.
            try:
                req = server.require_request()
            except:
                print("server did not receive a request (%s)" % test_desc)
                raise
            expected_method = 'CONNECT' if secure else action_method
            assert req.method == expected_method, "method should be %s, was %s (%s)" % (
                expected_method, req.method, test_desc)
            if use_auth:
                expected_auth = 'Basic dXNlcjpwYXNz'
                actual_auth = req.headers.get('Proxy-Authorization')
                assert actual_auth == expected_auth, "auth header should be %s, was %s (%s)" % (
                    expected_auth, actual_auth, test_desc)
            print("do_proxy_tests succeeded for: %s" % test_desc)
def test_client_starts_in_streaming_mode():
    with start_server() as stream_server:
        with stream_content(make_put_event([always_true_flag
                                            ])) as stream_handler:
            stream_server.for_path('/all', stream_handler)
            config = Config(sdk_key=sdk_key,
                            stream_uri=stream_server.uri,
                            send_events=False)

            with LDClient(config=config) as client:
                assert client.is_initialized()
                assert client.variation(always_true_flag['key'], user,
                                        False) == True

                r = stream_server.await_request()
                assert r.headers['Authorization'] == sdk_key
def test_client_starts_in_polling_mode():
    with start_server() as poll_server:
        poll_server.for_path('/sdk/latest-all',
                             poll_content([always_true_flag]))
        config = Config(sdk_key=sdk_key,
                        base_uri=poll_server.uri,
                        stream=False,
                        send_events=False)

        with LDClient(config=config) as client:
            assert client.is_initialized()
            assert client.variation(always_true_flag['key'], user,
                                    False) == True

            r = poll_server.await_request()
            assert r.headers['Authorization'] == sdk_key
def test_unrecoverable_http_error(status):
    error_handler = BasicResponse(status)
    store = InMemoryFeatureStore()
    ready = Event()
    with start_server() as server:
        with stream_content(make_put_event()) as stream:
            error_then_success = SequentialHandler(error_handler, stream)
            config = Config(sdk_key='sdk-key',
                            stream_uri=server.uri,
                            initial_reconnect_delay=brief_delay)
            server.for_path('/all', error_then_success)

            with StreamingUpdateProcessor(config, store, ready, None) as sp:
                sp.start()
                ready.wait(5)
                assert not sp.initialized()
                server.should_have_requests(1)
def test_request_properties():
    store = InMemoryFeatureStore()
    ready = Event()

    with start_server() as server:
        with stream_content(make_put_event()) as stream:
            config = Config(sdk_key='sdk-key', stream_uri=server.uri)
            server.for_path('/all', stream)

            with StreamingUpdateProcessor(config, store, ready, None) as sp:
                sp.start()
                req = server.await_request()
                assert req.method == 'GET'
                assert req.headers.get('Authorization') == 'sdk-key'
                assert req.headers.get(
                    'User-Agent') == 'PythonClient/' + VERSION
                assert req.headers.get('X-LaunchDarkly-Wrapper') is None
def test_sends_wrapper_header():
    store = InMemoryFeatureStore()
    ready = Event()

    with start_server() as server:
        with stream_content(make_put_event()) as stream:
            config = Config(sdk_key='sdk-key',
                            stream_uri=server.uri,
                            wrapper_name='Flask',
                            wrapper_version='0.1.0')
            server.for_path('/all', stream)

            with StreamingUpdateProcessor(config, store, ready, None) as sp:
                sp.start()
                req = server.await_request()
                assert req.headers.get(
                    'X-LaunchDarkly-Wrapper') == 'Flask/0.1.0'
Beispiel #25
0
def test_records_diagnostic_on_stream_init_failure():
    store = InMemoryFeatureStore()
    ready = Event()
    with start_server() as server:
        config = Config(sdk_key='sdk-key', stream_uri=server.uri)
        server.setup_response('/all', 200, 'event:put\ndata: {\n\n',
                              response_headers)
        diag_accum = _DiagnosticAccumulator(1)

        with StreamingUpdateProcessor(config, None, store, ready,
                                      diag_accum) as sp:
            sp.start()
            server.await_request()
            server.await_request()
            recorded_inits = diag_accum.create_event_and_reset(
                0, 0)['streamInits']

            assert recorded_inits[0]['failed'] is True
def test_records_diagnostic_on_stream_init_success():
    store = InMemoryFeatureStore()
    ready = Event()
    with start_server() as server:
        with stream_content(make_put_event()) as stream:
            config = Config(sdk_key='sdk-key', stream_uri=server.uri)
            server.for_path('/all', stream)
            diag_accum = _DiagnosticAccumulator(1)

            with StreamingUpdateProcessor(config, store, ready,
                                          diag_accum) as sp:
                sp.start()
                ready.wait(start_wait)
                recorded_inits = diag_accum.create_event_and_reset(
                    0, 0)['streamInits']

                assert len(recorded_inits) == 1
                assert recorded_inits[0]['failed'] is False
def test_client_retries_connection_in_streaming_mode_with_non_fatal_error():
    with start_server() as stream_server:
        with stream_content(make_put_event([always_true_flag
                                            ])) as stream_handler:
            error_then_success = SequentialHandler(BasicResponse(503),
                                                   stream_handler)
            stream_server.for_path('/all', error_then_success)
            config = Config(sdk_key=sdk_key,
                            stream_uri=stream_server.uri,
                            initial_reconnect_delay=0.001,
                            send_events=False)

            with LDClient(config=config) as client:
                assert client.is_initialized()
                assert client.variation(always_true_flag['key'], user,
                                        False) == True

                r = stream_server.await_request()
                assert r.headers['Authorization'] == sdk_key
def test_retries_on_network_error():
    error_handler = CauseNetworkError()
    store = InMemoryFeatureStore()
    ready = Event()
    with start_server() as server:
        with stream_content(make_put_event()) as stream:
            two_errors_then_success = SequentialHandler(
                error_handler, error_handler, stream)
            config = Config(sdk_key='sdk-key',
                            stream_uri=server.uri,
                            initial_reconnect_delay=brief_delay)
            server.for_path('/all', two_errors_then_success)

            with StreamingUpdateProcessor(config, store, ready, None) as sp:
                sp.start()
                ready.wait(start_wait)
                assert sp.initialized()
                server.await_request
                server.await_request
def test_get_one_flag_does_not_use_etags():
    with start_server() as server:
        config = Config(sdk_key='sdk-key', base_uri=server.uri)
        fr = FeatureRequesterImpl(config)

        etag = 'my-etag'
        key = 'flag1'
        flag_data = {'key': key}
        req_path = '/sdk/latest-flags/' + key
        server.setup_json_response(req_path, flag_data, {'Etag': etag})

        result = fr.get_one(FEATURES, key)
        assert result == flag_data
        req = server.require_request()
        assert 'If-None-Match' not in req.headers.keys()

        result = fr.get_one(FEATURES, key)
        assert result == flag_data
        req = server.require_request()
        assert 'If-None-Match' not in req.headers.keys(
        )  # did not send etag from previous request
def test_get_all_data_can_use_cached_data():
    with start_server() as server:
        config = Config(sdk_key='sdk-key', base_uri=server.uri)
        fr = FeatureRequesterImpl(config)

        etag1 = 'my-etag-1'
        etag2 = 'my-etag-2'
        resp_data1 = {'flags': {}, 'segments': {}}
        resp_data2 = {'flags': {'flag1': {'key': 'flag1'}}, 'segments': {}}
        expected_data1 = {FEATURES: {}, SEGMENTS: {}}
        expected_data2 = {FEATURES: {'flag1': {'key': 'flag1'}}, SEGMENTS: {}}
        req_path = '/sdk/latest-all'
        server.for_path(req_path, JsonResponse(resp_data1, {'Etag': etag1}))

        result = fr.get_all_data()
        assert result == expected_data1
        req = server.require_request()
        assert 'If-None-Match' not in req.headers.keys()

        server.for_path(req_path, BasicResponse(304, None, {'Etag': etag1}))

        result = fr.get_all_data()
        assert result == expected_data1
        req = server.require_request()
        assert req.headers['If-None-Match'] == etag1

        server.for_path(req_path, JsonResponse(resp_data2, {'Etag': etag2}))

        result = fr.get_all_data()
        assert result == expected_data2
        req = server.require_request()
        assert req.headers['If-None-Match'] == etag1

        server.for_path(req_path, BasicResponse(304, None, {'Etag': etag2}))

        result = fr.get_all_data()
        assert result == expected_data2
        req = server.require_request()
        assert req.headers['If-None-Match'] == etag2