Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117916434
D3989.1775410376.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
27 KB
Referenced Files
None
Subscribers
None
D3989.1775410376.diff
View Options
diff --git a/docker/proxy/rootfs/etc/nginx/nginx.conf b/docker/proxy/rootfs/etc/nginx/nginx.conf
--- a/docker/proxy/rootfs/etc/nginx/nginx.conf
+++ b/docker/proxy/rootfs/etc/nginx/nginx.conf
@@ -140,7 +140,9 @@
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
- rewrite ^/\\.well-known/(caldav|carddav) https://\$server_name/iRony/ redirect;
+ location ~ ^/\\.well-known/(caldav|carddav)(.*)$ {
+ return 301 /iRony/$2;
+ }
location /iRony {
auth_request /auth;
diff --git a/src/WOPITest.php b/src/WOPITest.php
new file mode 100644
--- /dev/null
+++ b/src/WOPITest.php
@@ -0,0 +1,54 @@
+<?php
+
+namespace Tests\Infrastructure;
+
+use Tests\TestCase;
+
+class WOPITest extends TestCase
+{
+ private \GuzzleHttp\Client $client;
+
+ /**
+ * {@inheritDoc}
+ */
+ public function setUp(): void
+ {
+ parent::setUp();
+
+ $this->getTestUser('jane@kolab.org', ['password' => 'simple123'], true, true);
+
+ if (!$this->client) {
+ $this->client = new \GuzzleHttp\Client([
+ 'base_uri' => \config('sevices.wopi.uri'),
+ 'verify' => false,
+ 'auth' => [$this->user->email, 'simple123'],
+ 'connect_timeout' => 10,
+ 'timeout' => 10
+ ]);
+ }
+ }
+
+ public function testAccess()
+ {
+ $response = $this->client->request('GET', 'api/?method=authenticate&version=4');
+ $this->assertEquals($response->getStatusCode(), 200);
+ $json = json_decode($response->getBody(), true);
+
+ $this->assertEquals('OK', $json['status']);
+ $token = $json['result']['token'];
+ $this->assertTrue(!empty($token));
+
+ //FIXME the session token doesn't seem to be required here?
+ $response = $this->client->request('GET', 'api/?method=mimetypes', [
+ 'headers' => [
+ 'X-Session_token' => $token
+ ]
+ ]);
+ $this->assertEquals($response->getStatusCode(), 200);
+ $json = json_decode($response->getBody(), true);
+ $this->assertEquals('OK', $json['status']);
+ $this->assertEquals('OK', $json['status']);
+ $this->assertContains('image/png', $json['result']['view']);
+ $this->assertArrayHasKey('text/plain', $json['result']['edit']);
+ }
+}
diff --git a/src/app/Backends/DAV.php b/src/app/Backends/DAV.php
--- a/src/app/Backends/DAV.php
+++ b/src/app/Backends/DAV.php
@@ -26,7 +26,7 @@
*/
public function __construct($user, $password)
{
- $this->url = \config('dav.uri');
+ $this->url = \config('services.dav.uri');
$this->user = $user;
$this->password = $password;
}
diff --git a/src/config/dav.php b/src/config/dav.php
deleted file mode 100644
--- a/src/config/dav.php
+++ /dev/null
@@ -1,5 +0,0 @@
-<?php
-
-return [
- 'uri' => env('DAV_URI', 'http://kolab/dav'),
-];
diff --git a/src/config/services.php b/src/config/services.php
--- a/src/config/services.php
+++ b/src/config/services.php
@@ -54,6 +54,21 @@
'openexchangerates' => [
'api_key' => env('OPENEXCHANGERATES_API_KEY', null),
- ]
+ ],
+ 'dav' => [
+ 'uri' => env('DAV_URI', 'https://proxy/'),
+ ],
+
+ 'activesync' => [
+ 'uri' => env('ACTIVESYNC_URI', 'https://proxy/Microsoft-Server-ActiveSync'),
+ ],
+
+ 'wopi' => [
+ 'uri' => env('WOPI_URI', 'http://roundcube/chwala/'),
+ ],
+
+ 'webmail' => [
+ 'uri' => env('WEBMAIL_URI', 'http://roundcube/roundcubemail/'),
+ ]
];
diff --git a/src/tests/Infrastructure/ActivesyncTest.php b/src/tests/Infrastructure/ActivesyncTest.php
new file mode 100644
--- /dev/null
+++ b/src/tests/Infrastructure/ActivesyncTest.php
@@ -0,0 +1,160 @@
+<?php
+
+namespace Tests\Infrastructure;
+
+use Tests\TestCase;
+
+class ActivesyncTest extends TestCase
+{
+ private ?\GuzzleHttp\Client $client = null;
+
+ private static function toWbxml($xml)
+ {
+ $outputStream = fopen("php://temp", 'r+');
+ $encoder = new \Syncroton_Wbxml_Encoder($outputStream, 'UTF-8', 3);
+ $dom = new \DOMDocument();
+ $dom->loadXML($xml);
+ $encoder->encode($dom);
+ rewind($outputStream);
+ return stream_get_contents($outputStream);
+ }
+
+ private static function fromWbxml($binary)
+ {
+ $stream = fopen('php://memory', 'r+');
+ fwrite($stream, $binary);
+ rewind($stream);
+ $decoder = new \Syncroton_Wbxml_Decoder($stream);
+ return $decoder->decode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function setUp(): void
+ {
+ parent::setUp();
+
+ $this->getTestUser('jane@kolab.org', ['password' => 'simple123'], true, true);
+
+ if (!$this->client) {
+ $this->client = new \GuzzleHttp\Client([
+ 'http_errors' => false, // No exceptions
+ 'base_uri' => \config("services.activesync.uri"),
+ 'verify' => false,
+ 'auth' => [$this->user->email, 'simple123'],
+ 'connect_timeout' => 10,
+ 'timeout' => 10,
+ 'headers' => [
+ "Content-Type" => "application/xml; charset=utf-8",
+ "Depth" => "1",
+ ]
+ ]);
+ }
+ }
+
+ public function testOptions()
+ {
+ $response = $this->client->request('OPTIONS', '');
+ $this->assertEquals(200, $response->getStatusCode());
+ $this->assertStringContainsString('14', $response->getHeader('MS-Server-ActiveSync')[0]);
+ $this->assertStringContainsString('14.1', $response->getHeader('MS-ASProtocolVersions')[0]);
+ $this->assertStringContainsString('FolderSync', $response->getHeader('MS-ASProtocolCommands')[0]);
+ }
+
+ public function testFolderList()
+ {
+ $request = <<<EOF
+ <?xml version="1.0" encoding="utf-8"?>
+ <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">
+ <FolderSync xmlns="uri:FolderHierarchy">
+ <SyncKey>0</SyncKey>
+ </FolderSync>
+ EOF;
+ $body = self::toWbxml($request);
+ $response = $this->client->request(
+ 'POST',
+ "?Cmd=FolderSync&User={$this->user->email}&DeviceId=v140Device&DeviceType=iphone",
+ [
+ 'headers' => [
+ "Content-Type" => "application/vnd.ms-sync.wbxml",
+ 'MS-ASProtocolVersion' => "14.0"
+ ],
+ 'body' => $body
+ ]
+ );
+ $this->assertEquals(200, $response->getStatusCode());
+ $dom = self::fromWbxml($response->getBody());
+ $xml = $dom->saveXML();
+
+ $this->assertStringContainsString('INBOX', $xml);
+ //TODO for this to work we need to create the default folders in IMAP::createUser
+ // $this->assertStringContainsString('Drafts', $result);
+ // $this->assertStringContainsString('Sent', $result);
+ // $this->assertStringContainsString('Trash', $result);
+ // $this->assertStringContainsString('Calendar', $result);
+ // $this->assertStringContainsString('Contacts', $result);
+
+ // Find the inbox for the next step
+ $collectionIds = $dom->getElementsByTagName('ServerId');
+ $inboxId = $collectionIds[0]->nodeValue;
+ // The hash is based on the name, so it's always the same
+ $this->assertEquals("38b950ebd62cd9a66929c89615d0fc04", $inboxId);
+ return $inboxId;
+ }
+
+ /**
+ * @depends testFolderList
+ */
+ public function testInitialSync($collectionId)
+ {
+ $request = <<<EOF
+ <?xml version="1.0" encoding="utf-8"?>
+ <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">
+ <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase">
+ <Collections>
+ <Collection>
+ <SyncKey>0</SyncKey>
+ <CollectionId>{$collectionId}</CollectionId>
+ <DeletesAsMoves>0</DeletesAsMoves>
+ <GetChanges>0</GetChanges>
+ <WindowSize>512</WindowSize>
+ <Options>
+ <FilterType>0</FilterType>
+ <BodyPreference xmlns="uri:AirSyncBase">
+ <Type>1</Type>
+ <AllOrNone>1</AllOrNone>
+ </BodyPreference>
+ </Options>
+ </Collection>
+ </Collections>
+ <WindowSize>16</WindowSize>
+ </Sync>
+ EOF;
+ $body = self::toWbxml($request);
+ $response = $this->client->request(
+ 'POST',
+ "?Cmd=Sync&User={$this->user->email}&DeviceId=v140Device&DeviceType=iphone",
+ [
+ 'headers' => [
+ "Content-Type" => "application/vnd.ms-sync.wbxml",
+ 'MS-ASProtocolVersion' => "14.0"
+ ],
+ 'body' => $body
+ ]
+ );
+ $this->assertEquals(200, $response->getStatusCode());
+ $dom = self::fromWbxml($response->getBody());
+ $status = $dom->getElementsByTagName('Status');
+ $this->assertEquals("1", $status[0]->nodeValue);
+ $collections = $dom->getElementsByTagName('Collection');
+ $this->assertEquals(0, $collections->length);
+ $collection = $collections->item(0);
+ $this->assertEquals("Class", $collection->childNodes->item(0)->nodeName);
+ $this->assertEquals("Email", $collection->childNodes->item(0)->nodeValue);
+ $this->assertEquals("SyncKey", $collection->childNodes->item(1)->nodeName);
+ $this->assertEquals("1", $collection->childNodes->item(1)->nodeValue);
+ $this->assertEquals("Status", $collection->childNodes->item(3)->nodeName);
+ $this->assertEquals("1", $collection->childNodes->item(3)->nodeValue);
+ }
+}
diff --git a/src/tests/Infrastructure/AutodiscoverTest.php b/src/tests/Infrastructure/AutodiscoverTest.php
new file mode 100644
--- /dev/null
+++ b/src/tests/Infrastructure/AutodiscoverTest.php
@@ -0,0 +1,89 @@
+<?php
+
+namespace Tests\Infrastructure;
+
+use Tests\TestCase;
+
+class AutodiscoverTest extends TestCase
+{
+ private \GuzzleHttp\Client $client;
+ /**
+ * {@inheritDoc}
+ */
+ public function setUp(): void
+ {
+ parent::setUp();
+ $this->client = new \GuzzleHttp\Client([
+ 'http_errors' => false, // No exceptions
+ 'base_uri' => "http://roundcube/",
+ 'verify' => false,
+ 'connect_timeout' => 10,
+ 'timeout' => 10,
+ ]);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function tearDown(): void
+ {
+ parent::tearDown();
+ }
+
+ public function testWellKnownOutlook()
+ {
+ $body = <<<EOF
+ <Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006">
+ <Request>
+ <EMailAddress>admin@example.local</EMailAddress>
+ <AcceptableResponseSchema>
+ http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a
+ </AcceptableResponseSchema>
+ </Request>
+ </Autodiscover>
+ EOF;
+ $response = $this->client->request('POST', 'autodiscover/autodiscover.xml', [
+ 'headers' => [
+ "Content-Type" => "text/xml; charset=utf-8"
+ ],
+ 'body' => $body
+ ]);
+ $this->assertEquals($response->getStatusCode(), 200);
+ $data = $response->getBody();
+ $this->assertTrue(str_contains($data, '<Server>example.local</Server>'));
+ $this->assertTrue(str_contains($data, 'admin@example.local'));
+ }
+
+ public function testWellKnownActivesync()
+ {
+ $body = <<<EOF
+ <Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/mobilesync/requestschema/2006">
+ <Request>
+ <EMailAddress>admin@example.local</EMailAddress>
+ <AcceptableResponseSchema>
+ http://schemas.microsoft.com/exchange/autodiscover/mobilesync/responseschema/2006
+ </AcceptableResponseSchema>
+ </Request>
+ </Autodiscover>
+ EOF;
+ $response = $this->client->request('POST', 'autodiscover/autodiscover.xml', [
+ 'headers' => [
+ "Content-Type" => "text/xml; charset=utf-8"
+ ],
+ 'body' => $body
+ ]);
+ $this->assertEquals($response->getStatusCode(), 200);
+ $data = $response->getBody();
+ $this->assertTrue(str_contains($data, '<Url>https://example.local/Microsoft-Server-ActiveSync</Url>'));
+ $this->assertTrue(str_contains($data, 'admin@example.local'));
+ }
+
+ public function testWellKnownMail()
+ {
+ $response = $this->client->request(
+ 'GET',
+ '.well-known/autoconfig/mail/config-v1.1.xml?emailaddress=fred@example.com'
+ );
+ $this->assertEquals($response->getStatusCode(), 200);
+ }
+}
diff --git a/src/tests/Infrastructure/DavTest.php b/src/tests/Infrastructure/DavTest.php
new file mode 100644
--- /dev/null
+++ b/src/tests/Infrastructure/DavTest.php
@@ -0,0 +1,282 @@
+<?php
+
+namespace Tests\Infrastructure;
+
+use Tests\TestCase;
+
+class DavTest extends TestCase
+{
+ private ?\GuzzleHttp\Client $client = null;
+
+ /**
+ * {@inheritDoc}
+ */
+ public function setUp(): void
+ {
+ parent::setUp();
+
+ $this->getTestUser('jane@kolab.org', ['password' => 'simple123'], true, true);
+
+ if (!$this->client) {
+ $this->client = new \GuzzleHttp\Client([
+ 'http_errors' => false, // No exceptions
+ 'base_uri' => \config("services.dav.uri"),
+ 'verify' => false,
+ 'auth' => [$this->user->email, 'simple123'],
+ 'connect_timeout' => 10,
+ 'timeout' => 10,
+ 'headers' => [
+ "Content-Type" => "application/xml; charset=utf-8",
+ "Depth" => "1",
+ ]
+ ]);
+ }
+ }
+
+ public function testDiscoverPrincipal()
+ {
+ $user = $this->user;
+ $body = "<d:propfind xmlns:d='DAV:'><d:prop><d:current-user-principal/></d:prop></d:propfind>";
+ $response = $this->client->request('PROPFIND', '/iRony/', ['body' => $body]);
+ $this->assertEquals(207, $response->getStatusCode());
+ $data = $response->getBody();
+ $this->assertStringContainsString("<d:href>/iRony/principals/{$user->email}/</d:href>", $data);
+ $this->assertStringContainsString('<d:href>/iRony/calendars/</d:href>', $data);
+ $this->assertStringContainsString('<d:href>/iRony/addressbooks/</d:href>', $data);
+ }
+
+ /**
+ * This codepath is triggerd by MacOS CalDAV when it tries to login.
+ * Verify we don't crash and end up with a 500 status code.
+ */
+ public function testFailingLogin()
+ {
+ $body = "<d:propfind xmlns:d='DAV:'><d:prop><d:current-user-principal/></d:prop></d:propfind>";
+ $headers = [
+ "Content-Type" => "application/xml; charset=utf-8",
+ "Depth" => "1",
+ 'body' => $body,
+ 'auth' => ['invaliduser@kolab.org', 'invalid']
+ ];
+
+ $response = $this->client->request('PROPFIND', '/iRony/', $headers);
+ $this->assertEquals(403, $response->getStatusCode());
+ }
+
+ /**
+ * This codepath is triggerd by MacOS CardDAV when it tries to login.
+ * NOTE: This depends on the username_domain roundcube config option.
+ */
+ public function testShortlogin()
+ {
+ $this->markTestSkipped(
+ 'Shortlogins dont work with the nginx proxy.'
+ );
+ $body = "<d:propfind xmlns:d='DAV:'><d:prop><d:current-user-principal/></d:prop></d:propfind>";
+ $response = $this->client->request('PROPFIND', '/iRony/', [
+ 'body' => $body,
+ 'auth' => ['jane', 'simple123']
+ ]);
+ $this->assertEquals(207, $response->getStatusCode());
+ }
+
+ public function testDiscoverCalendarHomeset()
+ {
+ $user = $this->user;
+ $body = <<<EOF
+ <d:propfind xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
+ <d:prop>
+ <c:calendar-home-set />
+ </d:prop>
+ </d:propfind>
+ EOF;
+
+ $response = $this->client->request('PROPFIND', '/iRony/', ['body' => $body]);
+ $this->assertEquals(207, $response->getStatusCode());
+ $data = $response->getBody();
+ $this->assertStringContainsString("<d:href>/iRony/calendars/{$user->email}/</d:href>", $data);
+ }
+
+ public function testDiscoverCalendars()
+ {
+ $user = $this->user;
+ $body = <<<EOF
+ <d:propfind xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/" xmlns:c="urn:ietf:params:xml:ns:caldav">
+ <d:prop>
+ <d:resourcetype />
+ <d:displayname />
+ <cs:getctag />
+ <c:supported-calendar-component-set />
+ </d:prop>
+ </d:propfind>
+ EOF;
+
+ $response = $this->client->request('PROPFIND', "/iRony/calendars/{$user->email}", [
+ 'headers' => [
+ "Depth" => "infinity",
+ ],
+ 'body' => $body
+ ]);
+ $this->assertEquals(207, $response->getStatusCode());
+ $data = $response->getBody();
+ $this->assertStringContainsString("<d:href>/iRony/calendars/{$user->email}/</d:href>", $data);
+
+ $doc = new \DOMDocument('1.0', 'UTF-8');
+ $doc->loadXML($data);
+ $response = $doc->getElementsByTagName('response')->item(1);
+ $doc->getElementsByTagName('href')->item(0);
+
+ $this->assertEquals("d:href", $response->childNodes->item(0)->nodeName);
+ $href = $response->childNodes->item(0)->nodeValue;
+ return $href;
+ }
+
+ /**
+ * @depends testDiscoverCalendars
+ */
+ public function testPropfindCalendar($href)
+ {
+ $body = <<<EOF
+ <d:propfind xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/" xmlns:c="urn:ietf:params:xml:ns:caldav">
+ <d:prop>
+ <d:resourcetype />
+ <d:owner/>
+ <d:current-user-principal/>
+ <d:current-user-privilege-set/>
+ <d:supported-report-set/>
+ <cs:getctag />
+ <c:supported-calendar-component-set />
+ </d:prop>
+ </d:propfind>
+ EOF;
+
+ $response = $this->client->request('PROPFIND', $href, [
+ 'headers' => [
+ "Depth" => "0",
+ ],
+ 'body' => $body,
+ ]);
+ $this->assertEquals(207, $response->getStatusCode());
+ $data = $response->getBody();
+ $this->assertStringContainsString("<d:href>$href</d:href>", $data);
+ }
+
+ /**
+ * Thunderbird does this and relies on the WWW-Authenticate header response to
+ * start sending authenticated requests.
+ *
+ * @depends testDiscoverCalendars
+ */
+ public function testPropfindCalendarWithoutAuth($href)
+ {
+ $body = <<<EOF
+ <d:propfind xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/" xmlns:c="urn:ietf:params:xml:ns:caldav">
+ <d:prop>
+ <d:resourcetype />
+ <d:owner/>
+ <d:current-user-principal/>
+ <d:current-user-privilege-set/>
+ <d:supported-report-set/>
+ <cs:getctag />
+ <c:supported-calendar-component-set />
+ </d:prop>
+ </d:propfind>
+ EOF;
+
+ $response = $this->client->request('PROPFIND', $href, [
+ 'headers' => [
+ "Depth" => "0",
+ ],
+ 'body' => $body,
+ 'auth' => []
+ ]);
+ $this->assertEquals(401, $response->getStatusCode());
+ $this->assertStringContainsString('Basic realm=', $response->getHeader('WWW-Authenticate')[0]);
+ $data = $response->getBody();
+ $this->assertStringContainsString("<s:exception>Sabre\DAV\Exception\NotAuthenticated</s:exception>", $data);
+ }
+
+ /**
+ * Required for MacOS autoconfig
+ */
+ public function testOptions()
+ {
+ $user = $this->user;
+ $body = <<<EOF
+ <d:propfind xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/" xmlns:c="urn:ietf:params:xml:ns:caldav">
+ <d:prop>
+ <d:resourcetype />
+ <d:displayname />
+ <cs:getctag />
+ <c:supported-calendar-component-set />
+ </d:prop>
+ </d:propfind>
+ EOF;
+
+ $response = $this->client->request('OPTIONS', "/iRony/principals/{$user->email}/", ['body' => $body]);
+ $this->assertEquals(200, $response->getStatusCode());
+ $this->assertStringContainsString('PROPFIND', $response->getHeader('Allow')[0]);
+ }
+
+ public function testWellKnown()
+ {
+ $user = $this->user;
+ $body = <<<EOF
+ <d:propfind xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/" xmlns:c="urn:ietf:params:xml:ns:caldav">
+ <d:prop>
+ <d:resourcetype />
+ <d:displayname />
+ <cs:getctag />
+ <c:supported-calendar-component-set />
+ </d:prop>
+ </d:propfind>
+ EOF;
+
+ // The base URL needs to work as a redirect
+ $response = $this->client->request('PROPFIND', '/.well-known/caldav', [
+ 'headers' => [
+ "Depth" => "infinity",
+ ],
+ 'body' => $body,
+ 'allow_redirects' => false
+ ]);
+ $this->assertEquals(301, $response->getStatusCode());
+ $redirectTarget = $response->getHeader('location')[0];
+ $this->assertEquals(\config('services.dav.uri') . "iRony/", $redirectTarget);
+
+ // Follow the redirect
+ $response = $this->client->request('PROPFIND', $redirectTarget, [
+ 'headers' => [
+ "Depth" => "infinity",
+ ],
+ 'body' => $body,
+ 'allow_redirects' => false
+ ]);
+ $this->assertEquals(207, $response->getStatusCode());
+
+ // Any URL should result in a redirect to the same path
+ $response = $this->client->request('PROPFIND', "/.well-known/caldav/calendars/{$user->email}", [
+ 'headers' => [
+ "Depth" => "infinity",
+ ],
+ 'body' => $body,
+ 'allow_redirects' => false
+ ]);
+ $this->assertEquals(301, $response->getStatusCode());
+ $redirectTarget = $response->getHeader('location')[0];
+ //FIXME we have an extra slash that we don't technically want here
+ $this->assertEquals(\config('services.dav.uri') . "iRony//calendars/{$user->email}", $redirectTarget);
+
+ // Follow the redirect
+ $response = $this->client->request('PROPFIND', $redirectTarget, [
+ 'headers' => [
+ "Depth" => "infinity",
+ ],
+ 'body' => $body,
+ 'allow_redirects' => false
+ ]);
+ $this->assertEquals(207, $response->getStatusCode());
+ $data = $response->getBody();
+ $this->assertStringContainsString("<d:href>/iRony/calendars/{$user->email}/</d:href>", $data);
+ }
+}
diff --git a/src/tests/Infrastructure/RoundcubeTest.php b/src/tests/Infrastructure/RoundcubeTest.php
new file mode 100644
--- /dev/null
+++ b/src/tests/Infrastructure/RoundcubeTest.php
@@ -0,0 +1,68 @@
+<?php
+
+namespace Tests\Infrastructure;
+
+use Tests\Browser;
+use Tests\TestCaseDusk;
+
+class RoundcubeTest extends TestCaseDusk
+{
+ /**
+ * {@inheritDoc}
+ */
+ public function setUp(): void
+ {
+ parent::setUp();
+ Browser::$baseUrl = \config("services.webmail.uri");
+ $this->getTestUser('jane@kolab.org', ['password' => 'simple123'], true, true);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function tearDown(): void
+ {
+ parent::tearDown();
+ }
+
+ public function testLogin()
+ {
+ $this->browse(function (Browser $browser) {
+ $browser->visit('/')
+ ->type('#rcmloginuser', $this->user->email)
+ ->type('#rcmloginpwd', "simple123")
+ ->press('#rcmloginsubmit')
+ ->waitFor('#logo')
+ ->waitUntil('!rcmail.busy')
+ ->assertSee('Inbox');
+
+ $browser->press('.contacts')
+ ->waitUntil('!rcmail.busy')
+ ->assertVisible('#directorylist')
+ ->assertVisible('.addressbook.personal')
+ ->assertSee('Contacts');
+
+ $browser->press('.button-calendar')
+ ->waitUntil('!rcmail.busy')
+ ->assertSee('Calendar');
+
+ //TODO requires the default folders to be created
+ // $browser->press('.button-files')
+ // ->waitUntil('!rcmail.busy')
+ // ->assertSeeIn('#files-folder-list', 'Files');
+
+ $browser->press('.button-notes')
+ ->waitUntil('!rcmail.busy')
+ ->assertSeeIn('#notebooks-content', 'Notes');
+
+ $browser->press('.button-tasklist')
+ ->waitUntil('!rcmail.busy')
+ ->assertSee('Tasks');
+
+ $browser->press('.settings')
+ ->waitUntil('!rcmail.busy')
+ ->assertSee('Activesync');
+ // print($browser->dump());
+ });
+ }
+}
diff --git a/src/tests/TestCaseTrait.php b/src/tests/TestCaseTrait.php
--- a/src/tests/TestCaseTrait.php
+++ b/src/tests/TestCaseTrait.php
@@ -2,6 +2,7 @@
namespace Tests;
+use App\Backends\IMAP;
use App\Backends\LDAP;
use App\CompanionApp;
use App\Domain;
@@ -94,6 +95,13 @@
*/
protected $userPassword;
+ /**
+ * A cached test user.
+ *
+ * @var ?\App\User
+ */
+ protected $user;
+
/**
* Register the beta entitlement for a user
*/
@@ -403,7 +411,12 @@
return;
}
- LDAP::deleteUser($user);
+ if (\config('app.with_imap')) {
+ IMAP::deleteUser($user);
+ }
+ if (\config('app.with_ldap')) {
+ LDAP::deleteUser($user);
+ }
$user->forceDelete();
}
@@ -553,10 +566,16 @@
*
* @coversNothing
*/
- protected function getTestUser($email, $attrib = [])
+ protected function getTestUser($email, $attrib = [], $createInBackends = false, $cached = false)
{
+ if ($cached && $this->user) {
+ return $this->user;
+ }
+
// Disable jobs (i.e. skip LDAP oprations)
- Queue::fake();
+ if (!$createInBackends) {
+ Queue::fake();
+ }
$user = User::firstOrCreate(['email' => $email], $attrib);
if ($user->trashed()) {
@@ -565,6 +584,13 @@
$user = User::create(['email' => $email] + $attrib);
}
+ if ($cached) {
+ $this->user = $user;
+ $this->beforeApplicationDestroyed(function () use ($user) {
+ $this->deleteTestUser($user->email);
+ });
+ }
+
return $user;
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Apr 5, 5:32 PM (10 h, 23 m ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18834042
Default Alt Text
D3989.1775410376.diff (27 KB)
Attached To
Mode
D3989: Added infrastructure tests for Activesync/CalDav/WOPI/Roundcube & fixed the well-known redirect for caldav.
Attached
Detach File
Event Timeline