@toa.io/extensions.exposition 0.22.1 → 1.0.0-alpha.0
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.
- package/components/identity.basic/source/authenticate.ts +3 -2
- package/components/identity.basic/source/transit.ts +4 -3
- package/components/octets.storage/manifest.toa.yaml +26 -0
- package/components/octets.storage/operations/delete.js +7 -0
- package/components/octets.storage/operations/fetch.js +46 -0
- package/components/octets.storage/operations/get.js +7 -0
- package/components/octets.storage/operations/list.js +7 -0
- package/components/octets.storage/operations/permute.js +7 -0
- package/components/octets.storage/operations/store.js +11 -0
- package/cucumber.js +0 -1
- package/documentation/access.md +2 -3
- package/documentation/cache.md +42 -0
- package/documentation/octets.md +196 -0
- package/documentation/protocol.md +49 -5
- package/documentation/tree.md +1 -5
- package/features/access.feature +1 -0
- package/features/cache.feature +160 -0
- package/features/errors.feature +18 -0
- package/features/identity.basic.feature +2 -0
- package/features/octets.feature +295 -0
- package/features/octets.workflows.feature +114 -0
- package/features/routes.feature +40 -0
- package/features/steps/HTTP.ts +56 -6
- package/features/steps/Parameters.ts +5 -2
- package/features/steps/Workspace.ts +8 -5
- package/features/steps/components/octets.tester/manifest.toa.yaml +15 -0
- package/features/steps/components/octets.tester/operations/bar.js +12 -0
- package/features/steps/components/octets.tester/operations/baz.js +11 -0
- package/features/steps/components/octets.tester/operations/diversify.js +14 -0
- package/features/steps/components/octets.tester/operations/err.js +16 -0
- package/features/steps/components/octets.tester/operations/foo.js +7 -0
- package/features/steps/components/octets.tester/operations/lenna.png +0 -0
- package/features/steps/components/pots/manifest.toa.yaml +1 -1
- package/features/streams.feature +5 -1
- package/package.json +16 -9
- package/readme.md +8 -5
- package/schemas/octets/context.cos.yaml +1 -0
- package/schemas/octets/delete.cos.yaml +1 -0
- package/schemas/octets/fetch.cos.yaml +3 -0
- package/schemas/octets/list.cos.yaml +1 -0
- package/schemas/octets/permute.cos.yaml +1 -0
- package/schemas/octets/store.cos.yaml +3 -0
- package/source/Gateway.ts +9 -4
- package/source/HTTP/Server.fixtures.ts +2 -6
- package/source/HTTP/Server.test.ts +9 -31
- package/source/HTTP/Server.ts +33 -19
- package/source/HTTP/exceptions.ts +2 -12
- package/source/HTTP/formats/index.ts +7 -4
- package/source/HTTP/formats/json.ts +3 -0
- package/source/HTTP/formats/msgpack.ts +3 -0
- package/source/HTTP/formats/text.ts +3 -0
- package/source/HTTP/formats/yaml.ts +3 -0
- package/source/HTTP/messages.test.ts +3 -49
- package/source/HTTP/messages.ts +60 -35
- package/source/RTD/Route.ts +1 -1
- package/source/RTD/segment.ts +2 -1
- package/source/RTD/syntax/parse.ts +2 -1
- package/source/Remotes.ts +8 -0
- package/source/Tenant.ts +5 -0
- package/source/directives/auth/Family.ts +26 -22
- package/source/directives/auth/Rule.ts +1 -1
- package/source/directives/cache/Control.ts +59 -0
- package/source/directives/cache/Exact.ts +7 -0
- package/source/directives/cache/Family.ts +36 -0
- package/source/directives/cache/index.ts +3 -0
- package/source/directives/cache/types.ts +9 -0
- package/source/directives/index.ts +3 -1
- package/source/directives/octets/Context.ts +18 -0
- package/source/directives/octets/Delete.ts +32 -0
- package/source/directives/octets/Family.ts +68 -0
- package/source/directives/octets/Fetch.ts +85 -0
- package/source/directives/octets/List.ts +32 -0
- package/source/directives/octets/Permute.ts +37 -0
- package/source/directives/octets/Store.ts +158 -0
- package/source/directives/octets/index.ts +3 -0
- package/source/directives/octets/schemas.ts +12 -0
- package/source/directives/octets/types.ts +13 -0
package/features/errors.feature
CHANGED
|
@@ -191,3 +191,21 @@ Feature: Errors
|
|
|
191
191
|
| debug | response |
|
|
192
192
|
| false | content-length: 0 |
|
|
193
193
|
| true | Error: Broken! |
|
|
194
|
+
|
|
195
|
+
Scenario: Not acceptable request
|
|
196
|
+
Given the annotation:
|
|
197
|
+
"""yaml
|
|
198
|
+
/:
|
|
199
|
+
GET:
|
|
200
|
+
anonymous: true
|
|
201
|
+
dev:stub: hello
|
|
202
|
+
"""
|
|
203
|
+
When the following request is received:
|
|
204
|
+
"""
|
|
205
|
+
GET / HTTP/1.1
|
|
206
|
+
accept: image/jpeg
|
|
207
|
+
"""
|
|
208
|
+
Then the following reply is sent:
|
|
209
|
+
"""
|
|
210
|
+
406 Not Acceptable
|
|
211
|
+
"""
|
|
@@ -181,6 +181,7 @@ Feature: Basic authentication
|
|
|
181
181
|
When the following request is received:
|
|
182
182
|
"""
|
|
183
183
|
POST /identity/basic/ HTTP/1.1
|
|
184
|
+
accept: application/yaml
|
|
184
185
|
content-type: application/yaml
|
|
185
186
|
|
|
186
187
|
username: root
|
|
@@ -224,6 +225,7 @@ Feature: Basic authentication
|
|
|
224
225
|
"""
|
|
225
226
|
PATCH /identity/basic/${{ id }}/ HTTP/1.1
|
|
226
227
|
authorization: Token ${{ token }}
|
|
228
|
+
accept: application/yaml
|
|
227
229
|
content-type: application/yaml
|
|
228
230
|
|
|
229
231
|
username: admin
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
Feature: Octets directive family
|
|
2
|
+
|
|
3
|
+
Background:
|
|
4
|
+
Given the annotation:
|
|
5
|
+
"""yaml
|
|
6
|
+
/:
|
|
7
|
+
auth:anonymous: true
|
|
8
|
+
octets:context: octets
|
|
9
|
+
POST:
|
|
10
|
+
octets:store: ~
|
|
11
|
+
GET:
|
|
12
|
+
octets:list: ~
|
|
13
|
+
PUT:
|
|
14
|
+
octets:permute: ~
|
|
15
|
+
/*:
|
|
16
|
+
GET:
|
|
17
|
+
octets:fetch: ~
|
|
18
|
+
DELETE:
|
|
19
|
+
octets:delete: ~
|
|
20
|
+
/media:
|
|
21
|
+
/jpeg:
|
|
22
|
+
POST:
|
|
23
|
+
octets:store:
|
|
24
|
+
accept: image/jpeg
|
|
25
|
+
/jpeg-or-png:
|
|
26
|
+
POST:
|
|
27
|
+
octets:store:
|
|
28
|
+
accept:
|
|
29
|
+
- image/jpeg
|
|
30
|
+
- image/png
|
|
31
|
+
/images:
|
|
32
|
+
POST:
|
|
33
|
+
octets:store:
|
|
34
|
+
accept: image/*
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
Scenario: Basic storage operations
|
|
38
|
+
When the stream of `lenna.ascii` is received with the following headers:
|
|
39
|
+
"""
|
|
40
|
+
POST / HTTP/1.1
|
|
41
|
+
accept: application/yaml
|
|
42
|
+
content-type: application/octet-stream
|
|
43
|
+
"""
|
|
44
|
+
Then the following reply is sent:
|
|
45
|
+
"""
|
|
46
|
+
201 Created
|
|
47
|
+
content-type: application/yaml
|
|
48
|
+
|
|
49
|
+
id: 10cf16b458f759e0d617f2f3d83599ff
|
|
50
|
+
type: application/octet-stream
|
|
51
|
+
size: 8169
|
|
52
|
+
"""
|
|
53
|
+
When the following request is received:
|
|
54
|
+
"""
|
|
55
|
+
GET /10cf16b458f759e0d617f2f3d83599ff HTTP/1.1
|
|
56
|
+
"""
|
|
57
|
+
Then the stream equals to `lenna.ascii` is sent with the following headers:
|
|
58
|
+
"""
|
|
59
|
+
200 OK
|
|
60
|
+
content-type: application/octet-stream
|
|
61
|
+
content-length: 8169
|
|
62
|
+
etag: ${{ ETAG }}
|
|
63
|
+
"""
|
|
64
|
+
When the following request is received:
|
|
65
|
+
"""
|
|
66
|
+
GET /10cf16b458f759e0d617f2f3d83599ff HTTP/1.1
|
|
67
|
+
if-none-match: ${{ ETAG }}
|
|
68
|
+
"""
|
|
69
|
+
Then the following reply is sent:
|
|
70
|
+
"""
|
|
71
|
+
304 Not Modified
|
|
72
|
+
"""
|
|
73
|
+
When the following request is received:
|
|
74
|
+
"""
|
|
75
|
+
GET /10cf16b458f759e0d617f2f3d83599ff:meta HTTP/1.1
|
|
76
|
+
accept: text/plain
|
|
77
|
+
"""
|
|
78
|
+
Then the following reply is sent:
|
|
79
|
+
"""
|
|
80
|
+
403 Forbidden
|
|
81
|
+
|
|
82
|
+
Metadata is not accessible.
|
|
83
|
+
"""
|
|
84
|
+
When the following request is received:
|
|
85
|
+
"""
|
|
86
|
+
GET / HTTP/1.1
|
|
87
|
+
accept: application/yaml
|
|
88
|
+
"""
|
|
89
|
+
Then the following reply is sent:
|
|
90
|
+
"""
|
|
91
|
+
200 OK
|
|
92
|
+
content-type: application/yaml
|
|
93
|
+
|
|
94
|
+
- 10cf16b458f759e0d617f2f3d83599ff
|
|
95
|
+
"""
|
|
96
|
+
When the following request is received:
|
|
97
|
+
"""
|
|
98
|
+
GET /10cf16b458f759e0d617f2f3d83599ff?foo=bar HTTP/1.1
|
|
99
|
+
"""
|
|
100
|
+
Then the following reply is sent:
|
|
101
|
+
"""
|
|
102
|
+
404 Not Found
|
|
103
|
+
"""
|
|
104
|
+
When the following request is received:
|
|
105
|
+
"""
|
|
106
|
+
DELETE /10cf16b458f759e0d617f2f3d83599ff HTTP/1.1
|
|
107
|
+
"""
|
|
108
|
+
Then the following reply is sent:
|
|
109
|
+
"""
|
|
110
|
+
204 No Content
|
|
111
|
+
"""
|
|
112
|
+
When the following request is received:
|
|
113
|
+
"""
|
|
114
|
+
GET /10cf16b458f759e0d617f2f3d83599ff HTTP/1.1
|
|
115
|
+
"""
|
|
116
|
+
Then the following reply is sent:
|
|
117
|
+
"""
|
|
118
|
+
404 Not Found
|
|
119
|
+
"""
|
|
120
|
+
|
|
121
|
+
Scenario: Entries permutation
|
|
122
|
+
When the stream of `lenna.ascii` is received with the following headers:
|
|
123
|
+
"""
|
|
124
|
+
POST / HTTP/1.1
|
|
125
|
+
accept: application/yaml
|
|
126
|
+
content-type: application/octet-stream
|
|
127
|
+
"""
|
|
128
|
+
And the stream of `lenna.png` is received with the following headers:
|
|
129
|
+
"""
|
|
130
|
+
POST / HTTP/1.1
|
|
131
|
+
accept: application/yaml
|
|
132
|
+
content-type: application/octet-stream
|
|
133
|
+
"""
|
|
134
|
+
When the following request is received:
|
|
135
|
+
"""
|
|
136
|
+
GET / HTTP/1.1
|
|
137
|
+
accept: application/yaml
|
|
138
|
+
"""
|
|
139
|
+
Then the following reply is sent:
|
|
140
|
+
"""
|
|
141
|
+
200 OK
|
|
142
|
+
content-type: application/yaml
|
|
143
|
+
|
|
144
|
+
- 10cf16b458f759e0d617f2f3d83599ff
|
|
145
|
+
- 814a0034f5549e957ee61360d87457e5
|
|
146
|
+
"""
|
|
147
|
+
When the following request is received:
|
|
148
|
+
"""
|
|
149
|
+
PUT / HTTP/1.1
|
|
150
|
+
content-type: application/yaml
|
|
151
|
+
|
|
152
|
+
- 814a0034f5549e957ee61360d87457e5
|
|
153
|
+
- 10cf16b458f759e0d617f2f3d83599ff
|
|
154
|
+
"""
|
|
155
|
+
Then the following reply is sent:
|
|
156
|
+
"""
|
|
157
|
+
204 No Content
|
|
158
|
+
"""
|
|
159
|
+
When the following request is received:
|
|
160
|
+
"""
|
|
161
|
+
GET / HTTP/1.1
|
|
162
|
+
accept: application/yaml
|
|
163
|
+
"""
|
|
164
|
+
Then the following reply is sent:
|
|
165
|
+
"""
|
|
166
|
+
200 OK
|
|
167
|
+
content-type: application/yaml
|
|
168
|
+
|
|
169
|
+
- 814a0034f5549e957ee61360d87457e5
|
|
170
|
+
- 10cf16b458f759e0d617f2f3d83599ff
|
|
171
|
+
"""
|
|
172
|
+
|
|
173
|
+
Scenario: Media type control
|
|
174
|
+
When the stream of `lenna.png` is received with the following headers:
|
|
175
|
+
"""
|
|
176
|
+
POST /media/jpeg-or-png/ HTTP/1.1
|
|
177
|
+
content-type: image/jpeg
|
|
178
|
+
"""
|
|
179
|
+
Then the following reply is sent:
|
|
180
|
+
"""
|
|
181
|
+
400 Bad Request
|
|
182
|
+
"""
|
|
183
|
+
When the stream of `lenna.png` is received with the following headers:
|
|
184
|
+
"""
|
|
185
|
+
POST /media/jpeg/ HTTP/1.1
|
|
186
|
+
"""
|
|
187
|
+
Then the following reply is sent:
|
|
188
|
+
"""
|
|
189
|
+
415 Unsupported Media Type
|
|
190
|
+
"""
|
|
191
|
+
When the stream of `lenna.png` is received with the following headers:
|
|
192
|
+
"""
|
|
193
|
+
POST /media/jpeg-or-png/ HTTP/1.1
|
|
194
|
+
"""
|
|
195
|
+
Then the following reply is sent:
|
|
196
|
+
"""
|
|
197
|
+
201 Created
|
|
198
|
+
"""
|
|
199
|
+
|
|
200
|
+
Scenario Outline: Receiving <format> images
|
|
201
|
+
When the stream of `sample.<format>` is received with the following headers:
|
|
202
|
+
"""
|
|
203
|
+
POST /media/images/ HTTP/1.1
|
|
204
|
+
"""
|
|
205
|
+
Then the following reply is sent:
|
|
206
|
+
"""
|
|
207
|
+
201 Created
|
|
208
|
+
"""
|
|
209
|
+
Examples:
|
|
210
|
+
| format |
|
|
211
|
+
| jpeg |
|
|
212
|
+
| jxl |
|
|
213
|
+
| gif |
|
|
214
|
+
| heic |
|
|
215
|
+
| avif |
|
|
216
|
+
| webp |
|
|
217
|
+
|
|
218
|
+
Scenario: Fetching non-existent BLOB
|
|
219
|
+
When the following request is received:
|
|
220
|
+
"""
|
|
221
|
+
GET /whatever HTTP/1.1
|
|
222
|
+
"""
|
|
223
|
+
Then the following reply is sent:
|
|
224
|
+
"""
|
|
225
|
+
404 Not Found
|
|
226
|
+
"""
|
|
227
|
+
|
|
228
|
+
Scenario: Fetching a BLOB with trailing slash
|
|
229
|
+
When the stream of `lenna.ascii` is received with the following headers:
|
|
230
|
+
"""
|
|
231
|
+
POST / HTTP/1.1
|
|
232
|
+
accept: application/yaml
|
|
233
|
+
content-type: application/octet-stream
|
|
234
|
+
"""
|
|
235
|
+
And the following request is received:
|
|
236
|
+
"""
|
|
237
|
+
GET /10cf16b458f759e0d617f2f3d83599ff/ HTTP/1.1
|
|
238
|
+
accept: text/plain
|
|
239
|
+
"""
|
|
240
|
+
Then the following reply is sent:
|
|
241
|
+
"""
|
|
242
|
+
404 Not Found
|
|
243
|
+
content-type: text/plain
|
|
244
|
+
|
|
245
|
+
Trailing slash is redundant.
|
|
246
|
+
"""
|
|
247
|
+
|
|
248
|
+
Scenario: Accessing an Entry and the original BLOLB
|
|
249
|
+
Given the annotation:
|
|
250
|
+
"""yaml
|
|
251
|
+
debug: true
|
|
252
|
+
/:
|
|
253
|
+
auth:anonymous: true
|
|
254
|
+
octets:context: octets
|
|
255
|
+
POST:
|
|
256
|
+
octets:store: ~
|
|
257
|
+
/*:
|
|
258
|
+
GET:
|
|
259
|
+
octets:fetch:
|
|
260
|
+
meta: true
|
|
261
|
+
blob: false
|
|
262
|
+
"""
|
|
263
|
+
When the stream of `lenna.ascii` is received with the following headers:
|
|
264
|
+
"""
|
|
265
|
+
POST / HTTP/1.1
|
|
266
|
+
"""
|
|
267
|
+
Then the following reply is sent:
|
|
268
|
+
"""
|
|
269
|
+
201 Created
|
|
270
|
+
"""
|
|
271
|
+
When the following request is received:
|
|
272
|
+
"""
|
|
273
|
+
GET /10cf16b458f759e0d617f2f3d83599ff:meta HTTP/1.1
|
|
274
|
+
accept: application/yaml
|
|
275
|
+
"""
|
|
276
|
+
Then the following reply is sent:
|
|
277
|
+
"""
|
|
278
|
+
200 OK
|
|
279
|
+
content-type: application/yaml
|
|
280
|
+
content-length: 124
|
|
281
|
+
|
|
282
|
+
id: 10cf16b458f759e0d617f2f3d83599ff
|
|
283
|
+
type: application/octet-stream
|
|
284
|
+
size: 8169
|
|
285
|
+
"""
|
|
286
|
+
When the following request is received:
|
|
287
|
+
"""
|
|
288
|
+
GET /10cf16b458f759e0d617f2f3d83599ff HTTP/1.1
|
|
289
|
+
"""
|
|
290
|
+
Then the following reply is sent:
|
|
291
|
+
"""
|
|
292
|
+
403 Forbidden
|
|
293
|
+
|
|
294
|
+
BLOB variant must be specified.
|
|
295
|
+
"""
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
Feature: Octets storage workflows
|
|
2
|
+
|
|
3
|
+
Scenario: Running a workflow
|
|
4
|
+
Given the `octets.tester` is running
|
|
5
|
+
Given the annotation:
|
|
6
|
+
"""yaml
|
|
7
|
+
/:
|
|
8
|
+
auth:anonymous: true
|
|
9
|
+
octets:context: octets
|
|
10
|
+
POST:
|
|
11
|
+
octets:store:
|
|
12
|
+
workflow:
|
|
13
|
+
- add-foo: octets.tester.foo
|
|
14
|
+
add-bar: octets.tester.bar
|
|
15
|
+
- add-baz: octets.tester.baz
|
|
16
|
+
- diversify: octets.tester.diversify
|
|
17
|
+
/*:
|
|
18
|
+
GET:
|
|
19
|
+
octets:fetch:
|
|
20
|
+
meta: true
|
|
21
|
+
"""
|
|
22
|
+
When the stream of `lenna.ascii` is received with the following headers:
|
|
23
|
+
"""
|
|
24
|
+
POST / HTTP/1.1
|
|
25
|
+
accept: application/yaml
|
|
26
|
+
content-type: application/octet-stream
|
|
27
|
+
"""
|
|
28
|
+
Then the following reply is sent:
|
|
29
|
+
"""
|
|
30
|
+
201 Created
|
|
31
|
+
content-type: multipart/yaml; boundary=cut
|
|
32
|
+
|
|
33
|
+
--cut
|
|
34
|
+
id: 10cf16b458f759e0d617f2f3d83599ff
|
|
35
|
+
type: application/octet-stream
|
|
36
|
+
size: 8169
|
|
37
|
+
--cut
|
|
38
|
+
add-foo: null
|
|
39
|
+
--cut
|
|
40
|
+
add-bar:
|
|
41
|
+
bar: baz
|
|
42
|
+
--cut
|
|
43
|
+
add-baz: null
|
|
44
|
+
--cut
|
|
45
|
+
diversify: null
|
|
46
|
+
--cut--
|
|
47
|
+
"""
|
|
48
|
+
When the following request is received:
|
|
49
|
+
"""
|
|
50
|
+
GET /10cf16b458f759e0d617f2f3d83599ff:meta HTTP/1.1
|
|
51
|
+
accept: application/yaml
|
|
52
|
+
"""
|
|
53
|
+
Then the following reply is sent:
|
|
54
|
+
"""
|
|
55
|
+
200 OK
|
|
56
|
+
content-type: application/yaml
|
|
57
|
+
|
|
58
|
+
id: 10cf16b458f759e0d617f2f3d83599ff
|
|
59
|
+
type: application/octet-stream
|
|
60
|
+
size: 8169
|
|
61
|
+
meta:
|
|
62
|
+
foo: bar
|
|
63
|
+
bar: baz
|
|
64
|
+
baz: qux
|
|
65
|
+
"""
|
|
66
|
+
When the following request is received:
|
|
67
|
+
"""
|
|
68
|
+
GET /10cf16b458f759e0d617f2f3d83599ff.hello.png HTTP/1.1
|
|
69
|
+
"""
|
|
70
|
+
Then the stream equals to `lenna.png` is sent with the following headers:
|
|
71
|
+
"""
|
|
72
|
+
200 OK
|
|
73
|
+
content-type: image/png
|
|
74
|
+
content-length: 473831
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
Scenario: Getting error when adding metadata to a file
|
|
78
|
+
Given the `octets.tester` is running
|
|
79
|
+
Given the annotation:
|
|
80
|
+
"""yaml
|
|
81
|
+
/:
|
|
82
|
+
auth:anonymous: true
|
|
83
|
+
octets:context: octets
|
|
84
|
+
POST:
|
|
85
|
+
octets:store:
|
|
86
|
+
workflow:
|
|
87
|
+
add-foo: octets.tester.foo
|
|
88
|
+
add-bar: octets.tester.err
|
|
89
|
+
add-baz: octets.tester.baz
|
|
90
|
+
"""
|
|
91
|
+
When the stream of `lenna.ascii` is received with the following headers:
|
|
92
|
+
"""
|
|
93
|
+
POST / HTTP/1.1
|
|
94
|
+
accept: application/yaml
|
|
95
|
+
content-type: application/octet-stream
|
|
96
|
+
"""
|
|
97
|
+
Then the following reply is sent:
|
|
98
|
+
"""
|
|
99
|
+
201 Created
|
|
100
|
+
content-type: multipart/yaml; boundary=cut
|
|
101
|
+
|
|
102
|
+
--cut
|
|
103
|
+
id: 10cf16b458f759e0d617f2f3d83599ff
|
|
104
|
+
type: application/octet-stream
|
|
105
|
+
size: 8169
|
|
106
|
+
--cut
|
|
107
|
+
add-foo: null
|
|
108
|
+
--cut
|
|
109
|
+
error:
|
|
110
|
+
step: add-bar
|
|
111
|
+
code: ERROR
|
|
112
|
+
message: Something went wrong
|
|
113
|
+
--cut--
|
|
114
|
+
"""
|
package/features/routes.feature
CHANGED
|
@@ -47,3 +47,43 @@ Feature: Routes
|
|
|
47
47
|
|
|
48
48
|
Hello
|
|
49
49
|
"""
|
|
50
|
+
|
|
51
|
+
Scenario: Wildcard routes
|
|
52
|
+
Given the `greeter` is running with the following manifest:
|
|
53
|
+
"""yaml
|
|
54
|
+
exposition:
|
|
55
|
+
/*:
|
|
56
|
+
GET: greet
|
|
57
|
+
/foo/*/bar:
|
|
58
|
+
GET: greet
|
|
59
|
+
"""
|
|
60
|
+
When the following request is received:
|
|
61
|
+
"""
|
|
62
|
+
GET /greeter/baz/ HTTP/1.1
|
|
63
|
+
accept: text/plain
|
|
64
|
+
"""
|
|
65
|
+
Then the following reply is sent:
|
|
66
|
+
"""
|
|
67
|
+
200 OK
|
|
68
|
+
|
|
69
|
+
Hello
|
|
70
|
+
"""
|
|
71
|
+
When the following request is received:
|
|
72
|
+
"""
|
|
73
|
+
GET /greeter/baz/qux/ HTTP/1.1
|
|
74
|
+
"""
|
|
75
|
+
Then the following reply is sent:
|
|
76
|
+
"""
|
|
77
|
+
404 Not Found
|
|
78
|
+
"""
|
|
79
|
+
When the following request is received:
|
|
80
|
+
"""
|
|
81
|
+
GET /greeter/foo/baz/bar/ HTTP/1.1
|
|
82
|
+
accept: text/plain
|
|
83
|
+
"""
|
|
84
|
+
Then the following reply is sent:
|
|
85
|
+
"""
|
|
86
|
+
200 OK
|
|
87
|
+
|
|
88
|
+
Hello
|
|
89
|
+
"""
|
package/features/steps/HTTP.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import { binding, when, then } from 'cucumber-tsflow'
|
|
1
|
+
import { AssertionError } from 'node:assert'
|
|
2
|
+
import { binding, then, when } from 'cucumber-tsflow'
|
|
4
3
|
import * as http from '@toa.io/http'
|
|
5
4
|
import { trim } from '@toa.io/generic'
|
|
6
|
-
import {
|
|
5
|
+
import { buffer } from '@toa.io/streams'
|
|
6
|
+
import { open } from '../../../storages/source/test/util'
|
|
7
|
+
import { Parameters } from './Parameters'
|
|
7
8
|
import { Gateway } from './Gateway'
|
|
8
9
|
|
|
9
10
|
@binding([Gateway, Parameters])
|
|
@@ -47,7 +48,11 @@ export class HTTP {
|
|
|
47
48
|
const match = this.response.match(rx)
|
|
48
49
|
|
|
49
50
|
if (match === null)
|
|
50
|
-
throw new AssertionError({
|
|
51
|
+
throw new AssertionError({
|
|
52
|
+
message: `Response is missing '${line}'`,
|
|
53
|
+
expected: line,
|
|
54
|
+
actual: this.response
|
|
55
|
+
})
|
|
51
56
|
|
|
52
57
|
Object.assign(this.variables, match.groups)
|
|
53
58
|
}
|
|
@@ -62,9 +67,54 @@ export class HTTP {
|
|
|
62
67
|
|
|
63
68
|
const includes = this.response.includes(line)
|
|
64
69
|
|
|
65
|
-
|
|
70
|
+
if (includes)
|
|
71
|
+
throw new AssertionError({
|
|
72
|
+
message: `Response contains '${line}'`,
|
|
73
|
+
expected: line,
|
|
74
|
+
actual: this.response
|
|
75
|
+
})
|
|
66
76
|
}
|
|
67
77
|
}
|
|
78
|
+
|
|
79
|
+
@when('the stream of `{word}` is received with the following headers:')
|
|
80
|
+
public async streamRequest (filename: string, head: string): Promise<any> {
|
|
81
|
+
head = trim(head) + '\n\n'
|
|
82
|
+
|
|
83
|
+
await this.gateway.start()
|
|
84
|
+
|
|
85
|
+
const { url, method, headers } = http.parse.request(head)
|
|
86
|
+
const href = new URL(url, this.origin).href
|
|
87
|
+
const body = open(filename)
|
|
88
|
+
|
|
89
|
+
headers.connection = 'close' // required for interrupted streams
|
|
90
|
+
|
|
91
|
+
const request = {
|
|
92
|
+
method,
|
|
93
|
+
headers,
|
|
94
|
+
body: body as unknown as ReadableStream,
|
|
95
|
+
duplex: 'half'
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
const response = await fetch(href, request)
|
|
100
|
+
|
|
101
|
+
this.response = await http.parse.response(response)
|
|
102
|
+
} catch (e: any) {
|
|
103
|
+
console.error(e)
|
|
104
|
+
console.error(e.cause)
|
|
105
|
+
|
|
106
|
+
throw e
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@then('the stream equals to `{word}` is sent with the following headers:')
|
|
111
|
+
public async responseStreamMatch (filename: string, head: string): Promise<any> {
|
|
112
|
+
const buf = await buffer(open(filename))
|
|
113
|
+
const text = buf.toString('utf8')
|
|
114
|
+
const expected = head + '\n\n' + text
|
|
115
|
+
|
|
116
|
+
this.responseIncludes(expected)
|
|
117
|
+
}
|
|
68
118
|
}
|
|
69
119
|
|
|
70
120
|
const CAPTURE = /\\\$\\{\\{ (?<name>[A-Za-z_]{0,32}) \\}\\}/g
|
|
@@ -4,9 +4,12 @@ export class Parameters {
|
|
|
4
4
|
public readonly origin: string
|
|
5
5
|
|
|
6
6
|
public constructor () {
|
|
7
|
-
this.origin = 'http://
|
|
7
|
+
this.origin = 'http://127.0.0.1:8000'
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
setDefaultTimeout(
|
|
11
|
+
setDefaultTimeout(30 * 1000)
|
|
12
12
|
process.env.TOA_DEV = '1'
|
|
13
|
+
|
|
14
|
+
// { octets: tmp:///exposition-octets }
|
|
15
|
+
process.env.TOA_STORAGES = '3gABpm9jdGV0c7h0bXA6Ly8vZXhwb3NpdGlvbi1vY3RldHM='
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { join } from 'node:path'
|
|
2
|
-
import {
|
|
2
|
+
import { tmpdir } from 'node:os'
|
|
3
|
+
import { mkdtemp, copy } from 'fs-extra'
|
|
3
4
|
import * as yaml from '@toa.io/yaml'
|
|
4
5
|
|
|
5
6
|
export class Workspace {
|
|
6
7
|
private root: string = devnull
|
|
7
8
|
|
|
8
9
|
public static exists
|
|
9
|
-
(
|
|
10
|
+
(_0: unknown, _1: unknown, descriptor: PropertyDescriptor): PropertyDescriptor {
|
|
10
11
|
const method = descriptor.value
|
|
11
12
|
|
|
12
13
|
descriptor.value = async function (this: Workspace, ...args: any[]): Promise<any> {
|
|
13
|
-
if (this.root === devnull) this.root =
|
|
14
|
+
if (this.root === devnull) this.root =
|
|
15
|
+
await mkdtemp(join(tmpdir(), Math.random().toString(36).slice(2)))
|
|
14
16
|
|
|
15
17
|
return method.apply(this, args)
|
|
16
18
|
}
|
|
@@ -23,9 +25,10 @@ export class Workspace {
|
|
|
23
25
|
const source = join(__dirname, 'components', name)
|
|
24
26
|
const target = join(this.root, name)
|
|
25
27
|
|
|
26
|
-
await
|
|
28
|
+
await copy(source, target)
|
|
27
29
|
|
|
28
|
-
if (patch !== undefined)
|
|
30
|
+
if (patch !== undefined)
|
|
31
|
+
await this.patchManifest(target, patch)
|
|
29
32
|
|
|
30
33
|
return target
|
|
31
34
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { join } = require('node:path')
|
|
4
|
+
const { createReadStream } = require('node:fs')
|
|
5
|
+
|
|
6
|
+
const lenna = join(__dirname, 'lenna.png')
|
|
7
|
+
|
|
8
|
+
async function diversify (input, context) {
|
|
9
|
+
const stream = createReadStream(lenna)
|
|
10
|
+
|
|
11
|
+
return context.storages[input.storage].diversify(input.path, 'hello.png', stream)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
exports.effect = diversify
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
import { setTimeout } from 'node:timers/promises'
|
|
4
|
+
|
|
5
|
+
async function err (_) {
|
|
6
|
+
await setTimeout(20)
|
|
7
|
+
|
|
8
|
+
const err = Object.create(Error.prototype)
|
|
9
|
+
|
|
10
|
+
err.code = 'ERROR'
|
|
11
|
+
err.message = 'Something went wrong'
|
|
12
|
+
|
|
13
|
+
return err
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
exports.effect = err
|