nexus_mods 2.3.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0d5efb3b98f3d8b66565eff56b7b6360fc99bae69a256423e6eae391eb3cd676
4
- data.tar.gz: 7091d96c8a79ec591e805bcc09958199187b5f0afd73de85b5da314c2e24381a
3
+ metadata.gz: a55e8c7bacc06ef260c5b4e6f0ac64d3e9391e39f7d1ebb00c74c110a6eae214
4
+ data.tar.gz: 9647e6745975eb0c8c0fe9023a2e66936773fd9389a5d5087511e8edb3e06876
5
5
  SHA512:
6
- metadata.gz: 1485e5270d8fcffb7a2ebfec15848f0f2af3a2575beef6b2d1c4746af682bd13142d15f140adae1c9e7c15d731d85d63d01ec135f28600e73d58249bc130990e
7
- data.tar.gz: eccb9f4312f63a8c8fc459592c4c0c618378f59a69a261512981e890c0bfffa8c2044bafbcd16da9ec9c8d3b980a53a2e5322a89c5eece959240cafb7ac05e19
6
+ metadata.gz: 29732e93998b9b8b88d66af4ebd67d37d8eaa51f8ab47b487bf0ce2aa3f81312aed8e1275e83a428e5cfa60a2330a7603a6c114f9bf8898593695b0df79603c3
7
+ data.tar.gz: 8b3542308bd2736695165a337cef28a2e8ea7e63bd7f67d55f74b4ec797edf556d92e4792e3ea7f83a3f7f56dd028b914bcfba8f713b96679687bb29ddac8a00
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ # [v2.4.0](https://github.com/Muriel-Salvan/nexus_mods/compare/v2.3.0...v2.4.0) (2023-04-12 17:23:29)
2
+
3
+ ### Features
4
+
5
+ * [[Feature] Add options and methods for mod and mod_files to query for updates to check data freshness](https://github.com/Muriel-Salvan/nexus_mods/commit/72a933a6ac22faae601fbdc547cc9e0ffa8908fc)
6
+
1
7
  # [v2.3.0](https://github.com/Muriel-Salvan/nexus_mods/compare/v2.2.0...v2.3.0) (2023-04-12 15:08:22)
2
8
 
3
9
  ### Features
@@ -1,5 +1,5 @@
1
1
  class NexusMods
2
2
 
3
- VERSION = '2.3.0'
3
+ VERSION = '2.4.0'
4
4
 
5
5
  end
data/lib/nexus_mods.rb CHANGED
@@ -166,9 +166,13 @@ class NexusMods
166
166
  # * *game_domain_name* (String): Game domain name to query by default [default: @game_domain_name]
167
167
  # * *mod_id* (Integer): The mod ID [default: @mod_id]
168
168
  # * *clear_cache* (Boolean): Should we clear the API cache for this resource? [default: false]
169
+ # * *check_updates* (Boolean): Should we check updates?
170
+ # If yes then an extra call to updated_mods may be done to check for updates before retrieving the mod information.
171
+ # In case the mod was previously retrieved and may be in an old cache, then using this will optimize the calls to NexusMods API to the minimum.
169
172
  # Result::
170
173
  # * Mod: Mod information
171
- def mod(game_domain_name: @game_domain_name, mod_id: @mod_id, clear_cache: false)
174
+ def mod(game_domain_name: @game_domain_name, mod_id: @mod_id, clear_cache: false, check_updates: false)
175
+ mod_cache_up_to_date?(game_domain_name:, mod_id:) if check_updates
172
176
  mod_json = @api_client.api("games/#{game_domain_name}/mods/#{mod_id}", clear_cache:)
173
177
  Api::Mod.new(
174
178
  uid: mod_json['uid'],
@@ -228,9 +232,13 @@ class NexusMods
228
232
  # * *game_domain_name* (String): Game domain name to query by default [default: @game_domain_name]
229
233
  # * *mod_id* (Integer): The mod ID [default: @mod_id]
230
234
  # * *clear_cache* (Boolean): Should we clear the API cache for this resource? [default: false]
235
+ # * *check_updates* (Boolean): Should we check updates?
236
+ # If yes then an extra call to updated_mods may be done to check for updates before retrieving the mod information.
237
+ # In case the mod files were previously retrieved and may be in an old cache, then using this will optimize the calls to NexusMods API to the minimum.
231
238
  # Result::
232
239
  # * Array<ModFile>: List of mod's files
233
- def mod_files(game_domain_name: @game_domain_name, mod_id: @mod_id, clear_cache: false)
240
+ def mod_files(game_domain_name: @game_domain_name, mod_id: @mod_id, clear_cache: false, check_updates: false)
241
+ mod_files_cache_up_to_date?(game_domain_name:, mod_id:) if check_updates
234
242
  @api_client.api("games/#{game_domain_name}/mods/#{mod_id}/files", clear_cache:)['files'].map do |file_json|
235
243
  Api::ModFile.new(
236
244
  ids: file_json['id'],
@@ -327,6 +335,80 @@ class NexusMods
327
335
  @api_client.set_api_cache_timestamp("games/#{game_domain_name}/mods/updated", parameters: period_to_url_params(since), cache_timestamp:)
328
336
  end
329
337
 
338
+ # Does a given mod id have fresh information in our cache?
339
+ # This may fire queries to the updated mods API to get info from NexusMods about the latest updated mods.
340
+ # If we know the mod is up-to-date, then its mod information cache timestamp will be set to the time when we checked for updates if it was greater than the cache date.
341
+ #
342
+ # Here is the algorithm:
343
+ # If it is not in the cache, then it is not up-to-date.
344
+ # Otherwise, the API allows us to know if it has been updated up to 1 month in the past.
345
+ # Therefore if the current cache timestamp is older than 1 month, assume that it has to be updated.
346
+ # Otherwise query the API to know the latest updated mods since 1 month:
347
+ # * If the mod ID is not there, then it is up-to-date.
348
+ # * If the mod ID is there, then check if our cache timestamp is older than the last update timestamp from NexusMods.
349
+ #
350
+ # Parameters::
351
+ # * *game_domain_name* (String): Game domain name to query by default [default: @game_domain_name]
352
+ # * *mod_id* (Integer): The mod ID [default: @mod_id]
353
+ # Result::
354
+ # * Boolean: Is the mod cache up-to-date?
355
+ def mod_cache_up_to_date?(game_domain_name: @game_domain_name, mod_id: @mod_id)
356
+ existing_cache_timestamp = mod_cache_timestamp(game_domain_name:, mod_id:)
357
+ mod_up_to_date =
358
+ if existing_cache_timestamp.nil? || existing_cache_timestamp < Time.now - (30 * 24 * 60 * 60)
359
+ # It's not in the cache
360
+ # or it's older than 1 month
361
+ false
362
+ else
363
+ found_mod_updates = updated_mods(game_domain_name:, since: :one_month).find { |mod_updates| mod_updates.mod_id == mod_id }
364
+ # true if it has not been updated on NexusMods since 1 month
365
+ # or our cache timestamp is more recent
366
+ found_mod_updates.nil? || found_mod_updates.latest_mod_activity < existing_cache_timestamp
367
+ end
368
+ if mod_up_to_date
369
+ update_time = updated_mods_cache_timestamp(game_domain_name:, since: :one_month)
370
+ set_mod_cache_timestamp(cache_timestamp: update_time, game_domain_name:, mod_id:) if update_time > existing_cache_timestamp
371
+ end
372
+ mod_up_to_date
373
+ end
374
+
375
+ # Does a given mod id have fresh files information in our cache?
376
+ # This may fire queries to the updated mods API to get info from NexusMods about the latest updated mods.
377
+ # If we know the mod is up-to-date, then its mod information cache timestamp will be set to the time when we checked for updates if it was greater than the cache date.
378
+ #
379
+ # Here is the algorithm:
380
+ # If it is not in the cache, then it is not up-to-date.
381
+ # Otherwise, the API allows us to know if it has been updated up to 1 month in the past.
382
+ # Therefore if the current cache timestamp is older than 1 month, assume that it has to be updated.
383
+ # Otherwise query the API to know the latest updated mods since 1 month:
384
+ # * If the mod ID is not there, then it is up-to-date.
385
+ # * If the mod ID is there, then check if our cache timestamp is older than the last update timestamp from NexusMods.
386
+ #
387
+ # Parameters::
388
+ # * *game_domain_name* (String): Game domain name to query by default [default: @game_domain_name]
389
+ # * *mod_id* (Integer): The mod ID [default: @mod_id]
390
+ # Result::
391
+ # * Boolean: Is the mod cache up-to-date?
392
+ def mod_files_cache_up_to_date?(game_domain_name: @game_domain_name, mod_id: @mod_id)
393
+ existing_cache_timestamp = mod_files_cache_timestamp(game_domain_name:, mod_id:)
394
+ mod_up_to_date =
395
+ if existing_cache_timestamp.nil? || existing_cache_timestamp < Time.now - (30 * 24 * 60 * 60)
396
+ # It's not in the cache
397
+ # or it's older than 1 month
398
+ false
399
+ else
400
+ found_mod_updates = updated_mods(game_domain_name:, since: :one_month).find { |mod_updates| mod_updates.mod_id == mod_id }
401
+ # true if it has not been updated on NexusMods since 1 month
402
+ # or our cache timestamp is more recent
403
+ found_mod_updates.nil? || found_mod_updates.latest_file_update < existing_cache_timestamp
404
+ end
405
+ if mod_up_to_date
406
+ update_time = updated_mods_cache_timestamp(game_domain_name:, since: :one_month)
407
+ set_mod_files_cache_timestamp(cache_timestamp: update_time, game_domain_name:, mod_id:) if update_time > existing_cache_timestamp
408
+ end
409
+ mod_up_to_date
410
+ end
411
+
330
412
  private
331
413
 
332
414
  # Get the URL parameters from the required period
@@ -25,60 +25,47 @@ describe NexusMods::Api::ModFile do
25
25
  expect_mod_file_to_be2487(sorted_mod_files[1])
26
26
  end
27
27
 
28
- it 'returns a mod files list' do
29
- expect_http_call_to(
30
- path: '/v1/games/skyrimspecialedition/mods/2014/files.json',
31
- json: { files: json_example_mod_files }
32
- )
33
- expect_mod_files_to_be_example(nexus_mods.mod_files(game_domain_name: 'skyrimspecialedition', mod_id: 2014))
34
- end
28
+ context 'when testing a mod with 2 files' do
35
29
 
36
- it 'returns the default mod files list' do
37
- expect_http_call_to(
38
- path: '/v1/games/skyrimspecialedition/mods/2014/files.json',
39
- json: { files: json_example_mod_files }
40
- )
41
- expect_mod_files_to_be_example(nexus_mods(mod_id: 2014).mod_files(game_domain_name: 'skyrimspecialedition'))
42
- end
30
+ before do
31
+ expect_http_call_to(
32
+ path: '/v1/games/skyrimspecialedition/mods/2014/files.json',
33
+ json: { 'files' => json_example_mod_files }
34
+ )
35
+ end
43
36
 
44
- it 'returns mod files list for the default game' do
45
- expect_http_call_to(
46
- path: '/v1/games/skyrimspecialedition/mods/2014/files.json',
47
- json: { files: json_example_mod_files }
48
- )
49
- expect_mod_files_to_be_example(nexus_mods(game_domain_name: 'skyrimspecialedition').mod_files(mod_id: 2014))
50
- end
37
+ it 'returns a mod files list' do
38
+ expect_mod_files_to_be_example(nexus_mods.mod_files(game_domain_name: 'skyrimspecialedition', mod_id: 2014))
39
+ end
51
40
 
52
- it 'returns mod files list for the default game set using accessor' do
53
- expect_http_call_to(
54
- path: '/v1/games/skyrimspecialedition/mods/2014/files.json',
55
- json: { files: json_example_mod_files }
56
- )
57
- nexus_mods.game_domain_name = 'skyrimspecialedition'
58
- expect_mod_files_to_be_example(nexus_mods.mod_files(mod_id: 2014))
59
- end
41
+ it 'returns the default mod files list' do
42
+ expect_mod_files_to_be_example(nexus_mods(mod_id: 2014).mod_files(game_domain_name: 'skyrimspecialedition'))
43
+ end
60
44
 
61
- it 'returns mod files list for the default game and mod' do
62
- expect_http_call_to(
63
- path: '/v1/games/skyrimspecialedition/mods/2014/files.json',
64
- json: { files: json_example_mod_files }
65
- )
66
- expect_mod_files_to_be_example(nexus_mods(game_domain_name: 'skyrimspecialedition', mod_id: 2014).mod_files)
67
- end
45
+ it 'returns mod files list for the default game' do
46
+ expect_mod_files_to_be_example(nexus_mods(game_domain_name: 'skyrimspecialedition').mod_files(mod_id: 2014))
47
+ end
48
+
49
+ it 'returns mod files list for the default game set using accessor' do
50
+ nexus_mods.game_domain_name = 'skyrimspecialedition'
51
+ expect_mod_files_to_be_example(nexus_mods.mod_files(mod_id: 2014))
52
+ end
53
+
54
+ it 'returns mod files list for the default game and mod' do
55
+ expect_mod_files_to_be_example(nexus_mods(game_domain_name: 'skyrimspecialedition', mod_id: 2014).mod_files)
56
+ end
57
+
58
+ it 'returns mod files list for the default game and mod using accessor' do
59
+ nexus_mods.mod_id = 2014
60
+ expect_mod_files_to_be_example(nexus_mods.mod_files(game_domain_name: 'skyrimspecialedition'))
61
+ end
68
62
 
69
- it 'returns mod files list for the default game and mod using accessor' do
70
- expect_http_call_to(
71
- path: '/v1/games/skyrimspecialedition/mods/2014/files.json',
72
- json: { files: json_example_mod_files }
73
- )
74
- nexus_mods.mod_id = 2014
75
- expect_mod_files_to_be_example(nexus_mods.mod_files(game_domain_name: 'skyrimspecialedition'))
76
63
  end
77
64
 
78
65
  it 'compares objects for equality' do
79
66
  expect_http_call_to(
80
67
  path: '/v1/games/skyrimspecialedition/mods/2014/files.json',
81
- json: { files: [json_mod_file2472] }
68
+ json: { 'files' => [json_mod_file2472] }
82
69
  )
83
70
  mod_file1 = nexus_mods(game_domain_name: 'skyrimspecialedition', mod_id: 2014).mod_files.first
84
71
  mod_file2 = nexus_mods(game_domain_name: 'skyrimspecialedition', mod_id: 2014).mod_files.first
@@ -100,7 +87,7 @@ describe NexusMods::Api::ModFile do
100
87
  expect_http_call_to(
101
88
  path: '/v1/games/skyrimspecialedition/mods/2014/files.json',
102
89
  json: {
103
- files: [
90
+ 'files' => [
104
91
  {
105
92
  'id' => [
106
93
  2472,
@@ -134,6 +121,196 @@ describe NexusMods::Api::ModFile do
134
121
  end
135
122
  end
136
123
 
124
+ context 'when checking cache data freshness' do
125
+
126
+ it 'returns that mod files never retrieved are not up-to-date' do
127
+ expect(nexus_mods.mod_files_cache_up_to_date?(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to be false
128
+ end
129
+
130
+ context 'when retrieving mod files previously' do
131
+
132
+ before do
133
+ expect_http_call_to(
134
+ path: '/v1/games/skyrimspecialedition/mods/2014/files.json',
135
+ json: { 'files' => [json_mod_file2472] }
136
+ )
137
+ nexus_mods.mod_files(game_domain_name: 'skyrimspecialedition', mod_id: 2014)
138
+ end
139
+
140
+ context 'when retrieved 40 days ago' do
141
+
142
+ let(:forty_days_ago) { Time.now - (40 * 24 * 60 * 60) }
143
+
144
+ before do
145
+ nexus_mods.set_mod_files_cache_timestamp(cache_timestamp: forty_days_ago, game_domain_name: 'skyrimspecialedition', mod_id: 2014)
146
+ end
147
+
148
+ it 'returns that mod files are not up-to-date' do
149
+ expect(nexus_mods.mod_files_cache_up_to_date?(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to be false
150
+ expect(nexus_mods.mod_files_cache_timestamp(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to eq forty_days_ago
151
+ end
152
+
153
+ end
154
+
155
+ context 'when retrieved 2 days ago' do
156
+
157
+ let(:two_days_ago) { Time.now - (2 * 24 * 60 * 60) }
158
+
159
+ before do
160
+ nexus_mods.set_mod_files_cache_timestamp(cache_timestamp: two_days_ago, game_domain_name: 'skyrimspecialedition', mod_id: 2014)
161
+ end
162
+
163
+ it 'returns that mod files are up-to-date after checking updated mods and not finding it, and updates its cache timestamp to the update time' do
164
+ expect_http_call_to(
165
+ path: '/v1/games/skyrimspecialedition/mods/updated.json?period=1m',
166
+ json: []
167
+ )
168
+ expect(nexus_mods.mod_files_cache_up_to_date?(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to be true
169
+ expect(nexus_mods.mod_files_cache_timestamp(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to eq(
170
+ nexus_mods.updated_mods_cache_timestamp(game_domain_name: 'skyrimspecialedition', since: :one_month)
171
+ )
172
+ end
173
+
174
+ it 'returns that mod files are up-to-date after checking updated mods and finding that cache is more recent, and updates its cache timestamp to the update time' do
175
+ expect_http_call_to(
176
+ path: '/v1/games/skyrimspecialedition/mods/updated.json?period=1m',
177
+ json: [
178
+ {
179
+ 'mod_id' => 2014,
180
+ # Mock that mod was updated 3 days ago
181
+ 'latest_file_update' => Integer((Time.now - (3 * 24 * 60 * 60)).strftime('%s')),
182
+ 'latest_mod_activity' => 1
183
+ }
184
+ ]
185
+ )
186
+ expect(nexus_mods.mod_files_cache_up_to_date?(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to be true
187
+ expect(nexus_mods.mod_files_cache_timestamp(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to eq(
188
+ nexus_mods.updated_mods_cache_timestamp(game_domain_name: 'skyrimspecialedition', since: :one_month)
189
+ )
190
+ end
191
+
192
+ it 'returns that mod files are not up-to-date after checking updated mods and finding that cache is less recent' do
193
+ expect_http_call_to(
194
+ path: '/v1/games/skyrimspecialedition/mods/updated.json?period=1m',
195
+ json: [
196
+ {
197
+ 'mod_id' => 2014,
198
+ # Mock that mod was updated yesterday
199
+ 'latest_file_update' => Integer((Time.now - (24 * 60 * 60)).strftime('%s')),
200
+ 'latest_mod_activity' => 1
201
+ }
202
+ ]
203
+ )
204
+ expect(nexus_mods.mod_files_cache_up_to_date?(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to be false
205
+ expect(nexus_mods.mod_files_cache_timestamp(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to eq two_days_ago
206
+ end
207
+
208
+ end
209
+
210
+ context 'when retrieved 3 minutes ago with an updated mods query 4 minutes ago in the cache' do
211
+
212
+ let(:three_minutes_ago) { Time.now - (3 * 60) }
213
+ let(:four_minutes_ago) { Time.now - (4 * 60) }
214
+
215
+ before do
216
+ expect_http_call_to(
217
+ path: '/v1/games/skyrimspecialedition/mods/updated.json?period=1m',
218
+ json: [
219
+ {
220
+ 'mod_id' => 2014,
221
+ # Mock that mod was updated 3 days ago
222
+ 'latest_file_update' => Integer((Time.now - (3 * 24 * 60 * 60)).strftime('%s')),
223
+ 'latest_mod_activity' => 1
224
+ }
225
+ ]
226
+ )
227
+ nexus_mods.updated_mods(game_domain_name: 'skyrimspecialedition', since: :one_month)
228
+ nexus_mods.set_mod_files_cache_timestamp(cache_timestamp: three_minutes_ago, game_domain_name: 'skyrimspecialedition', mod_id: 2014)
229
+ nexus_mods.set_updated_mods_cache_timestamp(cache_timestamp: four_minutes_ago, game_domain_name: 'skyrimspecialedition', since: :one_month)
230
+ end
231
+
232
+ it 'returns that mod files are up-to-date but doesn\'t change its mod cache timestamp' do
233
+ expect(nexus_mods.mod_files_cache_up_to_date?(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to be true
234
+ expect(nexus_mods.mod_files_cache_timestamp(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to eq three_minutes_ago
235
+ expect(nexus_mods.updated_mods_cache_timestamp(game_domain_name: 'skyrimspecialedition', since: :one_month)).to eq four_minutes_ago
236
+ end
237
+
238
+ end
239
+
240
+ end
241
+
242
+ end
243
+
244
+ context 'when checking for updates' do
245
+
246
+ before do
247
+ nexus_mods(game_domain_name: 'skyrimspecialedition', mod_id: 2014)
248
+ end
249
+
250
+ it 'does not check for updates if mod files have not been retrieved before' do
251
+ expect_http_call_to(
252
+ path: '/v1/games/skyrimspecialedition/mods/2014/files.json',
253
+ json: { 'files' => [json_mod_file2472] }
254
+ )
255
+ expect_mod_file_to_be2472(nexus_mods.mod_files(check_updates: true).first)
256
+ end
257
+
258
+ it 'does not check for updates if mod files have been retrieved more than 1 month ago, and re-query the mod' do
259
+ expect_http_call_to(
260
+ path: '/v1/games/skyrimspecialedition/mods/2014/files.json',
261
+ json: { 'files' => [json_mod_file2472] },
262
+ times: 2
263
+ )
264
+ nexus_mods.mod_files
265
+ nexus_mods.set_mod_files_cache_timestamp(cache_timestamp: Time.now - (40 * 24 * 60 * 60), game_domain_name: 'skyrimspecialedition', mod_id: 2014)
266
+ expect_mod_file_to_be2472(nexus_mods.mod_files(check_updates: true).first)
267
+ end
268
+
269
+ it 'checks for updates when mod has been retrieved less than 1 month ago and does nothing if its date is less recent than the cache' do
270
+ expect_http_call_to(
271
+ path: '/v1/games/skyrimspecialedition/mods/2014/files.json',
272
+ json: { 'files' => [json_mod_file2472] }
273
+ )
274
+ expect_http_call_to(
275
+ path: '/v1/games/skyrimspecialedition/mods/updated.json?period=1m',
276
+ json: [
277
+ {
278
+ 'mod_id' => 2014,
279
+ # Mock that mod was updated 25 days ago
280
+ 'latest_file_update' => Integer((Time.now - (25 * 24 * 60 * 60)).strftime('%s')),
281
+ 'latest_mod_activity' => 1
282
+ }
283
+ ]
284
+ )
285
+ nexus_mods.mod_files
286
+ nexus_mods.set_mod_files_cache_timestamp(cache_timestamp: Time.now - (20 * 24 * 60 * 60), game_domain_name: 'skyrimspecialedition', mod_id: 2014)
287
+ expect_mod_file_to_be2472(nexus_mods.mod_files(check_updates: true).first)
288
+ end
289
+
290
+ it 'checks for updates when mod has been retrieved less than 1 month ago and re-query the mod if its date is more recent than the cache' do
291
+ expect_http_call_to(
292
+ path: '/v1/games/skyrimspecialedition/mods/2014/files.json',
293
+ json: { 'files' => [json_mod_file2472] },
294
+ times: 2
295
+ )
296
+ expect_http_call_to(
297
+ path: '/v1/games/skyrimspecialedition/mods/updated.json?period=1m',
298
+ json: [
299
+ {
300
+ 'mod_id' => 2014,
301
+ # Mock that mod was updated 15 days ago
302
+ 'latest_file_update' => Integer((Time.now - (15 * 24 * 60 * 60)).strftime('%s')),
303
+ 'latest_mod_activity' => 1
304
+ }
305
+ ]
306
+ )
307
+ nexus_mods.mod_files
308
+ nexus_mods.set_mod_files_cache_timestamp(cache_timestamp: Time.now - (20 * 24 * 60 * 60), game_domain_name: 'skyrimspecialedition', mod_id: 2014)
309
+ expect_mod_file_to_be2472(nexus_mods.mod_files(check_updates: true).first)
310
+ end
311
+
312
+ end
313
+
137
314
  end
138
315
 
139
316
  end
@@ -6,73 +6,253 @@ describe NexusMods::Api::Mod do
6
6
  expect_validate_user
7
7
  end
8
8
 
9
- it 'returns a mod complete information' do
10
- expect_http_call_to(
11
- path: '/v1/games/skyrimspecialedition/mods/2014.json',
12
- json: json_complete_mod
13
- )
14
- expect_mod_to_be_complete(nexus_mods.mod(game_domain_name: 'skyrimspecialedition', mod_id: 2014))
15
- end
9
+ context 'when accessing a partial mod' do
16
10
 
17
- it 'returns a mod partial information' do
18
- expect_http_call_to(
19
- path: '/v1/games/skyrimspecialedition/mods/2014.json',
20
- json: json_partial_mod
21
- )
22
- expect_mod_to_be_partial(nexus_mods.mod(game_domain_name: 'skyrimspecialedition', mod_id: 2014))
23
- end
11
+ before do
12
+ expect_http_call_to(
13
+ path: '/v1/games/skyrimspecialedition/mods/2014.json',
14
+ json: json_partial_mod
15
+ )
16
+ end
24
17
 
25
- it 'returns the default mod information' do
26
- expect_http_call_to(
27
- path: '/v1/games/skyrimspecialedition/mods/2014.json',
28
- json: json_complete_mod
29
- )
30
- expect_mod_to_be_complete(nexus_mods(mod_id: 2014).mod(game_domain_name: 'skyrimspecialedition'))
31
- end
18
+ it 'returns the mod information' do
19
+ expect_mod_to_be_partial(nexus_mods.mod(game_domain_name: 'skyrimspecialedition', mod_id: 2014))
20
+ end
32
21
 
33
- it 'returns mod information for the default game' do
34
- expect_http_call_to(
35
- path: '/v1/games/skyrimspecialedition/mods/2014.json',
36
- json: json_complete_mod
37
- )
38
- expect_mod_to_be_complete(nexus_mods(game_domain_name: 'skyrimspecialedition').mod(mod_id: 2014))
39
22
  end
40
23
 
41
- it 'returns mod information for the default game set using accessor' do
42
- expect_http_call_to(
43
- path: '/v1/games/skyrimspecialedition/mods/2014.json',
44
- json: json_complete_mod
45
- )
46
- nexus_mods.game_domain_name = 'skyrimspecialedition'
47
- expect_mod_to_be_complete(nexus_mods.mod(mod_id: 2014))
48
- end
24
+ context 'when accessing a complete mod' do
25
+
26
+ before do
27
+ expect_http_call_to(
28
+ path: '/v1/games/skyrimspecialedition/mods/2014.json',
29
+ json: json_complete_mod
30
+ )
31
+ end
32
+
33
+ it 'returns the mod information' do
34
+ expect_mod_to_be_complete(nexus_mods.mod(game_domain_name: 'skyrimspecialedition', mod_id: 2014))
35
+ end
36
+
37
+ it 'returns the default mod information' do
38
+ expect_mod_to_be_complete(nexus_mods(mod_id: 2014).mod(game_domain_name: 'skyrimspecialedition'))
39
+ end
40
+
41
+ it 'returns mod information for the default game' do
42
+ expect_mod_to_be_complete(nexus_mods(game_domain_name: 'skyrimspecialedition').mod(mod_id: 2014))
43
+ end
44
+
45
+ it 'returns mod information for the default game set using accessor' do
46
+ nexus_mods.game_domain_name = 'skyrimspecialedition'
47
+ expect_mod_to_be_complete(nexus_mods.mod(mod_id: 2014))
48
+ end
49
+
50
+ it 'returns mod information for the default game and mod' do
51
+ expect_mod_to_be_complete(nexus_mods(game_domain_name: 'skyrimspecialedition', mod_id: 2014).mod)
52
+ end
53
+
54
+ it 'returns mod information for the default game and mod set using accessor' do
55
+ nexus_mods.mod_id = 2014
56
+ expect_mod_to_be_complete(nexus_mods.mod(game_domain_name: 'skyrimspecialedition'))
57
+ end
58
+
59
+ it 'compares objects for equality' do
60
+ mod1 = nexus_mods.mod(game_domain_name: 'skyrimspecialedition', mod_id: 2014)
61
+ mod2 = nexus_mods.mod(game_domain_name: 'skyrimspecialedition', mod_id: 2014)
62
+ expect(mod1.object_id).not_to eq mod2.object_id
63
+ expect(mod1).to eq mod2
64
+ end
49
65
 
50
- it 'returns mod information for the default game and mod' do
51
- expect_http_call_to(
52
- path: '/v1/games/skyrimspecialedition/mods/2014.json',
53
- json: json_complete_mod
54
- )
55
- expect_mod_to_be_complete(nexus_mods(game_domain_name: 'skyrimspecialedition', mod_id: 2014).mod)
56
66
  end
57
67
 
58
- it 'returns mod information for the default game and mod set using accessor' do
59
- expect_http_call_to(
60
- path: '/v1/games/skyrimspecialedition/mods/2014.json',
61
- json: json_complete_mod
62
- )
63
- nexus_mods.mod_id = 2014
64
- expect_mod_to_be_complete(nexus_mods.mod(game_domain_name: 'skyrimspecialedition'))
68
+ context 'when checking cache data freshness' do
69
+
70
+ it 'returns that a mod never retrieved is not up-to-date' do
71
+ expect(nexus_mods.mod_cache_up_to_date?(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to be false
72
+ end
73
+
74
+ context 'when retrieving a mod previously' do
75
+
76
+ before do
77
+ expect_http_call_to(
78
+ path: '/v1/games/skyrimspecialedition/mods/2014.json',
79
+ json: json_complete_mod
80
+ )
81
+ nexus_mods.mod(game_domain_name: 'skyrimspecialedition', mod_id: 2014)
82
+ end
83
+
84
+ context 'when retrieved 40 days ago' do
85
+
86
+ let(:forty_days_ago) { Time.now - (40 * 24 * 60 * 60) }
87
+
88
+ before do
89
+ nexus_mods.set_mod_cache_timestamp(cache_timestamp: forty_days_ago, game_domain_name: 'skyrimspecialedition', mod_id: 2014)
90
+ end
91
+
92
+ it 'returns that the mod is not up-to-date' do
93
+ expect(nexus_mods.mod_cache_up_to_date?(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to be false
94
+ expect(nexus_mods.mod_cache_timestamp(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to eq forty_days_ago
95
+ end
96
+
97
+ end
98
+
99
+ context 'when retrieved 2 days ago' do
100
+
101
+ let(:two_days_ago) { Time.now - (2 * 24 * 60 * 60) }
102
+
103
+ before do
104
+ nexus_mods.set_mod_cache_timestamp(cache_timestamp: two_days_ago, game_domain_name: 'skyrimspecialedition', mod_id: 2014)
105
+ end
106
+
107
+ it 'returns that the mod is up-to-date after checking updated mods and not finding it, and updates its cache timestamp to the update time' do
108
+ expect_http_call_to(
109
+ path: '/v1/games/skyrimspecialedition/mods/updated.json?period=1m',
110
+ json: []
111
+ )
112
+ expect(nexus_mods.mod_cache_up_to_date?(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to be true
113
+ expect(nexus_mods.mod_cache_timestamp(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to eq(
114
+ nexus_mods.updated_mods_cache_timestamp(game_domain_name: 'skyrimspecialedition', since: :one_month)
115
+ )
116
+ end
117
+
118
+ it 'returns that the mod is up-to-date after checking updated mods and finding that cache is more recent, and updates its cache timestamp to the update time' do
119
+ expect_http_call_to(
120
+ path: '/v1/games/skyrimspecialedition/mods/updated.json?period=1m',
121
+ json: [
122
+ {
123
+ 'mod_id' => 2014,
124
+ # Mock that mod was updated 3 days ago
125
+ 'latest_file_update' => 1,
126
+ 'latest_mod_activity' => Integer((Time.now - (3 * 24 * 60 * 60)).strftime('%s'))
127
+ }
128
+ ]
129
+ )
130
+ expect(nexus_mods.mod_cache_up_to_date?(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to be true
131
+ expect(nexus_mods.mod_cache_timestamp(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to eq(
132
+ nexus_mods.updated_mods_cache_timestamp(game_domain_name: 'skyrimspecialedition', since: :one_month)
133
+ )
134
+ end
135
+
136
+ it 'returns that the mod is not up-to-date after checking updated mods and finding that cache is less recent' do
137
+ expect_http_call_to(
138
+ path: '/v1/games/skyrimspecialedition/mods/updated.json?period=1m',
139
+ json: [
140
+ {
141
+ 'mod_id' => 2014,
142
+ # Mock that mod was updated yesterday
143
+ 'latest_file_update' => 1,
144
+ 'latest_mod_activity' => Integer((Time.now - (24 * 60 * 60)).strftime('%s'))
145
+ }
146
+ ]
147
+ )
148
+ expect(nexus_mods.mod_cache_up_to_date?(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to be false
149
+ expect(nexus_mods.mod_cache_timestamp(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to eq two_days_ago
150
+ end
151
+
152
+ end
153
+
154
+ context 'when retrieved 3 minutes ago with an updated mods query 4 minutes ago in the cache' do
155
+
156
+ let(:three_minutes_ago) { Time.now - (3 * 60) }
157
+ let(:four_minutes_ago) { Time.now - (4 * 60) }
158
+
159
+ before do
160
+ expect_http_call_to(
161
+ path: '/v1/games/skyrimspecialedition/mods/updated.json?period=1m',
162
+ json: [
163
+ {
164
+ 'mod_id' => 2014,
165
+ # Mock that mod was updated 3 days ago
166
+ 'latest_file_update' => 1,
167
+ 'latest_mod_activity' => Integer((Time.now - (3 * 24 * 60 * 60)).strftime('%s'))
168
+ }
169
+ ]
170
+ )
171
+ nexus_mods.updated_mods(game_domain_name: 'skyrimspecialedition', since: :one_month)
172
+ nexus_mods.set_mod_cache_timestamp(cache_timestamp: three_minutes_ago, game_domain_name: 'skyrimspecialedition', mod_id: 2014)
173
+ nexus_mods.set_updated_mods_cache_timestamp(cache_timestamp: four_minutes_ago, game_domain_name: 'skyrimspecialedition', since: :one_month)
174
+ end
175
+
176
+ it 'returns that the mod is up-to-date but doesn\'t change its mod cache timestamp' do
177
+ expect(nexus_mods.mod_cache_up_to_date?(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to be true
178
+ expect(nexus_mods.mod_cache_timestamp(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to eq three_minutes_ago
179
+ expect(nexus_mods.updated_mods_cache_timestamp(game_domain_name: 'skyrimspecialedition', since: :one_month)).to eq four_minutes_ago
180
+ end
181
+
182
+ end
183
+
184
+ end
185
+
65
186
  end
66
187
 
67
- it 'compares objects for equality' do
68
- expect_http_call_to(
69
- path: '/v1/games/skyrimspecialedition/mods/2014.json',
70
- json: json_complete_mod
71
- )
72
- mod1 = nexus_mods.mod(game_domain_name: 'skyrimspecialedition', mod_id: 2014)
73
- mod2 = nexus_mods.mod(game_domain_name: 'skyrimspecialedition', mod_id: 2014)
74
- expect(mod1.object_id).not_to eq mod2.object_id
75
- expect(mod1).to eq mod2
188
+ context 'when checking for updates' do
189
+
190
+ before do
191
+ nexus_mods(game_domain_name: 'skyrimspecialedition', mod_id: 2014)
192
+ end
193
+
194
+ it 'does not check for updates if mod has not been retrieved before' do
195
+ expect_http_call_to(
196
+ path: '/v1/games/skyrimspecialedition/mods/2014.json',
197
+ json: json_complete_mod
198
+ )
199
+ expect_mod_to_be_complete(nexus_mods.mod(check_updates: true))
200
+ end
201
+
202
+ it 'does not check for updates if mod has been retrieved more than 1 month ago, and re-query the mod' do
203
+ expect_http_call_to(
204
+ path: '/v1/games/skyrimspecialedition/mods/2014.json',
205
+ json: json_complete_mod,
206
+ times: 2
207
+ )
208
+ nexus_mods.mod
209
+ nexus_mods.set_mod_cache_timestamp(cache_timestamp: Time.now - (40 * 24 * 60 * 60), game_domain_name: 'skyrimspecialedition', mod_id: 2014)
210
+ expect_mod_to_be_complete(nexus_mods.mod(check_updates: true))
211
+ end
212
+
213
+ it 'checks for updates when mod has been retrieved less than 1 month ago and does nothing if its date is less recent than the cache' do
214
+ expect_http_call_to(
215
+ path: '/v1/games/skyrimspecialedition/mods/2014.json',
216
+ json: json_complete_mod
217
+ )
218
+ expect_http_call_to(
219
+ path: '/v1/games/skyrimspecialedition/mods/updated.json?period=1m',
220
+ json: [
221
+ {
222
+ 'mod_id' => 2014,
223
+ # Mock that mod was updated 25 days ago
224
+ 'latest_file_update' => 1,
225
+ 'latest_mod_activity' => Integer((Time.now - (25 * 24 * 60 * 60)).strftime('%s'))
226
+ }
227
+ ]
228
+ )
229
+ nexus_mods.mod
230
+ nexus_mods.set_mod_cache_timestamp(cache_timestamp: Time.now - (20 * 24 * 60 * 60), game_domain_name: 'skyrimspecialedition', mod_id: 2014)
231
+ expect_mod_to_be_complete(nexus_mods.mod(check_updates: true))
232
+ end
233
+
234
+ it 'checks for updates when mod has been retrieved less than 1 month ago and re-query the mod if its date is more recent than the cache' do
235
+ expect_http_call_to(
236
+ path: '/v1/games/skyrimspecialedition/mods/2014.json',
237
+ json: json_complete_mod,
238
+ times: 2
239
+ )
240
+ expect_http_call_to(
241
+ path: '/v1/games/skyrimspecialedition/mods/updated.json?period=1m',
242
+ json: [
243
+ {
244
+ 'mod_id' => 2014,
245
+ # Mock that mod was updated 15 days ago
246
+ 'latest_file_update' => 1,
247
+ 'latest_mod_activity' => Integer((Time.now - (15 * 24 * 60 * 60)).strftime('%s'))
248
+ }
249
+ ]
250
+ )
251
+ nexus_mods.mod
252
+ nexus_mods.set_mod_cache_timestamp(cache_timestamp: Time.now - (20 * 24 * 60 * 60), game_domain_name: 'skyrimspecialedition', mod_id: 2014)
253
+ expect_mod_to_be_complete(nexus_mods.mod(check_updates: true))
254
+ end
255
+
76
256
  end
77
257
 
78
258
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nexus_mods
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Muriel Salvan