nexus_mods 2.1.0 → 2.2.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/CHANGELOG.md +6 -0
- data/lib/nexus_mods/api_client.rb +29 -3
- data/lib/nexus_mods/cacheable_with_expiry.rb +1 -1
- data/lib/nexus_mods/core_extensions/cacheable/cache_adapters/persistent_json_adapter.rb +2 -4
- data/lib/nexus_mods/version.rb +1 -1
- data/lib/nexus_mods.rb +68 -7
- data/spec/nexus_mods_test/factories/games.rb +10 -2
- data/spec/nexus_mods_test/factories/mod_files.rb +10 -2
- data/spec/nexus_mods_test/factories/mod_updates.rb +10 -2
- data/spec/nexus_mods_test/factories/mods.rb +10 -2
- data/spec/nexus_mods_test/scenarios/nexus_mods/nexus_mods_caching_spec.rb +215 -210
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a25aa2568a5be1e1a8592196344fde1ca68bcf814b67a51cf6921f7ed64c0f70
|
|
4
|
+
data.tar.gz: cdb50c9b1394af620109ea82439a3254b96ad223286ae1f797fcbc37c32a1a58
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b7f49167041ee67f3855c0a474cdba90a744660f424356943516016628f1e65f37154c7c6b596eca2b7ac2430eae4b0726db6a45d3685b750bdf7a33e8674d2e
|
|
7
|
+
data.tar.gz: ce904391c82e93f029a41a47d3e7e391af8dac23625ac38eda01b2066ea9261ae3ff7bbea2aed23fbbba9b124846be80640bdbbf94ef98291b1b020824ec74df
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
# [v2.2.0](https://github.com/Muriel-Salvan/nexus_mods/compare/v2.1.0...v2.2.0) (2023-04-12 12:56:31)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
* [[Feature] Add possibility to retrieve the cache timestamp of API resources](https://github.com/Muriel-Salvan/nexus_mods/commit/ba67323a32472deb1f063a51683ff9282ef96981)
|
|
6
|
+
|
|
1
7
|
# [v2.1.0](https://github.com/Muriel-Salvan/nexus_mods/compare/v2.0.1...v2.1.0) (2023-04-11 18:24:04)
|
|
2
8
|
|
|
3
9
|
### Features
|
|
@@ -60,6 +60,22 @@ class NexusMods
|
|
|
60
60
|
cached_api(path, parameters:, verb:)
|
|
61
61
|
end
|
|
62
62
|
|
|
63
|
+
# Get the timestamp of the cached data linked to a given API call
|
|
64
|
+
#
|
|
65
|
+
# Parameters::
|
|
66
|
+
# * *path* (String): API path to contact (from v1/ and without .json)
|
|
67
|
+
# * *parameters* (Hash<Symbol,Object>): Optional parameters to add to the path [default: {}]
|
|
68
|
+
# * *verb* (Symbol): Verb to be used (:get, :post...) [default: :get]
|
|
69
|
+
# Result::
|
|
70
|
+
# * Time or nil: The refresh time of the data, or nil if not part of the cache
|
|
71
|
+
def api_cache_timestamp(path, parameters: {}, verb: :get)
|
|
72
|
+
key = ApiClient.cache_key(path, parameters:, verb:)
|
|
73
|
+
return unless Cacheable.cache_adapter.exist?(key)
|
|
74
|
+
|
|
75
|
+
str_time = Cacheable.cache_adapter.context.dig(key, 'invalidate_time')
|
|
76
|
+
str_time.nil? ? nil : Time.parse(str_time)
|
|
77
|
+
end
|
|
78
|
+
|
|
63
79
|
# Send an HTTP request to the API and get back the HTTP response
|
|
64
80
|
#
|
|
65
81
|
# Parameters::
|
|
@@ -99,6 +115,18 @@ class NexusMods
|
|
|
99
115
|
# ApiClient: The API client to be used by the cacheable adapter (singleton pattern)
|
|
100
116
|
attr_accessor :api_client
|
|
101
117
|
|
|
118
|
+
# Get the cache key to be used for a given API query
|
|
119
|
+
#
|
|
120
|
+
# Parameters::
|
|
121
|
+
# * *path* (String): API path to contact (from v1/ and without .json)
|
|
122
|
+
# * *parameters* (Hash<Symbol,Object>): Optional parameters to add to the path [default: {}]
|
|
123
|
+
# * *verb* (Symbol): Verb to be used (:get, :post...) [default: :get]
|
|
124
|
+
# Result::
|
|
125
|
+
# * String: The corresponding cache key
|
|
126
|
+
def cache_key(path, parameters:, verb:)
|
|
127
|
+
"#{verb}/#{path}#{parameters.empty? ? '' : "/#{parameters.map { |param, value| "#{param}=#{value}" }.sort.join('/')}"}"
|
|
128
|
+
end
|
|
129
|
+
|
|
102
130
|
end
|
|
103
131
|
|
|
104
132
|
@api_client = nil
|
|
@@ -142,9 +170,7 @@ class NexusMods
|
|
|
142
170
|
cacheable_api(
|
|
143
171
|
:cached_api,
|
|
144
172
|
key_format: proc do |_target, _method_name, method_args, method_kwargs|
|
|
145
|
-
|
|
146
|
-
method_kwargs[:parameters].empty? ? '' : "/#{method_kwargs[:parameters].map { |param, value| "#{param}=#{value}" }.sort.join('/')}"
|
|
147
|
-
}"
|
|
173
|
+
cache_key(method_args.first, parameters: method_kwargs[:parameters], verb: method_kwargs[:verb])
|
|
148
174
|
end,
|
|
149
175
|
expiry_from_key: proc do |key|
|
|
150
176
|
# Example of keys:
|
|
@@ -45,7 +45,7 @@ class NexusMods
|
|
|
45
45
|
expiry_cache[key].nil? || (Time.now.utc - Time.parse(context['invalidate_time']).utc > expiry_cache[key])
|
|
46
46
|
end,
|
|
47
47
|
update_context_after_fetch: proc do |_key, _value, _options, context|
|
|
48
|
-
context['invalidate_time'] = Time.now.utc.strftime('%FT%
|
|
48
|
+
context['invalidate_time'] = Time.now.utc.strftime('%FT%T.%9NUTC')
|
|
49
49
|
end
|
|
50
50
|
}
|
|
51
51
|
)
|
|
@@ -13,6 +13,8 @@ module Cacheable
|
|
|
13
13
|
# * The context information is JSON serializable.
|
|
14
14
|
class PersistentJsonAdapter < MemoryAdapter
|
|
15
15
|
|
|
16
|
+
attr_reader :context
|
|
17
|
+
|
|
16
18
|
# Fetch a key with the givien cache options
|
|
17
19
|
#
|
|
18
20
|
# Parameters::
|
|
@@ -87,10 +89,6 @@ module Cacheable
|
|
|
87
89
|
@context = loaded_content['context']
|
|
88
90
|
end
|
|
89
91
|
|
|
90
|
-
private
|
|
91
|
-
|
|
92
|
-
attr_reader :context
|
|
93
|
-
|
|
94
92
|
end
|
|
95
93
|
|
|
96
94
|
end
|
data/lib/nexus_mods/version.rb
CHANGED
data/lib/nexus_mods.rb
CHANGED
|
@@ -143,6 +143,14 @@ class NexusMods
|
|
|
143
143
|
end
|
|
144
144
|
end
|
|
145
145
|
|
|
146
|
+
# Get the cached timestamp of the list of games
|
|
147
|
+
#
|
|
148
|
+
# Result::
|
|
149
|
+
# * Time or nil: Freshness time of the data in the API cache, or nil if not present in the cache
|
|
150
|
+
def games_cache_timestamp
|
|
151
|
+
@api_client.api_cache_timestamp('games')
|
|
152
|
+
end
|
|
153
|
+
|
|
146
154
|
# Get information about a mod
|
|
147
155
|
#
|
|
148
156
|
# Parameters::
|
|
@@ -183,6 +191,17 @@ class NexusMods
|
|
|
183
191
|
)
|
|
184
192
|
end
|
|
185
193
|
|
|
194
|
+
# Get the cached timestamp of a mod information
|
|
195
|
+
#
|
|
196
|
+
# Parameters::
|
|
197
|
+
# * *game_domain_name* (String): Game domain name to query by default [default: @game_domain_name]
|
|
198
|
+
# * *mod_id* (Integer): The mod ID [default: @mod_id]
|
|
199
|
+
# Result::
|
|
200
|
+
# * Time or nil: Freshness time of the data in the API cache, or nil if not present in the cache
|
|
201
|
+
def mod_cache_timestamp(game_domain_name: @game_domain_name, mod_id: @mod_id)
|
|
202
|
+
@api_client.api_cache_timestamp("games/#{game_domain_name}/mods/#{mod_id}")
|
|
203
|
+
end
|
|
204
|
+
|
|
186
205
|
# Get files belonging to a mod
|
|
187
206
|
#
|
|
188
207
|
# Parameters::
|
|
@@ -214,6 +233,17 @@ class NexusMods
|
|
|
214
233
|
end
|
|
215
234
|
end
|
|
216
235
|
|
|
236
|
+
# Get the cached timestamp of a mod files information
|
|
237
|
+
#
|
|
238
|
+
# Parameters::
|
|
239
|
+
# * *game_domain_name* (String): Game domain name to query by default [default: @game_domain_name]
|
|
240
|
+
# * *mod_id* (Integer): The mod ID [default: @mod_id]
|
|
241
|
+
# Result::
|
|
242
|
+
# * Time or nil: Freshness time of the data in the API cache, or nil if not present in the cache
|
|
243
|
+
def mod_files_cache_timestamp(game_domain_name: @game_domain_name, mod_id: @mod_id)
|
|
244
|
+
@api_client.api_cache_timestamp("games/#{game_domain_name}/mods/#{mod_id}/files")
|
|
245
|
+
end
|
|
246
|
+
|
|
217
247
|
# Get a list of updated mod ids since a given time
|
|
218
248
|
#
|
|
219
249
|
# Parameters::
|
|
@@ -227,6 +257,43 @@ class NexusMods
|
|
|
227
257
|
# Result::
|
|
228
258
|
# * Array<ModUpdates>: Mod's updates information
|
|
229
259
|
def updated_mods(game_domain_name: @game_domain_name, since: :one_day, clear_cache: false)
|
|
260
|
+
@api_client.api("games/#{game_domain_name}/mods/updated", parameters: period_to_url_params(since), clear_cache:).map do |updated_mod_json|
|
|
261
|
+
Api::ModUpdates.new(
|
|
262
|
+
mod_id: updated_mod_json['mod_id'],
|
|
263
|
+
latest_file_update: Time.at(updated_mod_json['latest_file_update']).utc,
|
|
264
|
+
latest_mod_activity: Time.at(updated_mod_json['latest_mod_activity']).utc
|
|
265
|
+
)
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
# Get the cached timestamp of a mod files information
|
|
270
|
+
#
|
|
271
|
+
# Parameters::
|
|
272
|
+
# * *game_domain_name* (String): Game domain name to query by default [default: @game_domain_name]
|
|
273
|
+
# * *since* (Symbol): The time from which we look for updated mods [default: :one_day]
|
|
274
|
+
# Possible values are:
|
|
275
|
+
# * *one_day*: Since 1 day
|
|
276
|
+
# * *one_week*: Since 1 week
|
|
277
|
+
# * *one_month*: Since 1 month
|
|
278
|
+
# Result::
|
|
279
|
+
# * Time or nil: Freshness time of the data in the API cache, or nil if not present in the cache
|
|
280
|
+
def updated_mods_cache_timestamp(game_domain_name: @game_domain_name, since: :one_day)
|
|
281
|
+
@api_client.api_cache_timestamp("games/#{game_domain_name}/mods/updated", parameters: period_to_url_params(since))
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
private
|
|
285
|
+
|
|
286
|
+
# Get the URL parameters from the required period
|
|
287
|
+
#
|
|
288
|
+
# Parameters::
|
|
289
|
+
# * *since* (Symbol): The time from which we look for updated mods
|
|
290
|
+
# Possible values are:
|
|
291
|
+
# * *one_day*: Since 1 day
|
|
292
|
+
# * *one_week*: Since 1 week
|
|
293
|
+
# * *one_month*: Since 1 month
|
|
294
|
+
# Result::
|
|
295
|
+
# * Hash<Symbol,Object>: Corresponding URL parameters
|
|
296
|
+
def period_to_url_params(since)
|
|
230
297
|
nexus_mods_period = {
|
|
231
298
|
one_day: '1d',
|
|
232
299
|
one_week: '1w',
|
|
@@ -234,13 +301,7 @@ class NexusMods
|
|
|
234
301
|
}[since]
|
|
235
302
|
raise "Unknown time stamp: #{since}" if nexus_mods_period.nil?
|
|
236
303
|
|
|
237
|
-
|
|
238
|
-
Api::ModUpdates.new(
|
|
239
|
-
mod_id: updated_mod_json['mod_id'],
|
|
240
|
-
latest_file_update: Time.at(updated_mod_json['latest_file_update']).utc,
|
|
241
|
-
latest_mod_activity: Time.at(updated_mod_json['latest_mod_activity']).utc
|
|
242
|
-
)
|
|
243
|
-
end
|
|
304
|
+
{ period: nexus_mods_period }
|
|
244
305
|
end
|
|
245
306
|
|
|
246
307
|
end
|
|
@@ -5,7 +5,7 @@ module NexusModsTest
|
|
|
5
5
|
module Games
|
|
6
6
|
|
|
7
7
|
# Test game with id 100
|
|
8
|
-
def json_game100
|
|
8
|
+
def self.json_game100
|
|
9
9
|
{
|
|
10
10
|
'id' => 100,
|
|
11
11
|
'name' => 'Morrowind',
|
|
@@ -35,8 +35,12 @@ module NexusModsTest
|
|
|
35
35
|
}
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
+
def json_game100
|
|
39
|
+
Games.json_game100
|
|
40
|
+
end
|
|
41
|
+
|
|
38
42
|
# Test game with id 101
|
|
39
|
-
def json_game101
|
|
43
|
+
def self.json_game101
|
|
40
44
|
{
|
|
41
45
|
'id' => 101,
|
|
42
46
|
'name' => 'Oblivion',
|
|
@@ -66,6 +70,10 @@ module NexusModsTest
|
|
|
66
70
|
}
|
|
67
71
|
end
|
|
68
72
|
|
|
73
|
+
def json_game101
|
|
74
|
+
Games.json_game101
|
|
75
|
+
end
|
|
76
|
+
|
|
69
77
|
# Expect a game to be the test game of id 100
|
|
70
78
|
#
|
|
71
79
|
# Parameters::
|
|
@@ -5,7 +5,7 @@ module NexusModsTest
|
|
|
5
5
|
module ModFiles
|
|
6
6
|
|
|
7
7
|
# Test mod file with id 2472
|
|
8
|
-
def json_mod_file2472
|
|
8
|
+
def self.json_mod_file2472
|
|
9
9
|
{
|
|
10
10
|
'id' => [
|
|
11
11
|
2472,
|
|
@@ -32,8 +32,12 @@ module NexusModsTest
|
|
|
32
32
|
}
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
+
def json_mod_file2472
|
|
36
|
+
ModFiles.json_mod_file2472
|
|
37
|
+
end
|
|
38
|
+
|
|
35
39
|
# Test mod file with id 2487
|
|
36
|
-
def json_mod_file2487
|
|
40
|
+
def self.json_mod_file2487
|
|
37
41
|
{
|
|
38
42
|
'id' => [
|
|
39
43
|
2487,
|
|
@@ -60,6 +64,10 @@ module NexusModsTest
|
|
|
60
64
|
}
|
|
61
65
|
end
|
|
62
66
|
|
|
67
|
+
def json_mod_file2487
|
|
68
|
+
ModFiles.json_mod_file2487
|
|
69
|
+
end
|
|
70
|
+
|
|
63
71
|
# Expect a mod's file to be the example one with id 2472
|
|
64
72
|
#
|
|
65
73
|
# Parameters::
|
|
@@ -5,7 +5,7 @@ module NexusModsTest
|
|
|
5
5
|
module ModUpdates
|
|
6
6
|
|
|
7
7
|
# Test mod updates with id 2014
|
|
8
|
-
def json_mod_updates2014
|
|
8
|
+
def self.json_mod_updates2014
|
|
9
9
|
{
|
|
10
10
|
'mod_id' => 2014,
|
|
11
11
|
'latest_file_update' => 1_655_813_855,
|
|
@@ -13,8 +13,12 @@ module NexusModsTest
|
|
|
13
13
|
}
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
def json_mod_updates2014
|
|
17
|
+
ModUpdates.json_mod_updates2014
|
|
18
|
+
end
|
|
19
|
+
|
|
16
20
|
# Test mod updates with id 100
|
|
17
|
-
def json_mod_updates100
|
|
21
|
+
def self.json_mod_updates100
|
|
18
22
|
{
|
|
19
23
|
'mod_id' => 100,
|
|
20
24
|
'latest_file_update' => 1_681_143_964,
|
|
@@ -22,6 +26,10 @@ module NexusModsTest
|
|
|
22
26
|
}
|
|
23
27
|
end
|
|
24
28
|
|
|
29
|
+
def json_mod_updates100
|
|
30
|
+
ModUpdates.json_mod_updates100
|
|
31
|
+
end
|
|
32
|
+
|
|
25
33
|
# Expect a mod's updates to be the example one with id 2014
|
|
26
34
|
#
|
|
27
35
|
# Parameters::
|
|
@@ -5,7 +5,7 @@ module NexusModsTest
|
|
|
5
5
|
module Mods
|
|
6
6
|
|
|
7
7
|
# Example of JSON object returned by the API for a mod information, having all possible fields
|
|
8
|
-
def json_complete_mod
|
|
8
|
+
def self.json_complete_mod
|
|
9
9
|
{
|
|
10
10
|
'name' => 'ApachiiSkyHair SSE',
|
|
11
11
|
'summary' => 'New Female and Male Hairstyles for Humans, Elves and Orcs. Converted hair from Sims2 and Sims3.<br />Standalone version.',
|
|
@@ -44,8 +44,12 @@ module NexusModsTest
|
|
|
44
44
|
}
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
+
def json_complete_mod
|
|
48
|
+
Mods.json_complete_mod
|
|
49
|
+
end
|
|
50
|
+
|
|
47
51
|
# Example of JSON object returned by the API for a mod information, having minimum fields
|
|
48
|
-
def json_partial_mod
|
|
52
|
+
def self.json_partial_mod
|
|
49
53
|
{
|
|
50
54
|
'mod_downloads' => 13_634_545,
|
|
51
55
|
'mod_unique_downloads' => 4_052_221,
|
|
@@ -75,6 +79,10 @@ module NexusModsTest
|
|
|
75
79
|
}
|
|
76
80
|
end
|
|
77
81
|
|
|
82
|
+
def json_partial_mod
|
|
83
|
+
Mods.json_partial_mod
|
|
84
|
+
end
|
|
85
|
+
|
|
78
86
|
# Expect a mod to be the example complete one
|
|
79
87
|
#
|
|
80
88
|
# Parameters::
|
|
@@ -10,163 +10,245 @@ describe NexusMods do
|
|
|
10
10
|
nexus_mods.api_limits
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
{
|
|
14
|
+
'games' => {
|
|
15
|
+
expected_api_path: '/v1/games.json',
|
|
16
|
+
mocked_api_json: [
|
|
17
|
+
NexusModsTest::Factories::Games.json_game100,
|
|
18
|
+
NexusModsTest::Factories::Games.json_game101
|
|
19
|
+
],
|
|
20
|
+
query: proc { |nm| nm.games },
|
|
21
|
+
query_without_cache: proc { |nm| nm.games(clear_cache: true) },
|
|
22
|
+
get_cache_timestamp: proc { |nm| nm.games_cache_timestamp },
|
|
23
|
+
expiry_cache_param: :games
|
|
24
|
+
},
|
|
25
|
+
'mods' => {
|
|
26
|
+
expected_api_path: '/v1/games/skyrimspecialedition/mods/2014.json',
|
|
27
|
+
mocked_api_json: NexusModsTest::Factories::Mods.json_complete_mod,
|
|
28
|
+
query: proc { |nm| nm.mod(game_domain_name: 'skyrimspecialedition', mod_id: 2014) },
|
|
29
|
+
query_without_cache: proc { |nm| nm.mod(game_domain_name: 'skyrimspecialedition', mod_id: 2014, clear_cache: true) },
|
|
30
|
+
get_cache_timestamp: proc { |nm| nm.mod_cache_timestamp(game_domain_name: 'skyrimspecialedition', mod_id: 2014) },
|
|
31
|
+
expiry_cache_param: :mod
|
|
32
|
+
},
|
|
33
|
+
'mod files' => {
|
|
34
|
+
expected_api_path: '/v1/games/skyrimspecialedition/mods/2014/files.json',
|
|
35
|
+
mocked_api_json: {
|
|
36
|
+
files: [
|
|
37
|
+
NexusModsTest::Factories::ModFiles.json_mod_file2472,
|
|
38
|
+
NexusModsTest::Factories::ModFiles.json_mod_file2487
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
query: proc { |nm| nm.mod_files(game_domain_name: 'skyrimspecialedition', mod_id: 2014) },
|
|
42
|
+
query_without_cache: proc { |nm| nm.mod_files(game_domain_name: 'skyrimspecialedition', mod_id: 2014, clear_cache: true) },
|
|
43
|
+
get_cache_timestamp: proc { |nm| nm.mod_files_cache_timestamp(game_domain_name: 'skyrimspecialedition', mod_id: 2014) },
|
|
44
|
+
expiry_cache_param: :mod_files
|
|
45
|
+
}
|
|
46
|
+
}.merge(
|
|
47
|
+
{
|
|
48
|
+
'last day' => {
|
|
49
|
+
since: :one_day,
|
|
50
|
+
expected_url_params: 'period=1d'
|
|
51
|
+
},
|
|
52
|
+
'last week' => {
|
|
53
|
+
since: :one_week,
|
|
54
|
+
expected_url_params: 'period=1w'
|
|
55
|
+
},
|
|
56
|
+
'last month' => {
|
|
57
|
+
since: :one_month,
|
|
58
|
+
expected_url_params: 'period=1m'
|
|
59
|
+
}
|
|
60
|
+
}.to_h do |since, since_config|
|
|
61
|
+
[
|
|
62
|
+
"mod updates since #{since}",
|
|
63
|
+
{
|
|
64
|
+
expected_api_path: "/v1/games/skyrimspecialedition/mods/updated.json?#{since_config[:expected_url_params]}",
|
|
65
|
+
mocked_api_json: [
|
|
66
|
+
NexusModsTest::Factories::ModUpdates.json_mod_updates2014,
|
|
67
|
+
NexusModsTest::Factories::ModUpdates.json_mod_updates100
|
|
68
|
+
],
|
|
69
|
+
query: proc { |nm| nm.updated_mods(game_domain_name: 'skyrimspecialedition', since: since_config[:since]) },
|
|
70
|
+
query_without_cache: proc { |nm| nm.updated_mods(game_domain_name: 'skyrimspecialedition', since: since_config[:since], clear_cache: true) },
|
|
71
|
+
get_cache_timestamp: proc { |nm| nm.updated_mods_cache_timestamp(game_domain_name: 'skyrimspecialedition', since: since_config[:since]) }
|
|
72
|
+
}
|
|
20
73
|
]
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
expect(nexus_mods.games).to eq games
|
|
24
|
-
end
|
|
74
|
+
end
|
|
75
|
+
).each do |resource, resource_config|
|
|
25
76
|
|
|
26
|
-
|
|
27
|
-
expect_validate_user
|
|
28
|
-
expect_http_call_to(
|
|
29
|
-
path: '/v1/games.json',
|
|
30
|
-
json: [
|
|
31
|
-
json_game100,
|
|
32
|
-
json_game101
|
|
33
|
-
],
|
|
34
|
-
times: 2
|
|
35
|
-
)
|
|
36
|
-
games = nexus_mods.games
|
|
37
|
-
expect(nexus_mods.games(clear_cache: true)).to eq games
|
|
38
|
-
end
|
|
77
|
+
context "when testing #{resource}" do
|
|
39
78
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
79
|
+
it 'caches API queries' do
|
|
80
|
+
expect_validate_user
|
|
81
|
+
expect_http_call_to(
|
|
82
|
+
path: resource_config[:expected_api_path],
|
|
83
|
+
json: resource_config[:mocked_api_json]
|
|
84
|
+
)
|
|
85
|
+
resource = resource_config[:query].call(nexus_mods)
|
|
86
|
+
expect(resource_config[:query].call(nexus_mods)).to eq resource
|
|
87
|
+
end
|
|
49
88
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
89
|
+
it 'does not cache API queries if asked' do
|
|
90
|
+
expect_validate_user
|
|
91
|
+
expect_http_call_to(
|
|
92
|
+
path: resource_config[:expected_api_path],
|
|
93
|
+
json: resource_config[:mocked_api_json],
|
|
94
|
+
times: 2
|
|
95
|
+
)
|
|
96
|
+
resource = resource_config[:query].call(nexus_mods)
|
|
97
|
+
expect(resource_config[:query_without_cache].call(nexus_mods)).to eq resource
|
|
98
|
+
end
|
|
60
99
|
|
|
61
|
-
|
|
62
|
-
expect_validate_user
|
|
63
|
-
expect_http_call_to(
|
|
64
|
-
path: '/v1/games/skyrimspecialedition/mods/2014/files.json',
|
|
65
|
-
json: { files: [json_mod_file2472, json_mod_file2487] }
|
|
66
|
-
)
|
|
67
|
-
mod_files = nexus_mods.mod_files(game_domain_name: 'skyrimspecialedition', mod_id: 2014)
|
|
68
|
-
expect(nexus_mods.mod_files(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to eq mod_files
|
|
69
|
-
end
|
|
100
|
+
if resource_config[:expiry_cache_param]
|
|
70
101
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
102
|
+
it 'expires API queries cache' do
|
|
103
|
+
expect_validate_user
|
|
104
|
+
expect_http_call_to(
|
|
105
|
+
path: resource_config[:expected_api_path],
|
|
106
|
+
json: resource_config[:mocked_api_json],
|
|
107
|
+
times: 2
|
|
108
|
+
)
|
|
109
|
+
nexus_mods_instance = nexus_mods(api_cache_expiry: { resource_config[:expiry_cache_param] => 1 })
|
|
110
|
+
resource = resource_config[:query].call(nexus_mods_instance)
|
|
111
|
+
sleep 2
|
|
112
|
+
expect(resource_config[:query].call(nexus_mods_instance)).to eq resource
|
|
113
|
+
end
|
|
81
114
|
|
|
82
|
-
|
|
83
|
-
'last day' => {
|
|
84
|
-
since: :one_day,
|
|
85
|
-
expected_url_params: 'period=1d'
|
|
86
|
-
},
|
|
87
|
-
'last week' => {
|
|
88
|
-
since: :one_week,
|
|
89
|
-
expected_url_params: 'period=1w'
|
|
90
|
-
},
|
|
91
|
-
'last month' => {
|
|
92
|
-
since: :one_month,
|
|
93
|
-
expected_url_params: 'period=1m'
|
|
94
|
-
}
|
|
95
|
-
}.each do |since, since_config|
|
|
115
|
+
end
|
|
96
116
|
|
|
97
|
-
|
|
117
|
+
it 'stores no timestamp of the data stored in the API cache before fetching data' do
|
|
118
|
+
expect_validate_user
|
|
119
|
+
expect(resource_config[:get_cache_timestamp].call(nexus_mods)).to be_nil
|
|
120
|
+
end
|
|
98
121
|
|
|
99
|
-
it '
|
|
122
|
+
it 'retrieves the timestamp of the data stored in the API cache' do
|
|
100
123
|
expect_validate_user
|
|
101
124
|
expect_http_call_to(
|
|
102
|
-
path:
|
|
103
|
-
json: [
|
|
104
|
-
json_mod_updates2014,
|
|
105
|
-
json_mod_updates100
|
|
106
|
-
]
|
|
125
|
+
path: resource_config[:expected_api_path],
|
|
126
|
+
json: resource_config[:mocked_api_json]
|
|
107
127
|
)
|
|
108
|
-
|
|
109
|
-
|
|
128
|
+
before = Time.now
|
|
129
|
+
resource_config[:query].call(nexus_mods)
|
|
130
|
+
after = Time.now
|
|
131
|
+
expect(resource_config[:get_cache_timestamp].call(nexus_mods)).to be_between(before, after)
|
|
110
132
|
end
|
|
111
133
|
|
|
112
|
-
it '
|
|
134
|
+
it 'retrieves the timestamp of the games data stored in the cache even after cache is used' do
|
|
113
135
|
expect_validate_user
|
|
114
136
|
expect_http_call_to(
|
|
115
|
-
path:
|
|
116
|
-
json: [
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
137
|
+
path: resource_config[:expected_api_path],
|
|
138
|
+
json: resource_config[:mocked_api_json]
|
|
139
|
+
)
|
|
140
|
+
before = Time.now
|
|
141
|
+
resource_config[:query].call(nexus_mods)
|
|
142
|
+
after = Time.now
|
|
143
|
+
resource_config[:query].call(nexus_mods)
|
|
144
|
+
expect(resource_config[:get_cache_timestamp].call(nexus_mods)).to be_between(before, after)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it 'retrieves the timestamp of the games data stored in the cache even after cache is persisted' do
|
|
148
|
+
with_api_cache_file do |api_cache_file|
|
|
149
|
+
expect_validate_user(times: 2)
|
|
150
|
+
expect_http_call_to(
|
|
151
|
+
path: resource_config[:expected_api_path],
|
|
152
|
+
json: resource_config[:mocked_api_json]
|
|
153
|
+
)
|
|
154
|
+
before = Time.now
|
|
155
|
+
resource_config[:query].call(nexus_mods(api_cache_file:))
|
|
156
|
+
after = Time.now
|
|
157
|
+
reset_nexus_mods
|
|
158
|
+
expect(resource_config[:get_cache_timestamp].call(nexus_mods(api_cache_file:))).to be_between(before, after)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
it 'updates the timestamp of the data stored in the API cache' do
|
|
163
|
+
expect_validate_user
|
|
164
|
+
expect_http_call_to(
|
|
165
|
+
path: resource_config[:expected_api_path],
|
|
166
|
+
json: resource_config[:mocked_api_json],
|
|
120
167
|
times: 2
|
|
121
168
|
)
|
|
122
|
-
|
|
123
|
-
|
|
169
|
+
resource_config[:query].call(nexus_mods)
|
|
170
|
+
sleep 1
|
|
171
|
+
before = Time.now
|
|
172
|
+
resource_config[:query_without_cache].call(nexus_mods)
|
|
173
|
+
after = Time.now
|
|
174
|
+
expect(resource_config[:get_cache_timestamp].call(nexus_mods)).to be_between(before, after)
|
|
124
175
|
end
|
|
125
176
|
|
|
126
|
-
|
|
177
|
+
context 'when testing cache persistence in files' do
|
|
127
178
|
|
|
128
|
-
|
|
179
|
+
it 'persists API cache in a file' do
|
|
180
|
+
with_api_cache_file do |api_cache_file|
|
|
181
|
+
expect_validate_user
|
|
182
|
+
expect_http_call_to(
|
|
183
|
+
path: resource_config[:expected_api_path],
|
|
184
|
+
json: resource_config[:mocked_api_json]
|
|
185
|
+
)
|
|
186
|
+
resource_config[:query].call(nexus_mods(api_cache_file:))
|
|
187
|
+
expect(File.exist?(api_cache_file)).to be true
|
|
188
|
+
expect(File.size(api_cache_file)).to be > 0
|
|
189
|
+
end
|
|
190
|
+
end
|
|
129
191
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
end
|
|
192
|
+
it 'uses API cache from a file' do
|
|
193
|
+
with_api_cache_file do |api_cache_file|
|
|
194
|
+
expect_validate_user(times: 2)
|
|
195
|
+
expect_http_call_to(
|
|
196
|
+
path: resource_config[:expected_api_path],
|
|
197
|
+
json: resource_config[:mocked_api_json]
|
|
198
|
+
)
|
|
199
|
+
# Generate the cache first
|
|
200
|
+
resource = resource_config[:query].call(nexus_mods(api_cache_file:))
|
|
201
|
+
# Force a new instance of NexusMods API to run
|
|
202
|
+
reset_nexus_mods
|
|
203
|
+
expect(resource_config[:query].call(nexus_mods(api_cache_file:))).to eq resource
|
|
204
|
+
end
|
|
205
|
+
end
|
|
145
206
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
207
|
+
if resource_config[:expiry_cache_param]
|
|
208
|
+
|
|
209
|
+
it 'uses API cache from a file, taking expiry time into account' do
|
|
210
|
+
with_api_cache_file do |api_cache_file|
|
|
211
|
+
expect_validate_user(times: 2)
|
|
212
|
+
expect_http_call_to(
|
|
213
|
+
path: resource_config[:expected_api_path],
|
|
214
|
+
json: resource_config[:mocked_api_json],
|
|
215
|
+
times: 2
|
|
216
|
+
)
|
|
217
|
+
# Generate the cache first
|
|
218
|
+
resource = resource_config[:query].call(nexus_mods(api_cache_file:, api_cache_expiry: { resource_config[:expiry_cache_param] => 1 }))
|
|
219
|
+
# Force a new instance of NexusMods API to run
|
|
220
|
+
reset_nexus_mods
|
|
221
|
+
sleep 2
|
|
222
|
+
# As the expiry time is 1 second, then the cache should still be invalidated
|
|
223
|
+
expect(resource_config[:query].call(nexus_mods(api_cache_file:, api_cache_expiry: { resource_config[:expiry_cache_param] => 1 }))).to eq resource
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
it 'uses API cache from a file, taking expiry time of the new process into account' do
|
|
228
|
+
with_api_cache_file do |api_cache_file|
|
|
229
|
+
expect_validate_user(times: 2)
|
|
230
|
+
expect_http_call_to(
|
|
231
|
+
path: resource_config[:expected_api_path],
|
|
232
|
+
json: resource_config[:mocked_api_json],
|
|
233
|
+
times: 2
|
|
234
|
+
)
|
|
235
|
+
# Generate the cache first
|
|
236
|
+
resource = resource_config[:query].call(nexus_mods(api_cache_file:, api_cache_expiry: { resource_config[:expiry_cache_param] => 10 }))
|
|
237
|
+
# Force a new instance of NexusMods API to run
|
|
238
|
+
reset_nexus_mods
|
|
239
|
+
sleep 2
|
|
240
|
+
# Even if the expiry time was 10 seconds while fetching the resource,
|
|
241
|
+
# if we decide it has to be 1 second now then it has to be invalidated.
|
|
242
|
+
expect(resource_config[:query].call(nexus_mods(api_cache_file:, api_cache_expiry: { resource_config[:expiry_cache_param] => 1 }))).to eq resource
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
end
|
|
158
251
|
|
|
159
|
-
it 'expires mod files queries cache' do
|
|
160
|
-
expect_validate_user
|
|
161
|
-
expect_http_call_to(
|
|
162
|
-
path: '/v1/games/skyrimspecialedition/mods/2014/files.json',
|
|
163
|
-
json: { files: [json_mod_file2472, json_mod_file2487] },
|
|
164
|
-
times: 2
|
|
165
|
-
)
|
|
166
|
-
nexus_mods_instance = nexus_mods(api_cache_expiry: { mod_files: 1 })
|
|
167
|
-
mod_files = nexus_mods_instance.mod_files(game_domain_name: 'skyrimspecialedition', mod_id: 2014)
|
|
168
|
-
sleep 2
|
|
169
|
-
expect(nexus_mods_instance.mod_files(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to eq mod_files
|
|
170
252
|
end
|
|
171
253
|
|
|
172
254
|
it 'only clears the cache of the wanted resource' do
|
|
@@ -190,83 +272,6 @@ describe NexusMods do
|
|
|
190
272
|
|
|
191
273
|
context 'with file persistence' do
|
|
192
274
|
|
|
193
|
-
it 'persists API cache in a file' do
|
|
194
|
-
with_api_cache_file do |api_cache_file|
|
|
195
|
-
expect_validate_user
|
|
196
|
-
expect_http_call_to(
|
|
197
|
-
path: '/v1/games.json',
|
|
198
|
-
json: [
|
|
199
|
-
json_game100,
|
|
200
|
-
json_game101
|
|
201
|
-
]
|
|
202
|
-
)
|
|
203
|
-
nexus_mods(api_cache_file:).games
|
|
204
|
-
expect(File.exist?(api_cache_file)).to be true
|
|
205
|
-
expect(File.size(api_cache_file)).to be > 0
|
|
206
|
-
end
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
it 'uses API cache from a file' do
|
|
210
|
-
with_api_cache_file do |api_cache_file|
|
|
211
|
-
expect_validate_user(times: 2)
|
|
212
|
-
expect_http_call_to(
|
|
213
|
-
path: '/v1/games.json',
|
|
214
|
-
json: [
|
|
215
|
-
json_game100,
|
|
216
|
-
json_game101
|
|
217
|
-
]
|
|
218
|
-
)
|
|
219
|
-
# Generate the cache first
|
|
220
|
-
games = nexus_mods(api_cache_file:).games
|
|
221
|
-
# Force a new instance of NexusMods API to run
|
|
222
|
-
reset_nexus_mods
|
|
223
|
-
expect(nexus_mods(api_cache_file:).games).to eq games
|
|
224
|
-
end
|
|
225
|
-
end
|
|
226
|
-
|
|
227
|
-
it 'uses API cache from a file, taking expiry time into account' do
|
|
228
|
-
with_api_cache_file do |api_cache_file|
|
|
229
|
-
expect_validate_user(times: 2)
|
|
230
|
-
expect_http_call_to(
|
|
231
|
-
path: '/v1/games.json',
|
|
232
|
-
json: [
|
|
233
|
-
json_game100,
|
|
234
|
-
json_game101
|
|
235
|
-
],
|
|
236
|
-
times: 2
|
|
237
|
-
)
|
|
238
|
-
# Generate the cache first
|
|
239
|
-
games = nexus_mods(api_cache_file:, api_cache_expiry: { games: 1 }).games
|
|
240
|
-
# Force a new instance of NexusMods API to run
|
|
241
|
-
reset_nexus_mods
|
|
242
|
-
sleep 2
|
|
243
|
-
# As the expiry time is 1 second, then the cache should still be invalidated
|
|
244
|
-
expect(nexus_mods(api_cache_file:, api_cache_expiry: { games: 1 }).games).to eq games
|
|
245
|
-
end
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
it 'uses API cache from a file, taking expiry time of the new process into account' do
|
|
249
|
-
with_api_cache_file do |api_cache_file|
|
|
250
|
-
expect_validate_user(times: 2)
|
|
251
|
-
expect_http_call_to(
|
|
252
|
-
path: '/v1/games.json',
|
|
253
|
-
json: [
|
|
254
|
-
json_game100,
|
|
255
|
-
json_game101
|
|
256
|
-
],
|
|
257
|
-
times: 2
|
|
258
|
-
)
|
|
259
|
-
# Generate the cache first
|
|
260
|
-
games = nexus_mods(api_cache_file:, api_cache_expiry: { games: 10 }).games
|
|
261
|
-
# Force a new instance of NexusMods API to run
|
|
262
|
-
reset_nexus_mods
|
|
263
|
-
sleep 2
|
|
264
|
-
# Even if the expiry time was 10 seconds while fetching the resource,
|
|
265
|
-
# if we decide it has to be 1 second now then it has to be invalidated.
|
|
266
|
-
expect(nexus_mods(api_cache_file:, api_cache_expiry: { games: 1 }).games).to eq games
|
|
267
|
-
end
|
|
268
|
-
end
|
|
269
|
-
|
|
270
275
|
it 'completes the API cache from a file' do
|
|
271
276
|
with_api_cache_file do |api_cache_file|
|
|
272
277
|
expect_validate_user(times: 3)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: nexus_mods
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Muriel Salvan
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2023-04-
|
|
11
|
+
date: 2023-04-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|