nexus_mods 2.3.0 → 2.4.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 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