nexus_mods 2.1.0 → 2.2.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: ac9b76be57a989b2cd00cb120912dc8360fc926e76589769b725879f582e7d82
4
- data.tar.gz: 61342738bb1678bdbbbf350bf645b90210c55c8b53a63bdbb9cc755ca6f146bd
3
+ metadata.gz: a25aa2568a5be1e1a8592196344fde1ca68bcf814b67a51cf6921f7ed64c0f70
4
+ data.tar.gz: cdb50c9b1394af620109ea82439a3254b96ad223286ae1f797fcbc37c32a1a58
5
5
  SHA512:
6
- metadata.gz: 8ad0436dd7917b94ebbedaa26e7f943a92520b0336413730e273108849b7f2659e026954ad1a68570e99c27ad6654a6c970be208ec500078a4490e65930ce896
7
- data.tar.gz: 67a49c5e42db887253894726eed4b7ff3adde7f6da0f31d123ce6587117abb99d80a26e9a0db69bb541368fec4c6561b3b0a9564a8fe5ac27a412b0fb3c0173e
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
- "#{method_kwargs[:verb]}/#{method_args.first}#{
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%TUTC')
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
@@ -1,5 +1,5 @@
1
1
  class NexusMods
2
2
 
3
- VERSION = '2.1.0'
3
+ VERSION = '2.2.0'
4
4
 
5
5
  end
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
- @api_client.api("games/#{game_domain_name}/mods/updated", parameters: { period: nexus_mods_period }, clear_cache:).map do |updated_mod_json|
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
- it 'caches games queries' do
14
- expect_validate_user
15
- expect_http_call_to(
16
- path: '/v1/games.json',
17
- json: [
18
- json_game100,
19
- json_game101
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
- games = nexus_mods.games
23
- expect(nexus_mods.games).to eq games
24
- end
74
+ end
75
+ ).each do |resource, resource_config|
25
76
 
26
- it 'does not cache games queries if asked' do
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
- it 'caches mod queries' do
41
- expect_validate_user
42
- expect_http_call_to(
43
- path: '/v1/games/skyrimspecialedition/mods/2014.json',
44
- json: json_complete_mod
45
- )
46
- mod = nexus_mods.mod(game_domain_name: 'skyrimspecialedition', mod_id: 2014)
47
- expect(nexus_mods.mod(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to eq mod
48
- end
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
- it 'does not cache mod queries if asked' do
51
- expect_validate_user
52
- expect_http_call_to(
53
- path: '/v1/games/skyrimspecialedition/mods/2014.json',
54
- json: json_complete_mod,
55
- times: 2
56
- )
57
- mod = nexus_mods.mod(game_domain_name: 'skyrimspecialedition', mod_id: 2014)
58
- expect(nexus_mods.mod(game_domain_name: 'skyrimspecialedition', mod_id: 2014, clear_cache: true)).to eq mod
59
- end
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
- it 'caches mod files queries' do
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
- it 'does not cache mod files queries if asked' do
72
- expect_validate_user
73
- expect_http_call_to(
74
- path: '/v1/games/skyrimspecialedition/mods/2014/files.json',
75
- json: { files: [json_mod_file2472, json_mod_file2487] },
76
- times: 2
77
- )
78
- mod_files = nexus_mods.mod_files(game_domain_name: 'skyrimspecialedition', mod_id: 2014)
79
- expect(nexus_mods.mod_files(game_domain_name: 'skyrimspecialedition', mod_id: 2014, clear_cache: true)).to eq mod_files
80
- end
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
- context "when testing updated months since #{since}" do
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 'caches mod updates queries' do
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: "/v1/games/skyrimspecialedition/mods/updated.json?#{since_config[:expected_url_params]}",
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
- mod_updates = nexus_mods.updated_mods(game_domain_name: 'skyrimspecialedition', since: since_config[:since])
109
- expect(nexus_mods.updated_mods(game_domain_name: 'skyrimspecialedition', since: since_config[:since])).to eq mod_updates
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 'does not cache mod updates queries if asked' do
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: "/v1/games/skyrimspecialedition/mods/updated.json?#{since_config[:expected_url_params]}",
116
- json: [
117
- json_mod_updates2014,
118
- json_mod_updates100
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
- mod_updates = nexus_mods.updated_mods(game_domain_name: 'skyrimspecialedition', since: since_config[:since])
123
- expect(nexus_mods.updated_mods(game_domain_name: 'skyrimspecialedition', since: since_config[:since], clear_cache: true)).to eq mod_updates
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
- end
177
+ context 'when testing cache persistence in files' do
127
178
 
128
- end
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
- it 'expires games queries cache' do
131
- expect_validate_user
132
- expect_http_call_to(
133
- path: '/v1/games.json',
134
- json: [
135
- json_game100,
136
- json_game101
137
- ],
138
- times: 2
139
- )
140
- nexus_mods_instance = nexus_mods(api_cache_expiry: { games: 1 })
141
- games = nexus_mods_instance.games
142
- sleep 2
143
- expect(nexus_mods_instance.games).to eq games
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
- it 'expires mod queries cache' do
147
- expect_validate_user
148
- expect_http_call_to(
149
- path: '/v1/games/skyrimspecialedition/mods/2014.json',
150
- json: json_complete_mod,
151
- times: 2
152
- )
153
- nexus_mods_instance = nexus_mods(api_cache_expiry: { mod: 1 })
154
- mod = nexus_mods_instance.mod(game_domain_name: 'skyrimspecialedition', mod_id: 2014)
155
- sleep 2
156
- expect(nexus_mods_instance.mod(game_domain_name: 'skyrimspecialedition', mod_id: 2014)).to eq mod
157
- end
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.1.0
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 00:00:00.000000000 Z
11
+ date: 2023-04-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday