diff --git a/.gitattributes b/.gitattributes index 510d810..0f21c38 100644 --- a/.gitattributes +++ b/.gitattributes @@ -9,10 +9,11 @@ /art export-ignore /docs export-ignore /tests export-ignore +/workbench export-ignore /.editorconfig export-ignore /.php_cs.dist.php export-ignore /psalm.xml export-ignore /psalm.xml.dist export-ignore -/testbench.yaml export-ignore /UPGRADING.md export-ignore /phpstan.neon.dist export-ignore + diff --git a/composer.json b/composer.json index d5d0b44..3283455 100644 --- a/composer.json +++ b/composer.json @@ -39,20 +39,31 @@ } }, "scripts": { - "post-autoload-dump": "@composer run prepare", + "post-autoload-dump": [ + "@clear", + "@prepare", + "@composer run prepare" + ], "clear": "@php vendor/bin/testbench package:purge-skeleton --ansi", "prepare": "@php vendor/bin/testbench package:discover --ansi", - "build": [ - "@composer run prepare", - "@php vendor/bin/testbench workbench:build --ansi" - ], + "build": "@php vendor/bin/testbench workbench:build --ansi", "start": [ "Composer\\Config::disableProcessTimeout", "@composer run build", "@php vendor/bin/testbench serve" ], "analyse": "vendor/bin/phpstan analyse", - "format": "vendor/bin/pint" + "test": "vendor/bin/phpunit", + "format": "vendor/bin/pint", + "serve": [ + "Composer\\Config::disableProcessTimeout", + "@build", + "@php vendor/bin/testbench serve" + ], + "lint": [ + "@php vendor/bin/pint", + "@php vendor/bin/phpstan analyse" + ] }, "extra": { "laravel": { @@ -70,5 +81,13 @@ } }, "minimum-stability": "dev", - "prefer-stable": true + "prefer-stable": true, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests/", + "Workbench\\App\\": "workbench/app/", + "Workbench\\Database\\Factories\\": "workbench/database/factories/", + "Workbench\\Database\\Seeders\\": "workbench/database/seeders/" + } + } } diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 03696e1..372793f 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -4,5 +4,7 @@ parameters: - config - database - src + - tests + - workbench tmpDir: build/phpstan checkMissingIterableValueType: false diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 5c3e79c..473321a 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -20,13 +20,6 @@ tests - - - - - - - diff --git a/tests/ModelDataConnectorTest.php b/tests/ModelDataConnectorTest.php new file mode 100644 index 0000000..afad07f --- /dev/null +++ b/tests/ModelDataConnectorTest.php @@ -0,0 +1,821 @@ +ltiEnvironment = SimpleLtiEnvironment::factory()->create(); + $this->connector = ModelDataConnector::make($this->ltiEnvironment); + } + + /** @test */ + public function it_should_load_platform(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + + // Assert + $this->assertEquals($client->name, $platform->name); + } + + /** @test */ + public function it_should_update_platform(): void + { + // Arrange + $originalName = 'Foobar'; + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create([ + 'name' => $originalName, + ]); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + $platform->name = 'Barfoo'; + $platform->setSetting('a', 'b'); + $platform->save(); + + $client->refresh(); + + // Assert + $this->assertEquals($originalName, $client->name); + $this->assertEquals('b', $client->lti_settings['a']); + } + + /** @test */ + public function it_should_not_insert_platform(): void + { + // Arrange + $platform = new Platform($this->connector); + + // Act + $ok = $platform->save(); + + // Assert + $this->assertFalse($ok); + $this->assertEmpty(SimpleClient::all()); + } + + /** @test */ + public function it_should_load_context_from_external_context_id(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + $context = $this->ltiEnvironment->contexts()->create([ + 'client_id' => $client->id, + 'external_context_id' => '123', + 'title' => 'Barfoo', + ]); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + $ltiContext = Context::fromPlatform($platform, $context->external_context_id); + + // Assert + $this->assertEquals($ltiContext->getRecordId(), $context->id); + } + + /** @test */ + public function it_should_insert_context(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + $ltiContext = Context::fromPlatform($platform, '123'); + $ltiContext->title = 'Barfoo'; + $ltiContext->save(); + + // Assert + $contexts = $client->contexts()->get(); + $this->assertCount(1, $contexts); + } + + /** @test */ + public function it_should_update_context(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + $context = $this->ltiEnvironment->contexts()->create([ + 'client_id' => $client->id, + 'external_context_id' => '123', + 'title' => 'Barfoo', + ]); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + $ltiContext = Context::fromPlatform($platform, $context->external_context_id); + + $ltiContext->setSetting('a', 'b'); + $ltiContext->save(); + + $context->refresh(); + + // Assert + $this->assertEquals('b', $context->settings['a']); + } + + /** @test */ + public function it_should_delete_context(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + $context = $this->ltiEnvironment->contexts()->create([ + 'client_id' => $client->id, + 'external_context_id' => '123', + 'title' => 'Barfoo', + ]); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + $ltiContext = Context::fromPlatform($platform, $context->external_context_id); + + $ltiContext->delete(); + + // Assert + $this->expectException(ModelNotFoundException::class); + $context->refresh(); + } + + /** @test */ + public function it_should_load_resource_link_from_record_id(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + $resourceLink = $this->ltiEnvironment->resourceLinks()->create([ + 'client_id' => $client->id, + 'external_resource_link_id' => '123', + 'title' => 'Barfoo', + ]); + + // Act + $ltiResourceLink = ResourceLink::fromRecordId($resourceLink->id, $this->connector); + + // Assert + $this->assertEquals($ltiResourceLink->ltiResourceLinkId, $resourceLink->external_resource_link_id); + } + + /** @test */ + public function it_should_load_resource_link_from_external_resource_link_id_without_context(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + $resourceLink = $this->ltiEnvironment->resourceLinks()->create([ + 'client_id' => $client->id, + 'external_resource_link_id' => '123', + 'title' => 'Barfoo', + ]); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + $ltiResourceLink = ResourceLink::fromPlatform($platform, $resourceLink->external_resource_link_id); + + // Assert + $this->assertEquals($ltiResourceLink->title, $resourceLink->title); + } + + /** @test */ + public function it_should_insert_resource_link_without_context(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + $ltiResourceLink = ResourceLink::fromPlatform($platform, '123'); + $ltiResourceLink->title = 'Barfoo'; + $ltiResourceLink->save(); + + // Assert + $resourceLinks = $client->resourceLinks()->get(); + $this->assertCount(1, $resourceLinks); + } + + /** @test */ + public function it_should_load_resource_link_from_external_resource_link_id_with_context(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + $context = $this->ltiEnvironment->contexts()->create([ + 'client_id' => $client->id, + 'external_context_id' => '123', + 'title' => 'Barfoo', + ]); + + $resourceLink = $this->ltiEnvironment->resourceLinks()->create([ + 'lti_context_id' => $context->id, + 'external_resource_link_id' => '123', + 'title' => 'Baz', + ]); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + $ltiContext = Context::fromPlatform($platform, $context->external_context_id); + $ltiResourceLink = ResourceLink::fromContext($ltiContext, $resourceLink->external_resource_link_id); + + // Assert + $this->assertEquals($ltiResourceLink->title, $resourceLink->title); + } + + /** @test */ + public function it_should_insert_resource_link_with_context(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + $context = $this->ltiEnvironment->contexts()->create([ + 'client_id' => $client->id, + 'external_context_id' => '123', + 'title' => 'Barfoo', + ]); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + $ltiContext = Context::fromPlatform($platform, $context->external_context_id); + $ltiResourceLink = ResourceLink::fromContext($ltiContext, '123'); + $ltiResourceLink->title = 'Barfoo'; + $ltiResourceLink->save(); + + // Assert + $contextResourceLinks = $context->resourceLinks()->get(); + $this->assertCount(1, $contextResourceLinks); + + $clientResourceLinks = $client->resourceLinks()->get(); + $this->assertCount(1, $clientResourceLinks); + } + + /** @test */ + public function it_should_delete_resource_link(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + $resourceLink = $this->ltiEnvironment->resourceLinks()->create([ + 'client_id' => $client->id, + 'external_resource_link_id' => '123', + 'title' => 'Baz', + ]); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + $ltiResourceLink = ResourceLink::fromPlatform($platform, $resourceLink->external_resource_link_id); + + $ltiResourceLink->delete(); + + // Assert + $this->expectException(ModelNotFoundException::class); + $resourceLink->refresh(); + } + + /** @test */ + public function it_should_get_user_results_for_resource_link(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + $context = $this->ltiEnvironment->contexts()->create([ + 'client_id' => $client->id, + 'external_context_id' => '123', + 'title' => 'Barfoo', + ]); + + $resourceLink1 = $this->ltiEnvironment->resourceLinks()->create([ + 'lti_context_id' => $context->id, + 'external_resource_link_id' => '123', + 'title' => 'Barfoo', + ]); + $resourceLink2 = $this->ltiEnvironment->resourceLinks()->create([ + 'lti_context_id' => $context->id, + 'external_resource_link_id' => '456', + 'title' => 'Barfoo', + ]); + + $userResult1 = $this->ltiEnvironment->userResults()->create([ + 'lti_resource_link_id' => $resourceLink1->id, + 'external_user_result_id' => '111', + 'external_user_id' => 'aaa', + ]); + $userResult2 = $this->ltiEnvironment->userResults()->create([ + 'lti_resource_link_id' => $resourceLink1->id, + 'external_user_result_id' => '222', + 'external_user_id' => 'bbb', + ]); + $userResult3 = $this->ltiEnvironment->userResults()->create([ + 'lti_resource_link_id' => $resourceLink2->id, + 'external_user_result_id' => '333', + 'external_user_id' => 'ccc', + ]); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + $ltiResourceLink1 = ResourceLink::fromPlatform($platform, $resourceLink1->external_resource_link_id); + $ltiResourceLink2 = ResourceLink::fromPlatform($platform, $resourceLink2->external_resource_link_id); + + $userResults1 = $ltiResourceLink1->getUserResultSourcedIDs(false, IdScope::Platform); + $userResults2 = $ltiResourceLink2->getUserResultSourcedIDs(); + + // Assert + $this->assertCount(2, $userResults1); + $key = $client->getLtiKey().IdScope::SEPARATOR.$userResult1->external_user_id; + $this->assertArrayHasKey($key, $userResults1); + + $this->assertCount(1, $userResults2); + } + + /** @test */ + public function it_should_never_return_shares_for_a_result_link(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + $context = $this->ltiEnvironment->contexts()->create([ + 'client_id' => $client->id, + 'external_context_id' => '123', + 'title' => 'Barfoo', + ]); + + $resourceLink = $this->ltiEnvironment->resourceLinks()->create([ + 'lti_context_id' => $context->id, + 'external_resource_link_id' => '123', + 'title' => 'Barfoo', + ]); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + $context = Context::fromPlatform($platform, $context->external_context_id); + $ltiResourceLink = ResourceLink::fromContext($context, $resourceLink->external_resource_link_id); + + $shares = $ltiResourceLink->getShares(); + + // Assert + $this->assertCount(0, $shares); + } + + /** @test */ + public function it_should_load_user_result_from_record_id(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + $resourceLink = $this->ltiEnvironment->resourceLinks()->create([ + 'client_id' => $client->id, + 'external_resource_link_id' => '123', + 'title' => 'Barfoo', + ]); + $userResult = $this->ltiEnvironment->userResults()->create([ + 'lti_resource_link_id' => $resourceLink->id, + 'external_user_result_id' => '123', + 'external_user_id' => '456', + ]); + + // Act + $ltiUserResult = UserResult::fromRecordId($userResult->id, $this->connector); + + // Assert + $this->assertEquals($ltiUserResult->ltiUserId, $userResult->external_user_id); + } + + /** @test */ + public function it_should_load_nonce(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + $nonce = $this->ltiEnvironment->nonces()->create([ + 'client_id' => $client->id, + 'nonce' => '123', + 'expires_at' => Carbon::now()->addMinutes(5), + ]); + + // Act + $platform = Platform::fromRecordId($client->getLtiRecordId(), $this->connector); + $ltiNonce = new PlatformNonce($platform, $nonce->nonce); + $this->connector->loadPlatformNonce($ltiNonce); + + // Assert + $this->assertEquals($nonce->expires_at->getTimestamp(), $ltiNonce->expires); + } + + /** @test */ + public function it_should_insert_nonce(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + $ltiNonce = new PlatformNonce($platform, '123'); + $ltiNonce->save(); + + // Assert + $this->assertDatabaseHas('lti_nonces', [ + 'nonce' => '123', + ]); + } + + /** @test */ + public function it_should_update_nonce(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + $nonce = $this->ltiEnvironment->nonces()->create([ + 'client_id' => $client->id, + 'nonce' => '123', + 'expires_at' => Carbon::now()->addMinutes(5), + ]); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + $ltiNonce = new PlatformNonce($platform, $nonce->nonce); + $ltiNonce->save(); + + // Assert + $nonce->refresh(); + $this->assertGreaterThan(Carbon::now()->addMinutes(PlatformNonce::MAX_NONCE_AGE - 5), $nonce->expires_at); + } + + /** @test */ + public function it_should_delete_nonce(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + $nonce = $this->ltiEnvironment->nonces()->create([ + 'client_id' => $client->id, + 'nonce' => '123', + 'expires_at' => Carbon::now()->addMinutes(5), + ]); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + $ltiNonce = new PlatformNonce($platform, $nonce->nonce); + $ltiNonce->delete(); + + // Assert + $this->assertDatabaseMissing('lti_nonces', [ + 'nonce' => '123', + ]); + } + + /** @test */ + public function it_should_load_access_token(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + $accessToken = $this->ltiEnvironment->accessTokens()->create([ + 'client_id' => $client->id, + 'access_token' => '123', + 'scopes' => ['foo', 'bar'], + 'expires_at' => Carbon::now()->addMinutes(5), + ]); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + $ltiAccessToken = new AccessToken($platform); + + // Assert + $this->assertEquals($ltiAccessToken->token, $accessToken->access_token); + } + + /** @test */ + public function it_should_insert_access_token(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + $ltiAccessToken = new AccessToken($platform, ['foo', 'bar'], '123', 5 * 60); + $ltiAccessToken->save(); + + // Assert + $this->assertDatabaseHas('lti_access_tokens', [ + 'access_token' => $ltiAccessToken->token, + ]); + } + + /** @test */ + public function it_should_update_access_token(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + $accessToken = $this->ltiEnvironment->accessTokens()->create([ + 'client_id' => $client->id, + 'access_token' => '123', + 'scopes' => ['foo', 'bar'], + 'expires_at' => Carbon::now()->addMinutes(5), + ]); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + $ltiAccessToken = new AccessToken($platform, ['foo', 'bar'], '456', 5 * 60); + $ltiAccessToken->save(); + + // Assert + $accessToken->refresh(); + $this->assertEquals('456', $accessToken->access_token); + } + + /** @test */ + public function it_should_never_load_resource_link_share_key(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + $context = $this->ltiEnvironment->contexts()->create([ + 'client_id' => $client->id, + 'external_context_id' => '123', + 'title' => 'Barfoo', + ]); + + $resourceLink = $this->ltiEnvironment->resourceLinks()->create([ + 'lti_context_id' => $context->id, + 'external_resource_link_id' => '123', + 'title' => 'Barfoo', + ]); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + $context = Context::fromPlatform($platform, $context->external_context_id); + $ltiResourceLink = ResourceLink::fromContext($context, $resourceLink->external_resource_link_id); + $shareKey = new ResourceLinkShareKey($ltiResourceLink); + + $ok = $this->connector->loadResourceLinkShareKey($shareKey); + + // Assert + $this->assertFalse($ok); + } + + /** @test */ + public function it_should_never_save_resource_link_share_key(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + $context = $this->ltiEnvironment->contexts()->create([ + 'client_id' => $client->id, + 'external_context_id' => '123', + 'title' => 'Barfoo', + ]); + + $resourceLink = $this->ltiEnvironment->resourceLinks()->create([ + 'lti_context_id' => $context->id, + 'external_resource_link_id' => '123', + 'title' => 'Barfoo', + ]); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + $context = Context::fromPlatform($platform, $context->external_context_id); + $ltiResourceLink = ResourceLink::fromContext($context, $resourceLink->external_resource_link_id); + $shareKey = new ResourceLinkShareKey($ltiResourceLink); + + $ok = $shareKey->save(); + + // Assert + $this->assertFalse($ok); + } + + public function it_should_never_delete_resource_link_share_key(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + $context = $this->ltiEnvironment->contexts()->create([ + 'client_id' => $client->id, + 'external_context_id' => '123', + 'title' => 'Barfoo', + ]); + + $resourceLink = $this->ltiEnvironment->resourceLinks()->create([ + 'lti_context_id' => $context->id, + 'external_resource_link_id' => '123', + 'title' => 'Barfoo', + ]); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + $context = Context::fromPlatform($platform, $context->external_context_id); + $ltiResourceLink = ResourceLink::fromContext($context, $resourceLink->external_resource_link_id); + $shareKey = new ResourceLinkShareKey($ltiResourceLink); + + $ok = $shareKey->delete(); + + // Assert + $this->assertFalse($ok); + } + + /** @test */ + public function it_should_load_user_result_from_user_id(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + $resourceLink = $this->ltiEnvironment->resourceLinks()->create([ + 'client_id' => $client->id, + 'external_resource_link_id' => '123', + 'title' => 'Barfoo', + ]); + + $userResult = $this->ltiEnvironment->userResults()->create([ + 'lti_resource_link_id' => $resourceLink->id, + 'external_user_result_id' => '123', + 'external_user_id' => '456', + ]); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + $ltiResourceLink = ResourceLink::fromPlatform($platform, $resourceLink->external_resource_link_id); + $ltiUserResult = UserResult::fromResourceLink($ltiResourceLink, $userResult->external_user_id); + + // Assert + $this->assertEquals($ltiUserResult->getRecordId(), $userResult->id); + } + + /** @test */ + public function it_should_insert_user_result(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + $context = $this->ltiEnvironment->contexts()->create([ + 'client_id' => $client->id, + 'external_context_id' => '123', + 'title' => 'Barfoo', + ]); + + $resourceLink = $this->ltiEnvironment->resourceLinks()->create([ + 'lti_context_id' => $context->id, + 'external_resource_link_id' => '123', + 'title' => 'Barfoo', + ]); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + $ltiContext = Context::fromPlatform($platform, $context->external_context_id); + $ltiResourceLink = ResourceLink::fromContext($ltiContext, $resourceLink->external_resource_link_id); + $ltiUserResult = new UserResult(); + $ltiUserResult->setDataConnector($this->connector); + $ltiUserResult->setResourceLinkId($ltiResourceLink->getRecordId()); + $ltiUserResult->ltiUserId = '456'; + $ltiUserResult->ltiResultSourcedId = '789'; + + $ltiUserResult->save(); + + // Assert + $this->assertNotNull($ltiUserResult->getRecordId()); + $this->assertDatabaseHas('lti_user_results', [ + 'id' => $ltiUserResult->getRecordId(), + 'external_user_result_id' => '789', + 'external_user_id' => '456', + 'lti_resource_link_id' => $resourceLink->id, + ]); + } + + /** @test */ + public function it_should_update_user_result(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + $context = $this->ltiEnvironment->contexts()->create([ + 'client_id' => $client->id, + 'external_context_id' => '123', + 'title' => 'Barfoo', + ]); + + $resourceLink = $this->ltiEnvironment->resourceLinks()->create([ + 'lti_context_id' => $context->id, + 'external_resource_link_id' => '123', + 'title' => 'Barfoo', + ]); + + $userResult = $this->ltiEnvironment->userResults()->create([ + 'lti_resource_link_id' => $resourceLink->id, + 'external_user_result_id' => '123', + 'external_user_id' => '456', + ]); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + $ltiContext = Context::fromPlatform($platform, $context->external_context_id); + $ltiResourceLink = ResourceLink::fromContext($ltiContext, $resourceLink->external_resource_link_id); + $ltiUserResult = UserResult::fromResourceLink($ltiResourceLink, $userResult->external_user_id); + + $ltiUserResult->ltiResultSourcedId = '789'; + $ltiUserResult->save(); + + // Assert + $this->assertDatabaseHas('lti_user_results', [ + 'id' => $ltiUserResult->getRecordId(), + 'external_user_result_id' => '789', + 'external_user_id' => '456', + 'lti_resource_link_id' => $ltiResourceLink->getRecordId(), + ]); + } + + /** @test */ + public function it_should_delete_user_result(): void + { + // Arrange + /** @var SimpleClient $client */ + $client = Factory::factoryForModel(SimpleClient::class)->create(); + + $context = $this->ltiEnvironment->contexts()->create([ + 'client_id' => $client->id, + 'external_context_id' => '123', + 'title' => 'Barfoo', + ]); + + $resourceLink = $this->ltiEnvironment->resourceLinks()->create([ + 'lti_context_id' => $context->id, + 'external_resource_link_id' => '123', + 'title' => 'Barfoo', + ]); + + $userResult = $this->ltiEnvironment->userResults()->create([ + 'lti_resource_link_id' => $resourceLink->id, + 'external_user_result_id' => '123', + 'external_user_id' => '456', + ]); + + // Act + $platform = Platform::fromRecordId($client->id, $this->connector); + $ltiContext = Context::fromPlatform($platform, $context->external_context_id); + $ltiResourceLink = ResourceLink::fromContext($ltiContext, $resourceLink->external_resource_link_id); + $ltiUserResult = UserResult::fromResourceLink($ltiResourceLink, $userResult->external_user_id); + + $ok = $ltiUserResult->delete(); + + // Assert + $this->assertTrue($ok); + $this->expectException(ModelNotFoundException::class); + $userResult->refresh(); + } +} diff --git a/tests/Models/ClientTest.php b/tests/Models/ClientTest.php new file mode 100644 index 0000000..56406e1 --- /dev/null +++ b/tests/Models/ClientTest.php @@ -0,0 +1,21 @@ +create(); + + self::assertDatabaseCount('clients', 1); + } +} diff --git a/tests/Models/SimpleLtiEnvironmentTest.php b/tests/Models/SimpleLtiEnvironmentTest.php new file mode 100644 index 0000000..f182c69 --- /dev/null +++ b/tests/Models/SimpleLtiEnvironmentTest.php @@ -0,0 +1,20 @@ +create(); + + self::assertDatabaseCount('simple_lti_environments', 1); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php index bd1ede9..3b8f6e0 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -1,10 +1,13 @@ 'Swis\\LaravelLtiProvider\\Database\\Factories\\'.class_basename($modelName).'Factory' + fn (string $modelName) => 'Workbench\\Database\\Factories\\'.class_basename($modelName).'Factory' ); } + protected function defineDatabaseMigrations() + { + $this->loadMigrationsFrom(workbench_path('database/migrations')); + $this->loadMigrationsFrom(package_path('database/migrations')); + } + protected function getPackageProviders($app) { return [ - LaravelLtiProviderServiceProvider::class, + LtiServiceProvider::class, ]; } public function getEnvironmentSetUp($app) { - config()->set('database.default', 'testing'); - - /* - $migration = include __DIR__.'/../database/migrations/create_laravel-lti-provider_table.php.stub'; - $migration->up(); - */ + config()->set('database.default', 'sqlite'); + config()->set('database.connections.sqlite', [ + 'driver' => 'sqlite', + 'database' => ':memory:', + 'prefix' => '', + ]); } } diff --git a/workbench/app/Models/SimpleLtiEnvironment.php b/workbench/app/Models/SimpleLtiEnvironment.php new file mode 100644 index 0000000..162db65 --- /dev/null +++ b/workbench/app/Models/SimpleLtiEnvironment.php @@ -0,0 +1,35 @@ + + */ +class SimpleClientFactory extends Factory +{ + protected $model = SimpleClient::class; + + /** + * {@inheritDoc} + */ + public function definition() + { + $name = $this->faker->company(); + + return [ + 'name' => $name, + 'key' => Str::slug($name), + 'secret' => Str::random(40), + 'lti_platform_id' => Str::random(8), + ]; + } +} diff --git a/workbench/database/factories/SimpleLtiEnvironmentFactory.php b/workbench/database/factories/SimpleLtiEnvironmentFactory.php new file mode 100644 index 0000000..14ff2bc --- /dev/null +++ b/workbench/database/factories/SimpleLtiEnvironmentFactory.php @@ -0,0 +1,24 @@ + + */ +class SimpleLtiEnvironmentFactory extends Factory +{ + protected $model = SimpleLtiEnvironment::class; + + /** + * {@inheritDoc} + */ + public function definition() + { + return [ + 'name' => ucfirst($this->faker->words(random_int(3, 5), true)), + ]; + } +} diff --git a/workbench/database/migrations/2023_10_26_300000_add_simple_lti_environments_table.php b/workbench/database/migrations/2023_10_26_300000_add_simple_lti_environments_table.php new file mode 100644 index 0000000..9465b69 --- /dev/null +++ b/workbench/database/migrations/2023_10_26_300000_add_simple_lti_environments_table.php @@ -0,0 +1,31 @@ +uuid('id')->primary(); + + // Admin title + $table->string('name'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::drop('simple_lti_environments'); + } +};