[Web] API: complete the OpenAPI docs, add route tests for json_api.php

This commit is contained in:
FreddleSpl0it committed 2026-11-10 20:04:05 +01:00
1 parent 9825c8d290
commit 2418da031f
47 files changed
+18848 -7491

No files matched your search

+71
View File
@@ -0,0 +1,71 @@
<?php
declare(strict_types=1);
namespace Mailcow\Tests\Api\Domains;
use Mailcow\Tests\Api\ApiTestCase;
/** get/add/edit/delete alias-domain */
class AliasDomainTest extends ApiTestCase
{
public function testAllAliasDomainsAreReadOneByOne(): void
{
$result = $this->get('get/alias-domain/all', ['script' => [
self::answer('mailbox', ['get', 'alias_domains'], ['example.net', 'example.com']),
self::answer('mailbox', ['get', 'alias_domain_details', 'example.net'], ['alias_domain' => 'example.net', 'target_domain' => 'example.org']),
self::answer('mailbox', ['get', 'alias_domain_details', 'example.com'], false),
]]);
$this->assertCalled($result, 'mailbox', ['get', 'alias_domains']);
$this->assertSame([['alias_domain' => 'example.net', 'target_domain' => 'example.org']], $result->json());
}
public function testAllAliasDomainsWithoutAliasDomains(): void
{
$result = $this->get('get/alias-domain/all', ['script' => [self::answer('mailbox', ['get', 'alias_domains'], [])]]);
$this->assertSame('{}', $result->body);
$this->assertSame([['get', 'alias_domains']], $result->callsTo('mailbox'));
}
public function testOneAliasDomain(): void
{
$result = $this->get('get/alias-domain/example.net', ['script' => [
self::answer('mailbox', ['get', 'alias_domain_details', 'example.net'], ['alias_domain' => 'example.net', 'rl' => false]),
]]);
$this->assertSame(['alias_domain' => 'example.net', 'rl' => false], $result->json());
}
public function testUnknownAliasDomain(): void
{
$result = $this->get('get/alias-domain/example.com', ['script' => [self::answer('mailbox', ['get', 'alias_domain_details'], false)]]);
$this->assertCalled($result, 'mailbox', ['get', 'alias_domain_details', 'example.com']);
$this->assertSame('{}', $result->body);
}
public function testAddAliasDomains(): void
{
$attr = ['alias_domain' => "example.net\nexample.com", 'target_domain' => 'example.org', 'active' => '1', 'key_size' => '2048', 'dkim_selector' => 'dkim'];
$result = $this->post('add/alias-domain', $attr);
$this->assertCalled($result, 'mailbox', ['add', 'alias_domain', $attr]);
}
public function testEditAliasDomains(): void
{
$result = $this->post('edit/alias-domain', ['items' => ['example.net', 'example.com'], 'attr' => ['active' => '0']]);
$this->assertCalled($result, 'mailbox', ['edit', 'alias_domain', ['alias_domain' => ['example.net', 'example.com'], 'active' => '0']]);
}
public function testDeleteAliasDomains(): void
{
$result = $this->post('delete/alias-domain', ['example.net']);
$this->assertCalled($result, 'mailbox', ['delete', 'alias_domain', ['alias_domain' => ['example.net']]]);
}
}
+62
View File
@@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
namespace Mailcow\Tests\Api\Domains;
use Mailcow\Tests\Api\ApiTestCase;
/** get/dkim, add/dkim, add/dkim_duplicate, add/dkim_import, delete/dkim */
class DkimTest extends ApiTestCase
{
public function testDkimKeyOfADomain(): void
{
$key = ['pubkey' => 'MIIBIjAN', 'length' => '2048', 'dkim_txt' => 'v=DKIM1;k=rsa;t=s;s=email;p=MIIBIjAN', 'dkim_selector' => 'dkim', 'privkey' => ''];
$result = $this->get('get/dkim/example.org', ['script' => [self::answer('dkim', ['details', 'example.org'], $key)]]);
$this->assertSame([['details', 'example.org']], $result->callsTo('dkim'));
$this->assertSame($key, $result->json());
}
public function testDomainWithoutKey(): void
{
$result = $this->get('get/dkim/example.com', ['script' => [self::answer('dkim', ['details'], [])]]);
$this->assertSame('{}', $result->body);
}
public function testGenerateKeys(): void
{
$attr = ['domains' => 'example.org, example.net', 'dkim_selector' => 'dkim', 'key_size' => 2048];
$result = $this->post('add/dkim', $attr);
$this->assertSame([['add', $attr]], $result->callsTo('dkim'));
}
public function testDuplicateKey(): void
{
$attr = ['from_domain' => 'example.org', 'to_domain' => ['example.net', 'example.com']];
$result = $this->post('add/dkim_duplicate', $attr);
$this->assertSame([['duplicate', $attr]], $result->callsTo('dkim'));
}
public function testImportKey(): void
{
$attr = ['domain' => 'example.org', 'dkim_selector' => 'dkim2026', 'private_key_file' => "-----BEGIN PRIVATE KEY-----\nMIIE\n-----END PRIVATE KEY-----", 'overwrite_existing' => '1'];
$result = $this->post('add/dkim_import', $attr);
$this->assertSame([['import', $attr]], $result->callsTo('dkim'));
}
public function testDeleteKeys(): void
{
$result = $this->post('delete/dkim', ['example.org', 'example.net']);
$this->assertSame([['delete', ['domains' => ['example.org', 'example.net']]]], $result->callsTo('dkim'));
}
}
@@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
namespace Mailcow\Tests\Api\Domains;
use Mailcow\Tests\Api\ApiTestCase;
/** get/policy_wl_domain, get/policy_bl_domain, add/domain-policy, delete/domain-policy */
class DomainPolicyTest extends ApiTestCase
{
private const LISTS = [
'whitelist' => [['object' => 'example.org', 'value' => '*@partner.example.com', 'prefid' => 12]],
'blacklist' => [['object' => 'anna@example.org', 'value' => '*@spam.example.com', 'prefid' => 13]],
];
public function testAllowListOfADomain(): void
{
$result = $this->get('get/policy_wl_domain/example.org', ['script' => [self::answer('policy', ['get', 'domain', 'example.org'], self::LISTS)]]);
$this->assertSame([['get', 'domain', 'example.org']], $result->callsTo('policy'));
$this->assertSame(self::LISTS['whitelist'], $result->json());
}
public function testDenyListOfADomain(): void
{
$result = $this->get('get/policy_bl_domain/example.org', ['script' => [self::answer('policy', ['get', 'domain', 'example.org'], self::LISTS)]]);
$this->assertSame([['get', 'domain', 'example.org']], $result->callsTo('policy'));
$this->assertSame(self::LISTS['blacklist'], $result->json());
}
public function testEmptyListsAndUnknownDomains(): void
{
$empty = $this->get('get/policy_wl_domain/example.org', ['script' => [self::answer('policy', ['get', 'domain'], ['whitelist' => [], 'blacklist' => []])]]);
$this->assertSame('{}', $empty->body);
$unknown = $this->get('get/policy_bl_domain/example.com', ['script' => [self::answer('policy', ['get', 'domain'], false)]]);
$this->assertSame('{}', $unknown->body);
}
public function testAddEntry(): void
{
$attr = ['domain' => 'example.org', 'object_list' => 'wl', 'object_from' => '*@partner.example.com'];
$result = $this->post('add/domain-policy', $attr);
$this->assertSame([['add', 'domain', $attr]], $result->callsTo('policy'));
}
public function testDeleteEntries(): void
{
$result = $this->post('delete/domain-policy', [12, 13]);
$this->assertSame([['delete', 'domain', ['prefid' => [12, 13]]]], $result->callsTo('policy'));
}
}
@@ -0,0 +1,68 @@
<?php
declare(strict_types=1);
namespace Mailcow\Tests\Api\Domains;
use Mailcow\Tests\Api\ApiTestCase;
/** get/rl-domain, edit/rl-domain */
class DomainRatelimitTest extends ApiTestCase
{
public function testRatelimitOfADomain(): void
{
$result = $this->get('get/rl-domain/example.org', ['script' => [self::answer('ratelimit', ['get', 'domain', 'example.org'], ['value' => '100', 'frame' => 'h'])]]);
$this->assertSame([['get', 'domain', 'example.org']], $result->callsTo('ratelimit'));
$this->assertSame(['value' => '100', 'frame' => 'h'], $result->json());
}
public function testDomainWithoutRatelimit(): void
{
$result = $this->get('get/rl-domain/example.org', ['script' => [self::answer('ratelimit', ['get', 'domain'], false)]]);
$this->assertSame('{}', $result->body);
}
public function testAllRatelimitsOfDomainsAndAliasDomains(): void
{
$result = $this->get('get/rl-domain/all', ['script' => [
self::answer('mailbox', ['get', 'domains'], ['example.org', 'example.com']),
self::answer('mailbox', ['get', 'alias_domains'], ['example.net']),
self::answer('ratelimit', ['get', 'domain', 'example.org'], ['value' => '100', 'frame' => 'h']),
self::answer('ratelimit', ['get', 'domain', 'example.com'], false),
self::answer('ratelimit', ['get', 'domain', 'example.net'], ['value' => '10', 'frame' => 's']),
]]);
$this->assertSame([['get', 'domains'], ['get', 'alias_domains']], $result->callsTo('mailbox'));
$this->assertSame([['get', 'domain', 'example.org'], ['get', 'domain', 'example.com'], ['get', 'domain', 'example.net']], $result->callsTo('ratelimit'));
$this->assertSame([
['value' => '100', 'frame' => 'h', 'domain' => 'example.org'],
['value' => '10', 'frame' => 's', 'domain' => 'example.net'],
], $result->json());
}
public function testAllWithoutRatelimits(): void
{
$none = $this->get('get/rl-domain/all', ['script' => [
self::answer('mailbox', ['get', 'domains'], ['example.org']),
self::answer('mailbox', ['get', 'alias_domains'], []),
self::answer('ratelimit', ['get', 'domain'], false),
]]);
$this->assertSame('{}', $none->body);
$noDomains = $this->get('get/rl-domain/all', ['script' => [
self::answer('mailbox', ['get', 'domains'], []),
self::answer('mailbox', ['get', 'alias_domains'], []),
]]);
$this->assertSame('{}', $noDomains->body);
$this->assertNotCalled($noDomains, 'ratelimit');
}
public function testSetRatelimits(): void
{
$result = $this->post('edit/rl-domain', ['items' => ['example.org', 'example.net'], 'attr' => ['rl_value' => 100, 'rl_frame' => 'h']]);
$this->assertSame([['edit', 'domain', ['object' => ['example.org', 'example.net'], 'rl_value' => 100, 'rl_frame' => 'h']]], $result->callsTo('ratelimit'));
}
}
+115
View File
@@ -0,0 +1,115 @@
<?php
declare(strict_types=1);
namespace Mailcow\Tests\Api\Domains;
use Mailcow\Tests\Api\ApiResult;
use Mailcow\Tests\Api\ApiTestCase;
/** search/domain: DataTables server-side processing (SSP) of the domain table */
class DomainSearchTest extends ApiTestCase
{
private const REQUEST = [
'draw' => 3,
'start' => 0,
'length' => 10,
'search' => ['value' => 'example'],
'order' => [['column' => 2, 'dir' => 'asc']],
'columns' => [
['data' => '', 'searchable' => false, 'orderable' => false],
['data' => 'chkbox', 'searchable' => false, 'orderable' => false],
['data' => 'domain_h_name', 'searchable' => true, 'orderable' => true, 'search' => ['value' => '']],
],
];
private const PAGE = ['draw' => 3, 'recordsTotal' => 12, 'recordsFiltered' => 2, 'data' => [[2 => 'example.org'], [2 => 'example.com']]];
public function testAdminsSearchAllDomains(): void
{
$result = $this->post('search/domain', self::REQUEST, ['script' => [self::answer('SSP::simple', [], self::PAGE)]]);
$call = $this->sspCall($result, 'SSP::simple');
$this->assertSame([self::REQUEST, '@pdo', ['domain', 'd'], 'domain'], array_slice($call, 0, 4));
$this->assertSame([
2 => 'domain', 3 => 'aliases', 4 => 'mailboxes', 5 => 'quota', 6 => 'stats', 7 => 'defquota', 8 => 'maxquota',
10 => 'backupmx', 14 => 'tags', 15 => 'active',
], array_column($call[4], 'db', 'dt'));
$this->assertNotCalled($result, 'SSP::complex');
}
public function testRowsAreReplacedByTheDomainDetails(): void
{
$result = $this->post('search/domain', self::REQUEST, ['script' => [
self::answer('SSP::simple', [], self::PAGE),
self::answer('mailbox', ['get', 'domain_details', 'example.org'], ['domain_name' => 'example.org']),
self::answer('mailbox', ['get', 'domain_details', 'example.com'], false),
]]);
$this->assertSame([['get', 'domain_details', 'example.org'], ['get', 'domain_details', 'example.com']], $result->callsTo('mailbox'));
$this->assertSame(['draw' => 3, 'recordsTotal' => 12, 'recordsFiltered' => 2, 'data' => [['domain_name' => 'example.org']]], $result->json());
}
public function testAnEmptyPageIsAnsweredAsItIs(): void
{
$page = ['draw' => 1, 'recordsTotal' => 12, 'recordsFiltered' => 0, 'data' => []];
$result = $this->post('search/domain', ['draw' => 1], ['script' => [self::answer('SSP::simple', [], $page)]]);
$this->assertSame($page, $result->json());
$this->assertNotCalled($result, 'mailbox');
}
public function testErrorsOfTheSearchArePassedOn(): void
{
$result = $this->post('search/domain', self::REQUEST, ['script' => [self::answer('SSP::simple', [], ['error' => 'An SQL error occurred: unknown column'])]]);
$this->assertSame(['error' => 'An SQL error occurred: unknown column'], $result->json());
}
public function testReadOnlyKeysCanSearch(): void
{
$result = $this->post('search/domain', self::REQUEST, ['session' => self::API_RO, 'script' => [self::answer('SSP::simple', [], self::PAGE)]]);
$this->assertSame(200, $result->status);
$this->assertSame(self::REQUEST, $this->sspCall($result, 'SSP::simple')[0]);
}
public function testDomainAdminsSearchTheirDomains(): void
{
$result = $this->post('search/domain', self::REQUEST, ['session' => self::DOMAIN_ADMIN, 'script' => [self::answer('SSP::complex', [], self::PAGE)]]);
$call = $this->sspCall($result, 'SSP::complex');
$this->assertSame([self::REQUEST, '@pdo', ['domain', 'd'], 'domain'], array_slice($call, 0, 4));
$this->assertSame(['INNER JOIN domain_admins as da ON da.domain = d.domain', [
'condition' => 'da.active = 1 and da.username = :username',
'bindings' => ['username' => 'domainadmin'],
]], array_slice($call, 5));
$this->assertNotCalled($result, 'SSP::simple');
}
public function testOtherLoginsAreRefused(): void
{
foreach ([self::USER, self::NO_SESSION] as $session) {
$result = $this->post('search/domain', self::REQUEST, ['session' => $session]);
$this->assertApiError($result, 403, 'Insufficient permissions');
$this->assertNotCalled($result, 'SSP::simple');
$this->assertNotCalled($result, 'SSP::complex');
}
}
public function testWithoutJsonBodyTheSearchGetsNoParameters(): void
{
$result = $this->request('POST', 'search/domain', ['script' => [self::answer('SSP::simple', [], self::PAGE)]]);
$this->assertNull($this->sspCall($result, 'SSP::simple')[0]);
}
private function sspCall(ApiResult $result, string $name): array
{
$calls = $result->callsTo($name);
$this->assertCount(1, $calls, "one call of $name");
return $calls[0];
}
}
@@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace Mailcow\Tests\Api\Domains;
use Mailcow\Tests\Api\ApiTestCase;
/** get/add/edit/delete domain/template */
class DomainTemplateTest extends ApiTestCase
{
private const TEMPLATE = ['id' => 1, 'template' => 'Default', 'type' => 'domain', 'attributes' => ['max_num_aliases_for_domain' => 400]];
public function testAllTemplates(): void
{
$result = $this->get('get/domain/template/all', ['script' => [self::answer('mailbox', ['get', 'domain_templates'], [self::TEMPLATE])]]);
$this->assertSame([['get', 'domain_templates']], $result->callsTo('mailbox'));
$this->assertSame([self::TEMPLATE], $result->json());
}
public function testOneTemplate(): void
{
$result = $this->get('get/domain/template/1', ['script' => [self::answer('mailbox', ['get', 'domain_templates', '1'], self::TEMPLATE)]]);
$this->assertSame(self::TEMPLATE, $result->json());
}
public function testUnknownTemplate(): void
{
$result = $this->get('get/domain/template/9', ['script' => [self::answer('mailbox', ['get', 'domain_templates'], false)]]);
$this->assertCalled($result, 'mailbox', ['get', 'domain_templates', '9']);
$this->assertSame('{}', $result->body);
}
public function testTemplateWithoutIdAsksForAll(): void
{
$result = $this->get('get/domain/template');
$this->assertSame([['get', 'domain_templates', null]], $result->callsTo('mailbox'));
}
public function testAddTemplate(): void
{
$attr = ['template' => 'Small business', 'max_num_mboxes_for_domain' => 25, 'def_quota_for_mbox' => 2048, 'tags' => ['small']];
$result = $this->post('add/domain/template', $attr);
$this->assertSame([['add', 'domain_templates', $attr]], $result->callsTo('mailbox'));
}
public function testEditTemplates(): void
{
$result = $this->post('edit/domain/template', ['items' => [2, 3], 'attr' => ['template' => 'Small business', 'active' => 1]]);
$this->assertCalled($result, 'mailbox', ['edit', 'domain_templates', ['ids' => [2, 3], 'template' => 'Small business', 'active' => 1]]);
}
public function testDeleteTemplates(): void
{
$result = $this->post('delete/domain/template', [2, 3]);
$this->assertCalled($result, 'mailbox', ['delete', 'domain_templates', ['ids' => [2, 3]]]);
}
}
+152
View File
@@ -0,0 +1,152 @@
<?php
declare(strict_types=1);
namespace Mailcow\Tests\Api\Domains;
use Mailcow\Tests\Api\ApiTestCase;
/** get/domain, add/domain, edit/domain, delete/domain, delete/domain/tag, edit/domain/footer */
class DomainTest extends ApiTestCase
{
public function testAllDomainsAreReadOneByOne(): void
{
$result = $this->get('get/domain/all', ['script' => [
self::answer('mailbox', ['get', 'domains'], ['example.org', 'example.com', 'example.net']),
self::answer('mailbox', ['get', 'domain_details', 'example.org'], ['domain_name' => 'example.org']),
self::answer('mailbox', ['get', 'domain_details', 'example.com'], false),
self::answer('mailbox', ['get', 'domain_details', 'example.net'], ['domain_name' => 'example.net']),
]]);
$this->assertCalled($result, 'mailbox', ['get', 'domains', null, null]);
$this->assertSame([['domain_name' => 'example.org'], ['domain_name' => 'example.net']], $result->json());
}
public function testAllDomainsFilteredByTags(): void
{
$result = $this->get('get/domain/all', ['query' => ['tags' => 'customer,premium'], 'script' => [
self::answer('mailbox', ['get', 'domains'], ['example.org']),
self::answer('mailbox', ['get', 'domain_details', 'example.org'], ['domain_name' => 'example.org', 'tags' => ['customer']]),
]]);
$this->assertCalled($result, 'mailbox', ['get', 'domains', null, ['customer', 'premium']]);
$this->assertSame([['domain_name' => 'example.org', 'tags' => ['customer']]], $result->json());
}
public function testAnEmptyTagsParameterDoesNotFilter(): void
{
$result = $this->get('get/domain/all', ['query' => ['tags' => ''], 'script' => [self::answer('mailbox', ['get', 'domains'], [])]]);
$this->assertCalled($result, 'mailbox', ['get', 'domains', null, null]);
}
public function testAllDomainsWithoutDomains(): void
{
$result = $this->get('get/domain/all', ['script' => [self::answer('mailbox', ['get', 'domains'], [])]]);
$this->assertSame('{}', $result->body);
$this->assertSame([['get', 'domains', null, null]], $result->callsTo('mailbox'));
}
public function testAllDomainsWithoutReadableDetails(): void
{
$result = $this->get('get/domain/all', ['script' => [
self::answer('mailbox', ['get', 'domains'], ['example.org']),
self::answer('mailbox', ['get', 'domain_details'], false),
]]);
$this->assertSame('{}', $result->body);
}
public function testOneDomain(): void
{
$result = $this->get('get/domain/example.org', ['script' => [
self::answer('mailbox', ['get', 'domain_details', 'example.org'], ['domain_name' => 'example.org', 'rl' => false]),
]]);
$this->assertSame(['domain_name' => 'example.org', 'rl' => false], $result->json());
$this->assertSame([['get', 'domain_details', 'example.org']], $result->callsTo('mailbox'));
}
public function testUnknownDomain(): void
{
$result = $this->get('get/domain/example.com', ['script' => [self::answer('mailbox', ['get', 'domain_details'], false)]]);
$this->assertSame('{}', $result->body);
}
public function testAddDomain(): void
{
$attr = ['domain' => 'example.org', 'description' => 'Example Org', 'defquota' => 3072, 'tags' => ['customer'], 'restart_sogo' => '1'];
$result = $this->post('add/domain', $attr);
$this->assertCalled($result, 'mailbox', ['add', 'domain', $attr]);
}
public function testAddDomainIgnoresFurtherSegments(): void
{
$result = $this->post('add/domain/example.org', ['domain' => 'example.org']);
$this->assertCalled($result, 'mailbox', ['add', 'domain', ['domain' => 'example.org']]);
}
public function testEditDomains(): void
{
$result = $this->post('edit/domain', ['items' => ['example.org', 'example.com'], 'attr' => ['quota' => 51200, 'tags' => ['premium']]]);
$this->assertCalled($result, 'mailbox', ['edit', 'domain', ['domain' => ['example.org', 'example.com'], 'quota' => 51200, 'tags' => ['premium']]]);
}
public function testEditDomainWithASingleItem(): void
{
$result = $this->post('edit/domain', ['items' => 'example.org', 'attr' => ['active' => '0']]);
$this->assertCalled($result, 'mailbox', ['edit', 'domain', ['domain' => ['example.org'], 'active' => '0']]);
}
public function testAnAttributeNamedLikeTheItemsWins(): void
{
$result = $this->post('edit/domain', ['items' => ['example.org'], 'attr' => ['domain' => 'example.com']]);
$this->assertCalled($result, 'mailbox', ['edit', 'domain', ['domain' => 'example.com']]);
}
public function testDeleteDomains(): void
{
$result = $this->post('delete/domain', ['example.org', 'example.com']);
$this->assertCalled($result, 'mailbox', ['delete', 'domain', ['domain' => ['example.org', 'example.com']]]);
}
public function testDeleteDomainTags(): void
{
$result = $this->post('delete/domain/tag/example.org', ['customer', 'premium']);
$this->assertCalled($result, 'mailbox', ['delete', 'tags_domain', ['tags' => ['customer', 'premium'], 'domain' => 'example.org']]);
}
public function testDeleteDomainTagsWithoutTags(): void
{
$result = $this->post('delete/domain/tag/example.org', [], ['script' => [self::answer('mailbox', ['delete', 'tags_domain'], false)]]);
$this->assertCalled($result, 'mailbox', ['delete', 'tags_domain', ['tags' => [], 'domain' => 'example.org']]);
$this->assertSame(['type' => 'error', 'msg' => 'Cannot delete item'], $result->json());
}
public function testDeleteDomainTagsWithoutDomain(): void
{
$result = $this->post('delete/domain/tag', ['customer']);
$this->assertCalled($result, 'mailbox', ['delete', 'tags_domain', ['tags' => ['customer'], 'domain' => null]]);
}
public function testEditDomainFooter(): void
{
$attr = ['html' => '<p>{= from_name =}</p>', 'plain' => '{= from_name =}', 'skip_replies' => 1, 'exclude' => ['noreply@example.org', 'example.net']];
$result = $this->post('edit/domain/footer', ['items' => ['example.org'], 'attr' => $attr]);
$this->assertCalled($result, 'mailbox', ['edit', 'domain_wide_footer', ['domains' => ['example.org']] + $attr]);
}
}
+34
View File
@@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace Mailcow\Tests\Api\Domains;
use Mailcow\Tests\Api\ApiTestCase;
/** add/mta-sts, edit/mta-sts (there is no read route) */
class MtaStsTest extends ApiTestCase
{
public function testAddPolicy(): void
{
$attr = ['domain' => 'example.org', 'version' => 'stsv1', 'mode' => 'enforce', 'mx' => 'mail.example.org,mx2.example.org', 'max_age' => 86400, 'active' => 1];
$result = $this->post('add/mta-sts', $attr);
$this->assertSame([['add', 'mta_sts', $attr]], $result->callsTo('mailbox'));
// the backend reports no success message of its own
$this->assertSame(['type' => 'success', 'msg' => 'Task completed'], $result->json());
}
public function testEditPolicies(): void
{
$result = $this->post('edit/mta-sts', ['items' => ['example.org'], 'attr' => ['version' => 'stsv1', 'mode' => 'testing']]);
$this->assertSame([['edit', 'mta_sts', ['domains' => ['example.org'], 'version' => 'stsv1', 'mode' => 'testing']]], $result->callsTo('mailbox'));
}
public function testThereIsNoReadRoute(): void
{
$this->assertApiError($this->get('get/mta-sts/example.org'), 404, 'route not found');
}
}