gem_server_conformance 0.1.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.
@@ -0,0 +1,423 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "support/step_helpers"
4
+
5
+ RSpec.describe GemServerConformance do # rubocop:disable RSpec/EmptyExampleGroup
6
+ include StepHelpers
7
+
8
+ before(:all) do
9
+ Gem.configuration.verbose = false
10
+ ENV["SOURCE_DATE_EPOCH"] = "0"
11
+ end
12
+
13
+ StepHelpers::Step
14
+ .new(context("with conformance runner"))
15
+ .then "after rebuilding empty versions list", before: ->(_) { rebuild_versions_list } do
16
+ request :get_versions do
17
+ it { is_expected.to be_valid_compact_index_reponse }
18
+
19
+ it {
20
+ is_expected.to have_body(
21
+ "created_at: 1990-01-01T00:00:00Z\n---\n"
22
+ )
23
+ }
24
+ end
25
+
26
+ request :get_names do
27
+ it { is_expected.to be_valid_compact_index_reponse }
28
+ it { is_expected.to have_body(eq("---\n\n")) }
29
+ end
30
+
31
+ request :get_specs do
32
+ it { is_expected.to be_ok }
33
+ it { is_expected.to unmarshal_as([]) }
34
+ end
35
+
36
+ request :get_specs, :prerelease do
37
+ it { is_expected.to be_ok }
38
+ it { is_expected.to unmarshal_as([]) }
39
+ end
40
+
41
+ request :get_specs, :latest do
42
+ it { is_expected.to be_ok }
43
+ it { is_expected.to unmarshal_as([]) }
44
+ end
45
+
46
+ request :get_info, "missing" do
47
+ it { is_expected.to be_not_found }
48
+ end
49
+
50
+ request :get_gem, "missing" do
51
+ it { is_expected.to be_not_found }
52
+ end
53
+
54
+ request :get_quick_spec, "missing" do
55
+ it { is_expected.to be_not_found }
56
+ end
57
+ end
58
+ .then "after first push", before: lambda { |_|
59
+ @gem_a_1_0_0 = build_gem("a", "1.0.0")
60
+ push_gem(@gem_a_1_0_0, expected_to: be_ok)
61
+ } do
62
+ pushed_gem("a-1.0.0")
63
+
64
+ request :get_versions, compact_index: true do
65
+ it { is_expected.to be_valid_compact_index_reponse }
66
+
67
+ it {
68
+ is_expected.to have_body(
69
+ parent_response.body + "a 1.0.0 8761412e66a014fe80723e251d96be29\n"
70
+ )
71
+ }
72
+ end
73
+
74
+ request :get_info, "a", compact_index: true do
75
+ it { is_expected.to be_ok }
76
+ it { is_expected.to have_body(<<~INFO) }
77
+ ---
78
+ 1.0.0 |checksum:2dfc054a348d36faae6e98e8c0222a76c07cfa0620b3c47acb154cb3d2de149b
79
+ INFO
80
+ it { is_expected.to have_header("content-type").with_value("text/plain; charset=utf-8") }
81
+ end
82
+
83
+ request :get_names, compact_index: true do
84
+ it { is_expected.to be_valid_compact_index_reponse }
85
+ it { is_expected.to have_body(eq("---\na\n")) }
86
+ end
87
+
88
+ request :get_specs do
89
+ it { is_expected.to be_ok, last_response.body }
90
+ it { is_expected.to unmarshal_as([["a", Gem::Version.new("1.0.0"), "ruby"]]) }
91
+ end
92
+
93
+ request :get_specs, :prerelease do
94
+ it { is_expected.to be_ok }
95
+ it { is_expected.to unmarshal_as([]) }
96
+ end
97
+
98
+ request :get_specs, :latest do
99
+ it { is_expected.to be_ok }
100
+ it { is_expected.to unmarshal_as([["a", Gem::Version.new("1.0.0"), "ruby"]]) }
101
+ end
102
+ end
103
+ .then "after yanking only gem", before: ->(_) { yank_gem(@gem_a_1_0_0, expected_to: be_ok) } do
104
+ yanked_gem("a-1.0.0")
105
+
106
+ request :get_versions, compact_index: true do
107
+ it { is_expected.to be_valid_compact_index_reponse }
108
+
109
+ it {
110
+ is_expected.to have_body(parent_response.body + "a -1.0.0 6105347ebb9825ac754615ca55ff3b0c\n")
111
+ }
112
+ end
113
+
114
+ request :get_info, "a", compact_index: true do
115
+ it { is_expected.to be_valid_compact_index_reponse }
116
+ it { is_expected.to have_body(<<~INFO) }
117
+ ---
118
+ INFO
119
+ end
120
+
121
+ request :get_names, compact_index: true do
122
+ it { is_expected.to be_valid_compact_index_reponse }
123
+ it { is_expected.to have_body(eq("---\n\n")) }
124
+ end
125
+
126
+ request :get_specs do
127
+ it { is_expected.to be_ok }
128
+ it { is_expected.to unmarshal_as([]) }
129
+ end
130
+
131
+ request :get_specs, :prerelease do
132
+ it { is_expected.to be_ok }
133
+ it { is_expected.to unmarshal_as([]) }
134
+ end
135
+
136
+ request :get_specs, :latest do
137
+ it { is_expected.to be_ok }
138
+ it { is_expected.to unmarshal_as([]) }
139
+ end
140
+ end
141
+ .then "after second push", before: lambda { |_|
142
+ push_gem(@a_0_0_1 = build_gem("a", "0.0.1"), expected_to: be_ok)
143
+ push_gem(@b_1_0_0_pre = build_gem("b", "1.0.0.pre") do |spec|
144
+ spec.add_runtime_dependency "a", "< 1.0.0", ">= 0.1.0"
145
+ spec.required_ruby_version = ">= 2.0"
146
+ spec.required_rubygems_version = ">= 2.0"
147
+ end, expected_to: be_ok)
148
+ } do
149
+ pushed_gem("a-0.0.1")
150
+ pushed_gem("b-1.0.0.pre")
151
+
152
+ request :get_versions, compact_index: true do
153
+ it { is_expected.to be_valid_compact_index_reponse }
154
+ it { is_expected.to have_body(parent_response.body + <<~BODY) }
155
+ a 0.0.1 22428c91ad748146bec818307104ed33
156
+ b 1.0.0.pre 688f5cdf79887aff5d87c86f36cfe063
157
+ BODY
158
+ end
159
+
160
+ request :get_info, "a", compact_index: true do
161
+ it { is_expected.to be_valid_compact_index_reponse }
162
+ it { is_expected.to have_body(parent_response.body + <<~INFO) }
163
+ 0.0.1 |checksum:5e25d516b8c19c9d26ef95efad565c2097865a0d3dba5ef3fade650a2e690b35
164
+ INFO
165
+ end
166
+
167
+ request :get_info, "b", compact_index: true do
168
+ it { is_expected.to be_valid_compact_index_reponse }
169
+ it { is_expected.to have_body(<<~INFO) }
170
+ ---
171
+ 1.0.0.pre a:< 1.0.0&>= 0.1.0|checksum:3f97419b7c35257f7aab3ae37521ab64ef8ec7646ef55b9f6a5e41d479bc128c,ruby:>= 2.0,rubygems:>= 2.0
172
+ INFO
173
+ end
174
+
175
+ request :get_names, compact_index: true do
176
+ it { is_expected.to be_valid_compact_index_reponse }
177
+ it { is_expected.to have_body(eq("---\na\nb\n")) }
178
+ end
179
+
180
+ request :get_specs do
181
+ it { is_expected.to be_ok }
182
+ it { is_expected.to unmarshal_as([["a", Gem::Version.new("0.0.1"), "ruby"]]) }
183
+ end
184
+
185
+ request :get_specs, :prerelease do
186
+ it { is_expected.to be_ok }
187
+ it { is_expected.to unmarshal_as([["b", Gem::Version.new("1.0.0.pre"), "ruby"]]) }
188
+ end
189
+
190
+ request :get_specs, :latest do
191
+ it { is_expected.to be_ok }
192
+ it { is_expected.to unmarshal_as([["a", Gem::Version.new("0.0.1"), "ruby"]]) }
193
+ end
194
+
195
+ request :get_gem, "a-0.0.1" do
196
+ it { is_expected.to be_ok }
197
+
198
+ it { is_expected.to have_content_length }
199
+ .metadata[:content_length_header] = true
200
+ it { is_expected.to have_body(eq(@a_0_0_1.contents)) }
201
+ end
202
+
203
+ request :get_gem, "b-1.0.0.pre" do
204
+ it { is_expected.to be_ok }
205
+
206
+ it { is_expected.to have_content_length }
207
+ .metadata[:content_length_header] = true
208
+ it { is_expected.to have_body(eq(@b_1_0_0_pre.contents)) }
209
+ end
210
+
211
+ request :get_quick_spec, "a-0.0.1" do
212
+ it { is_expected.to be_ok }
213
+
214
+ it { is_expected.to have_content_length }
215
+ .metadata[:content_length_header] = true
216
+ it {
217
+ is_expected.to unmarshal_as(Gem::Specification.new do |s|
218
+ s.name = "a"
219
+ s.version = Gem::Version.new("0.0.1")
220
+ s.installed_by_version = Gem::Version.new("0")
221
+ s.authors = ["Conformance"]
222
+ s.date = Time.utc(2024, 7, 9)
223
+ s.description = ""
224
+ s.require_paths = ["lib"]
225
+ s.rubygems_version = "3.5.11"
226
+ s.specification_version = 4
227
+ s.summary = "Conformance test"
228
+ end).inflate(true)
229
+ }
230
+ end
231
+
232
+ request :get_quick_spec, "b-1.0.0.pre" do
233
+ it { is_expected.to be_ok }
234
+
235
+ it { is_expected.to have_content_length }
236
+ .metadata[:content_length_header] = true
237
+ it {
238
+ is_expected.to unmarshal_as(Gem::Specification.new do |s|
239
+ s.name = "b"
240
+ s.version = Gem::Version.new("1.0.0.pre")
241
+ s.installed_by_version = Gem::Version.new("0")
242
+ s.authors = ["Conformance"]
243
+ s.date = Time.utc(2024, 7, 9)
244
+ s.description = ""
245
+ s.require_paths = ["lib"]
246
+ s.rubygems_version = "3.5.11"
247
+ s.specification_version = 4
248
+ s.summary = "Conformance test"
249
+ s.add_dependency "a", ">= 0.1.0", "< 1.0.0"
250
+ s.required_ruby_version = ">= 2.0"
251
+ s.required_rubygems_version = ">= 2.0"
252
+ end).inflate(true)
253
+ }
254
+ end
255
+ end
256
+ .then "third push", before: lambda { |_|
257
+ push_gem(build_gem("a", "0.0.1") { |s| s.add_runtime_dependency "b", ">= 1.0.0" },
258
+ expected_to: be_conflict)
259
+ @all_gems.pop
260
+ push_gem(@a_0_2_0 = build_gem("a", "0.2.0"), expected_to: be_ok)
261
+ push_gem(build_gem("a", "0.2.0", platform: "x86-mingw32"), expected_to: be_ok)
262
+ push_gem(build_gem("a", "0.2.0", platform: "java"), expected_to: be_ok)
263
+ } do
264
+ pushed_gem("a-0.2.0")
265
+ pushed_gem("a-0.2.0-x86-mingw32")
266
+ pushed_gem("a-0.2.0-java")
267
+
268
+ request :get_versions, compact_index: true do
269
+ it { is_expected.to be_valid_compact_index_reponse }
270
+ it { is_expected.to have_body(parent_response.body + <<~BODY) }
271
+ a 0.2.0 7a7528379bbd1e0420ea7f1305ba526a
272
+ a 0.2.0-x86-mingw32 17f9c2882d6f0a244f8bba2df1d14107
273
+ a 0.2.0-java ca5c12bc8ba4457ada41c71bee282bfb
274
+ BODY
275
+ end
276
+
277
+ request :get_info, "a", compact_index: true do
278
+ it { is_expected.to be_valid_compact_index_reponse }
279
+ it { is_expected.to have_body(parent_response.body + <<~INFO) }
280
+ 0.2.0 |checksum:a1753a0e8b6f0515a15e9cfa4ea143e36de235525f6f68c4ff45c4ae70be072f
281
+ 0.2.0-x86-mingw32 |checksum:e330e73d0dec030107c5656bbe89aecae738ba483471bf87f1bd943093fc9f27
282
+ 0.2.0-java |checksum:897332272ac159bf200a690dae5039df1e60355124848f2a6f889563311421f4
283
+ INFO
284
+ end
285
+
286
+ request :get_specs do
287
+ it { is_expected.to be_ok, last_response.body }
288
+
289
+ it {
290
+ is_expected.to unmarshal_as(
291
+ a_collection_containing_exactly(*(Marshal.load(Zlib.gunzip(parent_response.body)) + [
292
+ ["a", Gem::Version.new("0.2.0"), "x86-mingw32"],
293
+ ["a", Gem::Version.new("0.2.0"), "ruby"],
294
+ ["a", Gem::Version.new("0.2.0"), "java"]
295
+ ]))
296
+ )
297
+ }
298
+ end
299
+
300
+ request :get_specs, :latest do
301
+ it { is_expected.to be_ok }
302
+
303
+ it {
304
+ is_expected.to unmarshal_as a_collection_containing_exactly(
305
+ ["a", Gem::Version.new("0.2.0"), "x86-mingw32"],
306
+ ["a", Gem::Version.new("0.2.0"), "ruby"],
307
+ ["a", Gem::Version.new("0.2.0"), "java"]
308
+ )
309
+ }
310
+ end
311
+
312
+ request :get_specs, :prerelease do
313
+ it { is_expected.to be_ok }
314
+
315
+ it {
316
+ is_expected.to unmarshal_as([["b", Gem::Version.new("1.0.0.pre"), "ruby"]])
317
+ }
318
+ end
319
+ end
320
+ .then "after rebuilding versions list", before: ->(_) { rebuild_versions_list } do
321
+ request :get_versions, compact_index: true do
322
+ it { is_expected.to be_valid_compact_index_reponse }
323
+ it { is_expected.to have_body(<<~BODY) }
324
+ created_at: 1990-01-01T01:08:00Z
325
+ ---
326
+ a 0.0.1,0.2.0,0.2.0-x86-mingw32,0.2.0-java ca5c12bc8ba4457ada41c71bee282bfb
327
+ b 1.0.0.pre 688f5cdf79887aff5d87c86f36cfe063
328
+ BODY
329
+ end
330
+ end
331
+ .then "after fourth push", before: ->(_) { push_gem(build_gem("a", "0.3.0"), expected_to: be_ok) } do
332
+ pushed_gem("a-0.3.0")
333
+
334
+ request :get_versions, compact_index: true do
335
+ it { is_expected.to be_valid_compact_index_reponse }
336
+ it { is_expected.to have_body(parent_response.body + <<~BODY) }
337
+ a 0.3.0 6263c53d5a23dfe0339a3ebae0fed8da
338
+ BODY
339
+ end
340
+
341
+ request :get_info, "a", compact_index: true do
342
+ it { is_expected.to be_valid_compact_index_reponse }
343
+ it { is_expected.to have_body(parent_response.body + <<~INFO) }
344
+ 0.3.0 |checksum:40f19de3ce5c3fc5930fbc5dc3a08cd0b31572852d4885b37a19039bad7d9784
345
+ INFO
346
+ end
347
+
348
+ request :get_specs do
349
+ it { is_expected.to be_ok }
350
+
351
+ it {
352
+ is_expected.to unmarshal_as a_collection_containing_exactly(
353
+ *(Marshal.load(Zlib.gunzip(parent_response.body)) + [["a", Gem::Version.new("0.3.0"), "ruby"]])
354
+ )
355
+ }
356
+ end
357
+
358
+ request :get_specs, :latest do
359
+ it { is_expected.to be_ok }
360
+
361
+ it {
362
+ is_expected.to unmarshal_as a_collection_containing_exactly(
363
+ ["a", Gem::Version.new("0.2.0"), "x86-mingw32"],
364
+ ["a", Gem::Version.new("0.2.0"), "java"],
365
+ ["a", Gem::Version.new("0.3.0"), "ruby"]
366
+ )
367
+ }
368
+ end
369
+ end
370
+ .then "after yanking a gem", before: ->(_) { yank_gem(@a_0_2_0, expected_to: be_ok) } do
371
+ yanked_gem("a-0.2.0")
372
+
373
+ request :get_versions, compact_index: true do
374
+ it { is_expected.to be_valid_compact_index_reponse }
375
+ it { is_expected.to have_body(parent_response.body + "a -0.2.0 1fdcc4d621638a6ba75d8ed88b09f97a\n") }
376
+ end
377
+
378
+ request :get_info, "a", compact_index: true do
379
+ it { is_expected.to be_valid_compact_index_reponse }
380
+
381
+ it {
382
+ is_expected.to have_body(
383
+ parent_response.body.lines.tap do |lines|
384
+ lines.delete("0.2.0 |checksum:a1753a0e8b6f0515a15e9cfa4ea143e36de235525f6f68c4ff45c4ae70be072f\n")
385
+ end.join
386
+ )
387
+ }
388
+ end
389
+
390
+ request :get_specs do
391
+ it { is_expected.to be_ok }
392
+
393
+ it { is_expected.to have_content_length }
394
+ .metadata[:content_length_header] = true
395
+ it {
396
+ is_expected.to unmarshal_as(
397
+ a_collection_containing_exactly( \
398
+ *Marshal.load(Zlib.gunzip(parent_response.body)).tap do |entries|
399
+ entries.delete(["a", Gem::Version.new("0.2.0"), "ruby"])
400
+ end
401
+ )
402
+ )
403
+ }
404
+ end
405
+ end
406
+ .then "after rebuilding versions list", before: ->(_) { rebuild_versions_list } do
407
+ request :get_versions, compact_index: true do
408
+ it { is_expected.to be_valid_compact_index_reponse }
409
+ it { is_expected.to have_body(<<~VERSIONS) }
410
+ created_at: 1990-01-01T02:10:00Z
411
+ ---
412
+ a 0.0.1,0.2.0-x86-mingw32,0.2.0-java,0.3.0 1fdcc4d621638a6ba75d8ed88b09f97a
413
+ b 1.0.0.pre 688f5cdf79887aff5d87c86f36cfe063
414
+ VERSIONS
415
+ end
416
+ end
417
+ .then "after yanking a missing gem", before:
418
+ lambda { |_|
419
+ yank_gem(RequestHelpers::MockGem.new(name: "missing", version: "1.0.0"), expected_to: be_not_found)
420
+ } do
421
+ nil
422
+ end
423
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ ENV["RACK_ENV"] = ENV["APP_ENV"] = "test"
4
+ require "gem_server_conformance/server"
5
+ require_relative "support/request_helpers"
6
+
7
+ RSpec.configure do |config|
8
+ # Enable flags like --only-failures and --next-failure
9
+ config.example_status_persistence_file_path = ".gem_server_conformance.rspec_status"
10
+
11
+ # Disable RSpec exposing methods globally on `Module` and `main`
12
+ config.disable_monkey_patching!
13
+
14
+ config.include RequestHelpers
15
+
16
+ config.expect_with :rspec do |c|
17
+ c.syntax = :expect
18
+ c.include_chain_clauses_in_custom_matcher_descriptions = true
19
+ end
20
+ end