Skip to content

Commit

Permalink
Handled the case "no private key available for account(create a new k…
Browse files Browse the repository at this point in the history
…ey for email) (#2675)

* Handled the case "no private key available for account(create a new key for email)".| #597

* Fixed navigation.| #597

* Added ComposeScreenNoKeyAvailableCreateNewKeyFlowTest.| #597

* Refactored code

* Refactored code

* wip
  • Loading branch information
DenBond7 authored Apr 9, 2024
1 parent 398ca73 commit bc8015f
Show file tree
Hide file tree
Showing 19 changed files with 339 additions and 118 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* © 2016-present FlowCrypt a.s. Limitations apply. Contact [email protected]
* Contributors: DenBond7
*/

package com.flowcrypt.email.ui

import android.view.KeyEvent
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.clearText
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.action.ViewActions.pressImeActionButton
import androidx.test.espresso.action.ViewActions.pressKey
import androidx.test.espresso.action.ViewActions.replaceText
import androidx.test.espresso.action.ViewActions.typeText
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import com.flowcrypt.email.R
import com.flowcrypt.email.TestConstants
import com.flowcrypt.email.database.entity.KeyEntity
import com.flowcrypt.email.junit.annotations.FlowCryptTestSettings
import com.flowcrypt.email.rules.AddPrivateKeyToDatabaseRule
import com.flowcrypt.email.rules.ClearAppSettingsRule
import com.flowcrypt.email.rules.GrantPermissionRuleChooser
import com.flowcrypt.email.rules.RetryRule
import com.flowcrypt.email.rules.ScreenshotTestRule
import com.flowcrypt.email.ui.base.BaseComposeScreenNoKeyAvailableTest
import org.junit.Rule
import org.junit.Test
import org.junit.rules.RuleChain
import org.junit.rules.TestRule
import org.junit.runner.RunWith

/**
* @author Denys Bondarenko
*/
@MediumTest
@RunWith(AndroidJUnit4::class)
@FlowCryptTestSettings(useCommonIdling = false)
class ComposeScreenNoKeyAvailableCreateNewKeyFlowTest : BaseComposeScreenNoKeyAvailableTest() {
private val addPrivateKeyToDatabaseRule = AddPrivateKeyToDatabaseRule(
keyPath = "pgp/[email protected]_keyA_strong.asc",
passphraseType = KeyEntity.PassphraseType.RAM
)

@get:Rule
var ruleChain: TestRule = RuleChain
.outerRule(RetryRule.DEFAULT)
.around(ClearAppSettingsRule())
.around(GrantPermissionRuleChooser.grant(android.Manifest.permission.POST_NOTIFICATIONS))
.around(addAccountToDatabaseRule)
.around(addPrivateKeyToDatabaseRule)
.around(activeActivityRule)
.around(ScreenshotTestRule())

@Test
fun testCreatingNewKey() {
doBaseActions {
onView(withText(R.string.create_a_new_key))
.check(matches(isDisplayed()))
.perform(click())

Thread.sleep(1000)

onView(withId(R.id.editTextKeyPassword))
.perform(click(), typeText(TestConstants.DEFAULT_STRONG_PASSWORD))
Thread.sleep(1000)
onView(withId(R.id.editTextKeyPassword))
.perform(pressImeActionButton())

Thread.sleep(1000)

onView(withId(R.id.editTextKeyPasswordSecond))
.perform(replaceText(TestConstants.DEFAULT_STRONG_PASSWORD))
onView(withId(R.id.buttonConfirmPassPhrases))
.perform(click())
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,13 @@ import androidx.test.espresso.action.ViewActions.closeSoftKeyboard
import androidx.test.espresso.action.ViewActions.replaceText
import androidx.test.espresso.action.ViewActions.scrollTo
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.hasTextColor
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import com.flowcrypt.email.R
import com.flowcrypt.email.TestConstants
import com.flowcrypt.email.extensions.kotlin.asInternetAddress
import com.flowcrypt.email.junit.annotations.FlowCryptTestSettings
import com.flowcrypt.email.rules.AddPrivateKeyToDatabaseRule
import com.flowcrypt.email.rules.ClearAppSettingsRule
Expand All @@ -28,7 +26,6 @@ import com.flowcrypt.email.rules.RetryRule
import com.flowcrypt.email.rules.ScreenshotTestRule
import com.flowcrypt.email.ui.base.BaseComposeScreenNoKeyAvailableTest
import com.flowcrypt.email.util.PrivateKeysManager
import org.hamcrest.CoreMatchers.not
import org.junit.Rule
import org.junit.Test
import org.junit.rules.RuleChain
Expand Down Expand Up @@ -61,52 +58,26 @@ class ComposeScreenNoKeyAvailableSingleKeyWithPassphraseInDatabaseFlowTest : Bas

@Test
fun testImportKey() {
activeActivityRule?.launch(intent)
registerAllIdlingResources()
fillInAllFields(
to = setOf(
requireNotNull(TestConstants.RECIPIENT_WITH_PUBLIC_KEY_ON_ATTESTER.asInternetAddress())
)
)
doBaseActions {
addTextToClipboard("private key", requireNotNull(pgpKeyDetails.privateKey))
onView(withText(R.string.import_private_key))
.check(matches(isDisplayed()))
.perform(click())
Thread.sleep(1000)
onView(withText(R.string.load_from_clipboard))
.check(matches(isDisplayed()))
.perform(click())

//check that editTextFrom has gray text color. It means a sender doesn't have a private key
onView(withId(R.id.editTextFrom))
.check(matches(isDisplayed()))
.check(matches(hasTextColor(R.color.gray)))
onView(withId(R.id.editTextKeyPassword))
.perform(
replaceText(TestConstants.DEFAULT_STRONG_PASSWORD),
closeSoftKeyboard()
)
onView(withId(R.id.buttonPositiveAction))
.perform(scrollTo(), click())

onView(withId(R.id.menuActionSend))
.check(matches(isDisplayed()))
.perform(click())

isDialogWithTextDisplayed(
decorView,
getResString(R.string.no_key_available, addAccountToDatabaseRule.account.email)
)

addTextToClipboard("private key", requireNotNull(pgpKeyDetails.privateKey))
onView(withText(R.string.import_private_key))
.check(matches(isDisplayed()))
.perform(click())

Thread.sleep(1000)
onView(withText(R.string.load_from_clipboard))
.check(matches(isDisplayed()))
.perform(click())

onView(withId(R.id.editTextKeyPassword))
.perform(
replaceText(TestConstants.DEFAULT_STRONG_PASSWORD),
closeSoftKeyboard()
)
onView(withId(R.id.buttonPositiveAction))
.perform(scrollTo(), click())

waitForObjectWithText(addAccountToDatabaseRule.account.email, 5000)

//check that editTextFrom doesn't have gray text color. It means a sender has a private key.
onView(withId(R.id.editTextFrom))
.check(matches(isDisplayed()))
.check(matches(not(hasTextColor(R.color.gray))))
waitForObjectWithText(addAccountToDatabaseRule.account.email, 5000)
}
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ import java.net.HttpURLConnection
abstract class BaseComposeScreenNoKeyAvailableTest : BaseComposeScreenTest() {

protected fun doTestAddEmailToExistingKey(action: () -> Unit) {
doBaseActions {
onView(withText(R.string.add_email_to_existing_key))
.check(matches(isDisplayed()))
.perform(click())

action.invoke()
}
}

protected fun doBaseActions(action: () -> Unit) {
activeActivityRule?.launch(intent)
registerAllIdlingResources()
fillInAllFields(
Expand All @@ -52,13 +62,9 @@ abstract class BaseComposeScreenNoKeyAvailableTest : BaseComposeScreenTest() {
getResString(R.string.no_key_available, addAccountToDatabaseRule.account.email)
)

onView(withText(R.string.add_email_to_existing_key))
.check(matches(isDisplayed()))
.perform(click())

action.invoke()

Thread.sleep(2000)
waitForObjectWithText(getResString(R.string.compose), 5000)

//check that editTextFrom doesn't have gray text color. It means a sender has a private key.
onView(withId(R.id.editTextFrom))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import okhttp3.mockwebserver.Dispatcher
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.RecordedRequest
import org.junit.Assert.assertEquals
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.rules.RuleChain
Expand All @@ -48,6 +49,7 @@ import org.junit.runner.RunWith
message = BaseComposeScreenTest.MESSAGE,
subject = BaseComposeScreenTest.SUBJECT
)
@Ignore("Should be fixed before the next release")
class EncryptedWithAttachmentsComposeGmailApiFlow : BaseComposeGmailFlow() {
override val mockWebServerRule =
FlowCryptMockWebServerRule(TestConstants.MOCK_WEB_SERVER_PORT, object : Dispatcher() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,8 @@ fun LifecycleOwner.showActionDialogFragment(
requestKey: String,
dialogTitle: String? = null,
isCancelable: Boolean = true,
items: List<DialogItem>
items: List<DialogItem>,
bundle: Bundle? = null
) {
showDialogFragment(navController) {
return@showDialogFragment object : NavDirections {
Expand All @@ -177,7 +178,8 @@ fun LifecycleOwner.showActionDialogFragment(
requestKey = requestKey,
dialogTitle = dialogTitle,
isCancelable = isCancelable,
items = items.toTypedArray()
items = items.toTypedArray(),
bundle = bundle
).toBundle()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import android.view.MenuInflater
import android.view.MenuItem
import android.view.ViewGroup
import android.view.WindowManager
import androidx.activity.OnBackPressedCallback
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
Expand Down Expand Up @@ -51,6 +52,8 @@ abstract class BaseActivity<T : ViewBinding> : AppCompatActivity() {
protected abstract fun inflateBinding(inflater: LayoutInflater): T
protected abstract fun initAppBarConfiguration(): AppBarConfiguration

protected abstract val onBackPressedCallback: OnBackPressedCallback?

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//https://github.com/FlowCrypt/flowcrypt-android/issues/2442
Expand Down Expand Up @@ -83,6 +86,8 @@ abstract class BaseActivity<T : ViewBinding> : AppCompatActivity() {
}
})

onBackPressedCallback?.let { onBackPressedDispatcher.addCallback(this, it) }

initViews()
setupNavigation()
initAccountViewModel()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.widget.Toast
import androidx.activity.OnBackPressedCallback
import androidx.navigation.NavHostController
import androidx.navigation.ui.AppBarConfiguration
import com.flowcrypt.email.R
Expand Down Expand Up @@ -48,6 +49,21 @@ class CreateMessageActivity : BaseActivity<ActivityCreateMessageBinding>(),
})
}

override val onBackPressedCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (navController.currentDestination?.id == R.id.createMessageFragment) {
onBackPressed()
} else {
navController.navigateUp()
}
}

private fun onBackPressed() {
isEnabled = false
onBackPressedDispatcher.onBackPressed()
}
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
(navController as? NavHostController)?.enableOnBackPressed(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
override fun onServiceDisconnected(arg0: ComponentName) {}
}

private val onBackPressedCallback = object : OnBackPressedCallback(true) {
override val onBackPressedCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (binding.drawerLayout.isDrawerOpen(GravityCompat.START)) {
binding.drawerLayout.closeDrawer(GravityCompat.START)
Expand Down Expand Up @@ -153,7 +153,6 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
}
}
super.onCreate(savedInstanceState)
handleOnBackPressed()
observeMovingToBackground()

client = GoogleSignIn.getClient(this, GoogleApiClientHelper.generateGoogleSignInOptions())
Expand Down Expand Up @@ -438,10 +437,6 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
fragment?.onDrawerStateChanged(slideOffset, isOpened)
}

private fun handleOnBackPressed() {
onBackPressedDispatcher.addCallback(this, onBackPressedCallback)
}

private fun observeMovingToBackground() {
ProcessLifecycleOwner.get().lifecycle.addObserver(object : DefaultLifecycleObserver {
/**
Expand Down
Loading

0 comments on commit bc8015f

Please sign in to comment.