Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds fetch all-domains api call #2867

Merged
merged 8 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,24 @@ class DomainsFragment : StoreSelectingFragment() {
}
}
}

fetch_all_domains.setOnClickListener {
lifecycleScope.launch {
val result = store.fetchAllDomains(noWpCom = false) // fetching wpcom too for debugging purposes
when {
result.isError -> {
prependToLog("Error fetching all domains: ${result.error.message}")
}
else -> {
prependToLog("All domains count: ${result.domains?.size}")
val domains = result.domains
?.joinToString(separator = "\n") {
"${it.domain} (type: ${it.type}), expiry: ${it.expiry}"
}
prependToLog("Domains:\n$domains")
}
}
}
}
}
}
6 changes: 6 additions & 0 deletions example/src/main/res/layout/fragment_domains.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,11 @@
android:layout_height="wrap_content"
android:text="Fetch domain price" />

<Button
android:id="@+id/fetch_all_domains"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Fetch all domain" />

</LinearLayout>
</ScrollView>
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package org.wordpress.android.fluxc.network.rest.wpcom.site

import com.android.volley.RequestQueue
import com.android.volley.VolleyError
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import org.assertj.core.api.Assertions.assertThat
import org.junit.Before
import org.junit.Test
Expand All @@ -16,6 +18,7 @@ import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import org.wordpress.android.fluxc.Dispatcher
import org.wordpress.android.fluxc.UnitTestUtils
import org.wordpress.android.fluxc.model.SiteModel
import org.wordpress.android.fluxc.network.BaseRequest.BaseNetworkError
import org.wordpress.android.fluxc.network.BaseRequest.GenericErrorType
Expand Down Expand Up @@ -526,6 +529,66 @@ class SiteRestClientTest {
assertThat(options).containsEntry("site_creation_flow", siteCreationFlow)
}

@Test
fun `when all domains are requested, then the correct response is built`() = test {
val allDomainsJson = "wp/all-domains/all-domains.json"
val json = UnitTestUtils.getStringFromResourceFile(javaClass, allDomainsJson)
val responseType = object : TypeToken<AllDomainsResponse>() {}.type
val response = GsonBuilder().create().fromJson(json, responseType) as AllDomainsResponse

initAllDomainsResponse(data = response)

val responseModel = restClient.fetchAllDomains(noWpCom = true)
assert(responseModel is Success)
with((responseModel as Success).data) {
assertThat(domains).hasSize(2)
assertThat(domains[0].domain).isEqualTo("some.test.domain")
assertThat(domains[0].wpcomDomain).isFalse
assertThat(domains[1].domain).isEqualTo("some.test.domain 2")
assertThat(domains[1].wpcomDomain).isTrue
}
}

@Test
fun `given a network error, when all domains are requested, then return api error`() = test {
val error = WPComGsonNetworkError(BaseNetworkError(GenericErrorType.NETWORK_ERROR))
initAllDomainsResponse(error = error)

val response = restClient.fetchAllDomains(noWpCom = true)
assert(response is Response.Error)
with((response as Response.Error).error) {
assertThat(type).isEqualTo(GenericErrorType.NETWORK_ERROR)
assertThat(message).isNull()
}
}

@Test
fun `given timeout, when all domains are requested, then return timeout error`() = test {
val error = WPComGsonNetworkError(BaseNetworkError(GenericErrorType.TIMEOUT))
initAllDomainsResponse(error = error)

val response = restClient.fetchAllDomains(noWpCom = true)
assert(response is Response.Error)
with((response as Response.Error).error) {
assertThat(type).isEqualTo(GenericErrorType.TIMEOUT)
assertThat(message).isNull()
}
}

@Test
fun `given not authenticated, when all domains are requested, then retun auth required error`() = test {
val tokenErrorMessage = "An active access token must be used to query information about the current user."
val error = WPComGsonNetworkError(BaseNetworkError(GenericErrorType.NOT_AUTHENTICATED, tokenErrorMessage))
initAllDomainsResponse(error = error)

val response = restClient.fetchAllDomains(noWpCom = true)
assert(response is Response.Error)
with((response as Response.Error).error) {
assertThat(type).isEqualTo(GenericErrorType.NOT_AUTHENTICATED)
assertThat(message).isEqualTo(tokenErrorMessage)
}
}

