scorm_engine 0.7.1 → 0.7.2

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: '0499e8bbb95da53112a9bba9c98534272d25fc99a164bf483c7012aba545b366'
4
- data.tar.gz: eb9e248e8628d07d30ba0c8f2d20015cc1eccb3ae8c3d4a53bb9c7c61b47cac4
3
+ metadata.gz: a068e71a4053cf2657b2d017dad3c137bda74798e59f198badb017e2728f397f
4
+ data.tar.gz: '0494b968c5585104707284aa79014dbd3b4279609705d5eb7ef3823972f9d8e7'
5
5
  SHA512:
6
- metadata.gz: b51f47c3284f1c092325c449c65d784c4633a7b29458dbba887e0ab948a89304a43bfde311640c087d8e59183d2cd4de490b9b7bb8868e03ab87ad4d3af3e4eb
7
- data.tar.gz: 495d009b94290f634b1427523d460b4b7b3f39b2cb256fc874ea17793eabc9f083b9f01eb296f3e7b3f6cd105bfb5003e2b9a5c10798e6db13cfb667882125e1
6
+ metadata.gz: 955980d7acc49984f4814c489f83d3451b0ff636fec501f10069e9ca2ba3f54e8507e304c489c3c4cb5a3ef4257df722bf6356c68c6fa0117d08e2500a3936e6
7
+ data.tar.gz: d3d2eaa33f15c0ad4c13ab708c79c0ad9238e515f2914b292e74926b35e32328573d981679937601bcae6e02590a95093b51e5d701a844d31c2295b0cfee7811
@@ -288,6 +288,49 @@ module ScormEngine
288
288
  Response.new(raw_response: response, result: result)
289
289
  end
290
290
 
291
+ #
292
+ # Get the registration count and last reset time of a dispatch.
293
+ #
294
+ # @see http://rustici-docs.s3.amazonaws.com/engine/2017.1.x.dispatch/api-dispatch.html#tenant__dispatches__dispatchId__registrationCount_get
295
+ #
296
+ # @param [Hash] options
297
+ #
298
+ # @option options [String] :dispatch_id
299
+ # The ID of the dispatch to get.
300
+ #
301
+ # @return [ScormEngine::Models::DispatchRegistrationCount]
302
+ #
303
+ def get_dispatch_registration_count(options = {})
304
+ require_options(options, :dispatch_id)
305
+
306
+ response = get("dispatches/#{options[:dispatch_id]}/registrationCount")
307
+
308
+ # merge options to pick up dispatch_id which isn't passed back in the response
309
+ result = response.success? ? ScormEngine::Models::DispatchRegistrationCount.new_from_api({ "id" => options[:dispatch_id] }.merge(response.body)) : nil
310
+
311
+ Response.new(raw_response: response, result: result)
312
+ end
313
+
314
+ #
315
+ # Reset the registration count and last reset time of a dispatch.
316
+ #
317
+ # @see http://rustici-docs.s3.amazonaws.com/engine/2017.1.x.dispatch/api-dispatch.html#tenant__dispatches__dispatchId__registrationCount_delete
318
+ #
319
+ # @param [Hash] options
320
+ #
321
+ # @option options [String] :dispatch_id
322
+ # The ID of the dispatch to get.
323
+ #
324
+ # @return [ScormEngine::Response]
325
+ #
326
+ def delete_dispatch_registration_count(options = {})
327
+ require_options(options, :dispatch_id)
328
+
329
+ response = delete("dispatches/#{options[:dispatch_id]}/registrationCount")
330
+
331
+ Response.new(raw_response: response)
332
+ end
333
+
291
334
  private
292
335
 
293
336
  def coerce_dispatch_options(options = {})
@@ -300,6 +343,7 @@ module ScormEngine
300
343
 
301
344
  def coerce_expiration_date(date)
302
345
  return date if date == "none"
346
+
303
347
  date = date.is_a?(String) ? Date.parse(date) : date
304
348
  date&.iso8601 # might be nil
