Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Don't fetch the current item for a null test session #2469

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 33 additions & 16 deletions model/Service/ConcurringSessionService.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
use oat\taoQtiTest\models\container\QtiTestDeliveryContainer;
use oat\taoQtiTest\models\runner\QtiRunnerService;
use oat\taoQtiTest\models\runner\QtiRunnerServiceContext;
use oat\taoQtiTest\models\runner\time\TimerAdjustmentService;
use oat\taoQtiTest\models\runner\time\TimerAdjustmentServiceInterface;
use oat\taoQtiTest\models\TestSessionService;
use PHPSession;
use Psr\Log\LoggerInterface;
Expand All @@ -59,6 +59,8 @@ class ConcurringSessionService
private FeatureFlagCheckerInterface $featureFlagChecker;
private StateServiceInterface $stateService;
private ?PHPSession $currentSession;
private ?TestSessionService $testSessionService;
private ?TimerAdjustmentServiceInterface $timerAdjustmentService;

public function __construct(
LoggerInterface $logger,
Expand All @@ -67,15 +69,19 @@ public function __construct(
DeliveryExecutionService $deliveryExecutionService,
FeatureFlagCheckerInterface $featureFlagChecker,
StateServiceInterface $stateService,
PHPSession $currentSession = null
PHPSession $currentSession = null,
TestSessionService $testSessionService = null,
TimerAdjustmentServiceInterface $timerAdjustmentService = null
) {
$this->logger = $logger;
$this->qtiRunnerService = $qtiRunnerService;
$this->runtimeService = $runtimeService;
$this->deliveryExecutionService = $deliveryExecutionService;
$this->featureFlagChecker = $featureFlagChecker;
$this->currentSession = $currentSession ?? PHPSession::singleton();
$this->stateService = $stateService;
$this->currentSession = $currentSession ?? PHPSession::singleton();
$this->testSessionService = $testSessionService;
$this->timerAdjustmentService = $timerAdjustmentService;
}

public function pauseActiveDeliveryExecutionsForUser($activeExecution): void
Expand Down Expand Up @@ -168,7 +174,7 @@ public function adjustTimers(DeliveryExecution $execution): void

$testSession = $this->getTestSessionService()->getTestSession($execution);

if ($testSession->getCurrentAssessmentItemRef()) {
if ($testSession && $testSession->getCurrentAssessmentItemRef()) {
$duration = $testSession->getTimerDuration(
$testSession->getCurrentAssessmentItemRef()->getIdentifier(),
$testSession->getTimerTarget()
Expand All @@ -182,10 +188,10 @@ public function adjustTimers(DeliveryExecution $execution): void
)
);

$ids = [
$ids = array_unique([
$execution->getIdentifier(),
$execution->getOriginalIdentifier()
];
]);

foreach ($ids as $executionId) {
$key = "itemDuration-{$executionId}";
Expand All @@ -210,7 +216,11 @@ public function adjustTimers(DeliveryExecution $execution): void
if ($delta > 0) {
$this->logger->debug(sprintf('Adjusting timers by %d s', $delta));

$this->getTimerAdjustmentService()->increase($testSession, $delta);
$this->getTimerAdjustmentService()->increase(
$testSession,
$delta,
TimerAdjustmentServiceInterface::TYPE_TIME_ADJUSTMENT
);

$testSession->suspend();
$this->getTestSessionService()->persist($testSession);
Expand Down Expand Up @@ -298,20 +308,27 @@ private function getContextByDeliveryExecution(DeliveryExecutionInterface $execu
);
}

private function getTimerAdjustmentService(): TimerAdjustmentService
private function getTimerAdjustmentService(): TimerAdjustmentServiceInterface
{
/** @noinspection PhpIncompatibleReturnTypeInspection */
return $this->getServiceManager()->get(TimerAdjustmentService::SERVICE_ID);
if (!$this->timerAdjustmentService instanceof TimerAdjustmentServiceInterface) {
/** @noinspection PhpFieldAssignmentTypeMismatchInspection */
$this->timerAdjustmentService = ServiceManager::getServiceManager()->get(
TimerAdjustmentServiceInterface::SERVICE_ID
);
}

return $this->timerAdjustmentService;
}

private function getTestSessionService(): TestSessionService
{
/** @noinspection PhpIncompatibleReturnTypeInspection */
return $this->getServiceManager()->get(TestSessionService::SERVICE_ID);
}
if (!$this->testSessionService instanceof TestSessionService) {
gabrielfs7 marked this conversation as resolved.
Show resolved Hide resolved
/** @noinspection PhpFieldAssignmentTypeMismatchInspection */
$this->testSessionService = ServiceManager::getServiceManager()->get(
TestSessionService::SERVICE_ID
);
}

private function getServiceManager()
{
return ServiceManager::getServiceManager();
return $this->testSessionService;
}
}
126 changes: 123 additions & 3 deletions test/unit/model/Service/ConcurringSessionServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2023 (original work) Open Assessment Technologies SA;
* Copyright (c) 2023-2024 (original work) Open Assessment Technologies SA.
*/

declare(strict_types=1);
Expand All @@ -33,6 +33,8 @@
use oat\taoQtiTest\models\runner\QtiRunnerService;
use oat\taoQtiTest\models\runner\QtiRunnerServiceContext;
use oat\taoQtiTest\models\runner\session\TestSession;
use oat\taoQtiTest\models\runner\time\TimerAdjustmentServiceInterface;
use oat\taoQtiTest\models\TestSessionService;
use oat\taoTests\models\runner\time\TimePoint;
use PHPSession;
use PHPUnit\Framework\TestCase;
Expand All @@ -49,6 +51,8 @@ class ConcurringSessionServiceTest extends TestCase
private PHPSession $currentSession;
private ConcurringSessionService $subject;
private StateServiceInterface $stateService;
private TestSessionService $testSessionService;
private TimerAdjustmentServiceInterface $timerAdjustmentService;

protected function setUp(): void
{
Expand All @@ -58,6 +62,8 @@ protected function setUp(): void
$this->featureFlagChecker = $this->createMock(FeatureFlagCheckerInterface::class);
$this->currentSession = $this->createMock(PHPSession::class);
$this->stateService = $this->createMock(StateServiceInterface::class);
$this->testSessionService = $this->createMock(TestSessionService::class);
$this->timerAdjustmentService = $this->createMock(TimerAdjustmentServiceInterface::class);

$this->subject = new ConcurringSessionService(
$this->createMock(LoggerInterface::class),
Expand All @@ -66,7 +72,9 @@ protected function setUp(): void
$this->deliveryExecutionService,
$this->featureFlagChecker,
$this->stateService,
$this->currentSession
$this->currentSession,
$this->testSessionService,
$this->timerAdjustmentService
);
}

Expand Down Expand Up @@ -271,7 +279,7 @@ public function testPausesExecutionsForOtherDeliveries(): void
$this->subject->pauseConcurrentSessions($execution);
}

public function testPauseActiveDeliveryExecutionsForUser()
public function testPauseActiveDeliveryExecutionsForUser(): void
{
$this->featureFlagChecker
->method('isEnabled')
Expand Down Expand Up @@ -422,4 +430,116 @@ public function testPauseActiveDeliveryExecutionsForUser()

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

public function testAdjustTimersAddsAPositiveAdjustment(): void
{
$execution = $this->createMock(DeliveryExecution::class);
$execution
->expects($this->atLeastOnce())
->method('getIdentifier')
->willReturn('https://example.com/execution/1');
$execution
->expects($this->atLeastOnce())
->method('getOriginalIdentifier')
->willReturn('https://example.com/execution/1');

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

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

$testSession = $this->createMock(TestSession::class);
$testSession
->expects($this->exactly(2))
->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);

$this->testSessionService
->expects($this->once())
->method('getTestSession')
->with($execution)
->willReturn($testSession);

$this->currentSession
->expects($this->once())
->method('hasAttribute')
->with('itemDuration-https://example.com/execution/1')
->willReturn(true);

$this->currentSession
->expects($this->once())
->method('getAttribute')
->with('itemDuration-https://example.com/execution/1')
->willReturn(1.5);

$this->currentSession
->expects($this->once())
->method('removeAttribute')
->with('itemDuration-https://example.com/execution/1');

$this->timerAdjustmentService
->expects($this->once())
->method('increase')
->with(
$testSession,
ceil(2.5),
TimerAdjustmentServiceInterface::TYPE_TIME_ADJUSTMENT
);

$testSession
->expects($this->once())
->method('suspend');

$this->testSessionService
->expects($this->once())
->method('persist')
->with($testSession);

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

public function testAdjustTimersSkipsAdjustmentIfNoTestSessionExists(): void
{
$execution = $this->createMock(DeliveryExecution::class);
$execution
->method('getIdentifier')
->willReturn('https://example.com/execution/1');

$this->testSessionService
->expects($this->once())
->method('getTestSession')
->with($execution)
->willReturn(null);

$this->currentSession
->expects($this->never())
->method('removeAttribute');

$this->timerAdjustmentService
->expects($this->never())
->method('increase');

$this->testSessionService
->expects($this->never())
->method('persist');

$this->subject->adjustTimers($execution);
}
}
Loading