File: getting_started.rst

package info (click to toggle)
python-globus-sdk 3.54.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 5,032 kB
  • sloc: python: 34,226; sh: 44; makefile: 31
file content (217 lines) | stat: -rw-r--r-- 6,717 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
.. warning::

    This component is an *alpha*. Interfaces may change outside of the
    normal semver policy.

Getting Started with _testing
=============================

Dependencies
------------

This toolchain requires the ``responses`` library.

``globus_sdk._testing`` is tested to operate with the latest version of
``responses``.

Recommended Fixtures
--------------------

Under pytest, this is the recommended fixture for setting up responses and
guaranteeing that requests are sent to the production hostnames:

.. code-block:: python

    @pytest.fixture(autouse=True)
    def mocked_responses(monkeypatch):
        responses.start()
        monkeypatch.setitem(os.environ, "GLOBUS_SDK_ENVIRONMENT", "production")
        yield
        responses.stop()
        responses.reset()

Usage
-----

Activating Individual Responses
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Once ``responses`` has been activated, each response fixture can be loaded and
activated by name:

.. code-block:: python

    from globus_sdk._testing import load_response

    # load_response will add the response to `responses` and return it
    load_response("auth.get_identities")
    # "case" is used to have a single name map to multiple responses
    data = load_response("auth.get_identities", case="multiple")

Responses can also be activated by passing an SDK client method, bound or
unbound, as in:

.. code-block:: python

    import globus_sdk
    from globus_sdk._testing import load_response

    load_response(globus_sdk.AuthClient.get_identities)
    load_response(globus_sdk.AuthClient.get_identities, case="unauthorized")

    # or, with a bound method
    ac = globus_sdk.AuthClient()
    load_response(ac.get_identities, case="multiple")

Activating "Scenarios"
~~~~~~~~~~~~~~~~~~~~~~

Some sets of fixtures may describe a scenario, and therefore it's desirable to
load all of them at once:

.. code-block:: python

    from globus_sdk._testing import load_response_set

    fixtures = load_response_set("scenario.foo")

Getting Responses and ResponseSets without Activating
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you want to fetch a ``ResponseSet`` or ``RegisteredResponse`` without
activating it, you can do this via the ``get_response_set`` method. Responses
must always be part of a response set, and the default name for an individual
response is ``"default"``.

.. code-block:: python

    from globus_sdk import AuthClient
    from globus_sdk._testing import get_response_set

    # rset will not be activated
    rset = get_response_set(AuthClient.get_identities)
    # you can get an individual response from rset
    get_ids = rset.get("default")
    # you can manually activate a whole set
    rset.activate_all()
    # or just one response from it by name
    rset.activate("default")

Note that activating a whole response set may or may not make sense. For
example, the response set for ``AuthClient.get_identities`` provides various
responses for the same API call.

Registering Response Sets
~~~~~~~~~~~~~~~~~~~~~~~~~

You can register your own response sets dynamically, and then load them up with
the same ``load_response_set`` method. Note that custom response sets will
override the builtin response sets, if names match.

.. code-block:: python

    from globus_sdk._testing import load_response_set, register_response_set
    import uuid

    # register a scenario under which Globus Auth get_identities and Globus
    # Transfer operation_ls both return payloads of `{"foo": "bar"}`
    # use an autogenerated endpoint ID and put it into the response metadata
    # register_response_set takes dict data and converts it to fixtures
    endpoint_id = str(uuid.uuid1())
    register_response_set(
        "foobar",
        {
            "get_identities": {
                "service": "auth",
                "path": "/v2/api/identities",
                "json": {"foo": "bar"},
            },
            "operation_ls": {
                "service": "transfer",
                "path": f"/operation/endpoint/{endpoint_id}/ls",
                "json": {"foo": "bar"},
            },
        },
        metadata={
            "endpoint_id": endpoint_id,
        },
    )

    # activate the result, and get it as a ResponseSet
    fixtures = load_response_set("foobar")
    # you can then pull the epid from the metadata
    epid = fixtures.metadata["endpoint_id"]
    transfer_client.operation_ls(epid)

``register_response_set`` can therefore be used to load fixture data early in
a tetstsuite run (e.g. as an autouse session-level fixture), for reference
later in the testsuite.

Loading Responses without Registering
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Because ``RegisteredResponse`` takes care of resolving ``"auth"`` to the Auth
URL, ``"transfer"`` to the Transfer URL, and so forth, you might want to use
``globus_sdk._testing`` in lieu of ``responses`` even when registering single
responses for individual tests.

To support this mode of usage, ``load_response`` can take a
``RegisteredResponse`` instance, and ``load_response_set`` can take a
``ResponseSet`` instance.

Consider the following example of a parametrized test which uses
``load_response(RegisteredResponse(...))`` as a replacement for
``responses.add``:

.. code-block:: python

    from globus_sdk._testing import load_response, RegisteredResponse
    import pytest


    @pytest.mark.parametrize("message", ["foo", "bar"])
    def test_get_identities_sends_back_strange_message(message):
        load_response(
            RegisteredResponse(
                service="auth",
                path="/v2/api/identities",
                json={"message": message},
            )
        )

        ac = globus_sdk.AuthClient()
        res = ac.get_identities(usernames="foo@example.com")
        assert res["message"] == message


In this mode of usage, the response set registry is skipped altogether. It is
not necessary to name or organize the response fixtures in a way that is usable
outside of the specific test.

Using non-default responses.RequestsMock objects
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

By default, all methods in ``globus_sdk._testing`` which converse with
``responses`` use the default mock. This is the behavior offered by
``responses.add(...)`` and similar methods.

However, you can pass a custom ``RequestsMock`` if so desired to the following
methods:

* ``get_last_request``
* ``load_response_set``
* ``load_response``

as a keyword argument, ``requests_mock``.
e.g.


.. code-block:: python

    from globus_sdk._testing import get_last_request
    import responses

    custom_mock = responses.RequestsMock(...)
    ...

    get_last_request(requests_mock=custom_mock)