305
349
  rescue ArgumentError # unparsable date string
@@ -4,6 +4,7 @@ require_relative "models/course_configuration"
4
4
  require_relative "models/course_import"
5
5
  require_relative "models/destination"
6
6
  require_relative "models/dispatch"
7
+ require_relative "models/dispatch_registration_count"
7
8
  require_relative "models/dispatch_zip"
8
9
  require_relative "models/learner"
9
10
  require_relative "models/registration"
@@ -0,0 +1,49 @@
1
+ require "date"
2
+
3
+ module ScormEngine
4
+ module Models
5
+ class DispatchRegistrationCount < Base
6
+ # @attr
7
+ # The external identification of this dispatch.
8
+ # @return [String]
9
+ attr_accessor :id
10
+
11
+ # @attr
12
+ # The registration count for this dispatch.
13
+ # @return [Integer]
14
+ attr_accessor :registration_count
15
+
16
+ # @attr
17
+ # The date and time of the last count reset, if any.
18
+ # @return [DateTime]
19
+ attr_accessor :last_reset_at
20
+
21
+ def self.new_from_api(options = {})
22
+ this = new
23
+
24
+ this.options = options.dup
25
+ this.id = options["id"]
26
+ this.registration_count = options["registrationCount"].to_i
27
+ this.last_reset_at = get_last_reset_time(options)
28
+
29
+ this
30
+ end
31
+
32
+ #
33
+ # Extract and normalize the last reset datetime from the API options.
34
+ #
35
+ # @param [Hash] options
36
+ # The API options hash
37
+ #
38
+ # @return [Time]
39
+ # a date/time or nil if undefined.
40
+ #
41
+ def self.get_last_reset_time(options = {})
42
+ time = options["lastResetTime"]
43
+ return if time.nil? || time == "none"
44
+
45
+ Time.parse(time)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -1,3 +1,3 @@
1
1
  module ScormEngine
2
- VERSION = "0.7.1".freeze
2
+ VERSION = "0.7.2".freeze
3
3
  end
