traject 3.8.3 → 3.9.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.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +3 -2
- data/CHANGES.md +27 -6
- data/README.md +6 -0
- data/lib/tasks/load_maps.rake +3 -3
- data/lib/traject/csv_writer.rb +5 -1
- data/lib/traject/delimited_writer.rb +6 -1
- data/lib/traject/experimental_nokogiri_streaming_reader.rb +3 -1
- data/lib/traject/indexer/context.rb +3 -1
- data/lib/traject/indexer.rb +2 -1
- data/lib/traject/macros/marc21_semantics.rb +2 -1
- data/lib/traject/oai_pmh_nokogiri_reader.rb +2 -3
- data/lib/traject/solr_json_httpx_writer.rb +499 -0
- data/lib/traject/version.rb +1 -1
- data/lib/translation_maps/marc_geographic.yaml +7 -4
- data/lib/translation_maps/marc_languages.yaml +13 -6
- data/test/delimited_writer_test.rb +1 -0
- data/test/solr_json_httpx_writer_test.rb +428 -0
- data/test/test_helper.rb +1 -0
- data/traject.gemspec +5 -3
- metadata +50 -21
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
require 'httpx'
|
|
3
|
+
require 'traject/solr_json_httpx_writer'
|
|
4
|
+
require 'thread'
|
|
5
|
+
require 'json'
|
|
6
|
+
require 'stringio'
|
|
7
|
+
require 'logger'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
require "httpx/adapters/webmock"
|
|
11
|
+
WebMock.enable! # not sure why we need this
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# Some basic tests, using a mocked http client so we can see what it did --
|
|
15
|
+
# these tests do not run against a real solr server at present.
|
|
16
|
+
describe "Traject::SolrJsonHttpxWriter" do
|
|
17
|
+
TEST_SOLR_URL = "http://example.com/solr"
|
|
18
|
+
|
|
19
|
+
#######
|
|
20
|
+
# utilities to help testing
|
|
21
|
+
#######
|
|
22
|
+
|
|
23
|
+
def context_with(hash)
|
|
24
|
+
Traject::Indexer::Context.new(:output_hash => hash)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def create_writer(settings = {})
|
|
28
|
+
settings = {
|
|
29
|
+
"solr.url" => TEST_SOLR_URL,
|
|
30
|
+
}.merge!(settings)
|
|
31
|
+
|
|
32
|
+
Traject::SolrJsonHttpxWriter.new(settings)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# strio = StringIO.new
|
|
36
|
+
# logger_to_strio(strio)
|
|
37
|
+
#
|
|
38
|
+
# Later check for strio.string for contents
|
|
39
|
+
def logger_to_strio(strio)
|
|
40
|
+
# Yell makes this hard, let's do it with an ordinary logger, think
|
|
41
|
+
# it's okay.
|
|
42
|
+
Logger.new(strio)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
#########
|
|
46
|
+
# Actual tests
|
|
47
|
+
#########
|
|
48
|
+
|
|
49
|
+
before do
|
|
50
|
+
@writer = create_writer
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "defaults to 1 bg thread" do
|
|
54
|
+
assert_equal 1, @writer.thread_pool_size
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "adds a document" do
|
|
58
|
+
stub_request(:post, "#{TEST_SOLR_URL}/update/json").to_return(status: 200)
|
|
59
|
+
|
|
60
|
+
@writer.put context_with({"id" => "one", "key" => ["value1", "value2"]})
|
|
61
|
+
@writer.close
|
|
62
|
+
|
|
63
|
+
assert_requested :post, "#{TEST_SOLR_URL}/update/json" do |request|
|
|
64
|
+
posted_json = JSON.parse(request.body)
|
|
65
|
+
assert_equal [{"id" => "one", "key" => ["value1", "value2"]}], posted_json
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "adds more than a batch in batches" do
|
|
70
|
+
stub_request(:post, "#{TEST_SOLR_URL}/update/json").to_return(status: 200)
|
|
71
|
+
|
|
72
|
+
(Traject::SolrJsonHttpxWriter::DEFAULT_BATCH_SIZE + 1).times do |i|
|
|
73
|
+
doc = {"id" => "doc_#{i}", "key" => "value"}
|
|
74
|
+
@writer.put context_with(doc)
|
|
75
|
+
end
|
|
76
|
+
@writer.close
|
|
77
|
+
|
|
78
|
+
assert_requested(:post, "#{TEST_SOLR_URL}/update/json", times: 2)
|
|
79
|
+
|
|
80
|
+
# first batch with 100
|
|
81
|
+
assert_requested(:post, "#{TEST_SOLR_URL}/update/json") do |request|
|
|
82
|
+
posted_json = JSON.parse(request.body)
|
|
83
|
+
posted_json.length == Traject::SolrJsonHttpxWriter::DEFAULT_BATCH_SIZE
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# second batch with just one
|
|
87
|
+
assert_requested(:post, "#{TEST_SOLR_URL}/update/json") do |request|
|
|
88
|
+
posted_json = JSON.parse(request.body)
|
|
89
|
+
posted_json.length == 1
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "retries batch as individual records on failure" do
|
|
94
|
+
# capture post bodies for easier testing
|
|
95
|
+
post_bodies = []
|
|
96
|
+
stub_request(:post, "#{TEST_SOLR_URL}/update/json").with { |request|
|
|
97
|
+
post_bodies << JSON.parse(request.body)
|
|
98
|
+
true
|
|
99
|
+
}.to_return(status: 500)
|
|
100
|
+
|
|
101
|
+
@writer = create_writer("solr_writer.batch_size" => 2, "solr_writer.max_skipped" => 10)
|
|
102
|
+
|
|
103
|
+
2.times do |i|
|
|
104
|
+
@writer.put context_with({"id" => "doc_#{i}", "key" => "value"})
|
|
105
|
+
end
|
|
106
|
+
@writer.close
|
|
107
|
+
|
|
108
|
+
# 1 batch, then 2 for re-trying each individually
|
|
109
|
+
assert_requested(:post, "#{TEST_SOLR_URL}/update/json", times: 3)
|
|
110
|
+
|
|
111
|
+
batch_update = post_bodies.first
|
|
112
|
+
|
|
113
|
+
assert_length 2, batch_update
|
|
114
|
+
|
|
115
|
+
individual_update1, individual_update2 = post_bodies[1], post_bodies[2]
|
|
116
|
+
assert_length 1, individual_update1
|
|
117
|
+
assert_length 1, individual_update2
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
it "includes Solr reported error in base error message" do
|
|
121
|
+
stub_request(:post, "#{TEST_SOLR_URL}/update/json").
|
|
122
|
+
to_return(
|
|
123
|
+
status: 400,
|
|
124
|
+
headers: { content_type: "application/json;charset=utf-8" },
|
|
125
|
+
body: { "responseHeader"=>{"status"=>400, "QTime"=>0},
|
|
126
|
+
"error"=>{
|
|
127
|
+
"metadata"=>["error-class", "org.apache.solr.common.SolrException", "root-error-class", "org.apache.solr.common.SolrException"],
|
|
128
|
+
"msg"=>"ERROR: this is a solr error",
|
|
129
|
+
"code"=>400
|
|
130
|
+
}
|
|
131
|
+
}.to_json
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@writer = create_writer("solr_writer.batch_size" => 1, "solr_writer.max_skipped" => 0)
|
|
136
|
+
|
|
137
|
+
error = assert_raises(Traject::SolrJsonHttpxWriter::MaxSkippedRecordsExceeded) {
|
|
138
|
+
@writer.put context_with({"id" => "doc_1", "key" => "value"})
|
|
139
|
+
@writer.close
|
|
140
|
+
}
|
|
141
|
+
assert_match(/ERROR: this is a solr error/, error.message)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it "can #flush" do
|
|
145
|
+
stub_request(:post, "#{TEST_SOLR_URL}/update/json")
|
|
146
|
+
|
|
147
|
+
2.times do |i|
|
|
148
|
+
doc = {"id" => "doc_#{i}", "key" => "value"}
|
|
149
|
+
@writer.put context_with(doc)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Hasn't yet written
|
|
153
|
+
assert_not_requested(:post, "#{TEST_SOLR_URL}/update/json")
|
|
154
|
+
|
|
155
|
+
@writer.flush
|
|
156
|
+
|
|
157
|
+
# Has flushed to solr
|
|
158
|
+
assert_requested(:post, "#{TEST_SOLR_URL}/update/json")
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# We check the header on an actual (mocked) request, rather than looking at
|
|
162
|
+
# the httpx client's configured options -- httpx 1.7 moved basic auth out of
|
|
163
|
+
# the client's default headers and into an option only applied at request time.
|
|
164
|
+
AUTH_TEST_URL = "http://example.com/solr/foo"
|
|
165
|
+
|
|
166
|
+
def write_one_doc(writer)
|
|
167
|
+
writer.put context_with({"id" => "one"})
|
|
168
|
+
writer.close
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
it "defaults to not setting basic authentication" do
|
|
172
|
+
stub_request(:post, "#{AUTH_TEST_URL}/update/json")
|
|
173
|
+
|
|
174
|
+
write_one_doc Traject::SolrJsonHttpxWriter.new("solr.url" => AUTH_TEST_URL)
|
|
175
|
+
|
|
176
|
+
assert_requested(:post, "#{AUTH_TEST_URL}/update/json") do |request|
|
|
177
|
+
request.headers["Authorization"].nil?
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
describe "HTTP basic auth" do
|
|
182
|
+
let(:expected_auth_header) { "Basic #{Base64.strict_encode64("foo:bar")}" }
|
|
183
|
+
|
|
184
|
+
it "supports basic authentication settings" do
|
|
185
|
+
stub_request(:post, "#{AUTH_TEST_URL}/update/json")
|
|
186
|
+
|
|
187
|
+
write_one_doc Traject::SolrJsonHttpxWriter.new(
|
|
188
|
+
"solr.url" => AUTH_TEST_URL,
|
|
189
|
+
"solr_writer.basic_auth_user" => "foo",
|
|
190
|
+
"solr_writer.basic_auth_password" => "bar",
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
assert_requested(:post, "#{AUTH_TEST_URL}/update/json",
|
|
194
|
+
headers: { "Authorization" => expected_auth_header })
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
it "supports basic auth from solr.url" do
|
|
198
|
+
stub_request(:post, "#{AUTH_TEST_URL}/update/json")
|
|
199
|
+
|
|
200
|
+
write_one_doc Traject::SolrJsonHttpxWriter.new("solr.url" => "http://foo:bar@example.com/solr/foo")
|
|
201
|
+
|
|
202
|
+
assert_requested(:post, "#{AUTH_TEST_URL}/update/json",
|
|
203
|
+
headers: { "Authorization" => expected_auth_header })
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
it "does not log basic auth from solr.url" do
|
|
207
|
+
string_io = StringIO.new
|
|
208
|
+
settings = {
|
|
209
|
+
"solr.url" => "http://secret_username:secret_password@example.com/solr/foo",
|
|
210
|
+
"logger" => Logger.new(string_io)
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
writer = Traject::SolrJsonHttpxWriter.new(settings)
|
|
215
|
+
|
|
216
|
+
refute_includes string_io.string, "secret_username:secret_password"
|
|
217
|
+
assert_includes string_io.string, "(with HTTP basic auth)"
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
describe "commit" do
|
|
222
|
+
it "commits on close when set" do
|
|
223
|
+
stub_request(:post, "#{TEST_SOLR_URL}/update/json")
|
|
224
|
+
stub_request(:get, "#{TEST_SOLR_URL}/update/json?commit=true")
|
|
225
|
+
|
|
226
|
+
@writer = create_writer("solr.url" => TEST_SOLR_URL, "solr_writer.commit_on_close" => "true")
|
|
227
|
+
@writer.put context_with({"id" => "one", "key" => ["value1", "value2"]})
|
|
228
|
+
@writer.close
|
|
229
|
+
|
|
230
|
+
assert_requested(:get, "#{TEST_SOLR_URL}/update/json?commit=true")
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
it "commits on close with commit_solr_update_args" do
|
|
234
|
+
stub_request(:post, "#{TEST_SOLR_URL}/update/json")
|
|
235
|
+
stub_request(:get, "#{TEST_SOLR_URL}/update/json?softCommit=true")
|
|
236
|
+
|
|
237
|
+
@writer = create_writer(
|
|
238
|
+
"solr.url" => TEST_SOLR_URL,
|
|
239
|
+
"solr_writer.commit_on_close" => "true",
|
|
240
|
+
"solr_writer.commit_solr_update_args" => { softCommit: true }
|
|
241
|
+
)
|
|
242
|
+
@writer.put context_with({"id" => "one", "key" => ["value1", "value2"]})
|
|
243
|
+
@writer.close
|
|
244
|
+
|
|
245
|
+
assert_requested(:get, "#{TEST_SOLR_URL}/update/json?softCommit=true")
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
it "can manually send commit" do
|
|
249
|
+
stub_request(:get, "#{TEST_SOLR_URL}/update/json?commit=true")
|
|
250
|
+
|
|
251
|
+
@writer = create_writer("solr.url" => TEST_SOLR_URL)
|
|
252
|
+
@writer.commit
|
|
253
|
+
|
|
254
|
+
assert_requested(:get, "#{TEST_SOLR_URL}/update/json?commit=true")
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
it "can manually send commit with specified args" do
|
|
258
|
+
stub_request(:get, "#{TEST_SOLR_URL}/update/json?commit=true&optimize=true&waitFlush=false")
|
|
259
|
+
|
|
260
|
+
@writer = create_writer("solr.url" => TEST_SOLR_URL, "solr_writer.commit_solr_update_args" => { softCommit: true })
|
|
261
|
+
@writer.commit(commit: true, optimize: true, waitFlush: false)
|
|
262
|
+
|
|
263
|
+
assert_requested(:get, "#{TEST_SOLR_URL}/update/json?commit=true&optimize=true&waitFlush=false")
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
it "uses commit_solr_update_args settings by default" do
|
|
267
|
+
stub_request(:get, "#{TEST_SOLR_URL}/update/json?softCommit=true")
|
|
268
|
+
|
|
269
|
+
@writer = create_writer(
|
|
270
|
+
"solr.url" => TEST_SOLR_URL,
|
|
271
|
+
"solr_writer.commit_solr_update_args" => { softCommit: true }
|
|
272
|
+
)
|
|
273
|
+
@writer.commit
|
|
274
|
+
|
|
275
|
+
assert_requested(:get, "#{TEST_SOLR_URL}/update/json?softCommit=true")
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
it "overrides commit_solr_update_args with method arg" do
|
|
279
|
+
stub_request(:get, "#{TEST_SOLR_URL}/update/json?commit=true")
|
|
280
|
+
|
|
281
|
+
@writer = create_writer(
|
|
282
|
+
"solr.url" => TEST_SOLR_URL,
|
|
283
|
+
"solr_writer.commit_solr_update_args" => { softCommit: true, foo: "bar" }
|
|
284
|
+
)
|
|
285
|
+
@writer.commit(commit: true)
|
|
286
|
+
|
|
287
|
+
assert_requested(:get, "#{TEST_SOLR_URL}/update/json?commit=true")
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
describe "solr_writer.solr_update_args" do
|
|
292
|
+
before do
|
|
293
|
+
@writer = create_writer("solr_writer.solr_update_args" => { softCommit: true } )
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
it "sends update args" do
|
|
297
|
+
stub_request(:post, "#{TEST_SOLR_URL}/update/json?softCommit=true")
|
|
298
|
+
|
|
299
|
+
@writer.put context_with({"id" => "one", "key" => ["value1", "value2"]})
|
|
300
|
+
@writer.close
|
|
301
|
+
|
|
302
|
+
assert_requested(:post, "#{TEST_SOLR_URL}/update/json?softCommit=true")
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
it "sends update args with delete" do
|
|
306
|
+
stub_request(:post, "#{TEST_SOLR_URL}/update/json?softCommit=true")
|
|
307
|
+
|
|
308
|
+
@writer.delete("test-id")
|
|
309
|
+
@writer.close
|
|
310
|
+
|
|
311
|
+
assert_requested(:post, "#{TEST_SOLR_URL}/update/json?softCommit=true", times: 1)
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
it "sends update args on individual-retry after batch failure" do
|
|
315
|
+
stub_request(:post, "#{TEST_SOLR_URL}/update/json?softCommit=true").to_return(status: 500)
|
|
316
|
+
|
|
317
|
+
@writer = create_writer(
|
|
318
|
+
"solr_writer.batch_size" => 2,
|
|
319
|
+
"solr_writer.max_skipped" => 10,
|
|
320
|
+
"solr_writer.solr_update_args" => { softCommit: true }
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
2.times do |i|
|
|
324
|
+
@writer.put context_with({"id" => "doc_#{i}", "key" => "value"})
|
|
325
|
+
end
|
|
326
|
+
@writer.close
|
|
327
|
+
|
|
328
|
+
# 1 batch, then 2 for re-trying each individually
|
|
329
|
+
assert_requested(:post, "#{TEST_SOLR_URL}/update/json?softCommit=true", times: 3)
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
describe "skipped records" do
|
|
334
|
+
it "skips and reports under max_skipped" do
|
|
335
|
+
stub_request(:post, "#{TEST_SOLR_URL}/update/json").to_return(status: 500)
|
|
336
|
+
|
|
337
|
+
strio = StringIO.new
|
|
338
|
+
@writer = create_writer("solr_writer.max_skipped" => 10, "logger" => logger_to_strio(strio))
|
|
339
|
+
|
|
340
|
+
10.times do |i|
|
|
341
|
+
@writer.put context_with("id" => "doc_#{i}", "key" => "value")
|
|
342
|
+
end
|
|
343
|
+
@writer.close
|
|
344
|
+
|
|
345
|
+
assert_equal 10, @writer.skipped_record_count
|
|
346
|
+
|
|
347
|
+
logged = strio.string
|
|
348
|
+
|
|
349
|
+
10.times do |i|
|
|
350
|
+
assert_match(/ERROR.*Could not add record <output_id:doc_#{i}>: Solr error response: 500/, logged)
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
it "raises when skipped more than max_skipped" do
|
|
355
|
+
stub_request(:post, "#{TEST_SOLR_URL}/update/json").to_return(status: 500)
|
|
356
|
+
|
|
357
|
+
@writer = create_writer("solr_writer.max_skipped" => 5)
|
|
358
|
+
|
|
359
|
+
e = assert_raises(RuntimeError) do
|
|
360
|
+
6.times do |i|
|
|
361
|
+
@writer.put context_with("id" => "doc_#{i}", "key" => "value")
|
|
362
|
+
end
|
|
363
|
+
@writer.close
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
assert_includes e.message, "Exceeded maximum number of skipped records"
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
it "raises on one skipped record when max_skipped is 0" do
|
|
370
|
+
stub_request(:post, "#{TEST_SOLR_URL}/update/json").to_return(status: 500)
|
|
371
|
+
|
|
372
|
+
@writer = create_writer("solr_writer.max_skipped" => 0)
|
|
373
|
+
|
|
374
|
+
_e = assert_raises(RuntimeError) do
|
|
375
|
+
@writer.put context_with("id" => "doc_1", "key" => "value")
|
|
376
|
+
@writer.close
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
it "when catching additional skip errors, raise RuntimeError" do
|
|
382
|
+
stub_request(:post, "#{TEST_SOLR_URL}/update/json").to_raise(ArgumentError.new('bad stuff'))
|
|
383
|
+
|
|
384
|
+
strio = StringIO.new
|
|
385
|
+
@writer = create_writer(
|
|
386
|
+
"solr_writer.max_skipped" => 0,
|
|
387
|
+
"logger" => logger_to_strio(strio),
|
|
388
|
+
"solr_writer.skippable_exceptions" => [ArgumentError]
|
|
389
|
+
)
|
|
390
|
+
|
|
391
|
+
_e = assert_raises(Traject::SolrJsonHttpxWriter::MaxSkippedRecordsExceeded) do
|
|
392
|
+
@writer.put context_with("id" => "doc_1", "key" => "value")
|
|
393
|
+
@writer.close
|
|
394
|
+
end
|
|
395
|
+
logged = strio.string
|
|
396
|
+
assert_includes logged, 'ArgumentError: bad stuff'
|
|
397
|
+
end
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
describe "#delete" do
|
|
401
|
+
it "deletes" do
|
|
402
|
+
stub_request(:post, "#{TEST_SOLR_URL}/update/json")
|
|
403
|
+
|
|
404
|
+
id = "123456"
|
|
405
|
+
@writer.delete(id)
|
|
406
|
+
|
|
407
|
+
assert_requested(:post, "#{TEST_SOLR_URL}/update/json", body: JSON.generate({"delete" => id}))
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
it "raises on non-200 http response" do
|
|
411
|
+
stub_request(:post, "#{TEST_SOLR_URL}/update/json").to_return(status: 500)
|
|
412
|
+
|
|
413
|
+
assert_raises(RuntimeError) do
|
|
414
|
+
@writer.delete("12345")
|
|
415
|
+
end
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
describe "#delete_all!" do
|
|
420
|
+
it "deletes all" do
|
|
421
|
+
stub_request(:post, "#{TEST_SOLR_URL}/update/json")
|
|
422
|
+
|
|
423
|
+
@writer.delete_all!
|
|
424
|
+
|
|
425
|
+
assert_requested(:post, "#{TEST_SOLR_URL}/update/json", body: JSON.generate({"delete" => { "query" => "*:*"}}))
|
|
426
|
+
end
|
|
427
|
+
end
|
|
428
|
+
end
|
data/test/test_helper.rb
CHANGED
data/traject.gemspec
CHANGED
|
@@ -30,15 +30,17 @@ Gem::Specification.new do |spec|
|
|
|
30
30
|
spec.add_dependency "yell" # logging
|
|
31
31
|
spec.add_dependency "dot-properties", ">= 0.1.1" # reading java style .properties
|
|
32
32
|
spec.add_dependency "httpclient", "~> 2.5"
|
|
33
|
+
spec.add_dependency "httpx", "~> 1.4"
|
|
33
34
|
spec.add_dependency "mutex_m" # httpclient has an undelcared dep needed in ruby 3.4+, not yet released. https://github.com/nahi/httpclient/pull/455
|
|
35
|
+
spec.add_dependency "base64" # no longer inlcuded in stdlib
|
|
34
36
|
|
|
35
|
-
spec.add_dependency "http", ">= 3.0", "<
|
|
37
|
+
spec.add_dependency "http", ">= 3.0", "< 7" # used in oai_pmh_reader, may use more extensively in future instead of httpclient
|
|
36
38
|
spec.add_dependency 'marc-fastxmlwriter', '~>1.0' # fast marc->xml
|
|
37
39
|
spec.add_dependency "nokogiri", "~> 1.9" # NokogiriIndexer
|
|
38
40
|
|
|
39
|
-
spec.add_development_dependency 'bundler', '>= 1.7', '< 3'
|
|
40
|
-
|
|
41
41
|
spec.add_development_dependency "rake"
|
|
42
42
|
spec.add_development_dependency "minitest"
|
|
43
43
|
spec.add_development_dependency "rspec-mocks", '~> 3.4'
|
|
44
|
+
# rspec-mocks no longer includes rspec-core as a dependency, we need to include it.
|
|
45
|
+
spec.add_development_dependency "rspec-core", '~> 3.4'
|
|
44
46
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: traject
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jonathan Rochkind
|
|
8
8
|
- Bill Dueber
|
|
9
|
+
autorequire:
|
|
9
10
|
bindir: bin
|
|
10
11
|
cert_chain: []
|
|
11
|
-
date:
|
|
12
|
+
date: 2026-07-21 00:00:00.000000000 Z
|
|
12
13
|
dependencies:
|
|
13
14
|
- !ruby/object:Gem::Dependency
|
|
14
15
|
name: concurrent-ruby
|
|
@@ -128,6 +129,20 @@ dependencies:
|
|
|
128
129
|
- - "~>"
|
|
129
130
|
- !ruby/object:Gem::Version
|
|
130
131
|
version: '2.5'
|
|
132
|
+
- !ruby/object:Gem::Dependency
|
|
133
|
+
name: httpx
|
|
134
|
+
requirement: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - "~>"
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: '1.4'
|
|
139
|
+
type: :runtime
|
|
140
|
+
prerelease: false
|
|
141
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
142
|
+
requirements:
|
|
143
|
+
- - "~>"
|
|
144
|
+
- !ruby/object:Gem::Version
|
|
145
|
+
version: '1.4'
|
|
131
146
|
- !ruby/object:Gem::Dependency
|
|
132
147
|
name: mutex_m
|
|
133
148
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -142,6 +157,20 @@ dependencies:
|
|
|
142
157
|
- - ">="
|
|
143
158
|
- !ruby/object:Gem::Version
|
|
144
159
|
version: '0'
|
|
160
|
+
- !ruby/object:Gem::Dependency
|
|
161
|
+
name: base64
|
|
162
|
+
requirement: !ruby/object:Gem::Requirement
|
|
163
|
+
requirements:
|
|
164
|
+
- - ">="
|
|
165
|
+
- !ruby/object:Gem::Version
|
|
166
|
+
version: '0'
|
|
167
|
+
type: :runtime
|
|
168
|
+
prerelease: false
|
|
169
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
170
|
+
requirements:
|
|
171
|
+
- - ">="
|
|
172
|
+
- !ruby/object:Gem::Version
|
|
173
|
+
version: '0'
|
|
145
174
|
- !ruby/object:Gem::Dependency
|
|
146
175
|
name: http
|
|
147
176
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -151,7 +180,7 @@ dependencies:
|
|
|
151
180
|
version: '3.0'
|
|
152
181
|
- - "<"
|
|
153
182
|
- !ruby/object:Gem::Version
|
|
154
|
-
version: '
|
|
183
|
+
version: '7'
|
|
155
184
|
type: :runtime
|
|
156
185
|
prerelease: false
|
|
157
186
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -161,7 +190,7 @@ dependencies:
|
|
|
161
190
|
version: '3.0'
|
|
162
191
|
- - "<"
|
|
163
192
|
- !ruby/object:Gem::Version
|
|
164
|
-
version: '
|
|
193
|
+
version: '7'
|
|
165
194
|
- !ruby/object:Gem::Dependency
|
|
166
195
|
name: marc-fastxmlwriter
|
|
167
196
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -191,27 +220,21 @@ dependencies:
|
|
|
191
220
|
- !ruby/object:Gem::Version
|
|
192
221
|
version: '1.9'
|
|
193
222
|
- !ruby/object:Gem::Dependency
|
|
194
|
-
name:
|
|
223
|
+
name: rake
|
|
195
224
|
requirement: !ruby/object:Gem::Requirement
|
|
196
225
|
requirements:
|
|
197
226
|
- - ">="
|
|
198
227
|
- !ruby/object:Gem::Version
|
|
199
|
-
version: '
|
|
200
|
-
- - "<"
|
|
201
|
-
- !ruby/object:Gem::Version
|
|
202
|
-
version: '3'
|
|
228
|
+
version: '0'
|
|
203
229
|
type: :development
|
|
204
230
|
prerelease: false
|
|
205
231
|
version_requirements: !ruby/object:Gem::Requirement
|
|
206
232
|
requirements:
|
|
207
233
|
- - ">="
|
|
208
234
|
- !ruby/object:Gem::Version
|
|
209
|
-
version: '
|
|
210
|
-
- - "<"
|
|
211
|
-
- !ruby/object:Gem::Version
|
|
212
|
-
version: '3'
|
|
235
|
+
version: '0'
|
|
213
236
|
- !ruby/object:Gem::Dependency
|
|
214
|
-
name:
|
|
237
|
+
name: minitest
|
|
215
238
|
requirement: !ruby/object:Gem::Requirement
|
|
216
239
|
requirements:
|
|
217
240
|
- - ">="
|
|
@@ -225,21 +248,21 @@ dependencies:
|
|
|
225
248
|
- !ruby/object:Gem::Version
|
|
226
249
|
version: '0'
|
|
227
250
|
- !ruby/object:Gem::Dependency
|
|
228
|
-
name:
|
|
251
|
+
name: rspec-mocks
|
|
229
252
|
requirement: !ruby/object:Gem::Requirement
|
|
230
253
|
requirements:
|
|
231
|
-
- - "
|
|
254
|
+
- - "~>"
|
|
232
255
|
- !ruby/object:Gem::Version
|
|
233
|
-
version: '
|
|
256
|
+
version: '3.4'
|
|
234
257
|
type: :development
|
|
235
258
|
prerelease: false
|
|
236
259
|
version_requirements: !ruby/object:Gem::Requirement
|
|
237
260
|
requirements:
|
|
238
|
-
- - "
|
|
261
|
+
- - "~>"
|
|
239
262
|
- !ruby/object:Gem::Version
|
|
240
|
-
version: '
|
|
263
|
+
version: '3.4'
|
|
241
264
|
- !ruby/object:Gem::Dependency
|
|
242
|
-
name: rspec-
|
|
265
|
+
name: rspec-core
|
|
243
266
|
requirement: !ruby/object:Gem::Requirement
|
|
244
267
|
requirements:
|
|
245
268
|
- - "~>"
|
|
@@ -252,6 +275,7 @@ dependencies:
|
|
|
252
275
|
- - "~>"
|
|
253
276
|
- !ruby/object:Gem::Version
|
|
254
277
|
version: '3.4'
|
|
278
|
+
description:
|
|
255
279
|
email:
|
|
256
280
|
- none@nowhere.org
|
|
257
281
|
executables:
|
|
@@ -316,6 +340,7 @@ files:
|
|
|
316
340
|
- lib/traject/null_writer.rb
|
|
317
341
|
- lib/traject/oai_pmh_nokogiri_reader.rb
|
|
318
342
|
- lib/traject/qualified_const_get.rb
|
|
343
|
+
- lib/traject/solr_json_httpx_writer.rb
|
|
319
344
|
- lib/traject/solr_json_writer.rb
|
|
320
345
|
- lib/traject/thread_pool.rb
|
|
321
346
|
- lib/traject/translation_map.rb
|
|
@@ -357,6 +382,7 @@ files:
|
|
|
357
382
|
- test/marc_reader_test.rb
|
|
358
383
|
- test/nokogiri_reader_test.rb
|
|
359
384
|
- test/oai_pmh_nokogiri_reader_test.rb
|
|
385
|
+
- test/solr_json_httpx_writer_test.rb
|
|
360
386
|
- test/solr_json_writer_test.rb
|
|
361
387
|
- test/test_helper.rb
|
|
362
388
|
- test/test_support/245_no_ab.marc
|
|
@@ -414,6 +440,7 @@ homepage: http://github.com/traject/traject
|
|
|
414
440
|
licenses:
|
|
415
441
|
- MIT
|
|
416
442
|
metadata: {}
|
|
443
|
+
post_install_message:
|
|
417
444
|
rdoc_options: []
|
|
418
445
|
require_paths:
|
|
419
446
|
- lib
|
|
@@ -428,7 +455,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
428
455
|
- !ruby/object:Gem::Version
|
|
429
456
|
version: '0'
|
|
430
457
|
requirements: []
|
|
431
|
-
rubygems_version: 3.6
|
|
458
|
+
rubygems_version: 3.1.6
|
|
459
|
+
signing_key:
|
|
432
460
|
specification_version: 4
|
|
433
461
|
summary: An easy to use, high-performance, flexible and extensible metadata transformation
|
|
434
462
|
system, focused on library-archives-museums input, and indexing to Solr as output.
|
|
@@ -462,6 +490,7 @@ test_files:
|
|
|
462
490
|
- test/marc_reader_test.rb
|
|
463
491
|
- test/nokogiri_reader_test.rb
|
|
464
492
|
- test/oai_pmh_nokogiri_reader_test.rb
|
|
493
|
+
- test/solr_json_httpx_writer_test.rb
|
|
465
494
|
- test/solr_json_writer_test.rb
|
|
466
495
|
- test/test_helper.rb
|
|
467
496
|
- test/test_support/245_no_ab.marc
|