Repository: andregasser/bigbone (kotlin)

Issue:
Implement Admin Email Domain Blocks API
Mastodon's Admin Email Domain Blocks API allows an admin to disallow certain email domains from signing up. The goal of this task is to implement the following endpoints of this API in BigBone:

- List all blocked email domains
- Get a single blocked email domain
- Block an email domain from signups
- Delete an email domain block

The Admin Email Domain Blocks API as it is documented by Mastodon can be found here:
https://docs.joinmastodon.org/methods/admin/email_domain_blocks/

Tip: A lot of other endpoints similar to this have already been implemented. In order to get an idea how to implement this, I suggest that you study the code upfront. Start with one of the `*Methods.kt` files.

Please consult the following documents to make sure your contribution meets our projects criteria:

- [Code of Conduct](https://github.com/andregasser/bigbone/blob/master/CODE_OF_CONDUCT.md)
- [Code Contribution Guidelines](https://github.com/andregasser/bigbone/blob/master/CONTRIBUTING.md)

Pull request:
# Description

Adds methods to get, add, and remove email domain blocks.

Closes #329.

# Type of Change

- New feature
- Documentation

# Breaking Changes

- None

# How Has This Been Tested?

I’ve added new unit tests for every non-Rx version

# Mandatory Checklist

- [x] I ran `gradle check` and there were no errors reported
- [x] I have performed a self-review of my code
- [x] I have added tests that prove my fix is effective or that my feature works
- [x] All tests pass locally with my changes
- [x] I have added KDoc documentation to all public methods

# Optional Things To Check

The items below are some more things to check before asking other people to review your code.

- [x] In case you worked on a new feature: Did you also implement the reactive endpoint (bigbone-rx)?
- [x] In case you added new `*Methods` classes: Did you also reference it in the `MastodonClient` main class?
- [x] Did you also update the documentation in the `/docs` folder (e.g. API Coverage page)?

Patch:
diff --git a/bigbone-rx/src/main/kotlin/social/bigbone/rx/admin/RxAdminEmailDomainBlockMethods.kt b/bigbone-rx/src/main/kotlin/social/bigbone/rx/admin/RxAdminEmailDomainBlockMethods.kt
new file mode 100644
index 000000000..721ca494d
--- /dev/null
+++ b/bigbone-rx/src/main/kotlin/social/bigbone/rx/admin/RxAdminEmailDomainBlockMethods.kt
@@ -0,0 +1,65 @@
+package social.bigbone.rx.admin
+
+import io.reactivex.rxjava3.core.Completable
+import io.reactivex.rxjava3.core.Single
+import social.bigbone.MastodonClient
+import social.bigbone.api.Pageable
+import social.bigbone.api.Range
+import social.bigbone.api.entity.admin.AdminEmailDomainBlock
+import social.bigbone.api.method.admin.AdminEmailDomainBlockMethods
+
+/**
+ * Reactive implementation of [AdminEmailDomainBlockMethods].
+ *
+ * Disallow certain email domains from signing up.
+ *
+ * @see <a href="https://docs.joinmastodon.org/methods/admin/email_domain_blocks/">Mastodon admin/email_domain_blocks API methods</a>
+ */
+class RxAdminEmailDomainBlockMethods(client: MastodonClient) {
+
+    private val adminEmailDomainBlockMethods = AdminEmailDomainBlockMethods(client)
+
+    /**
+     * Show information about all email domains blocked from signing up.
+     *
+     * @param range optional Range for the pageable return value
+     *
+     * @see <a href="https://docs.joinmastodon.org/methods/admin/email_domain_blocks/#get">Mastodon API documentation: admin/email_domain_blocks/#get</a>
+     */
+    @JvmOverloads
+    fun getAllEmailDomainBlocks(range: Range = Range()): Single<Pageable<AdminEmailDomainBlock>> = Single.fromCallable {
+        adminEmailDomainBlockMethods.getAllEmailDomainBlocks(range).execute()
+    }
+
+    /**
+     * Show information about a single email domain that is blocked from signups.
+     *
+     * @param id The ID of the EmailDomainBlock in the database.
+     * @see <a href="https://docs.joinmastodon.org/methods/admin/email_domain_blocks/#get-one">
+     *     Mastodon API documentation: admin/email_domain_blocks/#get-one</a>
+     */
+    fun getEmailDomainBlock(id: String): Single<AdminEmailDomainBlock> = Single.fromCallable {
+        adminEmailDomainBlockMethods.getEmailDomainBlock(id).execute()
+    }
+
+    /**
+     * Add a domain to the list of email domains blocked from signups.
+     *
+     * @param domain The domain to block federation with.
+     * @see <a href="https://docs.joinmastodon.org/methods/admin/email_domain_blocks/#create">Mastodon API documentation: admin/email_domain_blocks/#create</a>
+     */
+    fun blockEmailDomain(domain: String): Single<AdminEmailDomainBlock> = Single.fromCallable {
+        adminEmailDomainBlockMethods.blockEmailDomain(domain).execute()
+    }
+
+    /**
+     * Lift a block against an email domain.
+     *
+     * @param id The ID of the EmailDomainBlock in the database.
+     *
+     * @see <a href="https://docs.joinmastodon.org/methods/admin/email_domain_blocks/#delete">Mastodon API documentation: admin/email_domain_blocks/#delete</a>
+     */
+    fun removeEmailDomainBlock(id: String) = Completable.fromAction {
+        adminEmailDomainBlockMethods.removeEmailDomainBlock(id)
+    }
+}
diff --git a/bigbone/src/main/kotlin/social/bigbone/MastodonClient.kt b/bigbone/src/main/kotlin/social/bigbone/MastodonClient.kt
index f3218b035..1c3e6b08e 100644
--- a/bigbone/src/main/kotlin/social/bigbone/MastodonClient.kt
+++ b/bigbone/src/main/kotlin/social/bigbone/MastodonClient.kt
@@ -67,6 +67,7 @@ import social.bigbone.api.method.TimelineMethods
 import social.bigbone.api.method.TrendMethods
 import social.bigbone.api.method.admin.AdminDimensionMethods
 import social.bigbone.api.method.admin.AdminDomainBlockMethods
+import social.bigbone.api.method.admin.AdminEmailDomainBlockMethods
 import social.bigbone.api.method.admin.AdminIpBlockMethods
 import social.bigbone.api.method.admin.AdminMeasureMethods
 import social.bigbone.api.method.admin.AdminRetentionMethods
@@ -117,8 +118,15 @@ private constructor(
      * Access API methods under the "admin/domain_blocks" endpoint.
      */
     @Suppress("unused") // public API
-    @get:JvmName("adminDomainBlock")
-    val adminDomainBlock: AdminDomainBlockMethods by lazy { AdminDomainBlockMethods(this) }
+    @get:JvmName("adminDomainBlocks")
+    val adminDomainBlocks: AdminDomainBlockMethods by lazy { AdminDomainBlockMethods(this) }
+
+    /**
+     * Access API methods under the "admin/email_domain_blocks" endpoint.
+     */
+    @Suppress("unused") // public API
+    @get:JvmName("adminEmailDomainBlocks")
+    val adminEmailDomainBlocks: AdminEmailDomainBlockMethods by lazy { AdminEmailDomainBlockMethods(this) }
 
     /**
      * Access API methods under the "admin/ip_blocks" endpoint.
diff --git a/bigbone/src/main/kotlin/social/bigbone/api/entity/admin/AdminEmailDomainBlock.kt b/bigbone/src/main/kotlin/social/bigbone/api/entity/admin/AdminEmailDomainBlock.kt
new file mode 100644
index 000000000..bae4be029
--- /dev/null
+++ b/bigbone/src/main/kotlin/social/bigbone/api/entity/admin/AdminEmailDomainBlock.kt
@@ -0,0 +1,41 @@
+package social.bigbone.api.entity.admin
+
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+import social.bigbone.DateTimeSerializer
+import social.bigbone.PrecisionDateTime
+import social.bigbone.api.entity.data.History
+
+/**
+ * Represents an email domain that cannot be used to sign up.
+ *
+ * @see <a href="https://docs.joinmastodon.org/entities/Admin_EmailDomainBlock/">Mastodon API Admin::EmailDomainBlock documentation</a>
+ */
+@Serializable
+data class AdminEmailDomainBlock(
+    /**
+     * The ID of the EmailDomainBlock in the database.
+     * String cast from an Integer, but not guaranteed to be a number.
+     */
+    @SerialName("id")
+    val id: String,
+
+    /**
+     * The email domain that is not allowed to be used for signups.
+     */
+    @SerialName("domain")
+    val domain: String,
+
+    /**
+     * The timestamp of the notification.
+     */
+    @SerialName("created_at")
+    @Serializable(with = DateTimeSerializer::class)
+    val createdAt: PrecisionDateTime = PrecisionDateTime.InvalidPrecisionDateTime.Unavailable,
+
+    /**
+     * Usage statistics for given days (typically the past week).
+     */
+    @SerialName("history")
+    val history: List<History>
+)
diff --git a/bigbone/src/main/kotlin/social/bigbone/api/entity/data/History.kt b/bigbone/src/main/kotlin/social/bigbone/api/entity/data/History.kt
index e25db1e28..2d3cec6c9 100644
--- a/bigbone/src/main/kotlin/social/bigbone/api/entity/data/History.kt
+++ b/bigbone/src/main/kotlin/social/bigbone/api/entity/data/History.kt
@@ -7,6 +7,7 @@ import kotlinx.serialization.Serializable
  * Usage statistics for given days (typically the past week).
  * @see <a href="https://docs.joinmastodon.org/entities/Tag/#history">Mastodon API Tag history</a>
  * @see <a href="https://docs.joinmastodon.org/entities/PreviewCard/#history">Mastodon API PreviewCard history
+ * @see <a href="https://docs.joinmastodon.org/entities/Admin_EmailDomainBlock/#history">Mastodon API Admin::EmailDomainBlock history
  */
 @Serializable
 data class History(
diff --git a/bigbone/src/main/kotlin/social/bigbone/api/method/admin/AdminEmailDomainBlockMethods.kt b/bigbone/src/main/kotlin/social/bigbone/api/method/admin/AdminEmailDomainBlockMethods.kt
new file mode 100644
index 000000000..00973bff5
--- /dev/null
+++ b/bigbone/src/main/kotlin/social/bigbone/api/method/admin/AdminEmailDomainBlockMethods.kt
@@ -0,0 +1,76 @@
+package social.bigbone.api.method.admin
+
+import social.bigbone.MastodonClient
+import social.bigbone.MastodonRequest
+import social.bigbone.Parameters
+import social.bigbone.api.Pageable
+import social.bigbone.api.Range
+import social.bigbone.api.entity.admin.AdminEmailDomainBlock
+
+/**
+ * Disallow certain email domains from signing up.
+ *
+ * @see <a href="https://docs.joinmastodon.org/methods/admin/email_domain_blocks/">Mastodon admin/email_domain_blocks API methods</a>
+ */
+class AdminEmailDomainBlockMethods(private val client: MastodonClient) {
+
+    private val adminEmailDomainBlockEndpoint = "api/v1/admin/email_domain_blocks"
+
+    /**
+     * Show information about all email domains blocked from signing up.
+     *
+     * @param range optional Range for the pageable return value
+     *
+     * @see <a href="https://docs.joinmastodon.org/methods/admin/email_domain_blocks/#get">Mastodon API documentation: admin/email_domain_blocks/#get</a>
+     */
+    @JvmOverloads
+    fun getAllEmailDomainBlocks(range: Range = Range()): MastodonRequest<Pageable<AdminEmailDomainBlock>> {
+        return client.getPageableMastodonRequest(
+            endpoint = adminEmailDomainBlockEndpoint,
+            method = MastodonClient.Method.GET,
+            parameters = range.toParameters()
+        )
+    }
+
+    /**
+     * Show information about a single email domain that is blocked from signups.
+     *
+     * @param id The ID of the EmailDomainBlock in the database.
+     * @see <a href="https://docs.joinmastodon.org/methods/admin/email_domain_blocks/#get-one">
+     *     Mastodon API documentation: admin/email_domain_blocks/#get-one</a>
+     */
+    fun getEmailDomainBlock(id: String): MastodonRequest<AdminEmailDomainBlock> {
+        return client.getMastodonRequest(
+            endpoint = "$adminEmailDomainBlockEndpoint/$id",
+            method = MastodonClient.Method.GET
+        )
+    }
+
+    /**
+     * Add a domain to the list of email domains blocked from signups.
+     *
+     * @param domain The domain to block federation with.
+     * @see <a href="https://docs.joinmastodon.org/methods/admin/email_domain_blocks/#create">Mastodon API documentation: admin/email_domain_blocks/#create</a>
+     */
+    fun blockEmailDomain(domain: String): MastodonRequest<AdminEmailDomainBlock> {
+        return client.getMastodonRequest(
+            endpoint = adminEmailDomainBlockEndpoint,
+            method = MastodonClient.Method.POST,
+            parameters = Parameters().append("domain", domain)
+        )
+    }
+
+    /**
+     * Lift a block against an email domain.
+     *
+     * @param id The ID of the EmailDomainBlock in the database.
+     *
+     * @see <a href="https://docs.joinmastodon.org/methods/admin/email_domain_blocks/#delete">Mastodon API documentation: admin/email_domain_blocks/#delete</a>
+     */
+    fun removeEmailDomainBlock(id: String) {
+        client.performAction(
+            endpoint = "$adminEmailDomainBlockEndpoint/$id",
+            method = MastodonClient.Method.DELETE
+        )
+    }
+}
diff --git a/docs/api-coverage/admin/email-domain-blocks.md b/docs/api-coverage/admin/email-domain-blocks.md
index bf4740c0d..1273e83a8 100644
--- a/docs/api-coverage/admin/email-domain-blocks.md
+++ b/docs/api-coverage/admin/email-domain-blocks.md
@@ -10,9 +10,9 @@ nav_order: 8
 
 <a href="https://docs.joinmastodon.org/methods/admin/email_domain_blocks/" target="_blank">https://docs.joinmastodon.org/methods/admin/email_domain_blocks/</a>
 
-| Method                                         | Description                        | Status | Comments | 
-|------------------------------------------------|------------------------------------|--------|----------|
-| `GET /api/v1/admin/email_domain_blocks`        | List all blocked email domains     | 🔴     |          |
-| `GET /api/v1/admin/email_domain_blocks/:id`    | Get a single blocked email domain  | 🔴     |          |
-| `POST /api/v1/admin/email_domain_blocks`       | Block an email domain from signups | 🔴     |          |
-| `DELETE /api/v1/admin/email_domain_blocks/:id` | Delete an email domain block       | 🔴     |          |
+| Method                                         | Description                        | Status                          | Comments        | 
+|------------------------------------------------|------------------------------------|---------------------------------|-----------------|
+| `GET /api/v1/admin/email_domain_blocks`        | List all blocked email domains     | <img src="/assets/green16.png"> | Fully supported |
+| `GET /api/v1/admin/email_domain_blocks/:id`    | Get a single blocked email domain  | <img src="/assets/green16.png"> | Fully supported |
+| `POST /api/v1/admin/email_domain_blocks`       | Block an email domain from signups | <img src="/assets/green16.png"> | Fully supported |
+| `DELETE /api/v1/admin/email_domain_blocks/:id` | Delete an email domain block       | <img src="/assets/green16.png"> | Fully supported |


Test patch:
diff --git a/bigbone/src/test/assets/admin_email_domain_blocks_all_blocked_success.json b/bigbone/src/test/assets/admin_email_domain_blocks_all_blocked_success.json
new file mode 100644
index 000000000..3080f569b
--- /dev/null
+++ b/bigbone/src/test/assets/admin_email_domain_blocks_all_blocked_success.json
@@ -0,0 +1,44 @@
+[
+  {
+    "id": "1",
+    "domain": "foo",
+    "created_at": "2022-11-16T06:09:36.176Z",
+    "history": [
+      {
+        "day": "1668556800",
+        "accounts": "0",
+        "uses": "0"
+      },
+      {
+        "day": "1668470400",
+        "accounts": "0",
+        "uses": "0"
+      },
+      {
+        "day": "1668384000",
+        "accounts": "0",
+        "uses": "0"
+      },
+      {
+        "day": "1668297600",
+        "accounts": "0",
+        "uses": "0"
+      },
+      {
+        "day": "1668211200",
+        "accounts": "0",
+        "uses": "0"
+      },
+      {
+        "day": "1668124800",
+        "accounts": "0",
+        "uses": "0"
+      },
+      {
+        "day": "1668038400",
+        "accounts": "0",
+        "uses": "0"
+      }
+    ]
+  }
+]
diff --git a/bigbone/src/test/assets/admin_email_domain_blocks_block_success.json b/bigbone/src/test/assets/admin_email_domain_blocks_block_success.json
new file mode 100644
index 000000000..4b12867b7
--- /dev/null
+++ b/bigbone/src/test/assets/admin_email_domain_blocks_block_success.json
@@ -0,0 +1,42 @@
+{
+  "id": "1",
+  "domain": "foo",
+  "created_at": "2022-11-16T06:09:36.176Z",
+  "history": [
+    {
+      "day": "1668556800",
+      "accounts": "0",
+      "uses": "0"
+    },
+    {
+      "day": "1668470400",
+      "accounts": "0",
+      "uses": "0"
+    },
+    {
+      "day": "1668384000",
+      "accounts": "0",
+      "uses": "0"
+    },
+    {
+      "day": "1668297600",
+      "accounts": "0",
+      "uses": "0"
+    },
+    {
+      "day": "1668211200",
+      "accounts": "0",
+      "uses": "0"
+    },
+    {
+      "day": "1668124800",
+      "accounts": "0",
+      "uses": "0"
+    },
+    {
+      "day": "1668038400",
+      "accounts": "0",
+      "uses": "0"
+    }
+  ]
+}
diff --git a/bigbone/src/test/assets/admin_email_domain_blocks_delete_success.json b/bigbone/src/test/assets/admin_email_domain_blocks_delete_success.json
new file mode 100644
index 000000000..0967ef424
--- /dev/null
+++ b/bigbone/src/test/assets/admin_email_domain_blocks_delete_success.json
@@ -0,0 +1,1 @@
+{}
diff --git a/bigbone/src/test/assets/admin_email_domain_blocks_single_success.json b/bigbone/src/test/assets/admin_email_domain_blocks_single_success.json
new file mode 100644
index 000000000..4b12867b7
--- /dev/null
+++ b/bigbone/src/test/assets/admin_email_domain_blocks_single_success.json
@@ -0,0 +1,42 @@
+{
+  "id": "1",
+  "domain": "foo",
+  "created_at": "2022-11-16T06:09:36.176Z",
+  "history": [
+    {
+      "day": "1668556800",
+      "accounts": "0",
+      "uses": "0"
+    },
+    {
+      "day": "1668470400",
+      "accounts": "0",
+      "uses": "0"
+    },
+    {
+      "day": "1668384000",
+      "accounts": "0",
+      "uses": "0"
+    },
+    {
+      "day": "1668297600",
+      "accounts": "0",
+      "uses": "0"
+    },
+    {
+      "day": "1668211200",
+      "accounts": "0",
+      "uses": "0"
+    },
+    {
+      "day": "1668124800",
+      "accounts": "0",
+      "uses": "0"
+    },
+    {
+      "day": "1668038400",
+      "accounts": "0",
+      "uses": "0"
+    }
+  ]
+}
diff --git a/bigbone/src/test/kotlin/social/bigbone/api/method/admin/AdminEmailDomainBlockMethodsTest.kt b/bigbone/src/test/kotlin/social/bigbone/api/method/admin/AdminEmailDomainBlockMethodsTest.kt
new file mode 100644
index 000000000..9deef63fc
--- /dev/null
+++ b/bigbone/src/test/kotlin/social/bigbone/api/method/admin/AdminEmailDomainBlockMethodsTest.kt
@@ -0,0 +1,151 @@
+package social.bigbone.api.method.admin
+
+import io.mockk.slot
+import io.mockk.verify
+import org.amshove.kluent.shouldBeEmpty
+import org.amshove.kluent.shouldBeEqualTo
+import org.amshove.kluent.shouldHaveSize
+import org.junit.jupiter.api.Test
+import social.bigbone.MastodonClient
+import social.bigbone.Parameters
+import social.bigbone.PrecisionDateTime.ValidPrecisionDateTime.ExactTime
+import social.bigbone.api.Pageable
+import social.bigbone.api.Range
+import social.bigbone.api.entity.admin.AdminEmailDomainBlock
+import social.bigbone.testtool.MockClient
+import java.time.Instant
+
+class AdminEmailDomainBlockMethodsTest {
+
+    @Test
+    fun `Given client returning success, when getting all blocked Email domains without Range, then call correct endpoint and parse response`() {
+        val client = MockClient.mock("admin_email_domain_blocks_all_blocked_success.json")
+        val adminEmailDomainBlockMethods = AdminEmailDomainBlockMethods(client)
+
+        val emailDomainBlocks: Pageable<AdminEmailDomainBlock> = adminEmailDomainBlockMethods
+            .getAllEmailDomainBlocks()
+            .execute()
+
+        with(emailDomainBlocks.part) {
+            shouldHaveSize(1)
+
+            with(get(0)) {
+                id shouldBeEqualTo "1"
+                domain shouldBeEqualTo "foo"
+                createdAt shouldBeEqualTo ExactTime(Instant.parse("2022-11-16T06:09:36.176Z"))
+
+                history shouldHaveSize 7
+                history[0].day shouldBeEqualTo "1668556800"
+                history[0].accounts shouldBeEqualTo "0"
+                history[0].uses shouldBeEqualTo "0"
+            }
+        }
+        val parametersCapturingSlot = slot<Parameters>()
+        verify {
+            client.get(
+                path = "api/v1/admin/email_domain_blocks",
+                query = capture(parametersCapturingSlot)
+            )
+        }
+        with(parametersCapturingSlot.captured) {
+            toQuery().shouldBeEmpty()
+        }
+    }
+
+    @Test
+    fun `Given client returning success, when getting all blocked Email domains with Range, then use correct parameters`() {
+        val client = MockClient.mock("admin_email_domain_blocks_all_blocked_success.json")
+        val adminEmailDomainBlockMethods = AdminEmailDomainBlockMethods(client)
+        val range = Range(limit = 5, sinceId = "1234")
+
+        adminEmailDomainBlockMethods.getAllEmailDomainBlocks(range).execute()
+
+        val parametersCapturingSlot = slot<Parameters>()
+        verify {
+            client.get(
+                path = "api/v1/admin/email_domain_blocks",
+                query = capture(parametersCapturingSlot)
+            )
+        }
+        with(parametersCapturingSlot.captured) {
+            toQuery() shouldBeEqualTo "since_id=${range.sinceId}&limit=${range.limit}"
+        }
+    }
+
+    @Test
+    fun `Given client returning success, when getting single Email domain, then call correct endpoint and parse response`() {
+        val client = MockClient.mock("admin_email_domain_blocks_single_success.json")
+        val adminEmailDomainBlockMethods = AdminEmailDomainBlockMethods(client)
+        val requestedId = "1"
+
+        val emailDomainBlock: AdminEmailDomainBlock = adminEmailDomainBlockMethods
+            .getEmailDomainBlock(requestedId)
+            .execute()
+
+        with(emailDomainBlock) {
+            id shouldBeEqualTo "1"
+            domain shouldBeEqualTo "foo"
+            createdAt shouldBeEqualTo ExactTime(Instant.parse("2022-11-16T06:09:36.176Z"))
+
+            history shouldHaveSize 7
+            history[0].day shouldBeEqualTo "1668556800"
+            history[0].accounts shouldBeEqualTo "0"
+            history[0].uses shouldBeEqualTo "0"
+        }
+        verify {
+            client.get(
+                path = "api/v1/admin/email_domain_blocks/$requestedId",
+                query = null
+            )
+        }
+    }
+
+    @Test
+    fun `Given client returning success, when blocking an Email domain, then call correct endpoint and parse response`() {
+        val client = MockClient.mock("admin_email_domain_blocks_block_success.json")
+        val adminEmailDomainBlockMethods = AdminEmailDomainBlockMethods(client)
+        val requestedDomain = "foo"
+
+        val emailDomainBlock: AdminEmailDomainBlock = adminEmailDomainBlockMethods
+            .blockEmailDomain(requestedDomain)
+            .execute()
+
+        with(emailDomainBlock) {
+            id shouldBeEqualTo "1"
+            domain shouldBeEqualTo "foo"
+            createdAt shouldBeEqualTo ExactTime(Instant.parse("2022-11-16T06:09:36.176Z"))
+
+            history shouldHaveSize 7
+            history[0].day shouldBeEqualTo "1668556800"
+            history[0].accounts shouldBeEqualTo "0"
+            history[0].uses shouldBeEqualTo "0"
+        }
+        val parametersCapturingSlot = slot<Parameters>()
+        verify {
+            client.post(
+                path = "api/v1/admin/email_domain_blocks",
+                body = capture(parametersCapturingSlot)
+            )
+        }
+        with(parametersCapturingSlot.captured) {
+            toQuery() shouldBeEqualTo "domain=$requestedDomain"
+        }
+    }
+
+    @Test
+    fun `Given client returning success, when removing an Email domain block, then call correct endpoint`() {
+        val client = MockClient.mock("admin_email_domain_blocks_delete_success.json")
+        val adminEmailDomainBlockMethods = AdminEmailDomainBlockMethods(client)
+        val requestedId = "foo"
+
+        adminEmailDomainBlockMethods.removeEmailDomainBlock(requestedId)
+
+        verify {
+            client.performAction(
+                endpoint = "api/v1/admin/email_domain_blocks/$requestedId",
+                method = MastodonClient.Method.DELETE,
+                parameters = null
+            )
+        }
+    }
+}