@@ -0,0 +1,30 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: delete
5
+ uri: https://<SCORM_ENGINE_HOST>/ScormEngineInterface/api/v1/ScormEngineGemTesting-default/dispatches/testing-dispatch-id-2/registrationCount
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ User-Agent:
11
+ - ScormEngine Ruby Gem 0.7.1
12
+ Authorization:
13
+ - Basic <BASIC_AUTH>
14
+ response:
15
+ status:
16
+ code: 204
17
+ message: ''
18
+ headers:
19
+ date:
20
+ - Fri, 15 Feb 2019 22:00:32 GMT
21
+ server:
22
+ - nginx
23
+ connection:
24
+ - Close
25
+ body:
26
+ encoding: UTF-8
27
+ string: ''
28
+ http_version:
29
+ recorded_at: Fri, 15 Feb 2019 22:00:32 GMT
30
+ recorded_with: VCR 4.0.0
@@ -0,0 +1,30 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: delete
5
+ uri: https://<SCORM_ENGINE_HOST>/ScormEngineInterface/api/v1/ScormEngineGemTesting-default/dispatches/nonexistent-dispatch/registrationCount
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ User-Agent:
11
+ - ScormEngine Ruby Gem 0.7.1
12
+ Authorization:
13
+ - Basic <BASIC_AUTH>
14
+ response:
15
+ status:
16
+ code: 204
17
+ message: ''
18
+ headers:
19
+ date:
20
+ - Fri, 15 Feb 2019 22:00:32 GMT
21
+ server:
22
+ - nginx
23
+ connection:
24
+ - Close
25
+ body:
26
+ encoding: UTF-8
27
+ string: ''
28
+ http_version:
29
+ recorded_at: Fri, 15 Feb 2019 22:00:32 GMT
30
+ recorded_with: VCR 4.0.0
@@ -0,0 +1,63 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: delete
5
+ uri: https://<SCORM_ENGINE_HOST>/ScormEngineInterface/api/v1/ScormEngineGemTesting-default/dispatches/testing-dispatch-id-2/registrationCount
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ User-Agent:
11
+ - ScormEngine Ruby Gem 0.7.1
12
+ Authorization:
13
+ - Basic <BASIC_AUTH>
14
+ response:
15
+ status:
16
+ code: 204
17
+ message: ''
18
+ headers:
19
+ date:
20
+ - Fri, 15 Feb 2019 22:00:38 GMT
21
+ server:
22
+ - nginx
23
+ connection:
24
+ - Close
25
+ body:
26
+ encoding: UTF-8
27
+ string: ''
28
+ http_version:
29
+ recorded_at: Fri, 15 Feb 2019 22:00:38 GMT
30
+ - request:
31
+ method: get
32
+ uri: https://<SCORM_ENGINE_HOST>/ScormEngineInterface/api/v1/ScormEngineGemTesting-default/dispatches/nonexistent-dispatch/registrationCount
33
+ body:
34
+ encoding: US-ASCII
35
+ string: ''
36
+ headers:
37
+ User-Agent:
38
+ - ScormEngine Ruby Gem 0.7.1
39
+ Authorization:
40
+ - Basic <BASIC_AUTH>
41
+ response:
42
+ status:
43
+ code: 404
44
+ message: ''
45
+ headers:
46
+ content-type:
47
+ - application/json
48
+ date:
49
+ - Fri, 15 Feb 2019 22:00:38 GMT
50
+ server:
51
+ - nginx
52
+ vary:
53
+ - Accept-Encoding
54
+ content-length:
55
+ - '77'
56
+ connection:
57
+ - Close
58
+ body:
59
+ encoding: ASCII-8BIT
60
+ string: '{"message":"No dispatches found with ID: nonexistent-dispatch"}'
61
+ http_version:
62
+ recorded_at: Fri, 15 Feb 2019 22:00:39 GMT
63
+ recorded_with: VCR 4.0.0
@@ -0,0 +1,63 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: delete
5
+ uri: https://<SCORM_ENGINE_HOST>/ScormEngineInterface/api/v1/ScormEngineGemTesting-default/dispatches/testing-dispatch-id-2/registrationCount
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ User-Agent:
11
+ - ScormEngine Ruby Gem 0.7.1
12
+ Authorization:
13
+ - Basic <BASIC_AUTH>
14
+ response:
15
+ status:
16
+ code: 204
17
+ message: ''
18
+ headers:
19
+ date:
20
+ - Fri, 15 Feb 2019 22:00:39 GMT
21
+ server:
22
+ - nginx
23
+ connection:
24
+ - Close
25
+ body:
26
+ encoding: UTF-8
27
+ string: ''
28
+ http_version:
29
+ recorded_at: Fri, 15 Feb 2019 22:00:39 GMT
30
+ - request:
31
+ method: get
32
+ uri: https://<SCORM_ENGINE_HOST>/ScormEngineInterface/api/v1/ScormEngineGemTesting-default/dispatches/testing-dispatch-id-2/registrationCount
33
+ body:
34
+ encoding: US-ASCII
35
+ string: ''
36
+ headers:
37
+ User-Agent:
38
+ - ScormEngine Ruby Gem 0.7.1
39
+ Authorization:
40
+ - Basic <BASIC_AUTH>
41
+ response:
42
+ status:
43
+ code: 200
44
+ message: ''
45
+ headers:
46
+ content-type:
47
+ - application/json
48
+ date:
49
+ - Fri, 15 Feb 2019 22:00:39 GMT
50
+ server:
51
+ - nginx
52
+ vary:
53
+ - Accept-Encoding
54
+ content-length:
55
+ - '86'
56
+ connection:
57
+ - Close
58
+ body:
59
+ encoding: ASCII-8BIT
60
+ string: '{"registrationCount":0,"lastResetTime":"2019-02-15T22:00:39.000Z"}'
61
+ http_version:
62
+ recorded_at: Fri, 15 Feb 2019 22:00:39 GMT
63
+ recorded_with: VCR 4.0.0
@@ -0,0 +1,63 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: delete
5
+ uri: https://<SCORM_ENGINE_HOST>/ScormEngineInterface/api/v1/ScormEngineGemTesting-default/dispatches/testing-dispatch-id-2/registrationCount
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ User-Agent:
11
+ - ScormEngine Ruby Gem 0.7.1
12
+ Authorization:
13
+ - Basic <BASIC_AUTH>
14
+ response:
15
+ status:
16
+ code: 204
17
+ message: ''
18
+ headers:
19
+ date:
20
+ - Fri, 15 Feb 2019 22:00:41 GMT
21
+ server:
22
+ - nginx
23
+ connection:
24
+ - Close
25
+ body:
26
+ encoding: UTF-8
27
+ string: ''
28
+ http_version:
29
+ recorded_at: Fri, 15 Feb 2019 22:00:41 GMT
30
+ - request:
31
+ method: get
32
+ uri: https://<SCORM_ENGINE_HOST>/ScormEngineInterface/api/v1/ScormEngineGemTesting-default/dispatches/testing-dispatch-id-2/registrationCount
33
+ body:
34
+ encoding: US-ASCII
35
+ string: ''
36
+ headers:
37
+ User-Agent:
38
+ - ScormEngine Ruby Gem 0.7.1
39
+ Authorization:
40
+ - Basic <BASIC_AUTH>
41
+ response:
42
+ status:
43
+ code: 200
44
+ message: ''
45
+ headers:
46
+ content-type:
47
+ - application/json
48
+ date:
49
+ - Fri, 15 Feb 2019 22:00:41 GMT
50
+ server:
51
+ - nginx
52
+ vary:
53
+ - Accept-Encoding
54
+ content-length:
55
+ - '86'
56
+ connection:
57
+ - Close
58
+ body:
59
+ encoding: ASCII-8BIT
60
+ string: '{"registrationCount":0,"lastResetTime":"2019-02-15T22:00:41.000Z"}'
61
+ http_version:
62
+ recorded_at: Fri, 15 Feb 2019 22:00:41 GMT
63
+ recorded_with: VCR 4.0.0
@@ -0,0 +1,63 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: delete
5
+ uri: https://<SCORM_ENGINE_HOST>/ScormEngineInterface/api/v1/ScormEngineGemTesting-default/dispatches/testing-dispatch-id-2/registrationCount
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ User-Agent:
11
+ - ScormEngine Ruby Gem 0.7.1
12
+ Authorization:
13
+ - Basic <BASIC_AUTH>
14
+ response:
15
+ status:
16
+ code: 204
17
+ message: ''
18
+ headers:
19
+ date:
20
+ - Fri, 15 Feb 2019 22:00:40 GMT
21
+ server:
22
+ - nginx
23
+ connection:
24
+ - Close
25
+ body:
26
+ encoding: UTF-8
27
+ string: ''
28
+ http_version:
29
+ recorded_at: Fri, 15 Feb 2019 22:00:40 GMT
30
+ - request:
31
+ method: get
32
+ uri: https://<SCORM_ENGINE_HOST>/ScormEngineInterface/api/v1/ScormEngineGemTesting-default/dispatches/testing-dispatch-id-2/registrationCount
33
+ body:
34
+ encoding: US-ASCII
35
+ string: ''
36
+ headers:
37
+ User-Agent:
38
+ - ScormEngine Ruby Gem 0.7.1
39
+ Authorization:
40
+ - Basic <BASIC_AUTH>
41
+ response:
42
+ status:
43
+ code: 200
44
+ message: ''
45
+ headers:
46
+ content-type:
47
+ - application/json
48
+ date:
49
+ - Fri, 15 Feb 2019 22:00:40 GMT
50
+ server:
51
+ - nginx
52
+ vary:
53
+ - Accept-Encoding
54
+ content-length:
55
+ - '86'
56
+ connection:
57
+ - Close
58
+ body:
59
+ encoding: ASCII-8BIT
60
+ string: '{"registrationCount":0,"lastResetTime":"2019-02-15T22:00:40.000Z"}'
61
+ http_version:
62
+ recorded_at: Fri, 15 Feb 2019 22:00:40 GMT
63
+ recorded_with: VCR 4.0.0
@@ -323,4 +323,50 @@ RSpec.describe ScormEngine::Api::Endpoints::Dispatches do
323
323
  end
