From 173db541622c091e08dfb594175a3287943681e9 Mon Sep 17 00:00:00 2001 From: Tim Korn Date: Mon, 11 Mar 2024 06:55:45 +0100 Subject: [PATCH 1/5] WIP --- tests/Util/FixturesTest.php | 464 ++++++++++++++++++ tests/fixtures/get_meeting_info.xml | 6 +- .../get_meeting_info_breakout_room.xml | 94 ++++ .../get_meeting_info_with_breakout_rooms.xml | 96 ++++ tests/fixtures/get_meetings.xml | 10 +- 5 files changed, 664 insertions(+), 6 deletions(-) create mode 100644 tests/Util/FixturesTest.php create mode 100644 tests/fixtures/get_meeting_info_breakout_room.xml create mode 100644 tests/fixtures/get_meeting_info_with_breakout_rooms.xml diff --git a/tests/Util/FixturesTest.php b/tests/Util/FixturesTest.php new file mode 100644 index 00000000..c9af7f3d --- /dev/null +++ b/tests/Util/FixturesTest.php @@ -0,0 +1,464 @@ +. + */ + +namespace BigBlueButton\Util; + +use BigBlueButton\BigBlueButton; +use BigBlueButton\Enum\GuestPolicy; +use BigBlueButton\Enum\Role; +use BigBlueButton\Parameters\CreateMeetingParameters; +use BigBlueButton\Parameters\EndMeetingParameters; +use BigBlueButton\Parameters\GetMeetingInfoParameters; +use BigBlueButton\Parameters\HooksCreateParameters; +use BigBlueButton\Parameters\IsMeetingRunningParameters; +use BigBlueButton\Parameters\JoinMeetingParameters; +use BigBlueButton\Responses\BaseResponse; +use BigBlueButton\Responses\CreateMeetingResponse; +use Faker\Factory as Faker; +use PHPUnit\Framework\TestCase; +use Tracy\Debugger; + +/** + * @internal + */ +class FixturesTest extends TestCase +{ + /** @var CreateMeetingResponse[] */ + private array $createMeetingResponseRepository = []; + + private BigBlueButton $bbb; + private Fixtures $fixtures; + + public function setUp(): void + { + parent::setUp(); + + EnvLoader::loadEnvironmentVariables(); + + $this->bbb = new BigBlueButton(); + $this->fixtures = new Fixtures(); + + $this->closeAllMeetings(); // ensure server is clean (e.g. tearDown not executed due to a previous failed tests) + $this->prepareBbbServer(); + } + + public function tearDown(): void + { + parent::tearDown(); + + $this->closeAllMeetings(); + } + + /** + * The purpose of this test is to determine whether the created fixture files still accurately reflect the + * response of the BBB-Server. It serves as an early indicator to determine if tests/functions need updates. + * + * @dataProvider xmlFileToFunctionMapping + */ + public function testStructureOfFixturesIsStillUpToDate(string $requestFunction, string $filename, ?\Closure $getParameters): void + { + // get parameters by closure from data provider + $parameters = ($getParameters) ? $getParameters($this->createMeetingResponseRepository) : null; + + /** @var BaseResponse $response */ + $response = $this->bbb->{$requestFunction}($parameters); + $xmlToBe = $this->fixtures->fromXmlFile($filename); + $xmlAsIs = $response->getRawXml(); + + $this->assertEquals('SUCCESS', $response->getReturnCode(), $response->getMessage()); + $this->assertTrue($response->success(), $response->getMessage()); + $this->assertInstanceOf(\SimpleXMLElement::class, $xmlAsIs); + $this->assertInstanceOf(\SimpleXMLElement::class, $xmlToBe); + $this->assertSameStructureOfXml($xmlToBe, $xmlAsIs); + } + + protected function closeAllMeetings(): void + { + foreach ($this->bbb->getMeetings()->getMeetings() as $meeting) { + $meetingId = $meeting->getInternalMeetingId(); + $endMeetingResponse = $this->bbb->endMeeting(new EndMeetingParameters($meetingId)); + self::assertEquals('SUCCESS', $endMeetingResponse->getReturnCode(), $endMeetingResponse->getMessage()); + self::assertTrue($endMeetingResponse->success()); + self::assertEquals('sentEndMeetingRequest', $endMeetingResponse->getMessageKey()); + } + } + + private function assertSameStructureOfXml(\SimpleXMLElement $xml1, \SimpleXMLElement $xml2): void + { + $array1 = $this->getStructureOfXmlAsArray($xml1); + $array2 = $this->getStructureOfXmlAsArray($xml2); + + // Debugger::dump($xml1); + // Debugger::dump($xml2); + // Debugger::dump($array1); + // Debugger::dump($array2); + + $this->assertEqualsCanonicalizing($array1, $array2); + } + + /** + * Recursive function to flatten an array, which shall represent the structure of an + * element. For this, arrays that contain several children (= array with sequential + * numbers as keys) will get a list of unique attributes across all children. + */ + private function flattenArray(array $array, string $prefix = ''): array + { + $result = []; + + foreach ($array as $key => $value) { + $new_key = $prefix . (empty($prefix) ? '' : '.') . $key; + + // prepare value + if (is_array($value)) { + // a sequential array (= not associative) is understood as a group of + // similar children, thus their attributes should be similar. + if (!$this->isAssociativeArray($value)) { + // get a full collection of unique attributes within the group of children + $attributeCollection = []; + + foreach ($value as $child) { + if (!is_array($child)) { + continue; + } + + foreach ($child as $attributeKey => $attributeValue) { + if (!key_exists($attributeKey, $attributeCollection)) { + $attributeCollection[$attributeKey] = $attributeValue; + } + } + } + + $value = $attributeCollection; + } + } + + // compose result + if (is_array($value)) { + if (count($value) > 0) { + $result = array_merge($result, [$new_key => $value], $this->flattenArray($value, $new_key)); + } else { + $result[$new_key] = 'empty array'; // empty array + } + } else { + $result[$new_key] = $value; + } + } + + return $result; + } + + /** + * Function that helps to determine if an array is sequential or associative. + * + * Remark: With 8.1 function can be replaced with 'array_is_list'. + */ + private function isAssociativeArray(array $array): bool + { + if (array_keys($array) === range(0, count($array) - 1)) { + return false; + } + + return true; + } + + private function getStructureOfXmlAsArray(\SimpleXMLElement $xml): array + { + // transform XML to ARRAY (via JSON) + $json = json_encode($xml); + $array = json_decode($json, true); + + // flatten multidimensional array to string-based hierarchic + $flattenArray = $this->flattenArray($array); + + // only the keys are needed + $keys = array_keys($flattenArray); + + // bring into order + sort($keys); + + return $keys; + } + + private function getChildrenOfXmlAsArray(\SimpleXMLElement $xml): array + { + $properties = []; + + foreach ($xml as $key => $value) { + $properties[] = $key; + } + + return $properties; + } + + private function xmlFileToFunctionMapping(): array + { + return [ + 'case01_api_version' => [ + 'function' => 'getApiVersion', + 'filename' => 'api_version.xml', + 'parameters' => null, + ], + 'case02_create_meeting' => [ + 'function' => 'createMeeting', + 'filename' => 'create_meeting.xml', + 'parameters' => function(array $creatMeetingResponses): CreateMeetingParameters { + $faker = Faker::create(); + + $createMeetingParameters = new CreateMeetingParameters(); + + return $createMeetingParameters->setMeetingId($faker->uuid)->setMeetingName('case02: ' . $faker->word); + }, + ], + 'case03_join_meeting' => [ + 'function' => 'joinMeeting', + 'filename' => 'join_meeting.xml', + 'parameters' => function(array $creatMeetingResponses): JoinMeetingParameters { + $faker = Faker::create(); + + $joinMeetingParameters = new JoinMeetingParameters(); + + /** @var CreateMeetingResponse $createMeetingResponse */ + $createMeetingResponse = $creatMeetingResponses['meeting_wo_breakout_rooms']; + + return $joinMeetingParameters + ->setMeetingId($createMeetingResponse->getMeetingId()) + ->setCreationTime($createMeetingResponse->getCreationTime()) + ->setUserId($faker->uuid) + ->setUsername($faker->name) + ->setRole(Role::VIEWER) + ->setRedirect(false) + ; + }, + ], + 'case04_end_meeting' => [ + 'function' => 'endMeeting', + 'filename' => 'end_meeting.xml', + 'parameters' => function(array $creatMeetingResponses): EndMeetingParameters { + /** @var CreateMeetingResponse $createMeetingResponse */ + $createMeetingResponse = $creatMeetingResponses['meeting_wo_breakout_rooms']; + + $endMeetingParameters = new EndMeetingParameters(); + + return $endMeetingParameters->setMeetingId($createMeetingResponse->getMeetingId()); + }, + ], + 'case05_is_meeting_running' => [ + 'function' => 'isMeetingRunning', + 'filename' => 'is_meeting_running.xml', + 'parameters' => function(array $creatMeetingResponses): IsMeetingRunningParameters { + $isMeetingRunningParameters = new IsMeetingRunningParameters(); + + /** @var CreateMeetingResponse $createMeetingResponse */ + $createMeetingResponse = $creatMeetingResponses['meeting_wo_breakout_rooms']; + + return $isMeetingRunningParameters->setMeetingId($createMeetingResponse->getMeetingId()); + }, + ], + 'case06_list_of_meetings' => [ + 'function' => 'getMeetings', + 'filename' => 'get_meetings.xml', + 'parameters' => null, + ], + 'case07_meeting_info_of_meeting_without_breakout_rooms' => [ + 'function' => 'getMeetingInfo', + 'filename' => 'get_meeting_info.xml', + 'parameters' => function(array $creatMeetingResponses): GetMeetingInfoParameters { + $getMeetingInfoParameters = new GetMeetingInfoParameters(); + + /** @var CreateMeetingResponse $createMeetingResponse */ + $createMeetingResponse = $creatMeetingResponses['meeting_wo_breakout_rooms']; + + return $getMeetingInfoParameters->setMeetingId($createMeetingResponse->getMeetingId()); + }, + ], + 'case08_meeting_info_of_breakout_room' => [ + 'function' => 'getMeetingInfo', + 'filename' => 'get_meeting_info_breakout_room.xml', + 'parameters' => function(array $creatMeetingResponses): GetMeetingInfoParameters { + $getMeetingInfoParameters = new GetMeetingInfoParameters(); + + /** @var CreateMeetingResponse $createMeetingResponse */ + $createMeetingResponse = $creatMeetingResponses['breakout_room_A']; + + return $getMeetingInfoParameters->setMeetingId($createMeetingResponse->getInternalMeetingId()); + }, + ], + 'case09_meeting_info_of_meeting_with_breakout_rooms' => [ + 'function' => 'getMeetingInfo', + 'filename' => 'get_meeting_info_with_breakout_rooms.xml', + 'parameters' => function(array $creatMeetingResponses): GetMeetingInfoParameters { + $getMeetingInfoParameters = new GetMeetingInfoParameters(); + + /** @var CreateMeetingResponse $createMeetingResponse */ + $createMeetingResponse = $creatMeetingResponses['meeting_with_breakout_rooms']; + + return $getMeetingInfoParameters->setMeetingId($createMeetingResponse->getMeetingId()); + }, + ], + /* + 'case10_hooks_create' => [ + 'function' => 'hooksCreate', + 'filename' => 'hooks_create.xml', + 'parameters' => function(array $creatMeetingResponses): HooksCreateParameters { + $faker = Faker::create(); + + return new HooksCreateParameters('https://bbb-123.requestcatcher.com/'); + }, + ], + */ + /* + 'case11_hooks_list' => [ + 'function' => 'hooksList', + 'filename' => null, + 'parameters' => null, + ], + 'case12_hooks_destroy' => [ + 'function' => 'hooksDestroy', + 'filename' => null, + 'parameters' => null, + ], + */ + ]; + } + + /** + * Create items on a real BBB-Sever: + * a) Meeting #1: A meeting without breakout rooms + * b) Meeting #2: A meeting containing two breakout rooms + * c) Meeting #3: Breakout Room #A of Meeting #2 + * c) Meeting #4: Breakout Room #B of Meeting #2 + */ + private function prepareBbbServer(): void + { + $faker = Faker::create(); + + // create meeting room #1 (no breakout rooms inside) + $createMeetingParameters_mr1 = new CreateMeetingParameters($faker->uuid, 'Meeting Room #1'); + $createMeetingParameters_mr1->addMeta('endcallbackurl', $faker->url); + $createMeetingParameters_mr1->addMeta('presenter', $faker->name); + $createMeetingResponse_mr1 = $this->bbb->createMeeting($createMeetingParameters_mr1); + self::assertEquals('SUCCESS', $createMeetingResponse_mr1->getReturnCode()); + self::assertTrue($createMeetingResponse_mr1->success()); + self::assertEquals('bbb-none', $createMeetingResponse_mr1->getParentMeetingId()); + $this->createMeetingResponseRepository['meeting_wo_breakout_rooms'] = $createMeetingResponse_mr1; + + // create meeting room #2 (two breakout rooms inside) + $createMeetingParameters_mr2 = new CreateMeetingParameters($faker->uuid, 'Meeting Room #2'); + $createMeetingParameters_mr2->addMeta('endcallbackurl', $faker->url); + $createMeetingParameters_mr2->addMeta('presenter', $faker->name); + $createMeetingParameters_mr2->setBreakoutRoomsEnabled(true); + self::assertTrue($createMeetingParameters_mr2->isBreakoutRoomsEnabled()); + $createMeetingResponse_mr2 = $this->bbb->createMeeting($createMeetingParameters_mr2); + self::assertEquals('SUCCESS', $createMeetingResponse_mr2->getReturnCode()); + self::assertTrue($createMeetingResponse_mr2->success()); + self::assertEquals('bbb-none', $createMeetingResponse_mr2->getParentMeetingId()); + $this->createMeetingResponseRepository['meeting_with_breakout_rooms'] = $createMeetingResponse_mr2; + + // create breakout rooms #A + $createMeetingParameters_brA = new CreateMeetingParameters($faker->uuid, 'Breakout Room #A'); + $createMeetingParameters_brA->setParentMeetingId($createMeetingResponse_mr2->getMeetingId())->setBreakout(true)->setSequence(1); + $createMeetingResponse_brA = $this->bbb->createMeeting($createMeetingParameters_brA); + self::assertEquals('SUCCESS', $createMeetingResponse_brA->getReturnCode(), $createMeetingResponse_brA->getMessage()); + self::assertTrue($createMeetingResponse_brA->success()); + self::assertEquals('', $createMeetingResponse_brA->getMessage()); + self::assertNotEquals('bbb-none', $createMeetingResponse_brA->getParentMeetingId()); + self::assertEquals($createMeetingResponse_mr2->getInternalMeetingId(), $createMeetingResponse_brA->getParentMeetingId()); + $this->createMeetingResponseRepository['breakout_room_A'] = $createMeetingResponse_brA; + + // create breakout rooms #B + $createMeetingParameters_brB = new CreateMeetingParameters($faker->uuid, 'Breakout Room #B'); + $createMeetingParameters_brB->setParentMeetingId($createMeetingResponse_mr2->getMeetingId())->setBreakout(true)->setSequence(2); + $createMeetingResponse_brB = $this->bbb->createMeeting($createMeetingParameters_brB); + self::assertEquals('SUCCESS', $createMeetingResponse_brB->getReturnCode(), $createMeetingResponse_brB->getMessage()); + self::assertTrue($createMeetingResponse_brB->success()); + self::assertEquals('', $createMeetingResponse_brB->getMessage()); + self::assertNotEquals('bbb-none', $createMeetingResponse_brB->getParentMeetingId()); + self::assertEquals($createMeetingResponse_mr2->getInternalMeetingId(), $createMeetingResponse_brB->getParentMeetingId()); + $this->createMeetingResponseRepository['breakout_room_B'] = $createMeetingResponse_brB; + + // check breakout room #A + $getMeetingInfoParameters_brA = new GetMeetingInfoParameters($createMeetingResponse_brA->getInternalMeetingId()); + $getMeetingInfoResponse_brA = $this->bbb->getMeetingInfo($getMeetingInfoParameters_brA); + self::assertEquals('SUCCESS', $getMeetingInfoResponse_brA->getReturnCode(), $getMeetingInfoResponse_brA->getMessage()); + self::assertTrue($getMeetingInfoResponse_brA->success()); + self::assertTrue($getMeetingInfoResponse_brA->getMeeting()->isBreakout()); + self::assertEquals($createMeetingResponse_brA->getParentMeetingId(), $getMeetingInfoResponse_brA->getRawXml()->parentMeetingID->__toString()); // not covered yet by a function + + // check breakout room #B + $getMeetingInfoParameters_brB = new GetMeetingInfoParameters($createMeetingResponse_brB->getInternalMeetingId()); + $getMeetingInfoResponse_brB = $this->bbb->getMeetingInfo($getMeetingInfoParameters_brB); + self::assertEquals('SUCCESS', $getMeetingInfoResponse_brB->getReturnCode(), $getMeetingInfoResponse_brB->getMessage()); + self::assertTrue($getMeetingInfoResponse_brB->success()); + self::assertTrue($getMeetingInfoResponse_brB->getMeeting()->isBreakout()); + self::assertEquals($createMeetingResponse_brB->getParentMeetingId(), $getMeetingInfoResponse_brB->getRawXml()->parentMeetingID->__toString()); // not covered yet by a function + + // check meeting room #2 + $getMeetingInfoParameters_mr2 = new GetMeetingInfoParameters($createMeetingResponse_mr2->getMeetingId()); + $getMeetingInfoResponse_mr2 = $this->bbb->getMeetingInfo($getMeetingInfoParameters_mr2); + self::assertEquals('SUCCESS', $getMeetingInfoResponse_mr2->getReturnCode(), $getMeetingInfoResponse_mr2->getMessage()); + self::assertTrue($getMeetingInfoResponse_mr2->success()); + self::assertFalse($getMeetingInfoResponse_mr2->getMeeting()->isBreakout()); + self::assertCount(2, $getMeetingInfoResponse_mr2->getRawXml()->breakoutRooms->breakout); // not covered yet by a function + self::assertArrayHasKey('presenter', $getMeetingInfoResponse_mr2->getMeeting()->getMetas()); + self::assertArrayHasKey('endcallbackurl', $getMeetingInfoResponse_mr2->getMeeting()->getMetas()); + + // join MODERATOR into meeting room #1 + $joinMeetingParameters = new JoinMeetingParameters($createMeetingResponse_mr1->getMeetingId(), $faker->name, Role::MODERATOR); + $joinMeetingParameters->setRedirect(false); + $joinMeetingResponse = $this->bbb->joinMeeting($joinMeetingParameters); + self::assertEquals('SUCCESS', $joinMeetingResponse->getReturnCode(), $joinMeetingResponse->getMessage()); + self::assertTrue($joinMeetingResponse->success()); + self::assertIsString($joinMeetingResponse->getUserId()); + self::assertEquals('successfullyJoined', $joinMeetingResponse->getMessageKey()); + self::assertEquals('You have joined successfully.', $joinMeetingResponse->getMessage()); + + // check meeting room #1 + $getMeetingInfoParameters_mr1 = new GetMeetingInfoParameters($createMeetingResponse_mr1->getMeetingId()); + $getMeetingInfoResponse_mr1 = $this->bbb->getMeetingInfo($getMeetingInfoParameters_mr1); + self::assertEquals('SUCCESS', $getMeetingInfoResponse_mr1->getReturnCode(), $getMeetingInfoResponse_mr1->getMessage()); + self::assertTrue($getMeetingInfoResponse_mr1->success()); + self::assertFalse($getMeetingInfoResponse_mr1->getMeeting()->isBreakout()); + self::assertNull($getMeetingInfoResponse_mr1->getRawXml()->breakoutRooms->breakout); // not covered yet by a function + self::assertArrayHasKey('presenter', $getMeetingInfoResponse_mr1->getMeeting()->getMetas()); + self::assertArrayHasKey('endcallbackurl', $getMeetingInfoResponse_mr1->getMeeting()->getMetas()); + + + /* + // create hook (basic) + $callBackUrl = 'https://bbb.website.com/hook/catcher'; + $callBackUrl = '123'; + + // create hook (manual) + $parameters = ['callbackURL' => $callBackUrl]; + $secret = getenv('BBB_SECRET'); + $base = getenv('BBB_SERVER_BASE_URL'); + $queryBuild = http_build_query($parameters); + $checksum = hash('sha256', 'hooks/create' . $queryBuild . $secret); + $url_manual = $base . 'api/hooks/create?' . $queryBuild . '&checksum=' . $checksum; + + // create hook (normal) + $hooksCreateParameters = new HooksCreateParameters($callBackUrl); + $url = $this->bbb->getHooksCreateUrl($hooksCreateParameters); + self::assertEquals($url, $url_manual); + $response = $this->bbb->hooksCreate($hooksCreateParameters); + self::assertEquals('SUCCESS', $response->getReturnCode(), $response->getMessage() . ' / url: ' . $url); + */ + } +} diff --git a/tests/fixtures/get_meeting_info.xml b/tests/fixtures/get_meeting_info.xml index f3e4e219..86d8ba66 100644 --- a/tests/fixtures/get_meeting_info.xml +++ b/tests/fixtures/get_meeting_info.xml @@ -73,9 +73,7 @@ - true - b97b512f2c92c0ffe7a3476152525807daa1c676-1524213151782 - 1 + false Best BBB Developers Club Moodle @@ -90,6 +88,4 @@ Bigbluebutton "Mock meeting for testing getMeetingInfo" - - \ No newline at end of file diff --git a/tests/fixtures/get_meeting_info_breakout_room.xml b/tests/fixtures/get_meeting_info_breakout_room.xml new file mode 100644 index 00000000..87a97a9f --- /dev/null +++ b/tests/fixtures/get_meeting_info_breakout_room.xml @@ -0,0 +1,94 @@ + + + SUCCESS + Mock meeting for testing getMeetingInfo API method + 117b12ae2656972d330b6bad58878541-28-15 + 178757fcedd9449054536162cdfe861ddebc70ba-1453206317376 + 1453206317376 + Tue Jan 19 07:25:17 EST 2016 + 70100 + 613-555-1234 + dbfc7207321527bbb870c82028 + 4bfbbeeb4a65cacaefe3676633 + true + 20 + true + true + false + 1453206317380 + 1453206325002 + 2 + 1 + 2 + 1 + 20 + 2 + + + amslzbgzzddp + Ernie Abernathy + MODERATOR + true + false + true + true + HTML5 + + + + xi7y7gpmyq1g + Barrett Kutch + MODERATOR + false + false + true + false + FLASH + + true + #FF0033 + a:focus{color:#0181eb} + + + + srfd2uad4x9s + Peter Parker + VIEWER + false + false + true + true + HTML5 + + + + 6ntb564ibhnq + Bruce Wayne + VIEWER + false + true + false + false + HTML5 + + + + true + ParentMeetingId + 1 + false + + Best BBB Developers Club + Moodle + + http://bigbluebutton.org/moodle/mod/bigbluebuttonbn/bbb_broker.php?action=recording_ready + + moodle-mod_bigbluebuttonbn (2015080609) + 3.0.2 (Build: 20160111) + + bigbluebutton.org + + Bigbluebutton "Mock meeting for testing getMeetingInfo" + + + \ No newline at end of file diff --git a/tests/fixtures/get_meeting_info_with_breakout_rooms.xml b/tests/fixtures/get_meeting_info_with_breakout_rooms.xml new file mode 100644 index 00000000..54e8003d --- /dev/null +++ b/tests/fixtures/get_meeting_info_with_breakout_rooms.xml @@ -0,0 +1,96 @@ + + + SUCCESS + Mock meeting for testing getMeetingInfo API method + 117b12ae2656972d330b6bad58878541-28-15 + 178757fcedd9449054536162cdfe861ddebc70ba-1453206317376 + 1453206317376 + Tue Jan 19 07:25:17 EST 2016 + 70100 + 613-555-1234 + dbfc7207321527bbb870c82028 + 4bfbbeeb4a65cacaefe3676633 + true + 20 + true + true + false + 1453206317380 + 1453206325002 + 2 + 1 + 2 + 1 + 20 + 2 + + + amslzbgzzddp + Ernie Abernathy + MODERATOR + true + false + true + true + HTML5 + + + + xi7y7gpmyq1g + Barrett Kutch + MODERATOR + false + false + true + false + FLASH + + true + #FF0033 + a:focus{color:#0181eb} + + + + srfd2uad4x9s + Peter Parker + VIEWER + false + false + true + true + HTML5 + + + + 6ntb564ibhnq + Bruce Wayne + VIEWER + false + true + false + false + HTML5 + + + + false + + breakout-room-id-1 + breakout-room-id-2 + breakout-room-id-3 + + + Best BBB Developers Club + Moodle + + http://bigbluebutton.org/moodle/mod/bigbluebuttonbn/bbb_broker.php?action=recording_ready + + moodle-mod_bigbluebuttonbn (2015080609) + 3.0.2 (Build: 20160111) + + bigbluebutton.org + + Bigbluebutton "Mock meeting for testing getMeetingInfo" + + + \ No newline at end of file diff --git a/tests/fixtures/get_meetings.xml b/tests/fixtures/get_meetings.xml index 39a8afe4..adde2a46 100644 --- a/tests/fixtures/get_meetings.xml +++ b/tests/fixtures/get_meetings.xml @@ -61,7 +61,10 @@ Prof. Maud Corkery II http://www.hegmann.biz/explicabo-praesentium-labore-dolor - false + true + ParentMeetingId + 1 + false Marty Lueilwitz @@ -93,6 +96,11 @@ http://www.muller.biz/autem-dolor-aut-nam-doloribus-molestiae false + + breakout-room-id-1 + breakout-room-id-2 + breakout-room-id-3 + \ No newline at end of file From 500ef3b486f7fa0a28244bcf3648cf440a48976c Mon Sep 17 00:00:00 2001 From: Tim Korn Date: Mon, 22 Apr 2024 17:20:33 +0100 Subject: [PATCH 2/5] finalize test of fixtures --- src/Parameters/DocumentableTrait.php | 30 + tests/BigBlueButtonTest.php | 4 +- .../CreateMeetingParametersTest.php | 14 +- .../InsertDocumentParametersTest.php | 27 +- tests/Responses/HooksCreateResponseTest.php | 71 +- tests/Responses/HooksDestroyResponseTest.php | 52 +- tests/TestServices/Fixtures.php | 9 +- tests/Util/FixturesTest.php | 747 +++++++++++------- tests/fixtures/hooks_destroy_params_no_id.xml | 5 - tests/fixtures/{ => images}/bbb_logo.png | Bin .../insert_document_presentations.xml | 8 - tests/fixtures/presentation_with_filename.xml | 6 - .../insert_document_presentations.xml | 9 + .../presentation_with_embedded_file.xml | 0 .../requests/presentation_with_filename.xml | 6 + .../{ => requests}/presentation_with_url.xml | 2 +- .../fixtures/{ => responses}/api_version.xml | 0 .../{ => responses}/create_meeting.xml | 0 .../{ => responses}/delete_recordings.xml | 0 .../fixtures/{ => responses}/end_meeting.xml | 0 .../{ => responses}/get_meeting_info.xml | 0 .../get_meeting_info_breakout_room.xml | 11 - .../get_meeting_info_with_breakout_rooms.xml | 14 +- .../fixtures/{ => responses}/get_meetings.xml | 0 .../get_recording_text_tracks.json | 0 .../{ => responses}/get_recordings.xml | 0 .../fixtures/{ => responses}/hooks_create.xml | 0 .../{ => responses}/hooks_create_existing.xml | 0 .../hooks_create_failed_error.xml} | 0 .../{ => responses}/hooks_destroy.xml | 0 .../hooks_destroy_failed_error.xml} | 0 .../hooks_destroy_failed_no_id.xml} | 0 .../hooks_destroy_failed_not_found.xml} | 0 tests/fixtures/{ => responses}/hooks_list.xml | 0 .../{ => responses}/insert_document.xml | 0 .../{ => responses}/is_meeting_running.xml | 0 .../fixtures/{ => responses}/join_meeting.xml | 0 .../{ => responses}/publish_recordings.xml | 0 .../put_recording_text_track_success.json | 0 .../{ => responses}/update_recordings.xml | 0 40 files changed, 596 insertions(+), 419 deletions(-) delete mode 100644 tests/fixtures/hooks_destroy_params_no_id.xml rename tests/fixtures/{ => images}/bbb_logo.png (100%) delete mode 100644 tests/fixtures/insert_document_presentations.xml delete mode 100644 tests/fixtures/presentation_with_filename.xml create mode 100644 tests/fixtures/requests/insert_document_presentations.xml rename tests/fixtures/{ => requests}/presentation_with_embedded_file.xml (100%) create mode 100644 tests/fixtures/requests/presentation_with_filename.xml rename tests/fixtures/{ => requests}/presentation_with_url.xml (56%) rename tests/fixtures/{ => responses}/api_version.xml (100%) rename tests/fixtures/{ => responses}/create_meeting.xml (100%) rename tests/fixtures/{ => responses}/delete_recordings.xml (100%) rename tests/fixtures/{ => responses}/end_meeting.xml (100%) rename tests/fixtures/{ => responses}/get_meeting_info.xml (100%) rename tests/fixtures/{ => responses}/get_meeting_info_breakout_room.xml (81%) rename tests/fixtures/{ => responses}/get_meeting_info_with_breakout_rooms.xml (80%) rename tests/fixtures/{ => responses}/get_meetings.xml (100%) rename tests/fixtures/{ => responses}/get_recording_text_tracks.json (100%) rename tests/fixtures/{ => responses}/get_recordings.xml (100%) rename tests/fixtures/{ => responses}/hooks_create.xml (100%) rename tests/fixtures/{ => responses}/hooks_create_existing.xml (100%) rename tests/fixtures/{hooks_create_error.xml => responses/hooks_create_failed_error.xml} (100%) rename tests/fixtures/{ => responses}/hooks_destroy.xml (100%) rename tests/fixtures/{hooks_destroy_error.xml => responses/hooks_destroy_failed_error.xml} (100%) rename tests/fixtures/{hooks_create_no_hook_id.xml => responses/hooks_destroy_failed_no_id.xml} (100%) rename tests/fixtures/{hooks_destroy_not_found.xml => responses/hooks_destroy_failed_not_found.xml} (100%) rename tests/fixtures/{ => responses}/hooks_list.xml (100%) rename tests/fixtures/{ => responses}/insert_document.xml (100%) rename tests/fixtures/{ => responses}/is_meeting_running.xml (100%) rename tests/fixtures/{ => responses}/join_meeting.xml (100%) rename tests/fixtures/{ => responses}/publish_recordings.xml (100%) rename tests/fixtures/{ => responses}/put_recording_text_track_success.json (100%) rename tests/fixtures/{ => responses}/update_recordings.xml (100%) diff --git a/src/Parameters/DocumentableTrait.php b/src/Parameters/DocumentableTrait.php index 8fc08de2..5cb7c2fc 100644 --- a/src/Parameters/DocumentableTrait.php +++ b/src/Parameters/DocumentableTrait.php @@ -20,6 +20,8 @@ namespace BigBlueButton\Parameters; +use Tracy\Debugger; + trait DocumentableTrait { /** @@ -37,10 +39,18 @@ public function getPresentations(): array /** * @param mixed $content + * @throws \Exception */ public function addPresentation(string $nameOrUrl, $content = null, ?string $filename = null): self { if (!$filename) { + if (0 === mb_strpos($nameOrUrl, 'http')) { + $isExisting = $this->urlExists($nameOrUrl); + + if (!$isExisting) { + throw new \Exception('Resource not found: ' . $nameOrUrl); + } + } $this->presentations[$nameOrUrl] = !$content ?: base64_encode($content); } else { $this->presentations[$nameOrUrl] = $filename; @@ -80,4 +90,24 @@ public function getPresentationsAsXML(): string return $result; } + + private function urlExists(string $url): bool + { + $ch = curl_init($url); + + curl_setopt($ch, CURLOPT_TIMEOUT, 5); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + $data = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + + curl_close($ch); + + if ($httpCode >= 200 && $httpCode < 400) { + return true; + } + + return false; + } } diff --git a/tests/BigBlueButtonTest.php b/tests/BigBlueButtonTest.php index 57799876..4ba686b3 100644 --- a/tests/BigBlueButtonTest.php +++ b/tests/BigBlueButtonTest.php @@ -151,7 +151,7 @@ public function testCreateMeetingWithDocumentEmbedded(): void { $params = Fixtures::getCreateMeetingParametersMock(Fixtures::generateCreateParams()); - $params->addPresentation('bbb_logo.png', file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR . 'bbb_logo.png')); + $params->addPresentation('bbb_logo.png', file_get_contents(Fixtures::IMAGE_PATH . 'bbb_logo.png')); $result = $this->bbb->createMeeting($params); @@ -167,7 +167,7 @@ public function testCreateMeetingWithMultiDocument(): void { $params = Fixtures::getCreateMeetingParametersMock(Fixtures::generateCreateParams()); $params->addPresentation('https://picsum.photos/3840/2160/?random', null, 'presentation.png'); - $params->addPresentation('logo.png', file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR . 'bbb_logo.png')); + $params->addPresentation('logo.png', file_get_contents(Fixtures::IMAGE_PATH . 'bbb_logo.png')); $result = $this->bbb->createMeeting($params); diff --git a/tests/Parameters/CreateMeetingParametersTest.php b/tests/Parameters/CreateMeetingParametersTest.php index b58566b6..17250350 100644 --- a/tests/Parameters/CreateMeetingParametersTest.php +++ b/tests/Parameters/CreateMeetingParametersTest.php @@ -22,6 +22,7 @@ use BigBlueButton\TestCase; use BigBlueButton\TestServices\Fixtures; +use function PHPUnit\Framework\assertEquals; /** * Class CreateMeetingParametersTest. @@ -132,21 +133,22 @@ public function testCreateBreakoutMeeting(): void public function testGetPresentationsAsXMLWithUrl(): void { $createMeetingParams = Fixtures::getCreateMeetingParametersMock(Fixtures::generateCreateParams()); - $createMeetingParams->addPresentation('http://test-install.blindsidenetworks.com/default.pdf'); - $this->assertXmlStringEqualsXmlFile(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR . 'presentation_with_url.xml', $createMeetingParams->getPresentationsAsXML()); + $createMeetingParams->addPresentation('https://test-install.blindsidenetworks.com/default.pdf'); + $this->assertXmlStringEqualsXmlFile(Fixtures::REQUEST_PATH . 'presentation_with_url.xml', $createMeetingParams->getPresentationsAsXML()); } public function testGetPresentationsAsXMLWithUrlAndFilename(): void { $createMeetingParams = Fixtures::getCreateMeetingParametersMock(Fixtures::generateCreateParams()); - $createMeetingParams->addPresentation('http://test-install.blindsidenetworks.com/default.pdf', null, 'presentation.pdf'); - $this->assertXmlStringEqualsXmlFile(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR . 'presentation_with_filename.xml', $createMeetingParams->getPresentationsAsXML()); + $createMeetingParams->addPresentation('https://test-install.blindsidenetworks.com/default.pdf', null, 'presentation.pdf'); + $this->assertXmlStringEqualsXmlFile(Fixtures::REQUEST_PATH . 'presentation_with_filename.xml', $createMeetingParams->getPresentationsAsXML()); } public function testGetPresentationsAsXMLWithFile(): void { $createMeetingParams = Fixtures::getCreateMeetingParametersMock(Fixtures::generateCreateParams()); - $createMeetingParams->addPresentation('bbb_logo.png', file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR . 'bbb_logo.png')); - $this->assertXmlStringEqualsXmlFile(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR . 'presentation_with_embedded_file.xml', $createMeetingParams->getPresentationsAsXML()); + $createMeetingParams->addPresentation('bbb_logo.png', file_get_contents(Fixtures::IMAGE_PATH . 'bbb_logo.png')); + + $this->assertXmlStringEqualsXmlFile(Fixtures::REQUEST_PATH . 'presentation_with_embedded_file.xml', $createMeetingParams->getPresentationsAsXML()); } } diff --git a/tests/Parameters/InsertDocumentParametersTest.php b/tests/Parameters/InsertDocumentParametersTest.php index d15e3cca..873235d9 100644 --- a/tests/Parameters/InsertDocumentParametersTest.php +++ b/tests/Parameters/InsertDocumentParametersTest.php @@ -23,6 +23,7 @@ namespace BigBlueButton\Parameters; use BigBlueButton\TestCase; +use BigBlueButton\TestServices\Fixtures; /** * @internal @@ -31,15 +32,21 @@ final class InsertDocumentParametersTest extends TestCase { public function testInsertDocumentParameters(): void { - $meetingId = $this->faker->uuid; - $params = new InsertDocumentParameters($meetingId); - - $params->addPresentation('https://demo.bigbluebutton.org/biglbuebutton.png'); - $params->addPresentation('https://demo.bigbluebutton.org/biglbuebutton.pdf'); - $params->addPresentation('https://demo.bigbluebutton.org/biglbuebutton.svg'); - - $this->assertEquals($meetingId, $params->getMeetingID()); - - $this->assertXmlStringEqualsXmlFile(dirname(__DIR__) . \DIRECTORY_SEPARATOR . 'fixtures' . \DIRECTORY_SEPARATOR . 'insert_document_presentations.xml', $params->getPresentationsAsXML()); + $meetingId = $this->faker->uuid; + $insertDocumentParameters = new InsertDocumentParameters($meetingId); + + $insertDocumentParameters + ->addPresentation('https://freetestdata.com/wp-content/uploads/2021/09/Free_Test_Data_100KB_PDF.pdf') + ->addPresentation('https://freetestdata.com/wp-content/uploads/2022/02/Free_Test_Data_117KB_JPG.jpg') + ->addPresentation('https://freetestdata.com/wp-content/uploads/2021/09/500kb.png') + ->addPresentation('https://freetestdata.com/wp-content/uploads/2021/09/1.svg') + ; + + $this->assertEquals($meetingId, $insertDocumentParameters->getMeetingID()); + + $this->assertXmlStringEqualsXmlFile( + Fixtures::REQUEST_PATH . 'insert_document_presentations.xml', + $insertDocumentParameters->getPresentationsAsXML() + ); } } diff --git a/tests/Responses/HooksCreateResponseTest.php b/tests/Responses/HooksCreateResponseTest.php index df9cc097..89c0400f 100644 --- a/tests/Responses/HooksCreateResponseTest.php +++ b/tests/Responses/HooksCreateResponseTest.php @@ -29,9 +29,8 @@ class HooksCreateResponseTest extends TestCase { private HooksCreateResponse $createResponseCreate; - private HooksCreateResponse $createResponseError; - private HooksCreateResponse $createResponseExisting; - private HooksCreateResponse $createResponseNoHookId; + private HooksCreateResponse $createResponseFailedError; + private HooksCreateResponse $createResponseCreateExisting; public function setUp(): void { @@ -39,15 +38,13 @@ public function setUp(): void $fixtures = new Fixtures(); - $xmlCreate = $fixtures->fromXmlFile('hooks_create.xml'); - $xmlCreateError = $fixtures->fromXmlFile('hooks_create_error.xml'); - $xmlCreateExisting = $fixtures->fromXmlFile('hooks_create_existing.xml'); - $xmlCreateNoHookId = $fixtures->fromXmlFile('hooks_create_no_hook_id.xml'); + $xmlCreate = $fixtures->fromXmlFile('hooks_create.xml'); + $xmlCreateExisting = $fixtures->fromXmlFile('hooks_create_existing.xml'); + $xmlCreateFailedError = $fixtures->fromXmlFile('hooks_create_failed_error.xml'); - $this->createResponseCreate = new HooksCreateResponse($xmlCreate); - $this->createResponseError = new HooksCreateResponse($xmlCreateError); - $this->createResponseExisting = new HooksCreateResponse($xmlCreateExisting); - $this->createResponseNoHookId = new HooksCreateResponse($xmlCreateNoHookId); + $this->createResponseCreate = new HooksCreateResponse($xmlCreate); + $this->createResponseCreateExisting = new HooksCreateResponse($xmlCreateExisting); + $this->createResponseFailedError = new HooksCreateResponse($xmlCreateFailedError); } public function testHooksCreateResponseCreateContent(): void @@ -63,35 +60,24 @@ public function testHooksCreateResponseCreateContent(): void public function testHooksCreateResponseErrorContent(): void { - $this->assertEquals('FAILED', $this->createResponseError->getReturnCode()); - $this->assertEquals('createHookError', $this->createResponseError->getMessageKey()); - $this->assertFalse($this->createResponseError->success()); - $this->assertTrue($this->createResponseError->failed()); - $this->assertNull($this->createResponseError->getHookId()); - $this->assertNull($this->createResponseError->isPermanentHook()); - $this->assertNull($this->createResponseError->hasRawData()); + $this->assertEquals('FAILED', $this->createResponseFailedError->getReturnCode()); + $this->assertEquals('createHookError', $this->createResponseFailedError->getMessageKey()); + $this->assertFalse($this->createResponseFailedError->success()); + $this->assertTrue($this->createResponseFailedError->failed()); + $this->assertNull($this->createResponseFailedError->getHookId()); + $this->assertNull($this->createResponseFailedError->isPermanentHook()); + $this->assertNull($this->createResponseFailedError->hasRawData()); } public function testHooksCreateResponseExistingContent(): void { - $this->assertEquals('SUCCESS', $this->createResponseExisting->getReturnCode()); - $this->assertEquals('duplicateWarning', $this->createResponseExisting->getMessageKey()); - $this->assertTrue($this->createResponseExisting->success()); - $this->assertFalse($this->createResponseExisting->failed()); - $this->assertEquals(1, $this->createResponseExisting->getHookId()); - $this->assertNull($this->createResponseExisting->isPermanentHook()); - $this->assertNull($this->createResponseExisting->hasRawData()); - } - - public function testHooksCreateResponseNoHookIdContent(): void - { - $this->assertEquals('FAILED', $this->createResponseNoHookId->getReturnCode()); - $this->assertEquals('missingParamHookID', $this->createResponseNoHookId->getMessageKey()); - $this->assertFalse($this->createResponseNoHookId->success()); - $this->assertTrue($this->createResponseNoHookId->failed()); - $this->assertNull($this->createResponseNoHookId->getHookId()); - $this->assertNull($this->createResponseNoHookId->isPermanentHook()); - $this->assertNull($this->createResponseNoHookId->hasRawData()); + $this->assertEquals('SUCCESS', $this->createResponseCreateExisting->getReturnCode()); + $this->assertEquals('duplicateWarning', $this->createResponseCreateExisting->getMessageKey()); + $this->assertTrue($this->createResponseCreateExisting->success()); + $this->assertFalse($this->createResponseCreateExisting->failed()); + $this->assertEquals(1, $this->createResponseCreateExisting->getHookId()); + $this->assertNull($this->createResponseCreateExisting->isPermanentHook()); + $this->assertNull($this->createResponseCreateExisting->hasRawData()); } public function testHooksCreateResponseTypes(): void @@ -100,14 +86,11 @@ public function testHooksCreateResponseTypes(): void $this->assertEachGetterValueIsInteger($this->createResponseCreate, ['getHookId']); $this->assertEachGetterValueIsBoolean($this->createResponseCreate, ['isPermanentHook', 'hasRawData']); - $this->assertEachGetterValueIsString($this->createResponseError, ['getReturnCode']); - $this->assertEachGetterValueIsNull($this->createResponseError, ['getHookId', 'isPermanentHook', 'hasRawData']); - - $this->assertEachGetterValueIsString($this->createResponseExisting, ['getReturnCode']); - $this->assertEachGetterValueIsInteger($this->createResponseExisting, ['getHookId']); - $this->assertEachGetterValueIsNull($this->createResponseExisting, ['isPermanentHook', 'hasRawData']); + $this->assertEachGetterValueIsString($this->createResponseFailedError, ['getReturnCode']); + $this->assertEachGetterValueIsNull($this->createResponseFailedError, ['getHookId', 'isPermanentHook', 'hasRawData']); - $this->assertEachGetterValueIsString($this->createResponseNoHookId, ['getReturnCode']); - $this->assertEachGetterValueIsNull($this->createResponseNoHookId, ['getHookId', 'isPermanentHook', 'hasRawData']); + $this->assertEachGetterValueIsString($this->createResponseCreateExisting, ['getReturnCode']); + $this->assertEachGetterValueIsInteger($this->createResponseCreateExisting, ['getHookId']); + $this->assertEachGetterValueIsNull($this->createResponseCreateExisting, ['isPermanentHook', 'hasRawData']); } } diff --git a/tests/Responses/HooksDestroyResponseTest.php b/tests/Responses/HooksDestroyResponseTest.php index 70593468..46f6a512 100644 --- a/tests/Responses/HooksDestroyResponseTest.php +++ b/tests/Responses/HooksDestroyResponseTest.php @@ -29,9 +29,9 @@ class HooksDestroyResponseTest extends TestCase { private HooksDestroyResponse $destroyResponse; - private HooksDestroyResponse $destroyResponseError; - private HooksDestroyResponse $destroyResponseNotFound; - private HooksDestroyResponse $destroyResponseParamsNoId; + private HooksDestroyResponse $destroyResponseFailedError; + private HooksDestroyResponse $destroyResponseFailedNotFound; + private HooksDestroyResponse $destroyResponseFailedNoId; public function setUp(): void { @@ -39,15 +39,15 @@ public function setUp(): void $fixtures = new Fixtures(); - $xml = $fixtures->fromXmlFile('hooks_destroy.xml'); - $xmlError = $fixtures->fromXmlFile('hooks_destroy_error.xml'); - $xmlNotFound = $fixtures->fromXmlFile('hooks_destroy_not_found.xml'); - $xmlParamsNoId = $fixtures->fromXmlFile('hooks_destroy_params_no_id.xml'); + $xml = $fixtures->fromXmlFile('hooks_destroy.xml'); + $xmlFailedError = $fixtures->fromXmlFile('hooks_destroy_failed_error.xml'); + $xmlFailedNoId = $fixtures->fromXmlFile('hooks_destroy_failed_no_id.xml'); + $xmlFailedNotFound = $fixtures->fromXmlFile('hooks_destroy_failed_not_found.xml'); - $this->destroyResponse = new HooksDestroyResponse($xml); - $this->destroyResponseError = new HooksDestroyResponse($xmlError); - $this->destroyResponseNotFound = new HooksDestroyResponse($xmlNotFound); - $this->destroyResponseParamsNoId = new HooksDestroyResponse($xmlParamsNoId); + $this->destroyResponse = new HooksDestroyResponse($xml); + $this->destroyResponseFailedError = new HooksDestroyResponse($xmlFailedError); + $this->destroyResponseFailedNoId = new HooksDestroyResponse($xmlFailedNoId); + $this->destroyResponseFailedNotFound = new HooksDestroyResponse($xmlFailedNotFound); } public function testHooksDestroyResponseContent(): void @@ -59,23 +59,23 @@ public function testHooksDestroyResponseContent(): void public function testHooksDestroyErrorResponseContent(): void { - $this->assertEquals('FAILED', $this->destroyResponseError->getReturnCode()); - $this->assertEquals('destroyHookError', $this->destroyResponseError->getMessageKey()); - $this->assertNull($this->destroyResponseError->removed()); + $this->assertEquals('FAILED', $this->destroyResponseFailedError->getReturnCode()); + $this->assertEquals('destroyHookError', $this->destroyResponseFailedError->getMessageKey()); + $this->assertNull($this->destroyResponseFailedError->removed()); } public function testHooksDestroyNotFoundResponseContent(): void { - $this->assertEquals('FAILED', $this->destroyResponseNotFound->getReturnCode()); - $this->assertEquals('destroyMissingHook', $this->destroyResponseNotFound->getMessageKey()); - $this->assertNull($this->destroyResponseNotFound->removed()); + $this->assertEquals('FAILED', $this->destroyResponseFailedNotFound->getReturnCode()); + $this->assertEquals('destroyMissingHook', $this->destroyResponseFailedNotFound->getMessageKey()); + $this->assertNull($this->destroyResponseFailedNotFound->removed()); } public function testHooksDestroyParamsNoIdContent(): void { - $this->assertEquals('FAILED', $this->destroyResponseParamsNoId->getReturnCode()); - $this->assertEquals('missingParamHookID', $this->destroyResponseParamsNoId->getMessageKey()); - $this->assertNull($this->destroyResponseParamsNoId->removed()); + $this->assertEquals('FAILED', $this->destroyResponseFailedNoId->getReturnCode()); + $this->assertEquals('missingParamHookID', $this->destroyResponseFailedNoId->getMessageKey()); + $this->assertNull($this->destroyResponseFailedNoId->removed()); } public function testHooksDestroyResponseTypes(): void @@ -83,13 +83,13 @@ public function testHooksDestroyResponseTypes(): void $this->assertEachGetterValueIsString($this->destroyResponse, ['getReturnCode']); $this->assertEachGetterValueIsBoolean($this->destroyResponse, ['removed']); - $this->assertEachGetterValueIsString($this->destroyResponseError, ['getReturnCode']); - $this->assertEachGetterValueIsNull($this->destroyResponseError, ['removed']); + $this->assertEachGetterValueIsString($this->destroyResponseFailedError, ['getReturnCode']); + $this->assertEachGetterValueIsNull($this->destroyResponseFailedError, ['removed']); - $this->assertEachGetterValueIsString($this->destroyResponseNotFound, ['getReturnCode']); - $this->assertEachGetterValueIsNull($this->destroyResponseNotFound, ['removed']); + $this->assertEachGetterValueIsString($this->destroyResponseFailedNotFound, ['getReturnCode']); + $this->assertEachGetterValueIsNull($this->destroyResponseFailedNotFound, ['removed']); - $this->assertEachGetterValueIsString($this->destroyResponseParamsNoId, ['getReturnCode']); - $this->assertEachGetterValueIsNull($this->destroyResponseParamsNoId, ['removed']); + $this->assertEachGetterValueIsString($this->destroyResponseFailedNoId, ['getReturnCode']); + $this->assertEachGetterValueIsNull($this->destroyResponseFailedNoId, ['removed']); } } diff --git a/tests/TestServices/Fixtures.php b/tests/TestServices/Fixtures.php index 7040803f..f1205db7 100644 --- a/tests/TestServices/Fixtures.php +++ b/tests/TestServices/Fixtures.php @@ -32,12 +32,15 @@ class Fixtures { - public const PATH = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR; + public const RESPONSE_PATH = self::BASE_PATH . 'responses' . DIRECTORY_SEPARATOR; + public const REQUEST_PATH = self::BASE_PATH . 'requests' . DIRECTORY_SEPARATOR; + public const IMAGE_PATH = self::BASE_PATH . 'images' . DIRECTORY_SEPARATOR; + private const BASE_PATH = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR; // LOADERS --------------------------------------------------------------------------------------------------------- public static function fromXmlFile(string $filename): \SimpleXMLElement { - $uri = self::PATH . $filename; + $uri = self::RESPONSE_PATH . DIRECTORY_SEPARATOR . $filename; if (!file_exists($uri)) { throw new \RuntimeException("File '{$uri}' not found."); @@ -60,7 +63,7 @@ public static function fromXmlFile(string $filename): \SimpleXMLElement public static function fromJsonFile(string $filename): string { - $uri = self::PATH . $filename; + $uri = self::BASE_PATH . 'responses' . DIRECTORY_SEPARATOR . $filename; if (!file_exists($uri)) { throw new \RuntimeException("File '{$uri}' not found."); diff --git a/tests/Util/FixturesTest.php b/tests/Util/FixturesTest.php index c9af7f3d..a2d62baf 100644 --- a/tests/Util/FixturesTest.php +++ b/tests/Util/FixturesTest.php @@ -21,16 +21,19 @@ namespace BigBlueButton\Util; use BigBlueButton\BigBlueButton; -use BigBlueButton\Enum\GuestPolicy; +use BigBlueButton\Core\Hook; use BigBlueButton\Enum\Role; use BigBlueButton\Parameters\CreateMeetingParameters; use BigBlueButton\Parameters\EndMeetingParameters; use BigBlueButton\Parameters\GetMeetingInfoParameters; use BigBlueButton\Parameters\HooksCreateParameters; +use BigBlueButton\Parameters\HooksDestroyParameters; +use BigBlueButton\Parameters\InsertDocumentParameters; use BigBlueButton\Parameters\IsMeetingRunningParameters; use BigBlueButton\Parameters\JoinMeetingParameters; use BigBlueButton\Responses\BaseResponse; -use BigBlueButton\Responses\CreateMeetingResponse; +use BigBlueButton\TestServices\EnvLoader; +use BigBlueButton\TestServices\Fixtures; use Faker\Factory as Faker; use PHPUnit\Framework\TestCase; use Tracy\Debugger; @@ -40,9 +43,6 @@ */ class FixturesTest extends TestCase { - /** @var CreateMeetingResponse[] */ - private array $createMeetingResponseRepository = []; - private BigBlueButton $bbb; private Fixtures $fixtures; @@ -55,8 +55,9 @@ public function setUp(): void $this->bbb = new BigBlueButton(); $this->fixtures = new Fixtures(); - $this->closeAllMeetings(); // ensure server is clean (e.g. tearDown not executed due to a previous failed tests) - $this->prepareBbbServer(); + // ensure server is clean (e.g. tearDown() has not been executed due to a previous failed tests) + $this->closeAllMeetings(); + $this->destroyAllHooks(); } public function tearDown(): void @@ -64,178 +65,134 @@ public function tearDown(): void parent::tearDown(); $this->closeAllMeetings(); + $this->destroyAllHooks(); + } + + public function testCoverageOfFixtures(): void + { + // AS-IS: get all XML-file of the current test cases + $dataProvider = $this->xmlFileToFunctionMapping(); + $xmlFilenamesFromDataProvider = array_column($dataProvider, 'filename'); + + // TO-BE: get all XML-files of the fixtures-folder + $absolutePathnames = glob(Fixtures::RESPONSE_PATH . '*.xml'); + $xmlFilenamesFromFolder = array_map(function($absolutePathname) { + return basename($absolutePathname); + }, $absolutePathnames); + $xmlFilesThatAreNotTestable = [ + 'hooks_destroy_failed_no_id.xml', // because: It is mandatory to have an id in the destroy constructor + 'hooks_destroy_failed_error.xml', // because: No idea how to simulate this on a well configured BBB-Server + 'hooks_create_failed_error.xml', // because: No idea how to simulate this on a well configured BBB-Server + ]; + $xmlFilenamesFromFolderCleaned = array_diff($xmlFilenamesFromFolder, $xmlFilesThatAreNotTestable); + + // COMPARE AS-IS AND TO-BE + $diff = array_diff($xmlFilenamesFromFolderCleaned, $xmlFilenamesFromDataProvider); + + if (!empty($diff)) { + self::markTestIncomplete("Not all XML-fixtures are checked regarding correctness:\n - " . implode("\n - ", $diff)); + } } /** - * The purpose of this test is to determine whether the created fixture files still accurately reflect the + * Background: A lot of the tests rely on the correctness of the data in the fixture files. If the fixture + * files are wrong the tests are not accurate. + * + * The purpose of this test is to determine whether the created fixture files still reflect accurately the * response of the BBB-Server. It serves as an early indicator to determine if tests/functions need updates. * * @dataProvider xmlFileToFunctionMapping */ - public function testStructureOfFixturesIsStillUpToDate(string $requestFunction, string $filename, ?\Closure $getParameters): void + public function testStructureOfFixturesIsStillUpToDate(string $requestFunction, string $filename, bool $success, string $messageKey, ?\Closure $parameters): void { // get parameters by closure from data provider - $parameters = ($getParameters) ? $getParameters($this->createMeetingResponseRepository) : null; + $requestParameters = ($parameters) ? $parameters($this->bbb) : null; + // make the request and get the XML of the response /** @var BaseResponse $response */ - $response = $this->bbb->{$requestFunction}($parameters); - $xmlToBe = $this->fixtures->fromXmlFile($filename); + $response = $this->bbb->{$requestFunction}($requestParameters); $xmlAsIs = $response->getRawXml(); - $this->assertEquals('SUCCESS', $response->getReturnCode(), $response->getMessage()); - $this->assertTrue($response->success(), $response->getMessage()); + // load the XML of the fixture + $xmlToBe = $this->fixtures->fromXmlFile($filename); + + $this->assertEquals($success, $response->success()); + $this->assertEquals($messageKey, $response->getMessageKey()); $this->assertInstanceOf(\SimpleXMLElement::class, $xmlAsIs); $this->assertInstanceOf(\SimpleXMLElement::class, $xmlToBe); - $this->assertSameStructureOfXml($xmlToBe, $xmlAsIs); - } - - protected function closeAllMeetings(): void - { - foreach ($this->bbb->getMeetings()->getMeetings() as $meeting) { - $meetingId = $meeting->getInternalMeetingId(); - $endMeetingResponse = $this->bbb->endMeeting(new EndMeetingParameters($meetingId)); - self::assertEquals('SUCCESS', $endMeetingResponse->getReturnCode(), $endMeetingResponse->getMessage()); - self::assertTrue($endMeetingResponse->success()); - self::assertEquals('sentEndMeetingRequest', $endMeetingResponse->getMessageKey()); - } - } - private function assertSameStructureOfXml(\SimpleXMLElement $xml1, \SimpleXMLElement $xml2): void - { - $array1 = $this->getStructureOfXmlAsArray($xml1); - $array2 = $this->getStructureOfXmlAsArray($xml2); - - // Debugger::dump($xml1); - // Debugger::dump($xml2); - // Debugger::dump($array1); - // Debugger::dump($array2); - - $this->assertEqualsCanonicalizing($array1, $array2); - } - - /** - * Recursive function to flatten an array, which shall represent the structure of an - * element. For this, arrays that contain several children (= array with sequential - * numbers as keys) will get a list of unique attributes across all children. - */ - private function flattenArray(array $array, string $prefix = ''): array - { - $result = []; - - foreach ($array as $key => $value) { - $new_key = $prefix . (empty($prefix) ? '' : '.') . $key; - - // prepare value - if (is_array($value)) { - // a sequential array (= not associative) is understood as a group of - // similar children, thus their attributes should be similar. - if (!$this->isAssociativeArray($value)) { - // get a full collection of unique attributes within the group of children - $attributeCollection = []; - - foreach ($value as $child) { - if (!is_array($child)) { - continue; - } - - foreach ($child as $attributeKey => $attributeValue) { - if (!key_exists($attributeKey, $attributeCollection)) { - $attributeCollection[$attributeKey] = $attributeValue; - } - } - } - - $value = $attributeCollection; - } - } - - // compose result - if (is_array($value)) { - if (count($value) > 0) { - $result = array_merge($result, [$new_key => $value], $this->flattenArray($value, $new_key)); - } else { - $result[$new_key] = 'empty array'; // empty array - } - } else { - $result[$new_key] = $value; - } + /* + * There is a bug which prevent proper testing of the attendees. Once meetings are created on + * the server, you can join attendees, but by fetching the info of the meeting from the server + * the list of attendees is empty. So this needs to excluded temporary from the data that is + * coming from the fixture-files until that bug is solved. + * + * Remark: Once the bug is solved on the BBB-Server (= new Version), there must be a solution + * found to distinguish between versions prior and after the bug in order to keep the + * tests successful. + * + * @see https://github.com/bigbluebutton/bigbluebutton/issues/19767 + */ + if ( + 'get_meeting_info.xml' === $filename + || 'get_meeting_info_breakout_room.xml' === $filename + || 'get_meeting_info_with_breakout_rooms.xml' === $filename + ) { + unset($xmlToBe->attendees); // remove not empty node + $xmlToBe->addChild('attendees'); // add empty node } - return $result; + $this->assertSameStructureOfXml($xmlToBe, $xmlAsIs); } /** - * Function that helps to determine if an array is sequential or associative. + * The data provider for the test above. * - * Remark: With 8.1 function can be replaced with 'array_is_list'. + * @return array> */ - private function isAssociativeArray(array $array): bool - { - if (array_keys($array) === range(0, count($array) - 1)) { - return false; - } - - return true; - } - - private function getStructureOfXmlAsArray(\SimpleXMLElement $xml): array - { - // transform XML to ARRAY (via JSON) - $json = json_encode($xml); - $array = json_decode($json, true); - - // flatten multidimensional array to string-based hierarchic - $flattenArray = $this->flattenArray($array); - - // only the keys are needed - $keys = array_keys($flattenArray); - - // bring into order - sort($keys); - - return $keys; - } - - private function getChildrenOfXmlAsArray(\SimpleXMLElement $xml): array - { - $properties = []; - - foreach ($xml as $key => $value) { - $properties[] = $key; - } - - return $properties; - } - private function xmlFileToFunctionMapping(): array { return [ 'case01_api_version' => [ 'function' => 'getApiVersion', 'filename' => 'api_version.xml', + 'success' => true, + 'messageKey' => '', 'parameters' => null, ], 'case02_create_meeting' => [ 'function' => 'createMeeting', 'filename' => 'create_meeting.xml', - 'parameters' => function(array $creatMeetingResponses): CreateMeetingParameters { + 'success' => true, + 'messageKey' => '', + 'parameters' => function(BigBlueButton $bbb): CreateMeetingParameters { $faker = Faker::create(); + // create and return parameter for test $createMeetingParameters = new CreateMeetingParameters(); - return $createMeetingParameters->setMeetingId($faker->uuid)->setMeetingName('case02: ' . $faker->word); + return $createMeetingParameters + ->setMeetingId($faker->uuid) + ->setMeetingName('Meeting Room (case 02)') + ; }, ], 'case03_join_meeting' => [ 'function' => 'joinMeeting', 'filename' => 'join_meeting.xml', - 'parameters' => function(array $creatMeetingResponses): JoinMeetingParameters { + 'success' => true, + 'messageKey' => 'successfullyJoined', + 'parameters' => function(BigBlueButton $bbb): JoinMeetingParameters { $faker = Faker::create(); - $joinMeetingParameters = new JoinMeetingParameters(); + // arrange the BBB-server + $createMeetingParameters = new CreateMeetingParameters($faker->uuid, 'Meeting Room (case 03)'); + $createMeetingResponse = $bbb->createMeeting($createMeetingParameters); + self::assertTrue($createMeetingResponse->success()); + self::assertEquals('bbb-none', $createMeetingResponse->getParentMeetingId()); - /** @var CreateMeetingResponse $createMeetingResponse */ - $createMeetingResponse = $creatMeetingResponses['meeting_wo_breakout_rooms']; + // create and return parameter for test + $joinMeetingParameters = new JoinMeetingParameters(); return $joinMeetingParameters ->setMeetingId($createMeetingResponse->getMeetingId()) @@ -250,10 +207,18 @@ private function xmlFileToFunctionMapping(): array 'case04_end_meeting' => [ 'function' => 'endMeeting', 'filename' => 'end_meeting.xml', - 'parameters' => function(array $creatMeetingResponses): EndMeetingParameters { - /** @var CreateMeetingResponse $createMeetingResponse */ - $createMeetingResponse = $creatMeetingResponses['meeting_wo_breakout_rooms']; + 'success' => true, + 'messageKey' => 'sentEndMeetingRequest', + 'parameters' => function(BigBlueButton $bbb): EndMeetingParameters { + $faker = Faker::create(); + // arrange the BBB-server + $createMeetingParameters = new CreateMeetingParameters($faker->uuid, 'Meeting Room (case 04)'); + $createMeetingResponse = $bbb->createMeeting($createMeetingParameters); + self::assertTrue($createMeetingResponse->success()); + self::assertEquals('bbb-none', $createMeetingResponse->getParentMeetingId()); + + // create and return parameter for test $endMeetingParameters = new EndMeetingParameters(); return $endMeetingParameters->setMeetingId($createMeetingResponse->getMeetingId()); @@ -262,11 +227,19 @@ private function xmlFileToFunctionMapping(): array 'case05_is_meeting_running' => [ 'function' => 'isMeetingRunning', 'filename' => 'is_meeting_running.xml', - 'parameters' => function(array $creatMeetingResponses): IsMeetingRunningParameters { - $isMeetingRunningParameters = new IsMeetingRunningParameters(); + 'success' => true, + 'messageKey' => '', + 'parameters' => function(BigBlueButton $bbb): IsMeetingRunningParameters { + $faker = Faker::create(); + + // arrange the BBB-server + $createMeetingParameters = new CreateMeetingParameters($faker->uuid, 'Meeting Room (case 05)'); + $createMeetingResponse = $bbb->createMeeting($createMeetingParameters); + self::assertTrue($createMeetingResponse->success()); + self::assertEquals('bbb-none', $createMeetingResponse->getParentMeetingId()); - /** @var CreateMeetingResponse $createMeetingResponse */ - $createMeetingResponse = $creatMeetingResponses['meeting_wo_breakout_rooms']; + // create and return parameter for test + $isMeetingRunningParameters = new IsMeetingRunningParameters(); return $isMeetingRunningParameters->setMeetingId($createMeetingResponse->getMeetingId()); }, @@ -274,16 +247,66 @@ private function xmlFileToFunctionMapping(): array 'case06_list_of_meetings' => [ 'function' => 'getMeetings', 'filename' => 'get_meetings.xml', - 'parameters' => null, + 'success' => true, + 'messageKey' => '', + 'parameters' => function(BigBlueButton $bbb): void { + $faker = Faker::create(); + + // arrange the BBB-server + + // create meeting room + $createMeetingParametersParent = new CreateMeetingParameters($faker->uuid, 'Meeting Room 1 (case 06)'); + $createMeetingParametersParent + ->addMeta('endcallbackurl', $faker->url) + ->addMeta('presenter', $faker->name) + ; + $createMeetingResponseParent = $bbb->createMeeting($createMeetingParametersParent); + self::assertTrue($createMeetingResponseParent->success()); + self::assertEquals('bbb-none', $createMeetingResponseParent->getParentMeetingId()); + + // create breakout room + $createMeetingParametersChild = new CreateMeetingParameters($faker->uuid, 'Breakout Room (case 06)'); + $createMeetingParametersChild + ->addMeta('endcallbackurl', $faker->url) + ->addMeta('presenter', $faker->name) + ; + $createMeetingParametersChild->setParentMeetingId($createMeetingResponseParent->getMeetingId())->setBreakout(true)->setSequence(1); + $createMeetingResponseChild = $bbb->createMeeting($createMeetingParametersChild); + self::assertTrue($createMeetingResponseChild->success(), $createMeetingResponseChild->getMessage()); + self::assertEquals('', $createMeetingResponseChild->getMessage()); + self::assertNotEquals('bbb-none', $createMeetingResponseChild->getParentMeetingId()); + self::assertEquals($createMeetingResponseParent->getInternalMeetingId(), $createMeetingResponseChild->getParentMeetingId()); + }, ], 'case07_meeting_info_of_meeting_without_breakout_rooms' => [ 'function' => 'getMeetingInfo', 'filename' => 'get_meeting_info.xml', - 'parameters' => function(array $creatMeetingResponses): GetMeetingInfoParameters { - $getMeetingInfoParameters = new GetMeetingInfoParameters(); + 'success' => true, + 'messageKey' => '', + 'parameters' => function(BigBlueButton $bbb): GetMeetingInfoParameters { + $faker = Faker::create(); - /** @var CreateMeetingResponse $createMeetingResponse */ - $createMeetingResponse = $creatMeetingResponses['meeting_wo_breakout_rooms']; + // arrange the BBB-server + $createMeetingParameters = new CreateMeetingParameters($faker->uuid, 'Meeting Room 1 (case 07)'); + $createMeetingParameters + ->addMeta('bbb-context', $faker->word) + ->addMeta('bbb-origin-server-common-name', $faker->word) + ->addMeta('bbb-origin-server-name', $faker->word) + ->addMeta('bbb-origin-tag', $faker->word) + ->addMeta('bbb-origin-version', $faker->word) + ->addMeta('bbb-recording-description', $faker->word) + ->addMeta('bbb-recording-name', $faker->word) + ->addMeta('bbb-recording-tags', $faker->word) + ->addMeta('bn-origin', $faker->word) + ->addMeta('bn-recording-ready-url', $faker->word) + ; + + $createMeetingResponse = $bbb->createMeeting($createMeetingParameters); + self::assertTrue($createMeetingResponse->success()); + self::assertEquals('bbb-none', $createMeetingResponse->getParentMeetingId()); + + // create and return parameter for test + $getMeetingInfoParameters = new GetMeetingInfoParameters(); return $getMeetingInfoParameters->setMeetingId($createMeetingResponse->getMeetingId()); }, @@ -291,174 +314,328 @@ private function xmlFileToFunctionMapping(): array 'case08_meeting_info_of_breakout_room' => [ 'function' => 'getMeetingInfo', 'filename' => 'get_meeting_info_breakout_room.xml', - 'parameters' => function(array $creatMeetingResponses): GetMeetingInfoParameters { - $getMeetingInfoParameters = new GetMeetingInfoParameters(); + 'success' => true, + 'messageKey' => '', + 'parameters' => function(BigBlueButton $bbb): GetMeetingInfoParameters { + $faker = Faker::create(); - /** @var CreateMeetingResponse $createMeetingResponse */ - $createMeetingResponse = $creatMeetingResponses['breakout_room_A']; + // create meeting room + $createMeetingParametersParent = new CreateMeetingParameters($faker->uuid, 'Meeting Room 1 (case 08)'); + $createMeetingResponseParent = $bbb->createMeeting($createMeetingParametersParent); + self::assertTrue($createMeetingResponseParent->success()); + self::assertEquals('bbb-none', $createMeetingResponseParent->getParentMeetingId()); + + // create breakout room + $createMeetingParametersChild = new CreateMeetingParameters($faker->uuid, 'Breakout Room (case 08)'); + $createMeetingParametersChild + ->addMeta('bbb-context', $faker->word) + ->setParentMeetingId($createMeetingResponseParent->getMeetingId()) + ->setBreakout(true) + ->setSequence(1) + ; + $createMeetingResponseChild = $bbb->createMeeting($createMeetingParametersChild); + self::assertTrue($createMeetingResponseChild->success(), $createMeetingResponseChild->getMessage()); + self::assertEquals('', $createMeetingResponseChild->getMessage()); + self::assertNotEquals('bbb-none', $createMeetingResponseChild->getParentMeetingId()); + self::assertEquals($createMeetingResponseParent->getInternalMeetingId(), $createMeetingResponseChild->getParentMeetingId()); - return $getMeetingInfoParameters->setMeetingId($createMeetingResponse->getInternalMeetingId()); + // create and return parameter for test + $getMeetingInfoParameters = new GetMeetingInfoParameters(); + + return $getMeetingInfoParameters->setMeetingId($createMeetingResponseChild->getInternalMeetingId()); }, ], 'case09_meeting_info_of_meeting_with_breakout_rooms' => [ 'function' => 'getMeetingInfo', 'filename' => 'get_meeting_info_with_breakout_rooms.xml', - 'parameters' => function(array $creatMeetingResponses): GetMeetingInfoParameters { - $getMeetingInfoParameters = new GetMeetingInfoParameters(); - - /** @var CreateMeetingResponse $createMeetingResponse */ - $createMeetingResponse = $creatMeetingResponses['meeting_with_breakout_rooms']; + 'success' => true, + 'messageKey' => '', + 'parameters' => function(BigBlueButton $bbb): GetMeetingInfoParameters { + $faker = Faker::create(); - return $getMeetingInfoParameters->setMeetingId($createMeetingResponse->getMeetingId()); + // create meeting room + $createMeetingParametersParent = new CreateMeetingParameters($faker->uuid, 'Meeting Room 1 (case 09)'); + $createMeetingParametersParent + ->addMeta('endcallbackurl', $faker->url) + ->addMeta('presenter', $faker->name) + ; + $createMeetingResponseParent = $bbb->createMeeting($createMeetingParametersParent); + self::assertTrue($createMeetingResponseParent->success()); + self::assertEquals('bbb-none', $createMeetingResponseParent->getParentMeetingId()); + + // create breakout room + $createMeetingParametersChild = new CreateMeetingParameters($faker->uuid, 'Breakout Room (case 09)'); + $createMeetingParametersChild + ->setParentMeetingId($createMeetingResponseParent->getMeetingId()) + ->setBreakout(true) + ->setSequence(1) + ; + $createMeetingResponseChild = $bbb->createMeeting($createMeetingParametersChild); + self::assertTrue($createMeetingResponseChild->success(), $createMeetingResponseChild->getMessage()); + self::assertEquals('', $createMeetingResponseChild->getMessage()); + self::assertNotEquals('bbb-none', $createMeetingResponseChild->getParentMeetingId()); + self::assertEquals($createMeetingResponseParent->getInternalMeetingId(), $createMeetingResponseChild->getParentMeetingId()); + + // create and return parameter for test + return new GetMeetingInfoParameters($createMeetingResponseParent->getMeetingId()); }, ], - /* 'case10_hooks_create' => [ 'function' => 'hooksCreate', 'filename' => 'hooks_create.xml', - 'parameters' => function(array $creatMeetingResponses): HooksCreateParameters { + 'success' => true, + 'messageKey' => '', + 'parameters' => function(BigBlueButton $bbb): HooksCreateParameters { $faker = Faker::create(); - return new HooksCreateParameters('https://bbb-123.requestcatcher.com/'); + // create and return parameter for test + return new HooksCreateParameters($faker->url); }, ], - */ - /* - 'case11_hooks_list' => [ + 'case11_hooks_create_existing' => [ + 'function' => 'hooksCreate', + 'filename' => 'hooks_create_existing.xml', + 'success' => true, + 'messageKey' => 'duplicateWarning', + 'parameters' => function(BigBlueButton $bbb): HooksCreateParameters { + $faker = Faker::create(); + $url = $faker->url; + + // create hook + $hooksCreateParameters = new HooksCreateParameters($url); + $hooksCreateResponse = $bbb->hooksCreate($hooksCreateParameters); + self::assertTrue($hooksCreateResponse->success()); + + // create and return parameter for test + return new HooksCreateParameters($url); + }, + ], + 'case12_hooks_list' => [ 'function' => 'hooksList', - 'filename' => null, - 'parameters' => null, + 'filename' => 'hooks_list.xml', + 'success' => true, + 'messageKey' => '', + 'parameters' => function(BigBlueButton $bbb): void { + $faker = Faker::create(); + + // create meeting + $createMeetingParameters = new CreateMeetingParameters($faker->uuid, 'Meeting Room (case 12)'); + $createMeetingResponse = $bbb->createMeeting($createMeetingParameters); + self::assertTrue($createMeetingResponse->success()); + self::assertEquals('bbb-none', $createMeetingResponse->getParentMeetingId()); + + // create hook #1 (with meeting) + $hooksCreateParameters = new HooksCreateParameters($faker->url); + $hooksCreateParameters->setMeetingId($createMeetingResponse->getMeetingId()); + $hooksCreateResponse_2 = $bbb->hooksCreate($hooksCreateParameters); + self::assertTrue($hooksCreateResponse_2->success()); + + // create hook #2 (w/o meeting) + $hooksCreateParameters = new HooksCreateParameters($faker->url); + $hooksCreateResponse_1 = $bbb->hooksCreate($hooksCreateParameters); + self::assertTrue($hooksCreateResponse_1->success()); + }, ], - 'case12_hooks_destroy' => [ + 'case13_hooks_destroy' => [ 'function' => 'hooksDestroy', - 'filename' => null, - 'parameters' => null, + 'filename' => 'hooks_destroy.xml', + 'success' => true, + 'messageKey' => '', + 'parameters' => function(BigBlueButton $bbb): HooksDestroyParameters { + $faker = Faker::create(); + + // create hook + $hooksCreateParameters = new HooksCreateParameters($faker->url); + $hooksCreateResponse = $bbb->hooksCreate($hooksCreateParameters); + self::assertTrue($hooksCreateResponse->success()); + self::assertIsInt($hooksCreateResponse->getHookId()); + + // create and return parameter for test + return new HooksDestroyParameters($hooksCreateResponse->getHookId()); + }, + ], + 'case14_hooks_destroy_not_found' => [ + 'function' => 'hooksDestroy', + 'filename' => 'hooks_destroy_failed_not_found.xml', + 'success' => false, + 'messageKey' => 'destroyMissingHook', + 'parameters' => function(BigBlueButton $bbb): HooksDestroyParameters { + $faker = Faker::create(); + + // create and return parameter for test + return new HooksDestroyParameters($faker->numberBetween()); + }, + ], + 'case15_insert_document' => [ + 'function' => 'insertDocument', + 'filename' => 'insert_document.xml', + 'success' => true, + 'messageKey' => '', + 'parameters' => function(BigBlueButton $bbb): InsertDocumentParameters { + $faker = Faker::create(); + + // arrange the BBB-server + $createMeetingParameters = new CreateMeetingParameters($faker->uuid, 'Meeting Room (case 05)'); + $createMeetingResponse = $bbb->createMeeting($createMeetingParameters); + self::assertTrue($createMeetingResponse->success()); + self::assertEquals('bbb-none', $createMeetingResponse->getParentMeetingId()); + + // create and return parameter for test + $insertDocumentParameters = new InsertDocumentParameters($createMeetingResponse->getMeetingId()); + + $insertDocumentParameters + ->addPresentation('https://freetestdata.com/wp-content/uploads/2021/09/Free_Test_Data_100KB_PDF.pdf') + ->addPresentation('https://freetestdata.com/wp-content/uploads/2022/02/Free_Test_Data_117KB_JPG.jpg') + ->addPresentation('https://freetestdata.com/wp-content/uploads/2021/09/500kb.png') + ->addPresentation('https://freetestdata.com/wp-content/uploads/2021/09/1.svg') + ; + + return $insertDocumentParameters; + }, ], - */ ]; } + private function closeAllMeetings(): void + { + $meetings = $this->bbb->getMeetings()->getMeetings(); + + foreach ($meetings as $meeting) { + $meetingId = $meeting->getInternalMeetingId(); + $endMeetingResponse = $this->bbb->endMeeting(new EndMeetingParameters($meetingId)); + self::assertEquals('SUCCESS', $endMeetingResponse->getReturnCode(), $endMeetingResponse->getMessage()); + self::assertTrue($endMeetingResponse->success()); + self::assertEquals('sentEndMeetingRequest', $endMeetingResponse->getMessageKey()); + } + + // ensure that no meetings exist anymore + self::assertEmpty($this->bbb->getMeetings()->getMeetings()); + } + + private function destroyAllHooks(): void + { + $hooks = $this->bbb->hooksList()->getHooks(); + + foreach ($hooks as $hook) { + self::assertInstanceOf(Hook::class, $hook); + $hookId = $hook->getHookId(); + $hooksDestroyResponse = $this->bbb->hooksDestroy(new HooksDestroyParameters($hookId)); + self::assertEquals('SUCCESS', $hooksDestroyResponse->getReturnCode(), $hooksDestroyResponse->getMessage()); + self::assertTrue($hooksDestroyResponse->success()); + self::assertEquals('', $hooksDestroyResponse->getMessageKey()); + } + + // ensure that no hooks exist anymore + self::assertEmpty($this->bbb->hooksList()->getHooks()); + } + + private function assertSameStructureOfXml(\SimpleXMLElement $xmlToBe, \SimpleXMLElement $xmlAsIs): void + { + $arrayToBe = $this->getStructureOfXmlAsArray($xmlToBe); + $arrayAsIs = $this->getStructureOfXmlAsArray($xmlAsIs); + + $expectedItemsMissingInResponse = array_diff($arrayToBe, $arrayAsIs); + $respondedItemsNotExpected = array_diff($arrayAsIs, $arrayToBe); + + $this->assertEqualsCanonicalizing( + $arrayToBe, + $arrayAsIs, + "Details:\n\n" . + 'Missing items in response: ' . implode('; ', $expectedItemsMissingInResponse) . "\n\n" . + 'Missing items in the file: ' . implode('; ', $respondedItemsNotExpected) . "\n\n" + ); + } + /** - * Create items on a real BBB-Sever: - * a) Meeting #1: A meeting without breakout rooms - * b) Meeting #2: A meeting containing two breakout rooms - * c) Meeting #3: Breakout Room #A of Meeting #2 - * c) Meeting #4: Breakout Room #B of Meeting #2 + * Recursive function to flatten an array, which shall represent the structure of an + * element. For this, arrays that contain several children (= array with sequential + * numbers as keys) will get a list of unique attributes across all children. + * + * @param array $array + * + * @return array */ - private function prepareBbbServer(): void + private function flattenArray(array $array, string $prefix = ''): array { - $faker = Faker::create(); - - // create meeting room #1 (no breakout rooms inside) - $createMeetingParameters_mr1 = new CreateMeetingParameters($faker->uuid, 'Meeting Room #1'); - $createMeetingParameters_mr1->addMeta('endcallbackurl', $faker->url); - $createMeetingParameters_mr1->addMeta('presenter', $faker->name); - $createMeetingResponse_mr1 = $this->bbb->createMeeting($createMeetingParameters_mr1); - self::assertEquals('SUCCESS', $createMeetingResponse_mr1->getReturnCode()); - self::assertTrue($createMeetingResponse_mr1->success()); - self::assertEquals('bbb-none', $createMeetingResponse_mr1->getParentMeetingId()); - $this->createMeetingResponseRepository['meeting_wo_breakout_rooms'] = $createMeetingResponse_mr1; - - // create meeting room #2 (two breakout rooms inside) - $createMeetingParameters_mr2 = new CreateMeetingParameters($faker->uuid, 'Meeting Room #2'); - $createMeetingParameters_mr2->addMeta('endcallbackurl', $faker->url); - $createMeetingParameters_mr2->addMeta('presenter', $faker->name); - $createMeetingParameters_mr2->setBreakoutRoomsEnabled(true); - self::assertTrue($createMeetingParameters_mr2->isBreakoutRoomsEnabled()); - $createMeetingResponse_mr2 = $this->bbb->createMeeting($createMeetingParameters_mr2); - self::assertEquals('SUCCESS', $createMeetingResponse_mr2->getReturnCode()); - self::assertTrue($createMeetingResponse_mr2->success()); - self::assertEquals('bbb-none', $createMeetingResponse_mr2->getParentMeetingId()); - $this->createMeetingResponseRepository['meeting_with_breakout_rooms'] = $createMeetingResponse_mr2; - - // create breakout rooms #A - $createMeetingParameters_brA = new CreateMeetingParameters($faker->uuid, 'Breakout Room #A'); - $createMeetingParameters_brA->setParentMeetingId($createMeetingResponse_mr2->getMeetingId())->setBreakout(true)->setSequence(1); - $createMeetingResponse_brA = $this->bbb->createMeeting($createMeetingParameters_brA); - self::assertEquals('SUCCESS', $createMeetingResponse_brA->getReturnCode(), $createMeetingResponse_brA->getMessage()); - self::assertTrue($createMeetingResponse_brA->success()); - self::assertEquals('', $createMeetingResponse_brA->getMessage()); - self::assertNotEquals('bbb-none', $createMeetingResponse_brA->getParentMeetingId()); - self::assertEquals($createMeetingResponse_mr2->getInternalMeetingId(), $createMeetingResponse_brA->getParentMeetingId()); - $this->createMeetingResponseRepository['breakout_room_A'] = $createMeetingResponse_brA; - - // create breakout rooms #B - $createMeetingParameters_brB = new CreateMeetingParameters($faker->uuid, 'Breakout Room #B'); - $createMeetingParameters_brB->setParentMeetingId($createMeetingResponse_mr2->getMeetingId())->setBreakout(true)->setSequence(2); - $createMeetingResponse_brB = $this->bbb->createMeeting($createMeetingParameters_brB); - self::assertEquals('SUCCESS', $createMeetingResponse_brB->getReturnCode(), $createMeetingResponse_brB->getMessage()); - self::assertTrue($createMeetingResponse_brB->success()); - self::assertEquals('', $createMeetingResponse_brB->getMessage()); - self::assertNotEquals('bbb-none', $createMeetingResponse_brB->getParentMeetingId()); - self::assertEquals($createMeetingResponse_mr2->getInternalMeetingId(), $createMeetingResponse_brB->getParentMeetingId()); - $this->createMeetingResponseRepository['breakout_room_B'] = $createMeetingResponse_brB; - - // check breakout room #A - $getMeetingInfoParameters_brA = new GetMeetingInfoParameters($createMeetingResponse_brA->getInternalMeetingId()); - $getMeetingInfoResponse_brA = $this->bbb->getMeetingInfo($getMeetingInfoParameters_brA); - self::assertEquals('SUCCESS', $getMeetingInfoResponse_brA->getReturnCode(), $getMeetingInfoResponse_brA->getMessage()); - self::assertTrue($getMeetingInfoResponse_brA->success()); - self::assertTrue($getMeetingInfoResponse_brA->getMeeting()->isBreakout()); - self::assertEquals($createMeetingResponse_brA->getParentMeetingId(), $getMeetingInfoResponse_brA->getRawXml()->parentMeetingID->__toString()); // not covered yet by a function - - // check breakout room #B - $getMeetingInfoParameters_brB = new GetMeetingInfoParameters($createMeetingResponse_brB->getInternalMeetingId()); - $getMeetingInfoResponse_brB = $this->bbb->getMeetingInfo($getMeetingInfoParameters_brB); - self::assertEquals('SUCCESS', $getMeetingInfoResponse_brB->getReturnCode(), $getMeetingInfoResponse_brB->getMessage()); - self::assertTrue($getMeetingInfoResponse_brB->success()); - self::assertTrue($getMeetingInfoResponse_brB->getMeeting()->isBreakout()); - self::assertEquals($createMeetingResponse_brB->getParentMeetingId(), $getMeetingInfoResponse_brB->getRawXml()->parentMeetingID->__toString()); // not covered yet by a function - - // check meeting room #2 - $getMeetingInfoParameters_mr2 = new GetMeetingInfoParameters($createMeetingResponse_mr2->getMeetingId()); - $getMeetingInfoResponse_mr2 = $this->bbb->getMeetingInfo($getMeetingInfoParameters_mr2); - self::assertEquals('SUCCESS', $getMeetingInfoResponse_mr2->getReturnCode(), $getMeetingInfoResponse_mr2->getMessage()); - self::assertTrue($getMeetingInfoResponse_mr2->success()); - self::assertFalse($getMeetingInfoResponse_mr2->getMeeting()->isBreakout()); - self::assertCount(2, $getMeetingInfoResponse_mr2->getRawXml()->breakoutRooms->breakout); // not covered yet by a function - self::assertArrayHasKey('presenter', $getMeetingInfoResponse_mr2->getMeeting()->getMetas()); - self::assertArrayHasKey('endcallbackurl', $getMeetingInfoResponse_mr2->getMeeting()->getMetas()); - - // join MODERATOR into meeting room #1 - $joinMeetingParameters = new JoinMeetingParameters($createMeetingResponse_mr1->getMeetingId(), $faker->name, Role::MODERATOR); - $joinMeetingParameters->setRedirect(false); - $joinMeetingResponse = $this->bbb->joinMeeting($joinMeetingParameters); - self::assertEquals('SUCCESS', $joinMeetingResponse->getReturnCode(), $joinMeetingResponse->getMessage()); - self::assertTrue($joinMeetingResponse->success()); - self::assertIsString($joinMeetingResponse->getUserId()); - self::assertEquals('successfullyJoined', $joinMeetingResponse->getMessageKey()); - self::assertEquals('You have joined successfully.', $joinMeetingResponse->getMessage()); - - // check meeting room #1 - $getMeetingInfoParameters_mr1 = new GetMeetingInfoParameters($createMeetingResponse_mr1->getMeetingId()); - $getMeetingInfoResponse_mr1 = $this->bbb->getMeetingInfo($getMeetingInfoParameters_mr1); - self::assertEquals('SUCCESS', $getMeetingInfoResponse_mr1->getReturnCode(), $getMeetingInfoResponse_mr1->getMessage()); - self::assertTrue($getMeetingInfoResponse_mr1->success()); - self::assertFalse($getMeetingInfoResponse_mr1->getMeeting()->isBreakout()); - self::assertNull($getMeetingInfoResponse_mr1->getRawXml()->breakoutRooms->breakout); // not covered yet by a function - self::assertArrayHasKey('presenter', $getMeetingInfoResponse_mr1->getMeeting()->getMetas()); - self::assertArrayHasKey('endcallbackurl', $getMeetingInfoResponse_mr1->getMeeting()->getMetas()); + $result = []; + foreach ($array as $key => $value) { + $new_key = $prefix . (empty($prefix) ? '' : '.') . $key; - /* - // create hook (basic) - $callBackUrl = 'https://bbb.website.com/hook/catcher'; - $callBackUrl = '123'; - - // create hook (manual) - $parameters = ['callbackURL' => $callBackUrl]; - $secret = getenv('BBB_SECRET'); - $base = getenv('BBB_SERVER_BASE_URL'); - $queryBuild = http_build_query($parameters); - $checksum = hash('sha256', 'hooks/create' . $queryBuild . $secret); - $url_manual = $base . 'api/hooks/create?' . $queryBuild . '&checksum=' . $checksum; - - // create hook (normal) - $hooksCreateParameters = new HooksCreateParameters($callBackUrl); - $url = $this->bbb->getHooksCreateUrl($hooksCreateParameters); - self::assertEquals($url, $url_manual); - $response = $this->bbb->hooksCreate($hooksCreateParameters); - self::assertEquals('SUCCESS', $response->getReturnCode(), $response->getMessage() . ' / url: ' . $url); - */ + // prepare value + if (is_array($value)) { + // a sequential array (= not associative) is understood as a group of + // similar children, thus their attributes should be similar. + if (!$this->isAssociativeArray($value)) { + // get a full collection of unique attributes within the group of children + $attributeCollection = []; + + foreach ($value as $child) { + if (!is_array($child)) { + continue; + } + + foreach ($child as $attributeKey => $attributeValue) { + if (!key_exists($attributeKey, $attributeCollection)) { + $attributeCollection[$attributeKey] = $attributeValue; + } + } + } + + $value = $attributeCollection; + } + } + + // compose result + if (is_array($value)) { + if (count($value) > 0) { + $result = array_merge($result, [$new_key => $value], $this->flattenArray($value, $new_key)); + } else { + $result[$new_key] = 'empty array'; // empty array + } + } else { + $result[$new_key] = $value; + } + } + + return $result; + } + + /** + * Function that helps to determine if an array is sequential or associative. + * + * Remark: With PHP 8.1 this function can be replaced by 'array_is_list'. + * + * @param array $array + */ + private function isAssociativeArray(array $array): bool + { + if (array_keys($array) === range(0, count($array) - 1)) { + return false; + } + + return true; + } + + /** + * @return array + */ + private function getStructureOfXmlAsArray(\SimpleXMLElement $xml): array + { + // transform XML to ARRAY (via JSON) + $json = json_encode($xml); + self::assertIsString($json); + $array = json_decode($json, true); + + // flatten multidimensional array to string-based hierarchy + $flattenArray = $this->flattenArray($array); + + // only the keys are needed + $keys = array_keys($flattenArray); + + // bring the key into alphabetic order + sort($keys); + + return $keys; } } diff --git a/tests/fixtures/hooks_destroy_params_no_id.xml b/tests/fixtures/hooks_destroy_params_no_id.xml deleted file mode 100644 index 297fed8d..00000000 --- a/tests/fixtures/hooks_destroy_params_no_id.xml +++ /dev/null @@ -1,5 +0,0 @@ - - FAILED - missingParamHookID - You must specify a hookID in the parameters. - \ No newline at end of file diff --git a/tests/fixtures/bbb_logo.png b/tests/fixtures/images/bbb_logo.png similarity index 100% rename from tests/fixtures/bbb_logo.png rename to tests/fixtures/images/bbb_logo.png diff --git a/tests/fixtures/insert_document_presentations.xml b/tests/fixtures/insert_document_presentations.xml deleted file mode 100644 index 997ecaf5..00000000 --- a/tests/fixtures/insert_document_presentations.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/tests/fixtures/presentation_with_filename.xml b/tests/fixtures/presentation_with_filename.xml deleted file mode 100644 index 2b346089..00000000 --- a/tests/fixtures/presentation_with_filename.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/tests/fixtures/requests/insert_document_presentations.xml b/tests/fixtures/requests/insert_document_presentations.xml new file mode 100644 index 00000000..1edfb949 --- /dev/null +++ b/tests/fixtures/requests/insert_document_presentations.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/tests/fixtures/presentation_with_embedded_file.xml b/tests/fixtures/requests/presentation_with_embedded_file.xml similarity index 100% rename from tests/fixtures/presentation_with_embedded_file.xml rename to tests/fixtures/requests/presentation_with_embedded_file.xml diff --git a/tests/fixtures/requests/presentation_with_filename.xml b/tests/fixtures/requests/presentation_with_filename.xml new file mode 100644 index 00000000..f7da54da --- /dev/null +++ b/tests/fixtures/requests/presentation_with_filename.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/tests/fixtures/presentation_with_url.xml b/tests/fixtures/requests/presentation_with_url.xml similarity index 56% rename from tests/fixtures/presentation_with_url.xml rename to tests/fixtures/requests/presentation_with_url.xml index cf45ce3a..f216f0e9 100644 --- a/tests/fixtures/presentation_with_url.xml +++ b/tests/fixtures/requests/presentation_with_url.xml @@ -1,6 +1,6 @@ - + diff --git a/tests/fixtures/api_version.xml b/tests/fixtures/responses/api_version.xml similarity index 100% rename from tests/fixtures/api_version.xml rename to tests/fixtures/responses/api_version.xml diff --git a/tests/fixtures/create_meeting.xml b/tests/fixtures/responses/create_meeting.xml similarity index 100% rename from tests/fixtures/create_meeting.xml rename to tests/fixtures/responses/create_meeting.xml diff --git a/tests/fixtures/delete_recordings.xml b/tests/fixtures/responses/delete_recordings.xml similarity index 100% rename from tests/fixtures/delete_recordings.xml rename to tests/fixtures/responses/delete_recordings.xml diff --git a/tests/fixtures/end_meeting.xml b/tests/fixtures/responses/end_meeting.xml similarity index 100% rename from tests/fixtures/end_meeting.xml rename to tests/fixtures/responses/end_meeting.xml diff --git a/tests/fixtures/get_meeting_info.xml b/tests/fixtures/responses/get_meeting_info.xml similarity index 100% rename from tests/fixtures/get_meeting_info.xml rename to tests/fixtures/responses/get_meeting_info.xml diff --git a/tests/fixtures/get_meeting_info_breakout_room.xml b/tests/fixtures/responses/get_meeting_info_breakout_room.xml similarity index 81% rename from tests/fixtures/get_meeting_info_breakout_room.xml rename to tests/fixtures/responses/get_meeting_info_breakout_room.xml index 87a97a9f..743d4ccc 100644 --- a/tests/fixtures/get_meeting_info_breakout_room.xml +++ b/tests/fixtures/responses/get_meeting_info_breakout_room.xml @@ -79,16 +79,5 @@ false Best BBB Developers Club - Moodle - - http://bigbluebutton.org/moodle/mod/bigbluebuttonbn/bbb_broker.php?action=recording_ready - - moodle-mod_bigbluebuttonbn (2015080609) - 3.0.2 (Build: 20160111) - - bigbluebutton.org - - Bigbluebutton "Mock meeting for testing getMeetingInfo" - \ No newline at end of file diff --git a/tests/fixtures/get_meeting_info_with_breakout_rooms.xml b/tests/fixtures/responses/get_meeting_info_with_breakout_rooms.xml similarity index 80% rename from tests/fixtures/get_meeting_info_with_breakout_rooms.xml rename to tests/fixtures/responses/get_meeting_info_with_breakout_rooms.xml index 54e8003d..8a076f4a 100644 --- a/tests/fixtures/get_meeting_info_with_breakout_rooms.xml +++ b/tests/fixtures/responses/get_meeting_info_with_breakout_rooms.xml @@ -80,17 +80,7 @@ breakout-room-id-3 - Best BBB Developers Club - Moodle - - http://bigbluebutton.org/moodle/mod/bigbluebuttonbn/bbb_broker.php?action=recording_ready - - moodle-mod_bigbluebuttonbn (2015080609) - 3.0.2 (Build: 20160111) - - bigbluebutton.org - - Bigbluebutton "Mock meeting for testing getMeetingInfo" - + Prof. Maud Corkery II + http://www.hegmann.biz/explicabo-praesentium-labore-dolor \ No newline at end of file diff --git a/tests/fixtures/get_meetings.xml b/tests/fixtures/responses/get_meetings.xml similarity index 100% rename from tests/fixtures/get_meetings.xml rename to tests/fixtures/responses/get_meetings.xml diff --git a/tests/fixtures/get_recording_text_tracks.json b/tests/fixtures/responses/get_recording_text_tracks.json similarity index 100% rename from tests/fixtures/get_recording_text_tracks.json rename to tests/fixtures/responses/get_recording_text_tracks.json diff --git a/tests/fixtures/get_recordings.xml b/tests/fixtures/responses/get_recordings.xml similarity index 100% rename from tests/fixtures/get_recordings.xml rename to tests/fixtures/responses/get_recordings.xml diff --git a/tests/fixtures/hooks_create.xml b/tests/fixtures/responses/hooks_create.xml similarity index 100% rename from tests/fixtures/hooks_create.xml rename to tests/fixtures/responses/hooks_create.xml diff --git a/tests/fixtures/hooks_create_existing.xml b/tests/fixtures/responses/hooks_create_existing.xml similarity index 100% rename from tests/fixtures/hooks_create_existing.xml rename to tests/fixtures/responses/hooks_create_existing.xml diff --git a/tests/fixtures/hooks_create_error.xml b/tests/fixtures/responses/hooks_create_failed_error.xml similarity index 100% rename from tests/fixtures/hooks_create_error.xml rename to tests/fixtures/responses/hooks_create_failed_error.xml diff --git a/tests/fixtures/hooks_destroy.xml b/tests/fixtures/responses/hooks_destroy.xml similarity index 100% rename from tests/fixtures/hooks_destroy.xml rename to tests/fixtures/responses/hooks_destroy.xml diff --git a/tests/fixtures/hooks_destroy_error.xml b/tests/fixtures/responses/hooks_destroy_failed_error.xml similarity index 100% rename from tests/fixtures/hooks_destroy_error.xml rename to tests/fixtures/responses/hooks_destroy_failed_error.xml diff --git a/tests/fixtures/hooks_create_no_hook_id.xml b/tests/fixtures/responses/hooks_destroy_failed_no_id.xml similarity index 100% rename from tests/fixtures/hooks_create_no_hook_id.xml rename to tests/fixtures/responses/hooks_destroy_failed_no_id.xml diff --git a/tests/fixtures/hooks_destroy_not_found.xml b/tests/fixtures/responses/hooks_destroy_failed_not_found.xml similarity index 100% rename from tests/fixtures/hooks_destroy_not_found.xml rename to tests/fixtures/responses/hooks_destroy_failed_not_found.xml diff --git a/tests/fixtures/hooks_list.xml b/tests/fixtures/responses/hooks_list.xml similarity index 100% rename from tests/fixtures/hooks_list.xml rename to tests/fixtures/responses/hooks_list.xml diff --git a/tests/fixtures/insert_document.xml b/tests/fixtures/responses/insert_document.xml similarity index 100% rename from tests/fixtures/insert_document.xml rename to tests/fixtures/responses/insert_document.xml diff --git a/tests/fixtures/is_meeting_running.xml b/tests/fixtures/responses/is_meeting_running.xml similarity index 100% rename from tests/fixtures/is_meeting_running.xml rename to tests/fixtures/responses/is_meeting_running.xml diff --git a/tests/fixtures/join_meeting.xml b/tests/fixtures/responses/join_meeting.xml similarity index 100% rename from tests/fixtures/join_meeting.xml rename to tests/fixtures/responses/join_meeting.xml diff --git a/tests/fixtures/publish_recordings.xml b/tests/fixtures/responses/publish_recordings.xml similarity index 100% rename from tests/fixtures/publish_recordings.xml rename to tests/fixtures/responses/publish_recordings.xml diff --git a/tests/fixtures/put_recording_text_track_success.json b/tests/fixtures/responses/put_recording_text_track_success.json similarity index 100% rename from tests/fixtures/put_recording_text_track_success.json rename to tests/fixtures/responses/put_recording_text_track_success.json diff --git a/tests/fixtures/update_recordings.xml b/tests/fixtures/responses/update_recordings.xml similarity index 100% rename from tests/fixtures/update_recordings.xml rename to tests/fixtures/responses/update_recordings.xml From ffaea3a460cc1c8f416a6bbcd50b7b6783daf153 Mon Sep 17 00:00:00 2001 From: Tim Korn Date: Mon, 29 Apr 2024 00:04:03 +0200 Subject: [PATCH 3/5] Make PHPstan happy --- src/Parameters/Config/DocumentOptionsStore.php | 15 ++++++++++++--- src/Parameters/DocumentableTrait.php | 16 ++++++++++------ tests/BigBlueButtonTest.php | 11 ++++++++--- tests/Parameters/CreateMeetingParametersTest.php | 6 ++++-- tests/Util/FixturesTest.php | 4 ++-- 5 files changed, 36 insertions(+), 16 deletions(-) diff --git a/src/Parameters/Config/DocumentOptionsStore.php b/src/Parameters/Config/DocumentOptionsStore.php index a5aae896..9d805ee1 100644 --- a/src/Parameters/Config/DocumentOptionsStore.php +++ b/src/Parameters/Config/DocumentOptionsStore.php @@ -22,14 +22,20 @@ class DocumentOptionsStore { - private $attributes = []; + /** + * @var array + */ + private array $attributes; + /** + * @param array $attributes + */ public function __construct(array $attributes = []) { $this->attributes = $attributes; } - public function addAttribute($name, $value) + public function addAttribute(string $name, bool|string $value): void { if (is_bool($value)) { $value = $value ? 'true' : 'false'; @@ -37,7 +43,10 @@ public function addAttribute($name, $value) $this->attributes[$name] = $value; } - public function getAttributes() + /** + * @return array + */ + public function getAttributes(): array { return $this->attributes; } diff --git a/src/Parameters/DocumentableTrait.php b/src/Parameters/DocumentableTrait.php index 6f59251a..2766810d 100644 --- a/src/Parameters/DocumentableTrait.php +++ b/src/Parameters/DocumentableTrait.php @@ -38,11 +38,9 @@ public function getPresentations(): array } /** - * @param null|mixed $content - * * @throws \Exception */ - public function addPresentation(string $nameOrUrl, $content = null, ?string $filename = null, ?DocumentOptionsStore $attributes = null): self + public function addPresentation(string $nameOrUrl, ?string $content = null, ?string $filename = null, ?DocumentOptionsStore $attributes = null): self { // check if resource is existing if (0 === mb_strpos($nameOrUrl, 'http')) { @@ -54,7 +52,7 @@ public function addPresentation(string $nameOrUrl, $content = null, ?string $fil } $this->presentations[$nameOrUrl] = [ - 'content' => !$content ?: base64_encode($content), + 'content' => $content ? base64_encode($content) : null, 'filename' => $filename, 'attributes' => $attributes, ]; @@ -88,8 +86,10 @@ public function getPresentationsAsXML(): string } // Add attributes using DocumentAttributes class - foreach ($data['attributes']->getAttributes() as $attrName => $attrValue) { - $presentation->addAttribute($attrName, $attrValue); + if (!empty($data['attributes'])) { + foreach ($data['attributes']->getAttributes() as $attrName => $attrValue) { + $presentation->addAttribute($attrName, $attrValue); + } } } $result = $xml->asXML(); @@ -106,6 +106,10 @@ private function urlExists(string $url): bool { $ch = curl_init($url); + if (!$ch) { + throw new \RuntimeException('Unhandled curl error!'); + } + curl_setopt($ch, CURLOPT_TIMEOUT, 5); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); diff --git a/tests/BigBlueButtonTest.php b/tests/BigBlueButtonTest.php index 4ba686b3..57b15ba4 100644 --- a/tests/BigBlueButtonTest.php +++ b/tests/BigBlueButtonTest.php @@ -149,9 +149,11 @@ public function testCreateMeetingWithDocumentUrlAndFileName(): void */ public function testCreateMeetingWithDocumentEmbedded(): void { - $params = Fixtures::getCreateMeetingParametersMock(Fixtures::generateCreateParams()); + $content = file_get_contents(Fixtures::IMAGE_PATH . 'bbb_logo.png'); + $this->assertIsString($content); - $params->addPresentation('bbb_logo.png', file_get_contents(Fixtures::IMAGE_PATH . 'bbb_logo.png')); + $params = Fixtures::getCreateMeetingParametersMock(Fixtures::generateCreateParams()); + $params->addPresentation('bbb_logo.png', $content); $result = $this->bbb->createMeeting($params); @@ -165,9 +167,12 @@ public function testCreateMeetingWithDocumentEmbedded(): void */ public function testCreateMeetingWithMultiDocument(): void { + $content = file_get_contents(Fixtures::IMAGE_PATH . 'bbb_logo.png'); + $this->assertIsString($content); + $params = Fixtures::getCreateMeetingParametersMock(Fixtures::generateCreateParams()); $params->addPresentation('https://picsum.photos/3840/2160/?random', null, 'presentation.png'); - $params->addPresentation('logo.png', file_get_contents(Fixtures::IMAGE_PATH . 'bbb_logo.png')); + $params->addPresentation('logo.png', $content); $result = $this->bbb->createMeeting($params); diff --git a/tests/Parameters/CreateMeetingParametersTest.php b/tests/Parameters/CreateMeetingParametersTest.php index 17250350..545e0a48 100644 --- a/tests/Parameters/CreateMeetingParametersTest.php +++ b/tests/Parameters/CreateMeetingParametersTest.php @@ -22,7 +22,6 @@ use BigBlueButton\TestCase; use BigBlueButton\TestServices\Fixtures; -use function PHPUnit\Framework\assertEquals; /** * Class CreateMeetingParametersTest. @@ -146,8 +145,11 @@ public function testGetPresentationsAsXMLWithUrlAndFilename(): void public function testGetPresentationsAsXMLWithFile(): void { + $content = file_get_contents(Fixtures::IMAGE_PATH . 'bbb_logo.png'); + $this->assertIsString($content); + $createMeetingParams = Fixtures::getCreateMeetingParametersMock(Fixtures::generateCreateParams()); - $createMeetingParams->addPresentation('bbb_logo.png', file_get_contents(Fixtures::IMAGE_PATH . 'bbb_logo.png')); + $createMeetingParams->addPresentation('bbb_logo.png', $content); $this->assertXmlStringEqualsXmlFile(Fixtures::REQUEST_PATH . 'presentation_with_embedded_file.xml', $createMeetingParams->getPresentationsAsXML()); } diff --git a/tests/Util/FixturesTest.php b/tests/Util/FixturesTest.php index a2d62baf..3c7e931d 100644 --- a/tests/Util/FixturesTest.php +++ b/tests/Util/FixturesTest.php @@ -36,7 +36,6 @@ use BigBlueButton\TestServices\Fixtures; use Faker\Factory as Faker; use PHPUnit\Framework\TestCase; -use Tracy\Debugger; /** * @internal @@ -75,7 +74,8 @@ public function testCoverageOfFixtures(): void $xmlFilenamesFromDataProvider = array_column($dataProvider, 'filename'); // TO-BE: get all XML-files of the fixtures-folder - $absolutePathnames = glob(Fixtures::RESPONSE_PATH . '*.xml'); + $absolutePathnames = glob(Fixtures::RESPONSE_PATH . '*.xml'); + $this->assertIsArray($absolutePathnames); $xmlFilenamesFromFolder = array_map(function($absolutePathname) { return basename($absolutePathname); }, $absolutePathnames); From 11c1c6fc1925dec2e8ba93d9a2407568f647a7f7 Mon Sep 17 00:00:00 2001 From: Tim Korn Date: Wed, 1 May 2024 11:55:13 +0200 Subject: [PATCH 4/5] Remove check if resources do exist --- src/Parameters/DocumentableTrait.php | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/Parameters/DocumentableTrait.php b/src/Parameters/DocumentableTrait.php index 2766810d..02fe1e71 100644 --- a/src/Parameters/DocumentableTrait.php +++ b/src/Parameters/DocumentableTrait.php @@ -42,15 +42,6 @@ public function getPresentations(): array */ public function addPresentation(string $nameOrUrl, ?string $content = null, ?string $filename = null, ?DocumentOptionsStore $attributes = null): self { - // check if resource is existing - if (0 === mb_strpos($nameOrUrl, 'http')) { - $isExisting = $this->urlExists($nameOrUrl); - - if (!$isExisting) { - throw new \Exception('Resource not found: ' . $nameOrUrl); - } - } - $this->presentations[$nameOrUrl] = [ 'content' => $content ? base64_encode($content) : null, 'filename' => $filename, From f54e88cb18006c1549be3b5e840935371dd75d59 Mon Sep 17 00:00:00 2001 From: Tim Korn Date: Wed, 1 May 2024 18:16:38 +0200 Subject: [PATCH 5/5] shifting fixture file --- composer.json | 5 +++++ tests/Parameters/InsertDocumentParametersTest.php | 6 ++++-- .../insert_document_presentations_with_options.xml | 0 3 files changed, 9 insertions(+), 2 deletions(-) rename tests/fixtures/{ => requests}/insert_document_presentations_with_options.xml (100%) diff --git a/composer.json b/composer.json index e881bcdd..0d546020 100644 --- a/composer.json +++ b/composer.json @@ -14,6 +14,11 @@ "name": "Ghazi Triki", "email": "ghazi.triki@riadvice.tn", "role": "Developer" + }, + { + "name": "Tim Korn", + "email": "korn@aufKurs.de", + "role": "Developer" } ], "repositories": { diff --git a/tests/Parameters/InsertDocumentParametersTest.php b/tests/Parameters/InsertDocumentParametersTest.php index a570e874..94c9cfb2 100644 --- a/tests/Parameters/InsertDocumentParametersTest.php +++ b/tests/Parameters/InsertDocumentParametersTest.php @@ -68,7 +68,9 @@ public function testInsertDocumentWithOptions(): void $this->assertEquals($meetingId, $insertDocumentParameters->getMeetingID()); - $file = dirname(__DIR__) . \DIRECTORY_SEPARATOR . 'fixtures' . \DIRECTORY_SEPARATOR . 'insert_document_presentations_with_options.xml'; - $this->assertXmlStringEqualsXmlFile($file, $insertDocumentParameters->getPresentationsAsXML()); + $this->assertXmlStringEqualsXmlFile( + Fixtures::REQUEST_PATH . 'insert_document_presentations_with_options.xml', + $insertDocumentParameters->getPresentationsAsXML() + ); } } diff --git a/tests/fixtures/insert_document_presentations_with_options.xml b/tests/fixtures/requests/insert_document_presentations_with_options.xml similarity index 100% rename from tests/fixtures/insert_document_presentations_with_options.xml rename to tests/fixtures/requests/insert_document_presentations_with_options.xml