private suspend fun initSiteResponse(
data: SiteWPComRestResponse? = null,
error: WPComGsonNetworkError? = null
Expand Down Expand Up @@ -561,6 +624,13 @@ class SiteRestClientTest {
return initGetResponse(SitesFeaturesRestResponse::class.java, data ?: mock(), error)
}

private suspend fun initAllDomainsResponse(
data: AllDomainsResponse? = null,
error: WPComGsonNetworkError? = null
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional nitpick: the property is never used. If we don't want to test the error cases for the "fetch all domains" flow, we can remove it and pass null directly, or we can have a test for a bad case too. What do you think?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for catching this @justtwago 🙇
I've added some tests for the error cases with 5bed1ee

): Response<AllDomainsResponse> {
return initGetResponse(AllDomainsResponse::class.java, data ?: mock(), error)
}

private suspend fun <T> initGetResponse(
clazz: Class<T>,
data: T,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import org.wordpress.android.fluxc.network.BaseRequest.GenericErrorType.PARSE_ER
import org.wordpress.android.fluxc.network.rest.wpapi.site.SiteWPAPIRestClient
import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComGsonNetworkError
import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequestBuilder.Response
import org.wordpress.android.fluxc.network.rest.wpcom.site.AllDomainsResponse
import org.wordpress.android.fluxc.network.rest.wpcom.site.Domain
import org.wordpress.android.fluxc.network.rest.wpcom.site.DomainsResponse
import org.wordpress.android.fluxc.network.rest.wpcom.site.PlansResponse
Expand All @@ -38,7 +39,10 @@ import org.wordpress.android.fluxc.persistence.PostSqlUtils
import org.wordpress.android.fluxc.persistence.SiteSqlUtils
import org.wordpress.android.fluxc.persistence.domains.DomainDao
import org.wordpress.android.fluxc.persistence.jetpacksocial.JetpackSocialDao
import org.wordpress.android.fluxc.store.SiteStore.AllDomainsError
import org.wordpress.android.fluxc.store.SiteStore.AllDomainsErrorType
import org.wordpress.android.fluxc.store.SiteStore.FetchSitesPayload
import org.wordpress.android.fluxc.store.SiteStore.FetchedAllDomainsPayload
import org.wordpress.android.fluxc.store.SiteStore.FetchedDomainsPayload
import org.wordpress.android.fluxc.store.SiteStore.FetchedPlansPayload
import org.wordpress.android.fluxc.store.SiteStore.FetchedPostFormatsPayload
Expand Down Expand Up @@ -72,8 +76,10 @@ class SiteStoreTest {
@Mock lateinit var jetpackSocialDao: JetpackSocialDao
@Mock lateinit var jetpackSocialMapper: JetpackSocialMapper
@Mock lateinit var domainsSuccessResponse: Response.Success<DomainsResponse>
@Mock lateinit var allDomainsSuccessResponse: Response.Success<AllDomainsResponse>
@Mock lateinit var plansSuccessResponse: Response.Success<PlansResponse>
@Mock lateinit var domainsErrorResponse: Response.Error<DomainsResponse>
@Mock lateinit var allDomainsErrorResponse: Response.Error<AllDomainsResponse>
@Mock lateinit var plansErrorResponse: Response.Error<PlansResponse>
private lateinit var siteStore: SiteStore

Expand Down Expand Up @@ -487,4 +493,30 @@ class SiteStoreTest {

assertThat(onSitePlansFetched.error.type).isEqualTo(PlansError(PlansErrorType.GENERIC_ERROR, null).type)
}

@Test
fun `fetchAllDomains from WPCom endpoint`() = test {
whenever(siteRestClient.fetchAllDomains()).thenReturn(allDomainsSuccessResponse)
whenever(allDomainsSuccessResponse.data).thenReturn(AllDomainsResponse(listOf()))

val onAllDomainsFetched = siteStore.fetchAllDomains()

assertThat(onAllDomainsFetched.domains).isNotNull
assertThat(onAllDomainsFetched.error).isNull()
assertThat(onAllDomainsFetched).isEqualTo(FetchedAllDomainsPayload(onAllDomainsFetched.domains))
}

@Test
fun `fetchAllDomains error from WPCom endpoint returns error`() = test {
val site = SiteModel()
site.setIsWPCom(true)

whenever(siteRestClient.fetchAllDomains()).thenReturn(allDomainsErrorResponse)
whenever(allDomainsErrorResponse.error).thenReturn(WPComGsonNetworkError(BaseNetworkError(NETWORK_ERROR)))

val onAllDomainsFetched = siteStore.fetchAllDomains()

val expectedErrorType = AllDomainsError(AllDomainsErrorType.GENERIC_ERROR, null).type
assertThat(onAllDomainsFetched.error.type).isEqualTo(expectedErrorType)
}
}
32 changes: 32 additions & 0 deletions example/src/test/resources/wp/all-domains/all-domains.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"domains": [
{
"domain": "some.test.domain",
"blog_id": 11111,
"blog_name": "some test blog",
"type": "mapping",
"is_domain_only_site": false,
"is_wpcom_staging_domain": false,
"has_registration": false,
"registration_date": "2009-03-26T21:20:53+00:00",
"expiry": "2024-03-24T00:00:00+00:00",
"wpcom_domain": false,
"current_user_is_owner": true,
"site_slug": "test slug"
},
{
"domain": "some.test.domain 2",
"blog_id": 22222,
"blog_name": "some test blog 2",
"type": "mapping",
"is_domain_only_site": false,
"is_wpcom_staging_domain": false,
"has_registration": false,
"registration_date": "2009-03-26T21:20:53+00:00",
"expiry": "2024-03-24T00:00:00+00:00",
"wpcom_domain": true,
"current_user_is_owner": false,
"site_slug": "test slug 2"
}
]
}
2 changes: 2 additions & 0 deletions fluxc-processor/src/main/resources/wp-com-endpoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
/read/site/$site#String/post_email_subscriptions/$action#String
/read/site/$site#String/post_email_subscriptions/update

/all-domains

/domains/suggestions
/domains/supported-countries/
/domains/supported-states/$countryCode#String
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package org.wordpress.android.fluxc.network.rest.wpcom.site

import com.google.gson.annotations.JsonAdapter
import com.google.gson.annotations.SerializedName

data class AllDomainsResponse(val domains: List<AllDomainsDomain>)

data class AllDomainsDomain(
@SerializedName("domain")
val domain: String? = null,
@SerializedName("blog_id")
val blogId: Long = 0,
@SerializedName("blog_name")
val blogName: String? = null,
@SerializedName("type")
val type: String? = null,
@SerializedName("is_domain_only_site")
@JsonAdapter(BooleanTypeAdapter::class)
val isDomainOnlySite: Boolean = false,
@SerializedName("is_wpcom_staging_domain")
@JsonAdapter(BooleanTypeAdapter::class)
val isWpcomStagingDomain: Boolean = false,
@SerializedName("has_registration")
@JsonAdapter(BooleanTypeAdapter::class)
val hasRegistration: Boolean = false,
@SerializedName("registration_date")
val registrationDate: String? = null,
@SerializedName("expiry")
val expiry: String? = null,
@SerializedName("wpcom_domain")
@JsonAdapter(BooleanTypeAdapter::class)
val wpcomDomain: Boolean = false,
@SerializedName("current_user_is_owner")
@JsonAdapter(BooleanTypeAdapter::class)
val currentUserIsOwner: Boolean = false,
@SerializedName("site_slug")
val siteSlug: String? = null,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.wordpress.android.fluxc.network.rest.wpcom.site

import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.google.gson.JsonParseException
import java.lang.reflect.Type
import java.util.Locale

internal class BooleanTypeAdapter : JsonDeserializer<Boolean?> {
@Suppress("VariableNaming") private val TRUE_STRINGS: Set<String> = HashSet(listOf("true", "1", "yes"))

@Throws(JsonParseException::class)
override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Boolean {
val jsonPrimitive = json.asJsonPrimitive
return when {
jsonPrimitive.isBoolean -> jsonPrimitive.asBoolean
jsonPrimitive.isNumber -> jsonPrimitive.asNumber.toInt() == 1
jsonPrimitive.isString -> TRUE_STRINGS.contains(jsonPrimitive.asString.toLowerCase(
Locale.getDefault()
))
else -> false
}
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
package org.wordpress.android.fluxc.network.rest.wpcom.site

import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.google.gson.JsonParseException
import com.google.gson.annotations.JsonAdapter
import com.google.gson.annotations.SerializedName
import java.lang.reflect.Type
import java.util.Locale

data class DomainsResponse(val domains: List<Domain>)

Expand Down Expand Up @@ -155,17 +150,3 @@ data class TitanMailSubscription(
val status: String? = null
)

internal class BooleanTypeAdapter : JsonDeserializer<Boolean?> {
@Suppress("VariableNaming") private val TRUE_STRINGS: Set<String> = HashSet(listOf("true", "1", "yes"))

@Throws(JsonParseException::class)
override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Boolean {
val jsonPrimitive = json.asJsonPrimitive
return when {
jsonPrimitive.isBoolean -> jsonPrimitive.asBoolean
jsonPrimitive.isNumber -> jsonPrimitive.asNumber.toInt() == 1
jsonPrimitive.isString -> TRUE_STRINGS.contains(jsonPrimitive.asString.toLowerCase(Locale.getDefault()))
else -> false
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,11 @@ class SiteRestClient @Inject constructor(
add(request)
}

suspend fun fetchAllDomains(noWpCom: Boolean = true): Response<AllDomainsResponse> {
val url = WPCOMREST.all_domains.urlV1_1
val params = mapOf("no_wpcom" to noWpCom.toString())
return wpComGsonRequestBuilder.syncGetRequest(this, url, params, AllDomainsResponse::class.java)
}
suspend fun fetchSiteDomains(site: SiteModel): Response<DomainsResponse> {
val url = WPCOMREST.sites.site(site.siteId).domains.urlV1_1
return wpComGsonRequestBuilder.syncGetRequest(this, url, mapOf(), DomainsResponse::class.java)
Expand Down
Loading
Loading