324
324
  end
325
325
  end
326
+
327
+ describe "#get_dispatch_registration_count" do
328
+ before do
329
+ subject.delete_dispatch_registration_count(dispatch_id: dispatch_options[:dispatch_id])
330
+ end
331
+
332
+ let(:response) { subject.get_dispatch_registration_count(dispatch_id: dispatch_options[:dispatch_id]) }
333
+
334
+ it "is successful" do
335
+ expect(response.success?).to eq true
336
+ end
337
+
338
+ describe "results" do
339
+ it "sucessfully creates the dispatch attributes" do
340
+ dispatch = response.result
341
+ aggregate_failures do
342
+ expect(dispatch.id).to eq dispatch_options[:dispatch_id]
343
+ expect(dispatch.registration_count).to eq 0
344
+ expect(dispatch.last_reset_at).to be_a(Time)
345
+ end
346
+ end
347
+ end
348
+
349
+ it "fails when id is invalid" do
350
+ response = subject.get_dispatch_registration_count(dispatch_id: "nonexistent-dispatch")
351
+ aggregate_failures do
352
+ expect(response.success?).to eq false
353
+ expect(response.status).to eq 404
354
+ expect(response.message).to match(/No dispatches found with ID: nonexistent-dispatch/)
355
+ expect(response.result).to eq nil
356
+ end
357
+ end
358
+ end
359
+
360
+ describe "#delete_dispatch_registration_count" do
361
+ let(:response) { subject.delete_dispatch_registration_count(dispatch_id: dispatch_options[:dispatch_id]) }
362
+
363
+ it "is successful" do
364
+ expect(response.success?).to eq true
365
+ end
366
+
367
+ it "succeeds even when id is invalid" do
368
+ response = subject.delete_dispatch_registration_count(dispatch_id: "nonexistent-dispatch")
369
+ expect(response.success?).to eq true
370
+ end
371
+ end
326
372
  end
