airbyte-source-github 1.5.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- airbyte_source_github-1.5.7.dist-info/METADATA +144 -0
- airbyte_source_github-1.5.7.dist-info/RECORD +88 -0
- airbyte_source_github-1.5.7.dist-info/WHEEL +5 -0
- airbyte_source_github-1.5.7.dist-info/entry_points.txt +2 -0
- airbyte_source_github-1.5.7.dist-info/top_level.txt +3 -0
- integration_tests/__init__.py +0 -0
- integration_tests/abnormal_state.json +237 -0
- integration_tests/acceptance.py +16 -0
- integration_tests/configured_catalog.json +435 -0
- integration_tests/configured_catalog_full_refresh_test.json +415 -0
- integration_tests/invalid_config.json +5 -0
- integration_tests/sample_config.json +5 -0
- integration_tests/sample_state.json +137 -0
- source_github/__init__.py +27 -0
- source_github/config_migrations.py +106 -0
- source_github/constants.py +9 -0
- source_github/github_schema.py +41034 -0
- source_github/graphql.py +327 -0
- source_github/run.py +17 -0
- source_github/schemas/assignees.json +63 -0
- source_github/schemas/branches.json +48 -0
- source_github/schemas/collaborators.json +80 -0
- source_github/schemas/comments.json +104 -0
- source_github/schemas/commit_comment_reactions.json +4 -0
- source_github/schemas/commit_comments.json +53 -0
- source_github/schemas/commits.json +126 -0
- source_github/schemas/contributor_activity.json +109 -0
- source_github/schemas/deployments.json +77 -0
- source_github/schemas/events.json +63 -0
- source_github/schemas/issue_comment_reactions.json +4 -0
- source_github/schemas/issue_events.json +335 -0
- source_github/schemas/issue_labels.json +30 -0
- source_github/schemas/issue_milestones.json +61 -0
- source_github/schemas/issue_reactions.json +28 -0
- source_github/schemas/issue_timeline_events.json +1056 -0
- source_github/schemas/issues.json +281 -0
- source_github/schemas/organizations.json +197 -0
- source_github/schemas/project_cards.json +50 -0
- source_github/schemas/project_columns.json +38 -0
- source_github/schemas/projects.json +50 -0
- source_github/schemas/projects_v2.json +80 -0
- source_github/schemas/pull_request_comment_reactions.json +28 -0
- source_github/schemas/pull_request_commits.json +122 -0
- source_github/schemas/pull_request_stats.json +84 -0
- source_github/schemas/pull_requests.json +363 -0
- source_github/schemas/releases.json +126 -0
- source_github/schemas/repositories.json +313 -0
- source_github/schemas/review_comments.json +118 -0
- source_github/schemas/reviews.json +69 -0
- source_github/schemas/shared/events/comment.json +188 -0
- source_github/schemas/shared/events/commented.json +118 -0
- source_github/schemas/shared/events/committed.json +56 -0
- source_github/schemas/shared/events/cross_referenced.json +784 -0
- source_github/schemas/shared/events/reviewed.json +139 -0
- source_github/schemas/shared/reaction.json +27 -0
- source_github/schemas/shared/reactions.json +35 -0
- source_github/schemas/shared/user.json +59 -0
- source_github/schemas/shared/user_graphql.json +26 -0
- source_github/schemas/stargazers.json +19 -0
- source_github/schemas/tags.json +32 -0
- source_github/schemas/team_members.json +66 -0
- source_github/schemas/team_memberships.json +24 -0
- source_github/schemas/teams.json +50 -0
- source_github/schemas/users.json +63 -0
- source_github/schemas/workflow_jobs.json +109 -0
- source_github/schemas/workflow_runs.json +449 -0
- source_github/schemas/workflows.json +41 -0
- source_github/source.py +339 -0
- source_github/spec.json +179 -0
- source_github/streams.py +1678 -0
- source_github/utils.py +152 -0
- unit_tests/__init__.py +3 -0
- unit_tests/conftest.py +29 -0
- unit_tests/projects_v2_pull_requests_query.json +3 -0
- unit_tests/pull_request_stats_query.json +3 -0
- unit_tests/responses/contributor_activity_response.json +33 -0
- unit_tests/responses/graphql_reviews_responses.json +405 -0
- unit_tests/responses/issue_timeline_events.json +166 -0
- unit_tests/responses/issue_timeline_events_response.json +170 -0
- unit_tests/responses/projects_v2_response.json +45 -0
- unit_tests/responses/pull_request_comment_reactions.json +744 -0
- unit_tests/responses/pull_request_stats_response.json +317 -0
- unit_tests/test_migrations/test_config.json +8 -0
- unit_tests/test_migrations/test_new_config.json +8 -0
- unit_tests/test_multiple_token_authenticator.py +160 -0
- unit_tests/test_source.py +326 -0
- unit_tests/test_stream.py +1471 -0
- unit_tests/utils.py +78 -0
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
{
|
|
2
|
+
"data": {
|
|
3
|
+
"repository": {
|
|
4
|
+
"name": "integration-test",
|
|
5
|
+
"owner": {
|
|
6
|
+
"login": "airbytehq"
|
|
7
|
+
},
|
|
8
|
+
"pullRequests": {
|
|
9
|
+
"nodes": [
|
|
10
|
+
{
|
|
11
|
+
"node_id": "MDExOlB1bGxSZXF1ZXN0NzIxNDM1NTA2",
|
|
12
|
+
"id": 721435506,
|
|
13
|
+
"number": 5,
|
|
14
|
+
"updated_at": "2021-08-27T15:53:14Z",
|
|
15
|
+
"changed_files": 5,
|
|
16
|
+
"deletions": 0,
|
|
17
|
+
"additions": 5,
|
|
18
|
+
"merged": false,
|
|
19
|
+
"mergeable": "MERGEABLE",
|
|
20
|
+
"can_be_rebased": true,
|
|
21
|
+
"maintainer_can_modify": false,
|
|
22
|
+
"merge_state_status": "BLOCKED",
|
|
23
|
+
"comments": {
|
|
24
|
+
"totalCount": 0
|
|
25
|
+
},
|
|
26
|
+
"commits": {
|
|
27
|
+
"totalCount": 5
|
|
28
|
+
},
|
|
29
|
+
"review_comments": {
|
|
30
|
+
"totalCount": 1,
|
|
31
|
+
"nodes": [
|
|
32
|
+
{
|
|
33
|
+
"comments": {
|
|
34
|
+
"totalCount": 0
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
"merged_by": null
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"node_id": "MDExOlB1bGxSZXF1ZXN0NzIxNDM1NDA3",
|
|
43
|
+
"id": 721435407,
|
|
44
|
+
"number": 2,
|
|
45
|
+
"updated_at": "2021-08-27T15:53:27Z",
|
|
46
|
+
"changed_files": 5,
|
|
47
|
+
"deletions": 0,
|
|
48
|
+
"additions": 5,
|
|
49
|
+
"merged": false,
|
|
50
|
+
"mergeable": "MERGEABLE",
|
|
51
|
+
"can_be_rebased": true,
|
|
52
|
+
"maintainer_can_modify": false,
|
|
53
|
+
"merge_state_status": "BLOCKED",
|
|
54
|
+
"comments": {
|
|
55
|
+
"totalCount": 0
|
|
56
|
+
},
|
|
57
|
+
"commits": {
|
|
58
|
+
"totalCount": 5
|
|
59
|
+
},
|
|
60
|
+
"review_comments": {
|
|
61
|
+
"totalCount": 1,
|
|
62
|
+
"nodes": [
|
|
63
|
+
{
|
|
64
|
+
"comments": {
|
|
65
|
+
"totalCount": 0
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
},
|
|
70
|
+
"merged_by": null
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"node_id": "MDExOlB1bGxSZXF1ZXN0NzIxNDM1NDQw",
|
|
74
|
+
"id": 721435440,
|
|
75
|
+
"number": 3,
|
|
76
|
+
"updated_at": "2021-08-27T16:02:49Z",
|
|
77
|
+
"changed_files": 5,
|
|
78
|
+
"deletions": 0,
|
|
79
|
+
"additions": 5,
|
|
80
|
+
"merged": true,
|
|
81
|
+
"mergeable": "UNKNOWN",
|
|
82
|
+
"can_be_rebased": false,
|
|
83
|
+
"maintainer_can_modify": false,
|
|
84
|
+
"merge_state_status": "UNKNOWN",
|
|
85
|
+
"comments": {
|
|
86
|
+
"totalCount": 0
|
|
87
|
+
},
|
|
88
|
+
"commits": {
|
|
89
|
+
"totalCount": 5
|
|
90
|
+
},
|
|
91
|
+
"review_comments": {
|
|
92
|
+
"totalCount": 1,
|
|
93
|
+
"nodes": [
|
|
94
|
+
{
|
|
95
|
+
"comments": {
|
|
96
|
+
"totalCount": 0
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
},
|
|
101
|
+
"merged_by": {
|
|
102
|
+
"__typename": "User",
|
|
103
|
+
"node_id": "MDQ6VXNlcjc0MzkwMQ==",
|
|
104
|
+
"id": 743901,
|
|
105
|
+
"login": "gaart",
|
|
106
|
+
"avatar_url": "https://avatars.githubusercontent.com/u/743901?v=4",
|
|
107
|
+
"html_url": "https://github.com/gaart",
|
|
108
|
+
"site_admin": false
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"node_id": "MDExOlB1bGxSZXF1ZXN0NzIxNDM1NDY2",
|
|
113
|
+
"id": 721435466,
|
|
114
|
+
"number": 4,
|
|
115
|
+
"updated_at": "2021-08-31T12:01:15Z",
|
|
116
|
+
"changed_files": 5,
|
|
117
|
+
"deletions": 0,
|
|
118
|
+
"additions": 5,
|
|
119
|
+
"merged": false,
|
|
120
|
+
"mergeable": "MERGEABLE",
|
|
121
|
+
"can_be_rebased": true,
|
|
122
|
+
"maintainer_can_modify": false,
|
|
123
|
+
"merge_state_status": "BLOCKED",
|
|
124
|
+
"comments": {
|
|
125
|
+
"totalCount": 0
|
|
126
|
+
},
|
|
127
|
+
"commits": {
|
|
128
|
+
"totalCount": 5
|
|
129
|
+
},
|
|
130
|
+
"review_comments": {
|
|
131
|
+
"totalCount": 3,
|
|
132
|
+
"nodes": [
|
|
133
|
+
{
|
|
134
|
+
"comments": {
|
|
135
|
+
"totalCount": 0
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"comments": {
|
|
140
|
+
"totalCount": 0
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"comments": {
|
|
145
|
+
"totalCount": 1
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
]
|
|
149
|
+
},
|
|
150
|
+
"merged_by": null
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"node_id": "PR_kwDOF9hP9c4xmEi6",
|
|
154
|
+
"id": 832063674,
|
|
155
|
+
"number": 12,
|
|
156
|
+
"updated_at": "2022-01-26T03:46:56Z",
|
|
157
|
+
"changed_files": 1,
|
|
158
|
+
"deletions": 0,
|
|
159
|
+
"additions": 2,
|
|
160
|
+
"merged": true,
|
|
161
|
+
"mergeable": "UNKNOWN",
|
|
162
|
+
"can_be_rebased": false,
|
|
163
|
+
"maintainer_can_modify": false,
|
|
164
|
+
"merge_state_status": "UNKNOWN",
|
|
165
|
+
"comments": {
|
|
166
|
+
"totalCount": 0
|
|
167
|
+
},
|
|
168
|
+
"commits": {
|
|
169
|
+
"totalCount": 1
|
|
170
|
+
},
|
|
171
|
+
"review_comments": {
|
|
172
|
+
"totalCount": 1,
|
|
173
|
+
"nodes": [
|
|
174
|
+
{
|
|
175
|
+
"comments": {
|
|
176
|
+
"totalCount": 0
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
]
|
|
180
|
+
},
|
|
181
|
+
"merged_by": {
|
|
182
|
+
"__typename": "User",
|
|
183
|
+
"node_id": "MDQ6VXNlcjUxNTQzMjI=",
|
|
184
|
+
"id": 5154322,
|
|
185
|
+
"login": "marcosmarxm",
|
|
186
|
+
"avatar_url": "https://avatars.githubusercontent.com/u/5154322?u=92c89b82271d48f41fad03923b0a24083e049038&v=4",
|
|
187
|
+
"html_url": "https://github.com/marcosmarxm",
|
|
188
|
+
"site_admin": false
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"node_id": "MDExOlB1bGxSZXF1ZXN0NzIxNDM1Mzcz",
|
|
193
|
+
"id": 721435373,
|
|
194
|
+
"number": 1,
|
|
195
|
+
"updated_at": "2022-03-31T11:06:06Z",
|
|
196
|
+
"changed_files": 5,
|
|
197
|
+
"deletions": 0,
|
|
198
|
+
"additions": 5,
|
|
199
|
+
"merged": false,
|
|
200
|
+
"mergeable": "MERGEABLE",
|
|
201
|
+
"can_be_rebased": true,
|
|
202
|
+
"maintainer_can_modify": false,
|
|
203
|
+
"merge_state_status": "BLOCKED",
|
|
204
|
+
"comments": {
|
|
205
|
+
"totalCount": 0
|
|
206
|
+
},
|
|
207
|
+
"commits": {
|
|
208
|
+
"totalCount": 5
|
|
209
|
+
},
|
|
210
|
+
"review_comments": {
|
|
211
|
+
"totalCount": 1,
|
|
212
|
+
"nodes": [
|
|
213
|
+
{
|
|
214
|
+
"comments": {
|
|
215
|
+
"totalCount": 0
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
]
|
|
219
|
+
},
|
|
220
|
+
"merged_by": null
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"node_id": "PR_kwDOF9hP9c46s2Qa",
|
|
224
|
+
"id": 984835098,
|
|
225
|
+
"number": 14,
|
|
226
|
+
"updated_at": "2022-10-04T17:41:29Z",
|
|
227
|
+
"changed_files": 1,
|
|
228
|
+
"deletions": 0,
|
|
229
|
+
"additions": 1,
|
|
230
|
+
"merged": false,
|
|
231
|
+
"mergeable": "MERGEABLE",
|
|
232
|
+
"can_be_rebased": true,
|
|
233
|
+
"maintainer_can_modify": false,
|
|
234
|
+
"merge_state_status": "BLOCKED",
|
|
235
|
+
"comments": {
|
|
236
|
+
"totalCount": 0
|
|
237
|
+
},
|
|
238
|
+
"commits": {
|
|
239
|
+
"totalCount": 2
|
|
240
|
+
},
|
|
241
|
+
"review_comments": {
|
|
242
|
+
"totalCount": 1,
|
|
243
|
+
"nodes": [
|
|
244
|
+
{
|
|
245
|
+
"comments": {
|
|
246
|
+
"totalCount": 0
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
]
|
|
250
|
+
},
|
|
251
|
+
"merged_by": null
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
"node_id": "PR_kwDOF9hP9c41Vftv",
|
|
255
|
+
"id": 894827375,
|
|
256
|
+
"number": 13,
|
|
257
|
+
"updated_at": "2023-05-03T06:50:23Z",
|
|
258
|
+
"changed_files": 1,
|
|
259
|
+
"deletions": 1,
|
|
260
|
+
"additions": 1,
|
|
261
|
+
"merged": false,
|
|
262
|
+
"mergeable": "MERGEABLE",
|
|
263
|
+
"can_be_rebased": true,
|
|
264
|
+
"maintainer_can_modify": false,
|
|
265
|
+
"merge_state_status": "BLOCKED",
|
|
266
|
+
"comments": {
|
|
267
|
+
"totalCount": 0
|
|
268
|
+
},
|
|
269
|
+
"commits": {
|
|
270
|
+
"totalCount": 1
|
|
271
|
+
},
|
|
272
|
+
"review_comments": {
|
|
273
|
+
"totalCount": 0,
|
|
274
|
+
"nodes": []
|
|
275
|
+
},
|
|
276
|
+
"merged_by": null
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
"node_id": "PR_kwDOF9hP9c5PqZhG",
|
|
280
|
+
"id": 1336514630,
|
|
281
|
+
"number": 15,
|
|
282
|
+
"updated_at": "2023-05-04T10:07:46Z",
|
|
283
|
+
"changed_files": 1,
|
|
284
|
+
"deletions": 0,
|
|
285
|
+
"additions": 1,
|
|
286
|
+
"merged": false,
|
|
287
|
+
"mergeable": "MERGEABLE",
|
|
288
|
+
"can_be_rebased": false,
|
|
289
|
+
"maintainer_can_modify": false,
|
|
290
|
+
"merge_state_status": "BLOCKED",
|
|
291
|
+
"comments": {
|
|
292
|
+
"totalCount": 1
|
|
293
|
+
},
|
|
294
|
+
"commits": {
|
|
295
|
+
"totalCount": 1
|
|
296
|
+
},
|
|
297
|
+
"review_comments": {
|
|
298
|
+
"totalCount": 1,
|
|
299
|
+
"nodes": [
|
|
300
|
+
{
|
|
301
|
+
"comments": {
|
|
302
|
+
"totalCount": 0
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
]
|
|
306
|
+
},
|
|
307
|
+
"merged_by": null
|
|
308
|
+
}
|
|
309
|
+
],
|
|
310
|
+
"pageInfo": {
|
|
311
|
+
"hasNextPage": false,
|
|
312
|
+
"endCursor": "Y3Vyc29yOnYyOpK5MjAyMy0wNS0wNFQxMzowNzo0NiswMzowMM5PqZhG"
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"credentials": {
|
|
3
|
+
"personal_access_token": "personal_access_token"
|
|
4
|
+
},
|
|
5
|
+
"repositories": ["airbytehq/airbyte", "airbytehq/airbyte-platform"],
|
|
6
|
+
"start_date": "2000-01-01T00:00:00Z",
|
|
7
|
+
"branches": ["airbytehq/airbyte/master", "airbytehq/airbyte-platform/main"]
|
|
8
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2023 Airbyte, Inc., all rights reserved.
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from unittest.mock import patch
|
|
7
|
+
|
|
8
|
+
import pendulum
|
|
9
|
+
import responses
|
|
10
|
+
from freezegun import freeze_time
|
|
11
|
+
from source_github import SourceGithub
|
|
12
|
+
from source_github.streams import Organizations
|
|
13
|
+
from source_github.utils import MultipleTokenAuthenticatorWithRateLimiter, read_full_refresh
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@responses.activate
|
|
17
|
+
def test_multiple_tokens(rate_limit_mock_response):
|
|
18
|
+
authenticator = SourceGithub()._get_authenticator({"access_token": "token_1, token_2, token_3"})
|
|
19
|
+
assert isinstance(authenticator, MultipleTokenAuthenticatorWithRateLimiter)
|
|
20
|
+
assert ["token_1", "token_2", "token_3"] == list(authenticator._tokens)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@responses.activate
|
|
24
|
+
def test_authenticator_counter(rate_limit_mock_response):
|
|
25
|
+
"""
|
|
26
|
+
This test ensures that the rate limiter:
|
|
27
|
+
1. correctly handles the available limits from GitHub API and saves it.
|
|
28
|
+
2. correctly counts the number of requests made.
|
|
29
|
+
"""
|
|
30
|
+
authenticator = MultipleTokenAuthenticatorWithRateLimiter(tokens=["token1", "token2", "token3"])
|
|
31
|
+
|
|
32
|
+
assert [(x.count_rest, x.count_graphql) for x in authenticator._tokens.values()] == [(5000, 5000), (5000, 5000), (5000, 5000)]
|
|
33
|
+
organization_args = {"organizations": ["org1", "org2"], "authenticator": authenticator}
|
|
34
|
+
stream = Organizations(**organization_args)
|
|
35
|
+
responses.add("GET", "https://api.github.com/orgs/org1", json={"id": 1})
|
|
36
|
+
responses.add("GET", "https://api.github.com/orgs/org2", json={"id": 2})
|
|
37
|
+
list(read_full_refresh(stream))
|
|
38
|
+
assert authenticator._tokens["token1"].count_rest == 4998
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@responses.activate
|
|
42
|
+
def test_multiple_token_authenticator_with_rate_limiter(caplog):
|
|
43
|
+
"""
|
|
44
|
+
This test ensures that:
|
|
45
|
+
1. The rate limiter iterates over all tokens one-by-one after the previous is fully drained.
|
|
46
|
+
2. Counter is set to zero after 1500 requests were made. (500 available requests per key were set as default)
|
|
47
|
+
3. Exception is handled and log warning message could be found in output. Connector does not raise AirbyteTracedException because there might be GraphQL streams with remaining request we still can read.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
counter_rate_limits = 0
|
|
51
|
+
counter_orgs = 0
|
|
52
|
+
|
|
53
|
+
def request_callback_rate_limits(request):
|
|
54
|
+
nonlocal counter_rate_limits
|
|
55
|
+
while counter_rate_limits < 3:
|
|
56
|
+
counter_rate_limits += 1
|
|
57
|
+
resp_body = {
|
|
58
|
+
"resources": {
|
|
59
|
+
"core": {
|
|
60
|
+
"limit": 500,
|
|
61
|
+
"used": 0,
|
|
62
|
+
"remaining": 500,
|
|
63
|
+
"reset": 4070908800
|
|
64
|
+
},
|
|
65
|
+
"graphql": {
|
|
66
|
+
"limit": 500,
|
|
67
|
+
"used": 0,
|
|
68
|
+
"remaining": 500,
|
|
69
|
+
"reset": 4070908800
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return (200, {}, json.dumps(resp_body))
|
|
74
|
+
|
|
75
|
+
responses.add_callback(responses.GET, "https://api.github.com/rate_limit", callback=request_callback_rate_limits)
|
|
76
|
+
authenticator = MultipleTokenAuthenticatorWithRateLimiter(tokens=["token1", "token2", "token3"])
|
|
77
|
+
organization_args = {"organizations": ["org1"], "authenticator": authenticator}
|
|
78
|
+
stream = Organizations(**organization_args)
|
|
79
|
+
|
|
80
|
+
def request_callback_orgs(request):
|
|
81
|
+
nonlocal counter_orgs
|
|
82
|
+
while counter_orgs < 1_501:
|
|
83
|
+
counter_orgs += 1
|
|
84
|
+
resp_body = {"id": 1}
|
|
85
|
+
headers = {"Link": '<https://api.github.com/orgs/org1?page=2>; rel="next"'}
|
|
86
|
+
return (200, headers, json.dumps(resp_body))
|
|
87
|
+
|
|
88
|
+
responses.add_callback(
|
|
89
|
+
responses.GET,
|
|
90
|
+
"https://api.github.com/orgs/org1",
|
|
91
|
+
callback=request_callback_orgs,
|
|
92
|
+
content_type="application/json",
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
list(read_full_refresh(stream))
|
|
96
|
+
assert [(x.count_rest, x.count_graphql) for x in authenticator._tokens.values()] == [(0, 500), (0, 500), (0, 500)]
|
|
97
|
+
assert "Stream: `organizations`, slice: `{'organization': 'org1'}`. Limits for all provided tokens are reached, please try again later" in caplog.messages
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@freeze_time("2021-01-01 12:00:00")
|
|
101
|
+
@responses.activate
|
|
102
|
+
@patch("time.sleep")
|
|
103
|
+
def test_multiple_token_authenticator_with_rate_limiter_and_sleep(sleep_mock, caplog):
|
|
104
|
+
"""
|
|
105
|
+
This test ensures that:
|
|
106
|
+
1. The rate limiter will only wait (sleep) for token availability if the nearest available token appears within 600 seconds (see max_time).
|
|
107
|
+
2. Token Counter is reset to new values after 1500 requests were made and last token is still in use.
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
counter_rate_limits = 0
|
|
111
|
+
counter_orgs = 0
|
|
112
|
+
ACCEPTED_WAITING_TIME_IN_SECONDS = 595
|
|
113
|
+
reset_time = (pendulum.now() + pendulum.duration(seconds=ACCEPTED_WAITING_TIME_IN_SECONDS)).int_timestamp
|
|
114
|
+
|
|
115
|
+
def request_callback_rate_limits(request):
|
|
116
|
+
nonlocal counter_rate_limits
|
|
117
|
+
while counter_rate_limits < 6:
|
|
118
|
+
counter_rate_limits += 1
|
|
119
|
+
resp_body = {
|
|
120
|
+
"resources": {
|
|
121
|
+
"core": {
|
|
122
|
+
"limit": 500,
|
|
123
|
+
"used": 0,
|
|
124
|
+
"remaining": 500,
|
|
125
|
+
"reset": reset_time
|
|
126
|
+
},
|
|
127
|
+
"graphql": {
|
|
128
|
+
"limit": 500,
|
|
129
|
+
"used": 0,
|
|
130
|
+
"remaining": 500,
|
|
131
|
+
"reset": reset_time
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return (200, {}, json.dumps(resp_body))
|
|
136
|
+
|
|
137
|
+
responses.add_callback(responses.GET, "https://api.github.com/rate_limit", callback=request_callback_rate_limits)
|
|
138
|
+
authenticator = MultipleTokenAuthenticatorWithRateLimiter(tokens=["token1", "token2", "token3"])
|
|
139
|
+
organization_args = {"organizations": ["org1"], "authenticator": authenticator}
|
|
140
|
+
stream = Organizations(**organization_args)
|
|
141
|
+
|
|
142
|
+
def request_callback_orgs(request):
|
|
143
|
+
nonlocal counter_orgs
|
|
144
|
+
while counter_orgs < 1_501:
|
|
145
|
+
counter_orgs += 1
|
|
146
|
+
resp_body = {"id": 1}
|
|
147
|
+
headers = {"Link": '<https://api.github.com/orgs/org1?page=2>; rel="next"'}
|
|
148
|
+
return (200, headers, json.dumps(resp_body))
|
|
149
|
+
return (200, {}, json.dumps({"id": 2}))
|
|
150
|
+
|
|
151
|
+
responses.add_callback(
|
|
152
|
+
responses.GET,
|
|
153
|
+
"https://api.github.com/orgs/org1",
|
|
154
|
+
callback=request_callback_orgs,
|
|
155
|
+
content_type="application/json",
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
list(read_full_refresh(stream))
|
|
159
|
+
sleep_mock.assert_called_once_with(ACCEPTED_WAITING_TIME_IN_SECONDS)
|
|
160
|
+
assert [(x.count_rest, x.count_graphql) for x in authenticator._tokens.values()] == [(500, 500), (500, 500), (498, 500)]
|