Skip to content

Commit

Permalink
Merge branch 'release-48.4.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
github-actions committed Apr 23, 2024
2 parents b580485 + c65ea7c commit 5503d60
Show file tree
Hide file tree
Showing 4 changed files with 205 additions and 2 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,5 @@ Environment variables
| Var | Description |
|-----------------------------------------------|-------------------------------------------------------------------------------------|
| FEATURE_FLAG_FORCE_DISPLAY_TEST_ITEM_FEEDBACK | Even if itemSessionControl `showFeedback` option is false, show item feedback modal |
| FEATURE_FLAG_PAUSE_CONCURRENT_SESSIONS | When set, forces restoring the timers state from the browser storage on test init |
| FEATURE_FLAG_PAUSE_CONCURRENT_SESSIONS | When set, forces restoring the timers state from the browser storage on test init |
| FEATURE_FLAG_MAINTAIN_RESTARTED_DELIVERY_EXECUTION_STATE | Typed environment variable, controlling whether a delivery execution state should be kept as is or reset each time it starts. If `"false"` the state will be reset on each restart. Default behavior. If `"true"` the state will be maintained upon a restart |
1 change: 1 addition & 0 deletions model/Container/TestQtiServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ public function __invoke(ContainerConfigurator $configurator): void
service(RuntimeService::SERVICE_ID),
service(DeliveryExecutionService::SERVICE_ID),
service(FeatureFlagChecker::class),
service(StateServiceInterface::SERVICE_ID),
]
);
}
Expand Down
47 changes: 46 additions & 1 deletion model/Service/ConcurringSessionService.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
use oat\taoDelivery\model\execution\DeliveryExecution;
use oat\taoDelivery\model\execution\DeliveryExecutionInterface;
use oat\taoDelivery\model\execution\DeliveryExecutionService;
use oat\taoDelivery\model\execution\StateServiceInterface;
use oat\taoDelivery\model\RuntimeService;
use oat\taoQtiTest\models\container\QtiTestDeliveryContainer;
use oat\taoQtiTest\models\runner\QtiRunnerService;
Expand All @@ -43,12 +44,20 @@
class ConcurringSessionService
{
private const PAUSE_REASON_CONCURRENT_TEST = 'PAUSE_REASON_CONCURRENT_TEST';

/**
* @var string Controls whether a delivery execution state should be kept as is or reset each time it starts.
* `false` – the state will be reset on each restart.
* `true` – the state will be maintained upon a restart.
*
* phpcs:disable Generic.Files.LineLength
*/
private const FEATURE_FLAG_MAINTAIN_RESTARTED_DELIVERY_EXECUTION_STATE = 'FEATURE_FLAG_MAINTAIN_RESTARTED_DELIVERY_EXECUTION_STATE';
private LoggerInterface $logger;
private QtiRunnerService $qtiRunnerService;
private RuntimeService $runtimeService;
private DeliveryExecutionService $deliveryExecutionService;
private FeatureFlagCheckerInterface $featureFlagChecker;
private StateServiceInterface $stateService;
private ?PHPSession $currentSession;

public function __construct(
Expand All @@ -57,6 +66,7 @@ public function __construct(
RuntimeService $runtimeService,
DeliveryExecutionService $deliveryExecutionService,
FeatureFlagCheckerInterface $featureFlagChecker,
StateServiceInterface $stateService,
PHPSession $currentSession = null
) {
$this->logger = $logger;
Expand All @@ -65,6 +75,21 @@ public function __construct(
$this->deliveryExecutionService = $deliveryExecutionService;
$this->featureFlagChecker = $featureFlagChecker;
$this->currentSession = $currentSession ?? PHPSession::singleton();
$this->stateService = $stateService;
}

public function pauseActiveDeliveryExecutionsForUser($activeExecution): void
{
if ($activeExecution instanceof DeliveryExecution) {
$this->pauseConcurrentSessions($activeExecution);

if ($activeExecution->getState()->getUri() === DeliveryExecution::STATE_PAUSED) {
$this->adjustTimers($activeExecution);
}

$this->clearConcurringSession($activeExecution);
$this->resetDeliveryExecutionState($activeExecution);
}
}

public function pauseConcurrentSessions(DeliveryExecution $activeExecution): void
Expand Down Expand Up @@ -194,6 +219,26 @@ public function adjustTimers(DeliveryExecution $execution): void
}
}

private function resetDeliveryExecutionState(DeliveryExecution $activeExecution = null): void
{
if (
null === $activeExecution
|| !$this->isDeliveryExecutionStateResetEnabled()
|| $activeExecution->getState()->getUri() === DeliveryExecution::STATE_PAUSED
) {
return;
}

$this->stateService->pause($activeExecution);
}

private function isDeliveryExecutionStateResetEnabled(): bool
{
return !$this->featureFlagChecker->isEnabled(
static::FEATURE_FLAG_MAINTAIN_RESTARTED_DELIVERY_EXECUTION_STATE
);
}

private function storeItemDuration(
QtiRunnerServiceContext $context,
string $executionId
Expand Down
156 changes: 156 additions & 0 deletions test/unit/model/Service/ConcurringSessionServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use oat\tao\model\featureFlag\FeatureFlagCheckerInterface;
use oat\taoDelivery\model\execution\DeliveryExecution;
use oat\taoDelivery\model\execution\DeliveryExecutionService;
use oat\taoDelivery\model\execution\StateServiceInterface;
use oat\taoDelivery\model\RuntimeService;
use oat\taoQtiTest\model\Service\ConcurringSessionService;
use oat\taoQtiTest\models\container\QtiTestDeliveryContainer;
Expand All @@ -47,6 +48,7 @@ class ConcurringSessionServiceTest extends TestCase
private FeatureFlagCheckerInterface $featureFlagChecker;
private PHPSession $currentSession;
private ConcurringSessionService $subject;
private StateServiceInterface $stateService;

protected function setUp(): void
{
Expand All @@ -55,13 +57,15 @@ protected function setUp(): void
$this->deliveryExecutionService = $this->createMock(DeliveryExecutionService::class);
$this->featureFlagChecker = $this->createMock(FeatureFlagCheckerInterface::class);
$this->currentSession = $this->createMock(PHPSession::class);
$this->stateService = $this->createMock(StateServiceInterface::class);

$this->subject = new ConcurringSessionService(
$this->createMock(LoggerInterface::class),
$this->qtiRunnerService,
$this->runtimeService,
$this->deliveryExecutionService,
$this->featureFlagChecker,
$this->stateService,
$this->currentSession
);
}
Expand Down Expand Up @@ -266,4 +270,156 @@ public function testPausesExecutionsForOtherDeliveries(): void

$this->subject->pauseConcurrentSessions($execution);
}

public function testPauseActiveDeliveryExecutionsForUser()
{
$this->featureFlagChecker
->method('isEnabled')
->withConsecutive(
['FEATURE_FLAG_PAUSE_CONCURRENT_SESSIONS'],
['FEATURE_FLAG_MAINTAIN_RESTARTED_DELIVERY_EXECUTION_STATE']
)
->willReturn(true);

$otherDeliveryResource = $this->createMock(core_kernel_classes_Resource::class);
$executionDomainObject = $this->createMock(DeliveryExecution::class);
$otherExecutionDomainObject = $this->createMock(DeliveryExecution::class);

$executionDomainObject
->expects($this->atLeastOnce())
->method('getOriginalIdentifier')
->willReturn('https://example.com/execution/1');

$otherExecutionDomainObject
->expects($this->atLeastOnce())
->method('getDelivery')
->willReturn($otherDeliveryResource);
$otherExecutionDomainObject
->expects($this->atLeastOnce())
->method('getOriginalIdentifier')
->willReturn('https://example.com/execution/2');
$otherExecutionDomainObject
->expects($this->atLeastOnce())
->method('getIdentifier')
->willReturn('https://example.com/execution/2');

$this->deliveryExecutionService
->expects($this->atLeastOnce())
->method('getDeliveryExecutionsByStatus')
->willReturn([$executionDomainObject, $otherExecutionDomainObject]);

$otherDeliveryResource
->expects($this->once())
->method('getUri')
->willReturn('https://example.com/delivery/2');

$executionState = $this->createMock(core_kernel_classes_Resource::class);
$executionState
->method('getUri')
->willReturn(DeliveryExecution::STATE_ACTIVE);

$execution = $this->createMock(DeliveryExecution::class);
$execution
->expects($this->atLeastOnce())
->method('getOriginalIdentifier')
->willReturn('https://example.com/execution/1');
$execution
->expects($this->atLeastOnce())
->method('getUserIdentifier')
->willReturn('https://example.com/user/1');
$execution
->method('getState')
->willReturn($executionState);

$qtiTestDeliveryContainer = $this->createMock(QtiTestDeliveryContainer::class);
$qtiTestDeliveryContainer
->expects($this->once())
->method('getPrivateDirId')
->with($execution)
->willReturn('privateDirId');
$qtiTestDeliveryContainer
->expects($this->once())
->method('getPublicDirId')
->with($execution)
->willReturn('publicDirId');
$qtiTestDeliveryContainer
->expects($this->once())
->method('getSourceTest')
->with($execution)
->willReturn('http://example.com/sourceTest/1');

$this->runtimeService
->expects($this->once())
->method('getDeliveryContainer')
->with('https://example.com/delivery/2')
->willReturn($qtiTestDeliveryContainer);

$itemRef = $this->createMock(AssessmentItemRef::class);
$itemRef
->expects($this->once())
->method('getIdentifier')
->willReturn('itemRef');

$duration = $this->createMock(QtiDuration::class);
$duration
->expects($this->exactly(2))
->method('getSeconds')
->with(true)
->willReturn(123);

$testSession = $this->createMock(TestSession::class);
$testSession
->expects($this->once())
->method('getCurrentAssessmentItemRef')
->willReturn($itemRef);
$testSession
->expects($this->once())
->method('getTimerTarget')
->willReturn(TimePoint::TARGET_SERVER);
$testSession
->expects($this->once())
->method('getTimerDuration')
->with('itemRef', TimePoint::TARGET_SERVER)
->willReturn($duration);

$context = $this->createMock(QtiRunnerServiceContext::class);
$context
->expects($this->exactly(2))
->method('getTestSession')
->willReturn($testSession);

$this->qtiRunnerService
->expects($this->once())
->method('getServiceContext')
->with(
'http://example.com/sourceTest/1',
'privateDirId|publicDirId',
'https://example.com/execution/2'
)->willReturn($context);

$this->currentSession
->expects($this->exactly(2))
->method('setAttribute')
->withConsecutive(
[
'pauseReason-https://example.com/execution/2',
'PAUSE_REASON_CONCURRENT_TEST'
],
[
'itemDuration-https://example.com/execution/2',
123
]
)->willReturn(null);

$this->qtiRunnerService
->expects($this->once())
->method('endTimer')
->with($context);
$this->qtiRunnerService
->expects($this->once())
->method('pause')
->with($context);

$this->subject->pauseActiveDeliveryExecutionsForUser($execution);
}
}

0 comments on commit 5503d60

Please sign in to comment.