@@ -0,0 +1,42 @@
1
+ RSpec.describe ScormEngine::Models::DispatchRegistrationCount do
2
+ describe ".new_from_api" do
3
+ describe ":id" do
4
+ it "is set" do
5
+ dispatch = described_class.new_from_api(
6
+ "id" => "dispatch-id"
7
+ )
8
+ expect(dispatch.id).to eq "dispatch-id"
9
+ end
10
+ end
11
+
12
+ describe ":registration_count" do
13
+ it "is set" do
14
+ dispatch = described_class.new_from_api(
15
+ "registrationCount" => "456"
16
+ )
17
+ expect(dispatch.registration_count).to eq 456
18
+ end
19
+
20
+ it "is set to zero when not an integer" do
21
+ dispatch = described_class.new_from_api(
22
+ "registrationCount" => "oops"
23
+ )
24
+ expect(dispatch.registration_count).to eq 0
25
+ end
26
+ end
27
+
28
+ describe ":last_reset_at" do
29
+ it "is set" do
30
+ dispatch = described_class.new_from_api(
31
+ "lastResetTime" => "2018-05-24T08:09:10Z"
32
+ )
33
+ expect(dispatch.last_reset_at).to eq Time.new(2018, 5, 24, 8, 9, 10, 0)
34
+ end
35
+
36
+ it "is set to nil if blank" do
37
+ dispatch = described_class.new_from_api({})
38
+ expect(dispatch.last_reset_at).to eq nil
39
+ end
40
+ end
41
+ end
42
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scorm_engine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 0.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Philip Hallstrom
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-11-15 00:00:00.000000000 Z
11
+ date: 2019-02-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -196,6 +196,7 @@ files:
196
196
  - lib/scorm_engine/models/course_import.rb
