From f0b35e85b42acc0d402cac9a7261193ceed511f1 Mon Sep 17 00:00:00 2001 From: Surik Date: Thu, 9 Sep 2021 13:13:12 +0300 Subject: [PATCH 01/10] Added release pull request action --- .github/workflows/release_pull_requests.yml | 51 +++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 .github/workflows/release_pull_requests.yml diff --git a/.github/workflows/release_pull_requests.yml b/.github/workflows/release_pull_requests.yml new file mode 100644 index 000000000..9d7db91cd --- /dev/null +++ b/.github/workflows/release_pull_requests.yml @@ -0,0 +1,51 @@ +name: Release pull requests +on: + push: + tags: + - prerelease/* + +jobs: + prerelease: + runs-on: macos-latest + + steps: + - uses: actions/checkout@v2 + name: Checkout all + with: + fetch-depth: 0 + + - uses: olegtarasov/get-tag@v2.1 + id: tagName + with: + tagRegex: 'prerelease\/(\d*\.\d*\.\d*)' + + - name: Bump version + run: | + fastlane bump version:${{ steps.tagName.outputs.tag }} + + - name: Create pull request + uses: peter-evans/create-pull-request@v3 + with: + title: Release ${{ steps.tagName.outputs.tag }} + body: Release PR + labels: autocreated + branch: release/${{ steps.tagName.outputs.tag }} + base: develop + + - uses: actions/checkout@v2 + with: + ref: main + + - name: Reset main branch + run: | + git fetch origin release/${{ steps.tagName.outputs.tag }}:release/${{ steps.tagName.outputs.tag }} + git reset --hard release/${{ steps.tagName.outputs.tag }} + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v3 + with: + title: Release ${{ steps.tagName.outputs.tag }} + body: Release PR + labels: autocreated + branch: release/${{ steps.tagName.outputs.tag }} + base: main From 27bf47b37b39da3009efc36bd0b489d180f721cd Mon Sep 17 00:00:00 2001 From: Surik Date: Thu, 9 Sep 2021 13:52:24 +0300 Subject: [PATCH 02/10] Added github prerelease action --- .github/workflows/prerelease_github.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/workflows/prerelease_github.yml diff --git a/.github/workflows/prerelease_github.yml b/.github/workflows/prerelease_github.yml new file mode 100644 index 000000000..f41bd5216 --- /dev/null +++ b/.github/workflows/prerelease_github.yml @@ -0,0 +1,21 @@ +name: Pre-release Github + +on: + push: + branches: + - "main" + +jobs: + pre-release: + runs-on: macos-latest + + steps: + - uses: "marvinpinto/action-automatic-releases@latest" + with: + repo_token: "${{ secrets.GITHUB_TOKEN }}" + automatic_release_tag: "latest" + prerelease: true + title: "Development Build" + files: | + LICENSE.txt + *.jar From 6d589261f57c6199ca85d5a8795720ae3c436e02 Mon Sep 17 00:00:00 2001 From: Maria Bordunova Date: Mon, 13 Sep 2021 16:13:26 +0300 Subject: [PATCH 03/10] Bump version to 2.11.2 --- build.gradle | 2 +- .../main/java/com/qonversion/android/sdk/di/module/AppModule.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 4bb17b10c..1862782b5 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ buildscript { ext { release = [ - versionName: "2.11.1", + versionName: "2.11.2", versionCode: 1 ] } diff --git a/sdk/src/main/java/com/qonversion/android/sdk/di/module/AppModule.kt b/sdk/src/main/java/com/qonversion/android/sdk/di/module/AppModule.kt index 066fb9f91..a9c5ffe5b 100644 --- a/sdk/src/main/java/com/qonversion/android/sdk/di/module/AppModule.kt +++ b/sdk/src/main/java/com/qonversion/android/sdk/di/module/AppModule.kt @@ -68,6 +68,6 @@ class AppModule( } companion object { - private const val SDK_VERSION = "2.11.1" + private const val SDK_VERSION = "2.11.2" } } From 26baca207944f32edaf7b1c3f1b74d42d4c6048e Mon Sep 17 00:00:00 2001 From: Maria Bordunova Date: Wed, 22 Sep 2021 12:35:22 +0300 Subject: [PATCH 04/10] Add tests for GooglePurchaseConverter --- .../converter/GooglePurchaseConverterTest.kt | 321 ++++++++++++++++-- .../java/com/qonversion/android/sdk/utils.kt | 102 +++++- 2 files changed, 402 insertions(+), 21 deletions(-) diff --git a/sdk/src/test/java/com/qonversion/android/sdk/converter/GooglePurchaseConverterTest.kt b/sdk/src/test/java/com/qonversion/android/sdk/converter/GooglePurchaseConverterTest.kt index 03cb0f822..a69be3b38 100644 --- a/sdk/src/test/java/com/qonversion/android/sdk/converter/GooglePurchaseConverterTest.kt +++ b/sdk/src/test/java/com/qonversion/android/sdk/converter/GooglePurchaseConverterTest.kt @@ -1,43 +1,324 @@ package com.qonversion.android.sdk.converter import android.util.Pair -import com.android.billingclient.api.Purchase -import com.android.billingclient.api.SkuDetails -import com.qonversion.android.sdk.converter.Util.Companion.CORRECT_PURCHASE_INAPP_JSON -import com.qonversion.android.sdk.converter.Util.Companion.CORRECT_PURCHASE_SUB_JSON -import com.qonversion.android.sdk.converter.Util.Companion.CORRECT_SKU_DETAILS_INAPP_JSON -import com.qonversion.android.sdk.converter.Util.Companion.CORRECT_SKU_DETAILS_SUB_JSON +import com.qonversion.android.sdk.* import com.qonversion.android.sdk.extractor.SkuDetailsTokenExtractor +import io.mockk.* +import org.assertj.core.api.Assertions.assertThat +import org.junit.Assert +import org.junit.Before import org.junit.Test +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.assertAll import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner @RunWith(RobolectricTestRunner::class) class GooglePurchaseConverterTest { + private val mockExtractor: SkuDetailsTokenExtractor = mockk(relaxed = true) + private lateinit var purchaseConverter: GooglePurchaseConverter + + private val mockToken = "XXXXXXX" + private val mockOrderId = "GPA.0000-0000-0000-0000" + private val weeklySku = "subs_weekly" + private val annualSku = "subs_annual" + + @Before + fun setUp() { + clearAllMocks() + + purchaseConverter = GooglePurchaseConverter(mockExtractor) + } @Test - fun convertCorrectPurchase() { - val converted = GooglePurchaseConverter(SkuDetailsTokenExtractor()) - .convertPurchase( - Pair( - SkuDetails(CORRECT_SKU_DETAILS_INAPP_JSON), - Purchase(CORRECT_PURCHASE_INAPP_JSON, "SKU") + fun `should convert purchases when purchase and skuDetails skus match`() { + // given + val spykPurchaseConverter = spyk(purchaseConverter, recordPrivateCalls = true) + + val mockWeeklySkuDetails = mockSubsSkuDetails(weeklySku) + val mockWeeklyPurchase = mockSubsPurchase(weeklySku) + val mockAnnualSkuDetails = mockSubsSkuDetails(annualSku) + val mockAnnualPurchase = mockSubsPurchase(annualSku) + + val purchasesInfoMap = mapOf( + weeklySku to mockWeeklySkuDetails, + annualSku to mockAnnualSkuDetails + ) + val purchases = listOf(mockWeeklyPurchase, mockAnnualPurchase) + + // when + val result = spykPurchaseConverter.convertPurchases(purchasesInfoMap, purchases) + verifyOrder { + spykPurchaseConverter.convertPurchase( + Pair.create( + mockWeeklySkuDetails, + mockWeeklyPurchase ) ) + spykPurchaseConverter.convertPurchase( + Pair.create( + mockAnnualSkuDetails, + mockAnnualPurchase + ) + ) + } + + // then + assertThat(result.size).isEqualTo(2) + } + + @Test + fun `shouldn't convert purchases when purchase and skuDetails skus don't match`() { + // given + val spykPurchaseConverter = spyk(purchaseConverter, recordPrivateCalls = true) + + val wrongSku = "wrong_subs_weekly" + + val mockWeeklySkuDetails = mockSubsSkuDetails(weeklySku) + val mockWeeklyPurchase = mockSubsPurchase(wrongSku) + + val map = mapOf(weeklySku to mockWeeklySkuDetails) + val purchases = listOf(mockWeeklyPurchase) + + // when + val result = spykPurchaseConverter.convertPurchases(map, purchases) + + // then + verify(exactly = 0) { + spykPurchaseConverter.convertPurchase( + any() + ) + } + assertThat(result.size).isEqualTo(0) + } - // TODO: Update test for new Purchase fields + @Test + fun `shouldn't convert incorrect purchase without sku`() { + // given + val mockWeeklySkuDetails = mockSubsSkuDetails() + val mockWeeklyPurchase = mockIncorrectSubsPurchase() + val pair = Pair.create( + mockWeeklySkuDetails, + mockWeeklyPurchase + ) + + // when + val result = purchaseConverter.convertPurchase(pair) + + // then + assertThat(result).isNull() } @Test - fun convertSubscription() { - val converted = GooglePurchaseConverter(SkuDetailsTokenExtractor()) - .convertPurchase( - Pair( - SkuDetails(CORRECT_SKU_DETAILS_SUB_JSON), - Purchase(CORRECT_PURCHASE_SUB_JSON, "SKU") + fun `should convert subs purchase correctly`() { + // given + val spykPurchaseConverter = spyk(purchaseConverter, recordPrivateCalls = true) + + val mockWeeklySkuDetails = mockSubsSkuDetails() + val mockWeeklyPurchase = mockSubsPurchase() + + every { + mockExtractor.extract(mockSubsSkuDetailsJson()) + } returns mockToken + + // when + val result = spykPurchaseConverter.convertPurchase( + Pair.create( + mockWeeklySkuDetails, + mockWeeklyPurchase + ) + ) + + // then + Assert.assertNotNull(result) + assertAll( + "Converted purchase contains incorrect fields:", + { assertEquals(mockToken, result!!.detailsToken, "detailsToken is incorrect") }, + { assertEquals("Qonversion Subs", result!!.title) }, + { assertEquals("Weekly", result!!.description) }, + { assertEquals(weeklySku, result!!.productId) }, + { assertEquals("subs", result!!.type) }, + { assertEquals("RUB 439.00", result!!.originalPrice) }, + { assertEquals(439000000, result!!.originalPriceAmountMicros) }, + { assertEquals("RUB", result!!.priceCurrencyCode) }, + { assertEquals("439.00", result!!.price) }, + { assertEquals(439000000, result!!.priceAmountMicros) }, + { assertEquals(1, result!!.periodUnit, "periodUnit is incorrect") }, + { assertEquals(1, result!!.periodUnitsCount, "periodUnitsCount is incorrect") }, + { assertEquals(0, result!!.freeTrialPeriod.length, "freeTrialPeriod should be empty")}, + { assertEquals(true, result!!.introductoryAvailable, "introductoryAvailable should be true") }, + { assertEquals(85000000, result!!.introductoryPriceAmountMicros) }, + { assertEquals("85.00", result!!.introductoryPrice) }, + { assertEquals(1, result!!.introductoryPriceCycles, "introductoryPriceCycles is incorrect") }, + { assertEquals(0, result!!.introductoryPeriodUnit, "introductoryPeriodUnit is incorrect") }, + { assertEquals(null, result!!.introductoryPeriodUnitsCount, "introductoryPeriodUnitsCount should be null")}, + { assertEquals(mockOrderId, result!!.orderId, "orderId is incorrect") }, + { assertEquals(mockOrderId, result!!.originalOrderId, "originalOrderId is incorrect") }, + { assertEquals("com.qonversion.sample", result!!.packageName, "packageName is incorrect") }, + { assertEquals(1631867965, result!!.purchaseTime) }, + { assertEquals( 1, result!!.purchaseState, "purchaseState is incorrect") }, + { assertEquals(mockToken, result!!.purchaseToken, "purchaseToken is incorrect") }, + { assertEquals(true, result!!.acknowledged, "acknowledged should be true") }, + { assertEquals(true, result!!.autoRenewing, "autoRenewing should be true") }, + { assertEquals(0, result!!.paymentMode,"paymentMode is incorrect") } + ) + } + + @Test + fun `should convert subs purchase with trial correctly`() { + // given + val spykPurchaseConverter = spyk(purchaseConverter, recordPrivateCalls = true) + + val weeklySku = "subs_weekly" + + val mockWeeklySkuDetails = mockSubsSkuDetails(weeklySku, freeTrialPeriod = "P9W2D") + val mockWeeklyPurchase = mockSubsPurchase(weeklySku) + every { + mockExtractor.extract(mockSubsSkuDetailsJson(weeklySku, freeTrialPeriod = "P9W2D")) + } returns mockToken + + // when + val result = spykPurchaseConverter.convertPurchase( + Pair.create( + mockWeeklySkuDetails, + mockWeeklyPurchase + ) + ) + + // then + Assert.assertNotNull(result) + assertAll( + "Converted purchase contains incorrect fields", + { assertEquals(mockToken, result!!.detailsToken, "detailsToken token is incorrect") }, + { assertEquals("Qonversion Subs", result!!.title) }, + { assertEquals("Weekly", result!!.description) }, + { assertEquals(weeklySku, result!!.productId) }, + { assertEquals("subs", result!!.type) }, + { assertEquals("RUB 439.00", result!!.originalPrice) }, + { assertEquals(439000000, result!!.originalPriceAmountMicros) }, + { assertEquals("RUB", result!!.priceCurrencyCode) }, + { assertEquals("439.00", result!!.price) }, + { assertEquals(439000000, result!!.priceAmountMicros) }, + { assertEquals(1, result!!.periodUnit, "periodUnit is incorrect") }, + { assertEquals(1, result!!.periodUnitsCount, "periodUnitsCount is incorrect") }, + { assertEquals("P9W2D", result!!.freeTrialPeriod, "freeTrialPeriod is incorrect") }, + { assertEquals(true, result!!.introductoryAvailable, "introductoryAvailable should be true") }, + { assertEquals(85000000, result!!.introductoryPriceAmountMicros) }, + { assertEquals("0.0", result!!.introductoryPrice) }, + { assertEquals(0, result!!.introductoryPriceCycles, "introductoryPriceCycles is incorrect") }, + { assertEquals(0, result!!.introductoryPeriodUnit, "introductoryPriceCycles is incorrect") }, + { assertEquals(65, result!!.introductoryPeriodUnitsCount) }, + { assertEquals(mockOrderId, result!!.orderId, "orderId is incorrect") }, + { assertEquals(mockOrderId, result!!.originalOrderId, "originalOrderId is incorrect") }, + { assertEquals("com.qonversion.sample", result!!.packageName) }, + { assertEquals(1631867965, result!!.purchaseTime) }, + { assertEquals( 1, result!!.purchaseState, "purchaseState is incorrect") }, + { assertEquals(mockToken, result!!.purchaseToken, "purchaseToken is incorrect") }, + { assertEquals(true, result!!.acknowledged, "acknowledged should be true") }, + { assertEquals(true, result!!.autoRenewing, "autoRenewing should be true") }, + { assertEquals(2, result!!.paymentMode, "paymentMode is incorrect") } + ) + } + + @Test + fun `should get correct units type from period`() { + // given + val dailyPeriod = "P1D" + val weeklyPeriod = "P1W" + val monthlyPeriod = "P1M" + val annualPeriod = "P1Y" + val incorrectPeriod = "P1S" + + val mockWeeklySkuDetails = mockSubsSkuDetails(subsPeriod = weeklyPeriod) + val mockAnnualSkuDetails = mockSubsSkuDetails(subsPeriod = annualPeriod) + val mockMonthlySkuDetails = mockSubsSkuDetails(subsPeriod = monthlyPeriod) + val mockDailySkuDetails = mockSubsSkuDetails(subsPeriod = dailyPeriod) + val mockIncorrectSkuDetails = mockSubsSkuDetails(subsPeriod = incorrectPeriod) + val mockSubsPurchase = mockSubsPurchase() + + val skuDetailsMap = mapOf( + weeklyPeriod to mockWeeklySkuDetails, + annualPeriod to mockAnnualSkuDetails, + monthlyPeriod to mockMonthlySkuDetails, + dailyPeriod to mockDailySkuDetails, + incorrectPeriod to mockIncorrectSkuDetails + ) + + skuDetailsMap.forEach { entry -> + val skuDetails = entry.value + val periodUnit = when (entry.key) { + annualPeriod -> 3 + monthlyPeriod -> 2 + weeklyPeriod -> 1 + dailyPeriod -> 0 + else -> null + } + + // when + val result = purchaseConverter.convertPurchase( + Pair.create( + skuDetails, + mockSubsPurchase ) ) - // TODO: Update test for new Purchase fields + // then + assertEquals(periodUnit, result!!.periodUnit) + } + } + + @Test + fun `should convert inapp purchase correctly`() { + // given + val spykPurchaseConverter = spyk(purchaseConverter, recordPrivateCalls = true) + + val mockSkuDetails = mockInAppSkuDetails() + val mockPurchase = mockInAppPurchase() + + every { + mockExtractor.extract(mockInAppSkuDetailsJson()) + } returns mockToken + + // when + val result = spykPurchaseConverter.convertPurchase( + Pair.create( + mockSkuDetails, + mockPurchase + ) + ) + + // then + Assert.assertNotNull(result) + assertAll( + "Converted purchase contains incorrect fields", + { assertEquals(mockToken, result!!.detailsToken, "detailsToken is incorrect") }, + { assertEquals("Qonversion In-app", result!!.title) }, + { assertEquals("Consumable", result!!.description) }, + { assertEquals("qonversion_inapp_consumable", result!!.productId) }, + { assertEquals("inapp", result!!.type) }, + { assertEquals("RUB 75.00", result!!.originalPrice) }, + { assertEquals(75000000, result!!.originalPriceAmountMicros) }, + { assertEquals("RUB", result!!.priceCurrencyCode) }, + { assertEquals("75.00", result!!.price) }, + { assertEquals(75000000, result!!.priceAmountMicros) }, + { assertEquals(null, result!!.periodUnit, "periodUnit is incorrect") }, + { assertEquals(null, result!!.periodUnitsCount, "periodUnitsCount is incorrect") }, + { assertEquals(0, result!!.freeTrialPeriod.length, "freeTrialPeriod should be empty")}, + { assertEquals(false, result!!.introductoryAvailable, "introductoryAvailable should be false") }, + { assertEquals(0, result!!.introductoryPriceAmountMicros, "introductoryPriceAmountMicros is incorrect") }, + { assertEquals("0.00", result!!.introductoryPrice) }, + { assertEquals(0, result!!.introductoryPriceCycles, "introductoryPriceCycles is incorrect") }, + { assertEquals(0, result!!.introductoryPeriodUnit, "introductoryPeriodUnit is incorrect") }, + { assertEquals(null, result!!.introductoryPeriodUnitsCount, "introductoryPeriodUnitsCount should be null")}, + { assertEquals(mockOrderId, result!!.orderId, "orderId is incorrect") }, + { assertEquals(mockOrderId, result!!.originalOrderId, "originalOrderId is incorrect") }, + { assertEquals("com.qonversion.sample", result!!.packageName) }, + { assertEquals(1632238801, result!!.purchaseTime) }, + { assertEquals( 1, result!!.purchaseState, "purchaseState is incorrect") }, + { assertEquals(mockToken, result!!.purchaseToken, "purchaseToken is incorrect") }, + { assertEquals(true, result!!.acknowledged, "acknowledged should be true") }, + { assertEquals(false, result!!.autoRenewing, "autoRenewing should be false") }, + { assertEquals(0, result!!.paymentMode, "paymentMode is incorrect") } + ) } } \ No newline at end of file diff --git a/sdk/src/test/java/com/qonversion/android/sdk/utils.kt b/sdk/src/test/java/com/qonversion/android/sdk/utils.kt index a04670d8b..5900daa88 100644 --- a/sdk/src/test/java/com/qonversion/android/sdk/utils.kt +++ b/sdk/src/test/java/com/qonversion/android/sdk/utils.kt @@ -1,5 +1,14 @@ package com.qonversion.android.sdk +import com.android.billingclient.api.Purchase +import com.android.billingclient.api.SkuDetails +import com.qonversion.android.sdk.Constants.DEFAULT_SUBS_PERIOD +import com.qonversion.android.sdk.Constants.DEFAULT_SUBS_SKU +import com.qonversion.android.sdk.Constants.INAPP_PURCHASE +import com.qonversion.android.sdk.Constants.INAPP_SKU_DETAILS +import com.qonversion.android.sdk.Constants.SUBS_PURCHASE_INCOMPLETE +import com.qonversion.android.sdk.Constants.PURCHASE_SIGNATURE +import com.qonversion.android.sdk.Constants.SUBS_SKU_DETAILS_INCOMPLETE import java.lang.reflect.Modifier fun Any.mockPrivateField(fieldName: String, field: Any?) { @@ -17,4 +26,95 @@ fun Any.getPrivateField(name: String): T { return field.get(this) as T } -fun Boolean.toInt() = if (this) 1 else 0 +fun mockSubsSkuDetails( + sku: String = DEFAULT_SUBS_SKU, + subsPeriod: String = DEFAULT_SUBS_PERIOD, + freeTrialPeriod: String? = null +): SkuDetails { + val skuDetailsJson = mockSubsSkuDetailsJson(sku, subsPeriod, freeTrialPeriod) + return SkuDetails(skuDetailsJson) +} + +fun mockSubsSkuDetailsJson( + sku: String = DEFAULT_SUBS_SKU, + subsPeriod: String = DEFAULT_SUBS_PERIOD, + freeTrialPeriod: String? = null +): String { + val sb = StringBuilder() + sb.append("$SUBS_SKU_DETAILS_INCOMPLETE, \"productId\":\"$sku\", \"subscriptionPeriod\":$subsPeriod") + freeTrialPeriod?.let { + sb.append(",\"freeTrialPeriod\":\"$it\"") + } + + return "{${sb}}" +} + +fun mockSubsPurchase(sku: String = DEFAULT_SUBS_SKU): Purchase { + return Purchase("{$SUBS_PURCHASE_INCOMPLETE, \"productId\":\"$sku\"}", PURCHASE_SIGNATURE) +} + +fun mockIncorrectSubsPurchase(): Purchase { + return Purchase("{$SUBS_PURCHASE_INCOMPLETE}", PURCHASE_SIGNATURE) +} + +fun mockInAppSkuDetails(): SkuDetails { + return SkuDetails(mockInAppSkuDetailsJson()) +} + +fun mockInAppSkuDetailsJson( +): String { + return "{$INAPP_SKU_DETAILS}" +} + +fun mockInAppPurchase(): Purchase { + return Purchase("{$INAPP_PURCHASE}", PURCHASE_SIGNATURE) +} + +object Constants { + // Subscription purchase without productId + const val SUBS_PURCHASE_INCOMPLETE = "\"orderId\":\"GPA.0000-0000-0000-0000\"," + + "\"packageName\":\"com.qonversion.sample\"," + + "\"purchaseTime\":1631867965714," + + "\"purchaseState\":1," + + "\"purchaseToken\":\"XXXXXXX\"," + + "\"quantity\":1," + + "\"autoRenewing\":true," + + "\"acknowledged\":true" + + // Subscription SkuDetails without productId, subscriptionPeriod, freeTrialPeriod + const val SUBS_SKU_DETAILS_INCOMPLETE = "\"type\":\"subs\"," + + "\"title\":\"Qonversion Subs\"," + + "\"name\":\"Qonversion Subscription Weekly\"," + + "\"price\":\"RUB 439.00\"," + + "\"price_amount_micros\":439000000," + + "\"price_currency_code\":\"RUB\"," + + "\"description\":\"Weekly\"," + + "\"introductoryPriceAmountMicros\":85000000," + + "\"introductoryPricePeriod\":\"P3D\"," + + "\"introductoryPrice\":\"RUB 85.00\"," + + "\"introductoryPriceCycles\":1," + + "\"skuDetailsToken\":\"XXXXXXX\"" + + const val INAPP_SKU_DETAILS = "\"productId\":\"qonversion_inapp_consumable\"," + + "\"type\":\"inapp\"," + + "\"title\":\"Qonversion In-app\"," + + "\"name\":\"Qonversion In-app Consumable\"," + + "\"price\":\"RUB 75.00\"," + + "\"price_amount_micros\":75000000," + + "\"price_currency_code\":\"RUB\"," + + "\"description\":\"Consumable\"," + + "\"skuDetailsToken\":\"XXXXXXX\"}" + + const val INAPP_PURCHASE = "\"orderId\":\"GPA.0000-0000-0000-0000\"," + + "\"packageName\":\"com.qonversion.sample\"," + + "\"productId\":\"qonversion_inapp_consumable\"," + + "\"purchaseTime\":1632238801527," + + "\"purchaseState\":1," + + "\"purchaseToken\":\"XXXXXXX\"," + + "\"quantity\":1," + + "\"acknowledged\":true" + + const val PURCHASE_SIGNATURE = "mockSignature" + const val DEFAULT_SUBS_PERIOD = "P1W" + const val DEFAULT_SUBS_SKU = "subs_weekly" +} \ No newline at end of file From 22a8f7651ade3a8f2899caf591c87472ef90cf4b Mon Sep 17 00:00:00 2001 From: Maria Bordunova Date: Sun, 26 Sep 2021 18:24:23 +0300 Subject: [PATCH 05/10] Improve tests logic --- .../converter/GooglePurchaseConverterTest.kt | 71 ++++++++----------- 1 file changed, 31 insertions(+), 40 deletions(-) diff --git a/sdk/src/test/java/com/qonversion/android/sdk/converter/GooglePurchaseConverterTest.kt b/sdk/src/test/java/com/qonversion/android/sdk/converter/GooglePurchaseConverterTest.kt index a69be3b38..96d60ee18 100644 --- a/sdk/src/test/java/com/qonversion/android/sdk/converter/GooglePurchaseConverterTest.kt +++ b/sdk/src/test/java/com/qonversion/android/sdk/converter/GooglePurchaseConverterTest.kt @@ -2,6 +2,7 @@ package com.qonversion.android.sdk.converter import android.util.Pair import com.qonversion.android.sdk.* +import com.qonversion.android.sdk.entity.Purchase import com.qonversion.android.sdk.extractor.SkuDetailsTokenExtractor import io.mockk.* import org.assertj.core.api.Assertions.assertThat @@ -131,20 +132,10 @@ class GooglePurchaseConverterTest { // then Assert.assertNotNull(result) + assertCommonSubsFields(result) + // Assert intro and trial period fields of subscription assertAll( "Converted purchase contains incorrect fields:", - { assertEquals(mockToken, result!!.detailsToken, "detailsToken is incorrect") }, - { assertEquals("Qonversion Subs", result!!.title) }, - { assertEquals("Weekly", result!!.description) }, - { assertEquals(weeklySku, result!!.productId) }, - { assertEquals("subs", result!!.type) }, - { assertEquals("RUB 439.00", result!!.originalPrice) }, - { assertEquals(439000000, result!!.originalPriceAmountMicros) }, - { assertEquals("RUB", result!!.priceCurrencyCode) }, - { assertEquals("439.00", result!!.price) }, - { assertEquals(439000000, result!!.priceAmountMicros) }, - { assertEquals(1, result!!.periodUnit, "periodUnit is incorrect") }, - { assertEquals(1, result!!.periodUnitsCount, "periodUnitsCount is incorrect") }, { assertEquals(0, result!!.freeTrialPeriod.length, "freeTrialPeriod should be empty")}, { assertEquals(true, result!!.introductoryAvailable, "introductoryAvailable should be true") }, { assertEquals(85000000, result!!.introductoryPriceAmountMicros) }, @@ -152,14 +143,6 @@ class GooglePurchaseConverterTest { { assertEquals(1, result!!.introductoryPriceCycles, "introductoryPriceCycles is incorrect") }, { assertEquals(0, result!!.introductoryPeriodUnit, "introductoryPeriodUnit is incorrect") }, { assertEquals(null, result!!.introductoryPeriodUnitsCount, "introductoryPeriodUnitsCount should be null")}, - { assertEquals(mockOrderId, result!!.orderId, "orderId is incorrect") }, - { assertEquals(mockOrderId, result!!.originalOrderId, "originalOrderId is incorrect") }, - { assertEquals("com.qonversion.sample", result!!.packageName, "packageName is incorrect") }, - { assertEquals(1631867965, result!!.purchaseTime) }, - { assertEquals( 1, result!!.purchaseState, "purchaseState is incorrect") }, - { assertEquals(mockToken, result!!.purchaseToken, "purchaseToken is incorrect") }, - { assertEquals(true, result!!.acknowledged, "acknowledged should be true") }, - { assertEquals(true, result!!.autoRenewing, "autoRenewing should be true") }, { assertEquals(0, result!!.paymentMode,"paymentMode is incorrect") } ) } @@ -187,20 +170,10 @@ class GooglePurchaseConverterTest { // then Assert.assertNotNull(result) + assertCommonSubsFields(result) + // Assert intro and trial period fields of subscription assertAll( "Converted purchase contains incorrect fields", - { assertEquals(mockToken, result!!.detailsToken, "detailsToken token is incorrect") }, - { assertEquals("Qonversion Subs", result!!.title) }, - { assertEquals("Weekly", result!!.description) }, - { assertEquals(weeklySku, result!!.productId) }, - { assertEquals("subs", result!!.type) }, - { assertEquals("RUB 439.00", result!!.originalPrice) }, - { assertEquals(439000000, result!!.originalPriceAmountMicros) }, - { assertEquals("RUB", result!!.priceCurrencyCode) }, - { assertEquals("439.00", result!!.price) }, - { assertEquals(439000000, result!!.priceAmountMicros) }, - { assertEquals(1, result!!.periodUnit, "periodUnit is incorrect") }, - { assertEquals(1, result!!.periodUnitsCount, "periodUnitsCount is incorrect") }, { assertEquals("P9W2D", result!!.freeTrialPeriod, "freeTrialPeriod is incorrect") }, { assertEquals(true, result!!.introductoryAvailable, "introductoryAvailable should be true") }, { assertEquals(85000000, result!!.introductoryPriceAmountMicros) }, @@ -208,18 +181,36 @@ class GooglePurchaseConverterTest { { assertEquals(0, result!!.introductoryPriceCycles, "introductoryPriceCycles is incorrect") }, { assertEquals(0, result!!.introductoryPeriodUnit, "introductoryPriceCycles is incorrect") }, { assertEquals(65, result!!.introductoryPeriodUnitsCount) }, - { assertEquals(mockOrderId, result!!.orderId, "orderId is incorrect") }, - { assertEquals(mockOrderId, result!!.originalOrderId, "originalOrderId is incorrect") }, - { assertEquals("com.qonversion.sample", result!!.packageName) }, - { assertEquals(1631867965, result!!.purchaseTime) }, - { assertEquals( 1, result!!.purchaseState, "purchaseState is incorrect") }, - { assertEquals(mockToken, result!!.purchaseToken, "purchaseToken is incorrect") }, - { assertEquals(true, result!!.acknowledged, "acknowledged should be true") }, - { assertEquals(true, result!!.autoRenewing, "autoRenewing should be true") }, { assertEquals(2, result!!.paymentMode, "paymentMode is incorrect") } ) } + private fun assertCommonSubsFields(purchase: Purchase?) { + assertAll( + "Converted purchase contains incorrect fields", + { assertEquals(mockToken, purchase!!.detailsToken, "detailsToken token is incorrect") }, + { assertEquals("Qonversion Subs", purchase!!.title) }, + { assertEquals("Weekly", purchase!!.description) }, + { assertEquals(weeklySku, purchase!!.productId) }, + { assertEquals("subs", purchase!!.type) }, + { assertEquals("RUB 439.00", purchase!!.originalPrice) }, + { assertEquals(439000000, purchase!!.originalPriceAmountMicros) }, + { assertEquals("RUB", purchase!!.priceCurrencyCode) }, + { assertEquals("439.00", purchase!!.price) }, + { assertEquals(439000000, purchase!!.priceAmountMicros) }, + { assertEquals(1, purchase!!.periodUnit, "periodUnit is incorrect") }, + { assertEquals(1, purchase!!.periodUnitsCount, "periodUnitsCount is incorrect") }, + { assertEquals(mockOrderId, purchase!!.orderId, "orderId is incorrect") }, + { assertEquals(mockOrderId, purchase!!.originalOrderId, "originalOrderId is incorrect") }, + { assertEquals("com.qonversion.sample", purchase!!.packageName) }, + { assertEquals(1631867965, purchase!!.purchaseTime) }, + { assertEquals( 1, purchase!!.purchaseState, "purchaseState is incorrect") }, + { assertEquals(mockToken, purchase!!.purchaseToken, "purchaseToken is incorrect") }, + { assertEquals(true, purchase!!.acknowledged, "acknowledged should be true") }, + { assertEquals(true, purchase!!.autoRenewing, "autoRenewing should be true") } + ) + } + @Test fun `should get correct units type from period`() { // given From 9b4ee7535d21441393632bc3fd4d9baefc699e83 Mon Sep 17 00:00:00 2001 From: Maria Bordunova Date: Wed, 13 Oct 2021 15:10:09 +0300 Subject: [PATCH 06/10] Track only purchases with state PURCHASED --- .../java/com/qonversion/android/sdk/Consumer.kt | 2 +- .../qonversion/android/sdk/QProductCenterManager.kt | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/sdk/src/main/java/com/qonversion/android/sdk/Consumer.kt b/sdk/src/main/java/com/qonversion/android/sdk/Consumer.kt index 6215bd230..7e6f58421 100644 --- a/sdk/src/main/java/com/qonversion/android/sdk/Consumer.kt +++ b/sdk/src/main/java/com/qonversion/android/sdk/Consumer.kt @@ -21,7 +21,7 @@ class Consumer internal constructor( purchases.forEach { purchase -> val skuDetail = skuDetails[purchase.sku] skuDetail?.let { sku -> - if (purchase.purchaseState != Purchase.PurchaseState.PENDING) { + if (purchase.purchaseState == Purchase.PurchaseState.PURCHASED) { consume(sku.type, purchase.purchaseToken, purchase.isAcknowledged) } } diff --git a/sdk/src/main/java/com/qonversion/android/sdk/QProductCenterManager.kt b/sdk/src/main/java/com/qonversion/android/sdk/QProductCenterManager.kt index 09e194c3f..dec3b5084 100644 --- a/sdk/src/main/java/com/qonversion/android/sdk/QProductCenterManager.kt +++ b/sdk/src/main/java/com/qonversion/android/sdk/QProductCenterManager.kt @@ -8,7 +8,10 @@ import com.android.billingclient.api.Purchase import com.android.billingclient.api.SkuDetails import com.qonversion.android.sdk.ad.AdvertisingProvider import com.qonversion.android.sdk.ad.LoadStoreProductsState.* -import com.qonversion.android.sdk.billing.* +import com.qonversion.android.sdk.billing.BillingError +import com.qonversion.android.sdk.billing.BillingService +import com.qonversion.android.sdk.billing.QonversionBillingService +import com.qonversion.android.sdk.billing.milliSecondsToSeconds import com.qonversion.android.sdk.converter.GooglePurchaseConverter import com.qonversion.android.sdk.converter.PurchaseConverter import com.qonversion.android.sdk.dto.QLaunchResult @@ -529,12 +532,14 @@ class QProductCenterManager internal constructor( return@queryPurchases } + val completedPurchases = + purchases.filter { it.purchaseState == Purchase.PurchaseState.PURCHASED } billingService.getSkuDetailsFromPurchases( - purchases, + completedPurchases, onCompleted = { skuDetails -> val formattedSkuDetails: Map = configureSkuDetails(skuDetails) - val purchasesInfo = configurePurchaseInfo(formattedSkuDetails, purchases) + val purchasesInfo = configurePurchaseInfo(formattedSkuDetails, completedPurchases) val initRequestData = InitRequestData(installDate, advertisingID, purchasesInfo, callback) processInit(initRequestData) @@ -829,7 +834,7 @@ class QProductCenterManager internal constructor( val purchaseCallback = purchasingCallbacks[purchase.sku] purchasingCallbacks.remove(purchase.sku) - if (purchase.purchaseState == Purchase.PurchaseState.PENDING) { + if (purchase.purchaseState != Purchase.PurchaseState.PURCHASED) { purchaseCallback?.onError(QonversionError(QonversionErrorCode.PurchasePending)) return@forEach } From 7318fddba42126fb0c2a8aa1780cd95945b03dd9 Mon Sep 17 00:00:00 2001 From: Maria Bordunova Date: Wed, 13 Oct 2021 16:53:54 +0300 Subject: [PATCH 07/10] Add PurchaseUnspecified error --- config/detekt/baseline.xml | 12 +++--------- .../qonversion/android/sdk/QProductCenterManager.kt | 12 +++++++++--- .../com/qonversion/android/sdk/QonversionError.kt | 4 +++- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index 5065f23cf..de91b7aa3 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -68,6 +68,7 @@ ImplicitDefaultLocale:GooglePurchaseConverter.kt$GooglePurchaseConverter$String.format("%.2f", divideResult) ImplicitDefaultLocale:HomeFragment.kt$HomeFragment$String.format( "%s %s / %s", getStr(R.string.subscribe_for), subscription.prettyPrice, subscription.duration?.name ) ImplicitDefaultLocale:HomeFragment.kt$HomeFragment$String.format( "%s %s", getStr(R.string.buy_for), inApp.prettyPrice ) + LargeClass:QProductCenterManager.kt$QProductCenterManager : PurchasesListenerOfferingsDelegate LongParameterList:RepositoryModule.kt$RepositoryModule$( retrofit: Retrofit, environmentProvider: EnvironmentProvider, config: QonversionConfig, logger: Logger, purchasesCache: PurchasesCache, apiErrorMapper: ApiErrorMapper, sharedPreferences: SharedPreferences ) MagicNumber:ApiErrorMapper.kt$ApiErrorMapper$10002 MagicNumber:ApiErrorMapper.kt$ApiErrorMapper$10003 @@ -137,7 +138,6 @@ MaxLineLength:PurchasesCacheTest.kt$PurchasesCacheTest$purchaseToken = "gfegjilekkmecbonpfjiaakm.AO-J1OxQCaAn0NPlHTh5CoOiXK0p19X7qEymW9SHtssrggp7S9YafjA1oPBPlWO4Ur3W5rtyNJBzIrVoLOb5In0Jxofv4xV_7t1HaUYYd_f8xOBk7nRIY7g" MaxLineLength:PurchasesCacheTest.kt$PurchasesCacheTest.SavePurchase$"[${generatePurchaseJson("2")},${generatePurchaseJson("3")},${generatePurchaseJson("4")},${generatePurchaseJson("5")}]" MaxLineLength:QAutomationsManager.kt$QAutomationsManager$logger.release("AutomationsDelegate.$functionName() function can not be executed. It looks like Automations.setDelegate() was not called or delegate has been destroyed by GC") - MaxLineLength:QProductCenterManagerTest.kt$QProductCenterManagerTest$productCenterManager = QProductCenterManager(mockContext, mockRepository, mockLogger, mockDeviceStorage, mockLaunchResultCacheWrapper, mockUserInfoService, mockIdentityManager) MaxLineLength:QProductCenterManagerTest.kt$QProductCenterManagerTest${ Assert.assertEquals("Wrong installDate value", installDate.milliSecondsToSeconds(), installDateSlot.captured) } MaxLineLength:QProductCenterManagerTest.kt$QProductCenterManagerTest${ Assert.assertEquals("Wrong purchaseToken value", purchaseToken, entityPurchaseSlot.captured.purchaseToken) } MaxLineLength:QUserPropertiesManagerTest.kt$QUserPropertiesManagerTest$fun @@ -158,7 +158,6 @@ MaxLineLength:QonversionBillingServiceTest.kt$QonversionBillingServiceTest.QueryPurchasesHistory$assertThat(billingError!!.billingResponseCode).isEqualTo(BillingClient.BillingResponseCode.BILLING_UNAVAILABLE) MaxLineLength:QonversionBillingServiceTest.kt$QonversionBillingServiceTest.QueryPurchasesHistory$billingClientStateListener.onBillingSetupFinished(buildResult(BillingClient.BillingResponseCode.BILLING_UNAVAILABLE)) MaxLineLength:QonversionError.kt$QonversionErrorCode$* - MaxLineLength:QonversionError.kt$QonversionErrorCode$NetworkConnectionFailed : QonversionErrorCode MaxLineLength:ScreenPresenterTest.kt$ScreenPresenterTest$fun MaxLineLength:SharedPreferencesCacheTest.kt$SharedPreferencesCacheTest.Object${ Assert.assertEquals("Wrong available offerings size value", 1, realValue?.offerings?.availableOfferings?.size) } MaxLineLength:SharedPreferencesCacheTest.kt$SharedPreferencesCacheTest.Object${ Assert.assertEquals("Wrong experimentInfo value", expectedValue.offerings?.main?.experimentInfo, realValue?.offerings?.main?.experimentInfo) } @@ -171,11 +170,9 @@ MaxLineLength:util.kt$Util.Companion$"\"offerings\":[{\"id\":\"main\",\"tag\":1,\"products\":[{\"id\":\"in_app\",\"store_id\":\"qonversion_inapp_consumable\",\"type\":2},{\"id\":\"main\",\"store_id\":\"qonversion_subs_weekly\",\"type\":0,\"duration\":0}],\"experiment\":{\"uid\":\"secondary\",\"attached\":false}" MaxLineLength:util.kt$Util.Companion$"\"permissions\":[{\"id\":\"standart\",\"associated_product\":\"in_app\",\"renew_state\":-1,\"started_timestamp\":1612880300,\"active\":1},{\"id\":\"Test Permission\",\"associated_product\":\"in_app\",\"renew_state\":-1,\"started_timestamp\":1612880300,\"active\":1}],\"user_products\":[{\"id\":\"in_app\",\"store_id\":\"qonversion_inapp_consumable\",\"type\":2}],\"experiments\":[]," MaxLineLength:utils.kt$"ProductId: ${this.sku}; PurchaseTime: ${this.purchaseTime.convertLongToTime()}; PurchaseToken: ${this.purchaseToken}" - MaximumLineLength:com.qonversion.android.sdk.QProductCenterManagerTest.kt:141 - MaximumLineLength:com.qonversion.android.sdk.QProductCenterManagerTest.kt:143 - MaximumLineLength:com.qonversion.android.sdk.QProductCenterManagerTest.kt:58 + MaximumLineLength:com.qonversion.android.sdk.QProductCenterManagerTest.kt:151 + MaximumLineLength:com.qonversion.android.sdk.QProductCenterManagerTest.kt:153 MaximumLineLength:com.qonversion.android.sdk.QUserPropertiesManagerTest.kt:169 - MaximumLineLength:com.qonversion.android.sdk.QonversionError.kt:31 MaximumLineLength:com.qonversion.android.sdk.api.ApiErrorMapper.kt:117 MaximumLineLength:com.qonversion.android.sdk.api.ApiErrorMapper.kt:118 MaximumLineLength:com.qonversion.android.sdk.automations.AutomationsEventMapperTest.kt:105 @@ -301,7 +298,6 @@ NoWildcardImports:com.qonversion.android.sdk.QIdentityManagerTest.kt:4 NoWildcardImports:com.qonversion.android.sdk.QIdentityManagerTest.kt:6 NoWildcardImports:com.qonversion.android.sdk.QProductCenterManager.kt:10 - NoWildcardImports:com.qonversion.android.sdk.QProductCenterManager.kt:11 NoWildcardImports:com.qonversion.android.sdk.QProductCenterManagerTest.kt:18 NoWildcardImports:com.qonversion.android.sdk.QProductCenterManagerTest.kt:26 NoWildcardImports:com.qonversion.android.sdk.QUserPropertiesManagerTest.kt:10 @@ -330,7 +326,6 @@ NoWildcardImports:com.qonversion.android.sdk.di.module.NetworkModule.kt:9 NoWildcardImports:com.qonversion.android.sdk.di.module.RepositoryModule.kt:14 NoWildcardImports:com.qonversion.android.sdk.dto.QonversionMappingAdapters.kt:19 - NoWildcardImports:com.qonversion.android.sdk.services.QUserInfoService.kt:9 NoWildcardImports:com.qonversion.android.sdk.services.QUserInfoServiceTest.kt:11 NoWildcardImports:com.qonversion.android.sdk.services.QUserInfoServiceTest.kt:5 NoWildcardImports:com.qonversion.android.sdk.storage.LaunchResultCacheWrapperTest.kt:4 @@ -411,7 +406,6 @@ WildcardImport:NetworkModule.kt$import com.qonversion.android.sdk.dto.* WildcardImport:QAutomationsManager.kt$import com.qonversion.android.sdk.* WildcardImport:QProductCenterManager.kt$import com.qonversion.android.sdk.ad.LoadStoreProductsState.* - WildcardImport:QProductCenterManager.kt$import com.qonversion.android.sdk.billing.* WildcardImport:QonversionBillingService.kt$import com.android.billingclient.api.* WildcardImport:QonversionRepository.kt$import com.qonversion.android.sdk.dto.request.* WildcardImport:RepositoryModule.kt$import com.qonversion.android.sdk.storage.* diff --git a/sdk/src/main/java/com/qonversion/android/sdk/QProductCenterManager.kt b/sdk/src/main/java/com/qonversion/android/sdk/QProductCenterManager.kt index dec3b5084..36bf32152 100644 --- a/sdk/src/main/java/com/qonversion/android/sdk/QProductCenterManager.kt +++ b/sdk/src/main/java/com/qonversion/android/sdk/QProductCenterManager.kt @@ -834,9 +834,15 @@ class QProductCenterManager internal constructor( val purchaseCallback = purchasingCallbacks[purchase.sku] purchasingCallbacks.remove(purchase.sku) - if (purchase.purchaseState != Purchase.PurchaseState.PURCHASED) { - purchaseCallback?.onError(QonversionError(QonversionErrorCode.PurchasePending)) - return@forEach + when (purchase.purchaseState) { + Purchase.PurchaseState.PENDING -> { + purchaseCallback?.onError(QonversionError(QonversionErrorCode.PurchasePending)) + return@forEach + } + Purchase.PurchaseState.UNSPECIFIED_STATE -> { + purchaseCallback?.onError(QonversionError(QonversionErrorCode.PurchaseUnspecified)) + return@forEach + } } val skuDetail = skuDetails[purchase.sku] ?: return@forEach diff --git a/sdk/src/main/java/com/qonversion/android/sdk/QonversionError.kt b/sdk/src/main/java/com/qonversion/android/sdk/QonversionError.kt index 04ad63780..302ec3e53 100644 --- a/sdk/src/main/java/com/qonversion/android/sdk/QonversionError.kt +++ b/sdk/src/main/java/com/qonversion/android/sdk/QonversionError.kt @@ -22,13 +22,15 @@ enum class QonversionErrorCode(val specification: String) { PlayStoreError("There was an issue with the Play Store service"), BillingUnavailable("The Billing service is unavailable on the device"), PurchasePending("Purchase is pending"), + PurchaseUnspecified("Unspecified state of the purchase"), PurchaseInvalid("Failure of purchase"), CanceledPurchase("User pressed back or canceled a dialog for purchase"), ProductNotOwned("Failure to consume purchase since item is not owned"), ProductAlreadyOwned("Failure to purchase since item is already owned"), FeatureNotSupported("The requested feature is not supported"), ProductUnavailable("Requested product is not available for purchase"), - NetworkConnectionFailed("There was a network issue. Please make sure that the Internet connection is available on the device"), + NetworkConnectionFailed("There was a network issue. " + + "Please make sure that the Internet connection is available on the device"), ParseResponseFailed("A problem occurred when serializing or deserializing data"), BackendError("There was a backend error"), ProductNotFound("Failure to purchase since the Qonversion product was not found"), From 994a7342e22862d141e1512b292bed9cf4617414 Mon Sep 17 00:00:00 2001 From: Maria Bordunova Date: Wed, 13 Oct 2021 17:07:43 +0300 Subject: [PATCH 08/10] Change baseline.xml --- config/detekt/baseline.xml | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index 4f72e61c5..001c85038 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -55,10 +55,10 @@ FinalNewline:com.qonversion.android.sdk.storage.TokenExtractorTest.kt:1 FinalNewline:com.qonversion.android.sdk.storage.TokenStorageTest.kt:1 FinalNewline:com.qonversion.android.sdk.storage.util.kt:1 + FinalNewline:com.qonversion.android.sdk.utils.kt:1 FinalNewline:com.qonversion.android.sdk.validator.util.kt:1 ForbiddenComment:AttributionRequestTest.kt$AttributionRequestTest$// TODO: Update test for new AttributionRequest format ForbiddenComment:EnvironmentRequestTest.kt$EnvironmentRequestTest$// TODO: Update test for new Environment format - ForbiddenComment:GooglePurchaseConverterTest.kt$GooglePurchaseConverterTest$// TODO: Update test for new Purchase fields ForbiddenComment:InAppRequestTest.kt$InAppRequestTest$// TODO: Update test for new InApp format ForbiddenComment:InitRequestTest.kt$InitRequestTest$// TODO: Update test for new InitRequest format ForbiddenComment:PropertiesRequestTest.kt$PropertiesRequestTest$// TODO: Update test for new PropertiesRequest format @@ -159,7 +159,6 @@ MaxLineLength:QonversionBillingServiceTest.kt$QonversionBillingServiceTest.QueryPurchasesHistory$assertThat(billingError!!.billingResponseCode).isEqualTo(BillingClient.BillingResponseCode.BILLING_UNAVAILABLE) MaxLineLength:QonversionBillingServiceTest.kt$QonversionBillingServiceTest.QueryPurchasesHistory$billingClientStateListener.onBillingSetupFinished(buildResult(BillingClient.BillingResponseCode.BILLING_UNAVAILABLE)) MaxLineLength:QonversionError.kt$QonversionErrorCode$* - MaxLineLength:QonversionError.kt$QonversionErrorCode$NetworkConnectionFailed : QonversionErrorCode MaxLineLength:ScreenPresenterTest.kt$ScreenPresenterTest$fun MaxLineLength:SharedPreferencesCacheTest.kt$SharedPreferencesCacheTest.Object${ Assert.assertEquals("Wrong available offerings size value", 1, realValue?.offerings?.availableOfferings?.size) } MaxLineLength:SharedPreferencesCacheTest.kt$SharedPreferencesCacheTest.Object${ Assert.assertEquals("Wrong experimentInfo value", expectedValue.offerings?.main?.experimentInfo, realValue?.offerings?.main?.experimentInfo) } @@ -175,7 +174,6 @@ MaximumLineLength:com.qonversion.android.sdk.QProductCenterManagerTest.kt:152 MaximumLineLength:com.qonversion.android.sdk.QProductCenterManagerTest.kt:154 MaximumLineLength:com.qonversion.android.sdk.QUserPropertiesManagerTest.kt:169 - MaximumLineLength:com.qonversion.android.sdk.QonversionError.kt:31 MaximumLineLength:com.qonversion.android.sdk.api.ApiErrorMapper.kt:117 MaximumLineLength:com.qonversion.android.sdk.api.ApiErrorMapper.kt:118 MaximumLineLength:com.qonversion.android.sdk.automations.AutomationsEventMapperTest.kt:105 @@ -266,6 +264,7 @@ NewLineAtEndOfFile:util.kt$com.qonversion.android.sdk.storage.util.kt NewLineAtEndOfFile:util.kt$com.qonversion.android.sdk.validator.util.kt NewLineAtEndOfFile:utils.kt$com.qonversion.android.app.utils.kt + NewLineAtEndOfFile:utils.kt$com.qonversion.android.sdk.utils.kt NoBlankLineBeforeRbrace:com.qonversion.android.sdk.automations.QAutomationsManagerTest.kt:281 NoBlankLineBeforeRbrace:com.qonversion.android.sdk.converter.util.kt:55 NoBlankLineBeforeRbrace:com.qonversion.android.sdk.validator.RequestValidatorTest.kt:18 @@ -299,7 +298,6 @@ NoWildcardImports:com.qonversion.android.sdk.QIdentityManagerTest.kt:4 NoWildcardImports:com.qonversion.android.sdk.QIdentityManagerTest.kt:6 NoWildcardImports:com.qonversion.android.sdk.QProductCenterManager.kt:10 - NoWildcardImports:com.qonversion.android.sdk.QProductCenterManager.kt:11 NoWildcardImports:com.qonversion.android.sdk.QProductCenterManagerTest.kt:19 NoWildcardImports:com.qonversion.android.sdk.QProductCenterManagerTest.kt:27 NoWildcardImports:com.qonversion.android.sdk.QUserPropertiesManagerTest.kt:10 @@ -322,6 +320,8 @@ NoWildcardImports:com.qonversion.android.sdk.billing.QonversionBillingServiceTest.kt:5 NoWildcardImports:com.qonversion.android.sdk.billing.QonversionBillingServiceTest.kt:8 NoWildcardImports:com.qonversion.android.sdk.billing.utils.kt:8 + NoWildcardImports:com.qonversion.android.sdk.converter.GooglePurchaseConverterTest.kt:4 + NoWildcardImports:com.qonversion.android.sdk.converter.GooglePurchaseConverterTest.kt:7 NoWildcardImports:com.qonversion.android.sdk.di.component.AppComponent.kt:9 NoWildcardImports:com.qonversion.android.sdk.di.module.ManagersModule.kt:18 NoWildcardImports:com.qonversion.android.sdk.di.module.NetworkModule.kt:9 @@ -341,16 +341,25 @@ ReturnCount:ScreenPresenter.kt$ScreenPresenter$override fun shouldOverrideUrlLoading(url: String?): Boolean ReturnCount:SkuDetailsTokenExtractor.kt$SkuDetailsTokenExtractor$override fun extract(response: String?): String SpacingAroundColon:com.qonversion.android.sdk.requests.ProviderDataRequestTest.kt:43 + SpacingAroundComma:com.qonversion.android.sdk.converter.GooglePurchaseConverterTest.kt:146 SpacingAroundCurly:com.qonversion.android.sdk.ConsumerTest.kt:106 SpacingAroundCurly:com.qonversion.android.sdk.ConsumerTest.kt:122 SpacingAroundCurly:com.qonversion.android.sdk.ConsumerTest.kt:137 SpacingAroundCurly:com.qonversion.android.sdk.automations.QAutomationsManagerTest.kt:274 + SpacingAroundCurly:com.qonversion.android.sdk.converter.GooglePurchaseConverterTest.kt:139 + SpacingAroundCurly:com.qonversion.android.sdk.converter.GooglePurchaseConverterTest.kt:145 + SpacingAroundCurly:com.qonversion.android.sdk.converter.GooglePurchaseConverterTest.kt:297 + SpacingAroundCurly:com.qonversion.android.sdk.converter.GooglePurchaseConverterTest.kt:303 SpacingAroundCurly:com.qonversion.android.sdk.requests.PropertiesRequestTest.kt:13 SpacingAroundCurly:com.qonversion.android.sdk.requests.PropertiesRequestTest.kt:19 SpacingAroundParens:com.qonversion.android.sdk.QUserPropertiesManagerTest.kt:470 + SpacingAroundParens:com.qonversion.android.sdk.converter.GooglePurchaseConverterTest.kt:207 + SpacingAroundParens:com.qonversion.android.sdk.converter.GooglePurchaseConverterTest.kt:308 SpacingAroundParens:com.qonversion.android.sdk.storage.SharedPreferencesCacheTest.kt:212 SpacingAroundParens:com.qonversion.android.sdk.storage.SharedPreferencesCacheTest.kt:243 SpacingAroundParens:com.qonversion.android.sdk.storage.SharedPreferencesCacheTest.kt:262 + SpacingAroundParens:com.qonversion.android.sdk.utils.kt:64 + StringTemplate:com.qonversion.android.sdk.utils.kt:49 SwallowedException:ApiErrorMapper.kt$ApiErrorMapper$catch (e: JSONException) { errorMessage = "$ERROR=failed to parse the backend response" } SwallowedException:AutomationsEventMapper.kt$AutomationsEventMapper$catch (e: JSONException) { logger.release("getEventFromRemoteMessage() -> Failed to retrieve event that triggered push notification") } SwallowedException:EnvironmentProvider.kt$EnvironmentProvider$catch (throwable: Throwable) { UNKNOWN } @@ -376,8 +385,6 @@ TooManyFunctions:ScreenActivity.kt$ScreenActivity : AppCompatActivityView TooManyFunctions:utils.kt$com.qonversion.android.sdk.billing.utils.kt UnnecessaryAbstractClass:RequestData.kt$RequestData - UnusedPrivateMember:GooglePurchaseConverterTest.kt$GooglePurchaseConverterTest$val converted = GooglePurchaseConverter(SkuDetailsTokenExtractor()) .convertPurchase( Pair( SkuDetails(CORRECT_SKU_DETAILS_INAPP_JSON), Purchase(CORRECT_PURCHASE_INAPP_JSON, "SKU") ) ) - UnusedPrivateMember:GooglePurchaseConverterTest.kt$GooglePurchaseConverterTest$val converted = GooglePurchaseConverter(SkuDetailsTokenExtractor()) .convertPurchase( Pair( SkuDetails(CORRECT_SKU_DETAILS_SUB_JSON), Purchase(CORRECT_PURCHASE_SUB_JSON, "SKU") ) ) UnusedPrivateMember:PurchaseRequestTest.kt$PurchaseRequestTest$val purchase = converter.convertPurchase( Pair( SkuDetails(Util.CORRECT_SKU_DETAILS_INAPP_JSON), Purchase(Util.CORRECT_PURCHASE_INAPP_JSON, "SKU") ) ) UnusedPrivateMember:PurchaseRequestTest.kt$PurchaseRequestTest$val purchase = converter.convertPurchase( Pair( SkuDetails(Util.CORRECT_SKU_DETAILS_SUB_JSON), Purchase(Util.CORRECT_PURCHASE_SUB_JSON, "SKU") ) ) UnusedPrivateMember:QProductCenterManagerTest.kt$QProductCenterManagerTest$private val skuTypeSubs = BillingClient.SkuType.SUBS @@ -408,7 +415,6 @@ WildcardImport:NetworkModule.kt$import com.qonversion.android.sdk.dto.* WildcardImport:QAutomationsManager.kt$import com.qonversion.android.sdk.* WildcardImport:QProductCenterManager.kt$import com.qonversion.android.sdk.ad.LoadStoreProductsState.* - WildcardImport:QProductCenterManager.kt$import com.qonversion.android.sdk.billing.* WildcardImport:QonversionBillingService.kt$import com.android.billingclient.api.* WildcardImport:QonversionRepository.kt$import com.qonversion.android.sdk.dto.request.* WildcardImport:RepositoryModule.kt$import com.qonversion.android.sdk.storage.* From 268b81969ceebabeab157af74ea1f30c077ed1c7 Mon Sep 17 00:00:00 2001 From: Maria Bordunova Date: Wed, 13 Oct 2021 17:18:20 +0300 Subject: [PATCH 09/10] Change baseline.xml --- config/detekt/baseline.xml | 2 ++ .../java/com/qonversion/android/sdk/QProductCenterManager.kt | 5 +---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index 001c85038..d1894a203 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -298,6 +298,7 @@ NoWildcardImports:com.qonversion.android.sdk.QIdentityManagerTest.kt:4 NoWildcardImports:com.qonversion.android.sdk.QIdentityManagerTest.kt:6 NoWildcardImports:com.qonversion.android.sdk.QProductCenterManager.kt:10 + NoWildcardImports:com.qonversion.android.sdk.QProductCenterManager.kt:11 NoWildcardImports:com.qonversion.android.sdk.QProductCenterManagerTest.kt:19 NoWildcardImports:com.qonversion.android.sdk.QProductCenterManagerTest.kt:27 NoWildcardImports:com.qonversion.android.sdk.QUserPropertiesManagerTest.kt:10 @@ -415,6 +416,7 @@ WildcardImport:NetworkModule.kt$import com.qonversion.android.sdk.dto.* WildcardImport:QAutomationsManager.kt$import com.qonversion.android.sdk.* WildcardImport:QProductCenterManager.kt$import com.qonversion.android.sdk.ad.LoadStoreProductsState.* + WildcardImport:QProductCenterManager.kt$import com.qonversion.android.sdk.billing.* WildcardImport:QonversionBillingService.kt$import com.android.billingclient.api.* WildcardImport:QonversionRepository.kt$import com.qonversion.android.sdk.dto.request.* WildcardImport:RepositoryModule.kt$import com.qonversion.android.sdk.storage.* diff --git a/sdk/src/main/java/com/qonversion/android/sdk/QProductCenterManager.kt b/sdk/src/main/java/com/qonversion/android/sdk/QProductCenterManager.kt index 3e00c6a42..b515355b2 100644 --- a/sdk/src/main/java/com/qonversion/android/sdk/QProductCenterManager.kt +++ b/sdk/src/main/java/com/qonversion/android/sdk/QProductCenterManager.kt @@ -8,10 +8,7 @@ import com.android.billingclient.api.Purchase import com.android.billingclient.api.SkuDetails import com.qonversion.android.sdk.ad.AdvertisingProvider import com.qonversion.android.sdk.ad.LoadStoreProductsState.* -import com.qonversion.android.sdk.billing.BillingError -import com.qonversion.android.sdk.billing.BillingService -import com.qonversion.android.sdk.billing.QonversionBillingService -import com.qonversion.android.sdk.billing.milliSecondsToSeconds +import com.qonversion.android.sdk.billing.* import com.qonversion.android.sdk.converter.GooglePurchaseConverter import com.qonversion.android.sdk.converter.PurchaseConverter import com.qonversion.android.sdk.dto.QLaunchResult From 1744f5a046a1055e2b6ff3c236192cf9ab49a07c Mon Sep 17 00:00:00 2001 From: Maria-Bordunova Date: Wed, 13 Oct 2021 14:36:00 +0000 Subject: [PATCH 10/10] [create-pull-request] automated change --- build.gradle | 2 +- fastlane/README.md | 9 +++++++-- fastlane/report.xml | 7 +------ .../com/qonversion/android/sdk/di/module/AppModule.kt | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/build.gradle b/build.gradle index 9638cf6f2..28f9a7485 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ buildscript { ext { release = [ - versionName: "3.1.2", + versionName: "3.1.3", versionCode: 1 ] } diff --git a/fastlane/README.md b/fastlane/README.md index 5e20d1e83..ae96ba246 100644 --- a/fastlane/README.md +++ b/fastlane/README.md @@ -12,7 +12,7 @@ Install _fastlane_ using ``` [sudo] gem install fastlane -NV ``` -or alternatively using `brew cask install fastlane` +or alternatively using `brew install fastlane` # Available Actions ## Android @@ -21,9 +21,14 @@ or alternatively using `brew cask install fastlane` fastlane android test ``` Runs all the tests +### android bump +``` +fastlane android bump +``` + ---- -This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run. +This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run. More information about fastlane can be found on [fastlane.tools](https://fastlane.tools). The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools). diff --git a/fastlane/report.xml b/fastlane/report.xml index 05db6b849..77e0e6e15 100644 --- a/fastlane/report.xml +++ b/fastlane/report.xml @@ -5,12 +5,7 @@ - - - - - - + diff --git a/sdk/src/main/java/com/qonversion/android/sdk/di/module/AppModule.kt b/sdk/src/main/java/com/qonversion/android/sdk/di/module/AppModule.kt index 245f57f09..9660845aa 100644 --- a/sdk/src/main/java/com/qonversion/android/sdk/di/module/AppModule.kt +++ b/sdk/src/main/java/com/qonversion/android/sdk/di/module/AppModule.kt @@ -68,6 +68,6 @@ class AppModule( } companion object { - private const val SDK_VERSION = "3.1.2" + private const val SDK_VERSION = "3.1.3" } }