197
197
  - lib/scorm_engine/models/destination.rb
198
198
  - lib/scorm_engine/models/dispatch.rb
199
+ - lib/scorm_engine/models/dispatch_registration_count.rb
199
200
  - lib/scorm_engine/models/dispatch_zip.rb
200
201
  - lib/scorm_engine/models/learner.rb
201
202
  - lib/scorm_engine/models/registration.rb
@@ -276,11 +277,17 @@ files:
276
277
  - spec/fixtures/vcr/ScormEngine_Api_Endpoints_Destinations/_put_destination/results/sucessfully_creates_the_destination_attributes.yml
277
278
  - spec/fixtures/vcr/ScormEngine_Api_Endpoints_Dispatches/_delete_dispatch/returns_success_even_when_id_is_invalid.yml
278
279
  - spec/fixtures/vcr/ScormEngine_Api_Endpoints_Dispatches/_delete_dispatch/works.yml
280
+ - spec/fixtures/vcr/ScormEngine_Api_Endpoints_Dispatches/_delete_dispatch_registration_count/is_successful.yml
281
+ - spec/fixtures/vcr/ScormEngine_Api_Endpoints_Dispatches/_delete_dispatch_registration_count/succeeds_even_when_id_is_invalid.yml
279
282
  - spec/fixtures/vcr/ScormEngine_Api_Endpoints_Dispatches/_get_dispatch/fails_when_id_is_invalid.yml
280
283
  - spec/fixtures/vcr/ScormEngine_Api_Endpoints_Dispatches/_get_dispatch/is_successful.yml
281
284
  - spec/fixtures/vcr/ScormEngine_Api_Endpoints_Dispatches/_get_dispatch/results/sucessfully_creates_the_dispatch_attributes.yml
282
285
  - spec/fixtures/vcr/ScormEngine_Api_Endpoints_Dispatches/_get_dispatch_enabled/is_false_when_disabled.yml
283
286
  - spec/fixtures/vcr/ScormEngine_Api_Endpoints_Dispatches/_get_dispatch_enabled/is_true_when_enabled.yml
287
+ - spec/fixtures/vcr/ScormEngine_Api_Endpoints_Dispatches/_get_dispatch_registration_count/fails_when_id_is_invalid.yml
288
+ - spec/fixtures/vcr/ScormEngine_Api_Endpoints_Dispatches/_get_dispatch_registration_count/is_successful.yml
289
+ - spec/fixtures/vcr/ScormEngine_Api_Endpoints_Dispatches/_get_dispatch_registration_count/results/sucessfully_creates_the_dispatch_attributes.yml
290
+ - spec/fixtures/vcr/ScormEngine_Api_Endpoints_Dispatches/_get_dispatch_registration_count/when_dispatch_has_registrations/knows_it_s_registration_count.yml
284
291
  - spec/fixtures/vcr/ScormEngine_Api_Endpoints_Dispatches/_get_dispatch_zip/fails_given_an_invalid_id.yml
285
292
  - spec/fixtures/vcr/ScormEngine_Api_Endpoints_Dispatches/_get_dispatch_zip/fails_given_an_invalid_type.yml
286
293
  - spec/fixtures/vcr/ScormEngine_Api_Endpoints_Dispatches/_get_dispatch_zip/works.yml
@@ -367,6 +374,7 @@ files:
367
374
  - spec/scorm_engine/models/course_import_spec.rb
368
375
  - spec/scorm_engine/models/course_spec.rb
369
376
  - spec/scorm_engine/models/destination_spec.rb
377
+ - spec/scorm_engine/models/dispatch_registration_count_spec.rb
370
378
  - spec/scorm_engine/models/dispatch_spec.rb
371
379
  - spec/scorm_engine/models/dispatch_zip_spec.rb
372
380
  - spec/scorm_engine/models/learner_spec.rb