Browse Source

Add fxa/sync integration tests

fixing Jenkins path to tests and clean tests

commenting future tests and adding doc with info about the tests
master
Isabel Rios 2 years ago
committed by isabelrios
parent
commit
44f4cedefd
  1. 46
      Jenkinsfile
  2. 6
      app/build.gradle
  3. 33
      app/src/androidTest/java/org/mozilla/fenix/Experiments.kt
  4. 17
      app/src/androidTest/java/org/mozilla/fenix/components/FxaServer.kt
  5. 22
      app/src/androidTest/java/org/mozilla/fenix/syncintegration/Pipfile
  6. 561
      app/src/androidTest/java/org/mozilla/fenix/syncintegration/Pipfile.lock
  7. 173
      app/src/androidTest/java/org/mozilla/fenix/syncintegration/SyncIntegrationTest.kt
  8. 0
      app/src/androidTest/java/org/mozilla/fenix/syncintegration/__init__.py
  9. 16
      app/src/androidTest/java/org/mozilla/fenix/syncintegration/adbrun.py
  10. 166
      app/src/androidTest/java/org/mozilla/fenix/syncintegration/conftest.py
  11. 42
      app/src/androidTest/java/org/mozilla/fenix/syncintegration/gradlewbuild.py
  12. 26
      app/src/androidTest/java/org/mozilla/fenix/syncintegration/launchSimScript.sh
  13. 4
      app/src/androidTest/java/org/mozilla/fenix/syncintegration/pytest.ini
  14. 25
      app/src/androidTest/java/org/mozilla/fenix/syncintegration/test_bookmark.js
  15. 33
      app/src/androidTest/java/org/mozilla/fenix/syncintegration/test_history.js
  16. 14
      app/src/androidTest/java/org/mozilla/fenix/syncintegration/test_integration.py
  17. 52
      app/src/androidTest/java/org/mozilla/fenix/syncintegration/tps.py
  18. 1
      app/src/androidTest/resources/email.txt
  19. 1
      app/src/androidTest/resources/password.txt
  20. 38
      app/src/main/java/org/mozilla/fenix/components/BackgroundServices.kt
  21. 21
      app/src/main/java/org/mozilla/fenix/components/FxaServer.kt
  22. 4
      app/src/main/java/org/mozilla/fenix/components/Services.kt
  23. 2
      app/src/main/res/values/preference_keys.xml
  24. 26
      docs/syncIntegrationTests.md

46
Jenkinsfile

@ -0,0 +1,46 @@
pipeline {
agent any
triggers {
cron(env.BRANCH_NAME == 'master' ? 'H 0 * * *' : '')
}
options {
timestamps()
timeout(time: 1, unit: 'HOURS')
}
stages {
stage('test') {
steps {
dir('app/src/androidTest/java/org/mozilla/fenix/syncIntegration') {
sh 'pipenv install'
sh 'pipenv check'
sh 'pipenv run pytest'
}
}
}
}
post {
always {
script {
publishHTML(target: [
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: '/Users/synctesting/.jenkins/workspace/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/SyncIntegrationTests/results',
reportFiles: 'index.html',
reportName: 'HTML Report'])
}
}
failure {
slackSend(
color: 'danger',
message: "FAILED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})")
}
fixed {
slackSend(
color: 'good',
message: "FIXED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})")
}
}
}

6
app/build.gradle

@ -125,6 +125,12 @@ android {
flavorDimensions "engine"
sourceSets {
androidTest {
resources.srcDirs += ['src/androidTest/resources']
}
}
productFlavors {
geckoNightly {
dimension "engine"

33
app/src/androidTest/java/org/mozilla/fenix/Experiments.kt

@ -0,0 +1,33 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix
import android.content.Context
import mozilla.components.service.fretboard.ExperimentDescriptor
const val EXPERIMENTS_JSON_FILENAME = "experiments.json"
const val EXPERIMENTS_BASE_URL = "https://firefox.settings.services.mozilla.com/v1"
const val EXPERIMENTS_BUCKET_NAME = "main"
// collection name below, see https://bugzilla.mozilla.org/show_bug.cgi?id=1523395 for ownership details
const val EXPERIMENTS_COLLECTION_NAME = "fenix-experiments"
object Experiments {
val AATestDescriptor = ExperimentDescriptor("AAtest")
// application services flag to disable the Firefox Sync syncManager
val asFeatureSyncDisabled = ExperimentDescriptor("asFeatureSyncDisabled")
// application services flag to disable Firefox Accounts pairing button.
val asFeatureFxAPairingDisabled = ExperimentDescriptor("asFeatureFxAPairingDisabled")
// application services flag to disable Firefox Accounts WebChannel integration.
val asFeatureWebChannelsDisabled = ExperimentDescriptor("asFeatureWebChannelsDisabled")
}
val Context.app: FenixApplication
get() = applicationContext as FenixApplication
fun Context.isInExperiment(descriptor: ExperimentDescriptor): Boolean =
if (descriptor.name == "asFeatureWebChannelsDisabled")
true
else
app.fretboard.isInExperiment(this, descriptor)

17
app/src/androidTest/java/org/mozilla/fenix/components/FxaServer.kt

@ -0,0 +1,17 @@
package org.mozilla.fenix.components
import android.content.Context
import mozilla.components.service.fxa.ServerConfig
object FxaServer {
const val CLIENT_ID = "a2270f727f45f648"
const val REDIRECT_URL = "https://accounts.stage.mozaws.net/oauth/success/$CLIENT_ID"
@Suppress("UNUSED_PARAMETER")
fun redirectUrl(context: Context) = REDIRECT_URL
@Suppress("UNUSED_PARAMETER")
fun config(context: Context): ServerConfig {
return ServerConfig.dev(CLIENT_ID, REDIRECT_URL)
}
}

22
app/src/androidTest/java/org/mozilla/fenix/syncintegration/Pipfile

@ -0,0 +1,22 @@
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"
[packages]
fxapom = "*"
mozdownload = "*"
mozinstall = "*"
mozprofile = "*"
mozrunner = "*"
mozversion = "*"
pytest = "*"
pytest-fxa = "*"
pytest-html = "*"
pytest-metadata = "*"
requests = "*"
[dev-packages]
[requires]
python_version = "2.7"

561
app/src/androidTest/java/org/mozilla/fenix/syncintegration/Pipfile.lock

@ -0,0 +1,561 @@
{
"_meta": {
"hash": {
"sha256": "112a12fa2e9e8117b399b60a49b4c8799a614ef655992640c95149bf95f33e8b"
},
"pipfile-spec": 6,
"requires": {
"python_version": "2.7"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.python.org/simple",
"verify_ssl": true
}
]
},
"default": {
"asn1crypto": {
"hashes": [
"sha256:2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87",
"sha256:9d5c20441baf0cb60a4ac34cc447c6c189024b6b4c6cd7877034f4965c464e49"
],
"version": "==0.24.0"
},
"atomicwrites": {
"hashes": [
"sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4",
"sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"
],
"version": "==1.3.0"
},
"attrs": {
"hashes": [
"sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79",
"sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399"
],
"version": "==19.1.0"
},
"blessings": {
"hashes": [
"sha256:98e5854d805f50a5b58ac2333411b0482516a8210f23f43308baeb58d77c157d",
"sha256:b1fdd7e7a675295630f9ae71527a8ebc10bfefa236b3d6aa4932ee4462c17ba3",
"sha256:caad5211e7ba5afe04367cdd4cfc68fa886e2e08f6f35e76b7387d2109ccea6e"
],
"version": "==1.7"
},
"certifi": {
"hashes": [
"sha256:59b7658e26ca9c7339e00f8f4636cdfe59d34fa37b9b04f6f9e9926b3cece1a5",
"sha256:b26104d6835d1f5e49452a26eb2ff87fe7090b89dfcaee5ea2212697e1e1d7ae"
],
"version": "==2019.3.9"
},
"cffi": {
"hashes": [
"sha256:041c81822e9f84b1d9c401182e174996f0bae9991f33725d059b771744290774",
"sha256:046ef9a22f5d3eed06334d01b1e836977eeef500d9b78e9ef693f9380ad0b83d",
"sha256:066bc4c7895c91812eff46f4b1c285220947d4aa46fa0a2651ff85f2afae9c90",
"sha256:066c7ff148ae33040c01058662d6752fd73fbc8e64787229ea8498c7d7f4041b",
"sha256:2444d0c61f03dcd26dbf7600cf64354376ee579acad77aef459e34efcb438c63",
"sha256:300832850b8f7967e278870c5d51e3819b9aad8f0a2c8dbe39ab11f119237f45",
"sha256:34c77afe85b6b9e967bd8154e3855e847b70ca42043db6ad17f26899a3df1b25",
"sha256:46de5fa00f7ac09f020729148ff632819649b3e05a007d286242c4882f7b1dc3",
"sha256:4aa8ee7ba27c472d429b980c51e714a24f47ca296d53f4d7868075b175866f4b",
"sha256:4d0004eb4351e35ed950c14c11e734182591465a33e960a4ab5e8d4f04d72647",
"sha256:4e3d3f31a1e202b0f5a35ba3bc4eb41e2fc2b11c1eff38b362de710bcffb5016",
"sha256:50bec6d35e6b1aaeb17f7c4e2b9374ebf95a8975d57863546fa83e8d31bdb8c4",
"sha256:55cad9a6df1e2a1d62063f79d0881a414a906a6962bc160ac968cc03ed3efcfb",
"sha256:5662ad4e4e84f1eaa8efce5da695c5d2e229c563f9d5ce5b0113f71321bcf753",
"sha256:59b4dc008f98fc6ee2bb4fd7fc786a8d70000d058c2bbe2698275bc53a8d3fa7",
"sha256:73e1ffefe05e4ccd7bcea61af76f36077b914f92b76f95ccf00b0c1b9186f3f9",
"sha256:a1f0fd46eba2d71ce1589f7e50a9e2ffaeb739fb2c11e8192aa2b45d5f6cc41f",
"sha256:a2e85dc204556657661051ff4bab75a84e968669765c8a2cd425918699c3d0e8",
"sha256:a5457d47dfff24882a21492e5815f891c0ca35fefae8aa742c6c263dac16ef1f",
"sha256:a8dccd61d52a8dae4a825cdbb7735da530179fea472903eb871a5513b5abbfdc",
"sha256:ae61af521ed676cf16ae94f30fe202781a38d7178b6b4ab622e4eec8cefaff42",
"sha256:b012a5edb48288f77a63dba0840c92d0504aa215612da4541b7b42d849bc83a3",
"sha256:d2c5cfa536227f57f97c92ac30c8109688ace8fa4ac086d19d0af47d134e2909",
"sha256:d42b5796e20aacc9d15e66befb7a345454eef794fdb0737d1af593447c6c8f45",
"sha256:dee54f5d30d775f525894d67b1495625dd9322945e7fee00731952e0368ff42d",
"sha256:e070535507bd6aa07124258171be2ee8dfc19119c28ca94c9dfb7efd23564512",
"sha256:e1ff2748c84d97b065cc95429814cdba39bcbd77c9c85c89344b317dc0d9cbff",
"sha256:ed851c75d1e0e043cbf5ca9a8e1b13c4c90f3fbd863dacb01c0808e2b5204201"
],
"version": "==1.12.3"
},
"chardet": {
"hashes": [
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
],
"version": "==3.0.4"
},
"configparser": {
"hashes": [
"sha256:8be81d89d6e7b4c0d4e44bcc525845f6da25821de80cb5e06e7e0238a2899e32",
"sha256:da60d0014fd8c55eb48c1c5354352e363e2d30bbf7057e5e171a468390184c75"
],
"markers": "python_version < '3'",
"version": "==3.7.4"
},
"contextlib2": {
"hashes": [
"sha256:509f9419ee91cdd00ba34443217d5ca51f5a364a404e1dce9e8979cea969ca48",
"sha256:f5260a6e679d2ff42ec91ec5252f4eeffdcf21053db9113bd0a8e4d953769c00"
],
"markers": "python_version < '3'",
"version": "==0.5.5"
},
"cryptography": {
"hashes": [
"sha256:24b61e5fcb506424d3ec4e18bca995833839bf13c59fc43e530e488f28d46b8c",
"sha256:25dd1581a183e9e7a806fe0543f485103232f940fcfc301db65e630512cce643",
"sha256:3452bba7c21c69f2df772762be0066c7ed5dc65df494a1d53a58b683a83e1216",
"sha256:41a0be220dd1ed9e998f5891948306eb8c812b512dc398e5a01846d855050799",
"sha256:5751d8a11b956fbfa314f6553d186b94aa70fdb03d8a4d4f1c82dcacf0cbe28a",
"sha256:5f61c7d749048fa6e3322258b4263463bfccefecb0dd731b6561cb617a1d9bb9",
"sha256:72e24c521fa2106f19623a3851e9f89ddfdeb9ac63871c7643790f872a305dfc",
"sha256:7b97ae6ef5cba2e3bb14256625423413d5ce8d1abb91d4f29b6d1a081da765f8",
"sha256:961e886d8a3590fd2c723cf07be14e2a91cf53c25f02435c04d39e90780e3b53",
"sha256:96d8473848e984184b6728e2c9d391482008646276c3ff084a1bd89e15ff53a1",
"sha256:ae536da50c7ad1e002c3eee101871d93abdc90d9c5f651818450a0d3af718609",
"sha256:b0db0cecf396033abb4a93c95d1602f268b3a68bb0a9cc06a7cff587bb9a7292",
"sha256:cfee9164954c186b191b91d4193989ca994703b2fff406f71cf454a2d3c7327e",
"sha256:e6347742ac8f35ded4a46ff835c60e68c22a536a8ae5c4422966d06946b6d4c6",
"sha256:f27d93f0139a3c056172ebb5d4f9056e770fdf0206c2f422ff2ebbad142e09ed",
"sha256:f57b76e46a58b63d1c6375017f4564a28f19a5ca912691fd2e4261b3414b618d"
],
"version": "==2.7"
},
"enum34": {
"hashes": [
"sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850",
"sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a",
"sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79",
"sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1"
],
"markers": "python_version < '3'",
"version": "==1.1.6"
},
"funcsigs": {
"hashes": [
"sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca",
"sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50"
],
"markers": "python_version < '3.0'",
"version": "==1.0.2"
},
"fxapom": {
"hashes": [
"sha256:56fdff0a0f0ea58831337e3a859971f98c59fd028ebc14baa8e37ae08a40efa0",
"sha256:5fb902afaaa9d9b82b5d1d54b9e19f1f4c9be128deb3b0e0ac82a9303f76000f"
],
"index": "pypi",
"version": "==1.10.2"
},
"hawkauthlib": {
"hashes": [
"sha256:935878d3a75832aa76f78ddee13491f1466cbd69a8e7e4248902763cf9953ba9",
"sha256:effd64a2572e3c0d9090b55ad2180b36ad50e7760bea225cb6ce2248f421510d"
],
"version": "==2.0.0"
},
"idna": {
"hashes": [
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
"sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"
],
"version": "==2.8"
},
"importlib-metadata": {
"hashes": [
"sha256:a9f185022cfa69e9ca5f7eabfd5a58b689894cb78a11e3c8c89398a8ccbb8e7f",
"sha256:df1403cd3aebeb2b1dcd3515ca062eecb5bd3ea7611f18cba81130c68707e879"
],
"version": "==0.17"
},
"ipaddress": {
"hashes": [
"sha256:64b28eec5e78e7510698f6d4da08800a5c575caa4a286c93d651c5d3ff7b6794",
"sha256:b146c751ea45cad6188dd6cf2d9b757f6f4f8d6ffb96a023e6f2e26eea02a72c"
],
"markers": "python_version < '3'",
"version": "==1.0.22"
},
"more-itertools": {
"hashes": [
"sha256:38a936c0a6d98a38bcc2d03fdaaedaba9f412879461dd2ceff8d37564d6522e4",
"sha256:c0a5785b1109a6bd7fac76d6837fd1feca158e54e521ccd2ae8bfe393cc9d4fc",
"sha256:fe7a7cae1ccb57d33952113ff4fa1bc5f879963600ed74918f1236e212ee50b9"
],
"markers": "python_version <= '2.7'",
"version": "==5.0.0"
},
"mozdevice": {
"hashes": [
"sha256:a7b582331448f28c9f44d5a113a152537e5666b0f5ce1052dc569ab516ec99a8",
"sha256:ec618e0c8000663de99af076f9d5ffdf91eaa81105b75b42a2dbcdb0248c2acb"
],
"version": "==3.0.1"
},
"mozdownload": {
"hashes": [
"sha256:1664b0bf48eab69fafa73d3fc4dc19f4c66dfc21045fab3ca76a29b3eeb31702",
"sha256:d861936c2efcc7620858a097907bfaba5d6d114867b6633e4301da9263627819"
],
"index": "pypi",
"version": "==1.26.0"
},
"mozfile": {
"hashes": [
"sha256:22a43f3bc320c3bda27e54b293c23a51660f4a00ec6959ab70ca6136d702f578",
"sha256:7355643fca705f43d9412d444fb59588fbbd25f0d1e7592b9482f84e3d23bc8e"
],
"version": "==2.0.0"
},
"mozinfo": {
"hashes": [
"sha256:299827c42d54ebb3c3547e299846abd15d22ff677cf6c1adbf54faeb9f024832",
"sha256:4525c26350fb85c26b38c5f853a19f47b17b49a74de363d285d54258972a4cbc"
],
"version": "==1.1.0"
},
"mozinstall": {
"hashes": [
"sha256:219ba7c51308433487b4f30a2615cb9b3ecd40a76b9faf41cf1b1b005bb5dda7"
],
"index": "pypi",
"version": "==2.0.0"
},
"mozlog": {
"hashes": [
"sha256:70ad145949539a3229ffb9b9785058366f2645371a2371cf2ad7c8f2582893ae",
"sha256:d294a71433cca3c873176a87df2ebe8bd632caf63aea4c7c47c1b69700c83dd5"
],
"version": "==4.1"
},
"mozprocess": {
"hashes": [
"sha256:6c984ab251bf0b1d6eef7e4fff87c2c2b60f20953e75eae566cb2d239f39806a",
"sha256:a0fd8367e663d3cac74ee46bffa789667bc8d52f242d81a14522205fa6650cb2"
],
"version": "==1.0.0"
},
"mozprofile": {
"hashes": [
"sha256:65cd29ab2925e40130935b144de80d23270a1bc66bf312b813942b1ba6eb7a76",
"sha256:94a0e14fcf357a90c42418edd414e837ff63bab876ccd51b9a7810d6f3c9fe2d"
],
"index": "pypi",
"version": "==2.2.0"
},
"mozrunner": {
"hashes": [
"sha256:3d3d48ceff333262d4f648314d5c7ac8e1998bf7ed08a7f96ac2a08558958c7b",
"sha256:c98c7a3cabbe7b63348f7c495ed40e75c3946c01896a1bec756e782b30a7b7d5"
],
"index": "pypi",
"version": "==7.4.0"
},
"mozterm": {
"hashes": [
"sha256:b1e91acec188de07c704dbb7b0100a7be5c1e06567b3beb67f6ea11d00a483a4",
"sha256:f5eafa25c23d391e2a2bb1dd45ee928fc9e3c811977a3856b5a5a0778011053c"
],
"version": "==1.0.0"
},
"mozversion": {
"hashes": [
"sha256:35911badaaf02715e56c6062379688724e7afeffc2d25be8567312d24054cdd4",
"sha256:65f41d7dc14002f83d8f147c82ca34f7213ad07065d250939daaeeb3787dc0fa"
],
"index": "pypi",
"version": "==2.1.0"
},
"packaging": {
"hashes": [
"sha256:0c98a5d0be38ed775798ece1b9727178c4469d9c3b4ada66e8e6b7849f8732af",
"sha256:9e1cbf8c12b1f1ce0bb5344b8d7ecf66a6f8a6e91bcb0c84593ed6d3ab5c4ab3"
],
"version": "==19.0"
},
"pathlib2": {
"hashes": [
"sha256:25199318e8cc3c25dcb45cbe084cc061051336d5a9ea2a12448d3d8cb748f742",
"sha256:5887121d7f7df3603bca2f710e7219f3eca0eb69e0b7cc6e0a022e155ac931a7"
],
"markers": "python_version < '3.6'",
"version": "==2.3.3"
},
"pluggy": {
"hashes": [
"sha256:0825a152ac059776623854c1543d65a4ad408eb3d33ee114dff91e57ec6ae6fc",
"sha256:b9817417e95936bf75d85d3f8767f7df6cdde751fc40aed3bb3074cbcb77757c"
],
"version": "==0.12.0"
},
"progressbar2": {
"hashes": [
"sha256:9ecb2d35edaa30ed86eb92fb0135eb19a6ef9b3657be4350cc3d0d3563e6af65",
"sha256:c086fc1f718839c0ec95caaeb7bd5a1d0268a8775960b8f9dee06f2a04c84628"
],
"version": "==3.42.0"
},
"py": {
"hashes": [
"sha256:64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa",
"sha256:dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53"
],
"version": "==1.8.0"
},
"pybrowserid": {
"hashes": [
"sha256:6c227669e87cc25796ae76f6a0ef65025528c8ad82d352679fa9a3e5663a71e3",
"sha256:8e237d6a2bc9ead849a4472a84d3e6a9309bec99cf8e10d36213710dda8df8ca"
],
"version": "==0.14.0"
},
"pycparser": {
"hashes": [
"sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3"
],
"version": "==2.19"
},
"pyfxa": {
"hashes": [
"sha256:616689486d8d63956aa40836cffafde6e7590cdeb200badabaaf3c17d5b26cce"
],
"version": "==0.7.1"
},
"pyparsing": {
"hashes": [
"sha256:1873c03321fc118f4e9746baf201ff990ceb915f433f23b395f5580d1840cb2a",
"sha256:9b6323ef4ab914af344ba97510e966d64ba91055d6b9afa6b30799340e89cc03"
],
"version": "==2.4.0"
},
"pypom": {
"hashes": [
"sha256:4bdd57fceb72d7e6a3645cf6c9322f490d9cfb5d777eac2c851a3b658b813939",
"sha256:6772ec99f0a21a5bdc8c092007a8c813ed18359e67ed70258bbb233df5e28829"
],
"version": "==2.2.0"
},
"pytest": {
"hashes": [
"sha256:1a8aa4fa958f8f451ac5441f3ac130d9fc86ea38780dd2715e6d5c5882700b24",
"sha256:b8bf138592384bd4e87338cb0f256bf5f615398a649d4bd83915f0e4047a5ca6"
],
"index": "pypi",
"version": "==4.5.0"
},
"pytest-fxa": {
"hashes": [
"sha256:778dfdb019f1e0af8744704fe5f7ac5c08fd5d45ff054023b0a18d5f99d737f1",
"sha256:b75967e74e9b2f3ffa5558421fdf61c7fff5948fc9d7e357e7147c682988ecc1"
],
"index": "pypi",
"version": "==1.4.0"
},
"pytest-html": {
"hashes": [
"sha256:648b7ba1d6035cc021d607e9d44f4dc06e916bdb04e09572dd04fb82eecab9ed",
"sha256:a7c65cdd9d5e4d09cef2f500ca801f80c1110204f24e5b84d019c6f919b15e9e"
],
"index": "pypi",
"version": "==1.20.0"
},
"pytest-metadata": {
"hashes": [
"sha256:2071a59285de40d7541fde1eb9f1ddea1c9db165882df82781367471238b66ba",
"sha256:c29a1fb470424926c63154c1b632c02585f2ba4282932058a71d35295ff8c96d"
],
"index": "pypi",
"version": "==1.8.0"
},
"python-utils": {
"hashes": [
"sha256:34aaf26b39b0b86628008f2ae0ac001b30e7986a8d303b61e1357dfcdad4f6d3",
"sha256:e25f840564554eaded56eaa395bca507b0b9e9f0ae5ecb13a8cb785305c56d25"
],
"version": "==2.3.0"
},
"redo": {
"hashes": [
"sha256:36784bf8ae766e14f9db0e377ccfa02835d648321d2007b6ae0bf4fd612c0f94",
"sha256:71161cb0e928d824092a5f16203939bbc0867ce4c4685db263cf22c3ae7634a8"
],
"version": "==2.0.3"
},
"requests": {
"hashes": [
"sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4",
"sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"
],
"index": "pypi",
"version": "==2.22.0"
},
"scandir": {
"hashes": [
"sha256:2586c94e907d99617887daed6c1d102b5ca28f1085f90446554abf1faf73123e",
"sha256:2ae41f43797ca0c11591c0c35f2f5875fa99f8797cb1a1fd440497ec0ae4b022",
"sha256:2b8e3888b11abb2217a32af0766bc06b65cc4a928d8727828ee68af5a967fa6f",
"sha256:2c712840c2e2ee8dfaf36034080108d30060d759c7b73a01a52251cc8989f11f",
"sha256:4d4631f6062e658e9007ab3149a9b914f3548cb38bfb021c64f39a025ce578ae",
"sha256:67f15b6f83e6507fdc6fca22fedf6ef8b334b399ca27c6b568cbfaa82a364173",
"sha256:7d2d7a06a252764061a020407b997dd036f7bd6a175a5ba2b345f0a357f0b3f4",
"sha256:8c5922863e44ffc00c5c693190648daa6d15e7c1207ed02d6f46a8dcc2869d32",
"sha256:92c85ac42f41ffdc35b6da57ed991575bdbe69db895507af88b9f499b701c188",
"sha256:b24086f2375c4a094a6b51e78b4cf7ca16c721dcee2eddd7aa6494b42d6d519d",
"sha256:cb925555f43060a1745d0a321cca94bcea927c50114b623d73179189a4e100ac"
],
"markers": "python_version < '3.5'",
"version": "==1.10.0"
},
"selenium": {
"hashes": [
"sha256:2d7131d7bc5a5b99a2d9b04aaf2612c411b03b8ca1b1ee8d3de5845a9be2cb3c",
"sha256:deaf32b60ad91a4611b98d8002757f29e6f2c2d5fcaf202e1c9ad06d6772300d"
],
"version": "==3.141.0"
},
"six": {
"hashes": [
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
"sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
],
"version": "==1.12.0"
},
"treeherder-client": {
"hashes": [
"sha256:4020809424384574277232023c78bcee436ec5474020b4430b4770f0ddd8bba3",
"sha256:db25150480d0501c79b72966899e5c901a5a625e12739389f6bee03273e1d002"
],
"version": "==5.0.0"
},
"urllib3": {
"hashes": [
"sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1",
"sha256:dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232"
],
"version": "==1.25.3"
},
"wcwidth": {
"hashes": [
"sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e",
"sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c"
],
"version": "==0.1.7"
},
"webob": {
"hashes": [
"sha256:05aaab7975e0ee8af2026325d656e5ce14a71f1883c52276181821d6d5bf7086",
"sha256:36db8203c67023d68c1b00208a7bf55e3b10de2aa317555740add29c619de12b"
],
"version": "==1.8.5"
},
"zipp": {
"hashes": [
"sha256:8c1019c6aad13642199fbe458275ad6a84907634cc9f0989877ccc4a2840139d",
"sha256:ca943a7e809cc12257001ccfb99e3563da9af99d52f261725e96dfe0f9275bc3"
],
"version": "==0.5.1"
},
"zope.component": {
"hashes": [
"sha256:6edfd626c3b593b72895a8cfcf79bff41f4619194ce996a85bce31ac02b94e55",
"sha256:984a06ba3def0b02b1117fa4c45b56e772e8c29c0340820fbf367e440a93a3a4"
],
"version": "==4.5"
},
"zope.deferredimport": {
"hashes": [
"sha256:2ddef5a7ecfff132a2dd796253366ecf9748a446e30f1a0b3a636aec9d9c05c5",
"sha256:4aae9cbacb2146cca58e62be0a914f0cec034d3b2d41135ea212ca8a96f4b5ec"
],
"version": "==4.3"
},
"zope.deprecation": {
"hashes": [
"sha256:0d453338f04bacf91bbfba545d8bcdf529aa829e67b705eac8c1a7fdce66e2df",
"sha256:f1480b74995958b24ce37b0ef04d3663d2683e5d6debc96726eff18acf4ea113"
],
"version": "==4.4.0"
},
"zope.event": {
"hashes": [
"sha256:69c27debad9bdacd9ce9b735dad382142281ac770c4a432b533d6d65c4614bcf",
"sha256:d8e97d165fd5a0997b45f5303ae11ea3338becfe68c401dd88ffd2113fe5cae7"
],
"version": "==4.4"
},
"zope.hookable": {
"hashes": [
"sha256:22886e421234e7e8cedc21202e1d0ab59960e40a47dd7240e9659a2d82c51370",
"sha256:39912f446e45b4e1f1951b5ffa2d5c8b074d25727ec51855ae9eab5408f105ab",
"sha256:3adb7ea0871dbc56b78f62c4f5c024851fc74299f4f2a95f913025b076cde220",
"sha256:3d7c4b96341c02553d8b8d71065a9366ef67e6c6feca714f269894646bb8268b",
"sha256:4e826a11a529ed0464ffcecf34b0b7bd1b4928dd5848c5c61bedd7833e8f4801",
"sha256:700d68cc30728de1c4c62088a981c6daeaefdf20a0d81995d2c0b7f442c5f88c",
"sha256:77c82a430cedfbf508d1aa406b2f437363c24fa90c73f577ead0fb5295749b83",
"sha256:c1df3929a3666fc5a0c80d60a0c1e6f6ef97c7f6ed2f1b7cf49f3e6f3d4dde15",
"sha256:dba8b2dd2cd41cb5f37bfa3f3d82721b8ae10e492944e48ddd90a439227f2893",
"sha256:f492540305b15b5591bd7195d61f28946bb071de071cee5d68b6b8414da90fd2"
],
"version": "==4.2.0"
},
"zope.interface": {
"hashes": [
"sha256:086707e0f413ff8800d9c4bc26e174f7ee4c9c8b0302fbad68d083071822316c",
"sha256:1157b1ec2a1f5bf45668421e3955c60c610e31913cc695b407a574efdbae1f7b",
"sha256:11ebddf765bff3bbe8dbce10c86884d87f90ed66ee410a7e6c392086e2c63d02",
"sha256:14b242d53f6f35c2d07aa2c0e13ccb710392bcd203e1b82a1828d216f6f6b11f",
"sha256:1b3d0dcabc7c90b470e59e38a9acaa361be43b3a6ea644c0063951964717f0e5",
"sha256:20a12ab46a7e72b89ce0671e7d7a6c3c1ca2c2766ac98112f78c5bddaa6e4375",
"sha256:298f82c0ab1b182bd1f34f347ea97dde0fffb9ecf850ecf7f8904b8442a07487",
"sha256:2f6175722da6f23dbfc76c26c241b67b020e1e83ec7fe93c9e5d3dd18667ada2",
"sha256:3b877de633a0f6d81b600624ff9137312d8b1d0f517064dfc39999352ab659f0",
"sha256:4265681e77f5ac5bac0905812b828c9fe1ce80c6f3e3f8574acfb5643aeabc5b",
"sha256:550695c4e7313555549aa1cdb978dc9413d61307531f123558e438871a883d63",
"sha256:5f4d42baed3a14c290a078e2696c5f565501abde1b2f3f1a1c0a94fbf6fbcc39",
"sha256:62dd71dbed8cc6a18379700701d959307823b3b2451bdc018594c48956ace745",
"sha256:7040547e5b882349c0a2cc9b50674b1745db551f330746af434aad4f09fba2cc",
"sha256:7e099fde2cce8b29434684f82977db4e24f0efa8b0508179fce1602d103296a2",
"sha256:7e5c9a5012b2b33e87980cee7d1c82412b2ebabcb5862d53413ba1a2cfde23aa",
"sha256:81295629128f929e73be4ccfdd943a0906e5fe3cdb0d43ff1e5144d16fbb52b1",
"sha256:95cc574b0b83b85be9917d37cd2fad0ce5a0d21b024e1a5804d044aabea636fc",
"sha256:968d5c5702da15c5bf8e4a6e4b67a4d92164e334e9c0b6acf080106678230b98",
"sha256:9e998ba87df77a85c7bed53240a7257afe51a07ee6bc3445a0bf841886da0b97",
"sha256:a0c39e2535a7e9c195af956610dba5a1073071d2d85e9d2e5d789463f63e52ab",
"sha256:a15e75d284178afe529a536b0e8b28b7e107ef39626a7809b4ee64ff3abc9127",
"sha256:a6a6ff82f5f9b9702478035d8f6fb6903885653bff7ec3a1e011edc9b1a7168d",
"sha256:b639f72b95389620c1f881d94739c614d385406ab1d6926a9ffe1c8abbea23fe",
"sha256:bad44274b151d46619a7567010f7cde23a908c6faa84b97598fd2f474a0c6891",
"sha256:bbcef00d09a30948756c5968863316c949d9cedbc7aabac5e8f0ffbdb632e5f1",
"sha256:d788a3999014ddf416f2dc454efa4a5dbeda657c6aba031cf363741273804c6b",
"sha256:eed88ae03e1ef3a75a0e96a55a99d7937ed03e53d0cffc2451c208db445a2966",
"sha256:f99451f3a579e73b5dd58b1b08d1179791d49084371d9a47baad3b22417f0317"
],
"version": "==4.6.0"
},
"zope.proxy": {
"hashes": [
"sha256:0cbcfcafaa3b5fde7ba7a7b9a2b5f09af25c9b90087ad65f9e61359fed0ca63b",
"sha256:3de631dd5054a3a20b9ebff0e375f39c0565f1fb9131200d589a6a8f379214cd",
"sha256:5429134d04d42262f4dac25f6dea907f6334e9a751ffc62cb1d40226fb52bdeb",
"sha256:563c2454b2d0f23bca54d2e0e4d781149b7b06cb5df67e253ca3620f37202dd2",
"sha256:5bcf773345016b1461bb07f70c635b9386e5eaaa08e37d3939dcdf12d3fdbec5",
"sha256:8d84b7aef38c693874e2f2084514522bf73fd720fde0ce2a9352a51315ffa475",
"sha256:90de9473c05819b36816b6cb957097f809691836ed3142648bf62da84b4502fe",
"sha256:dd592a69fe872445542a6e1acbefb8e28cbe6b4007b8f5146da917e49b155cc3",
"sha256:e7399ab865399fce322f9cefc6f2f3e4099d087ba581888a9fea1bbe1db42a08",
"sha256:e7d1c280d86d72735a420610df592aac72332194e531a8beff43a592c3a1b8eb",
"sha256:e90243fee902adb0c39eceb3c69995c0f2004bc3fdb482fbf629efc656d124ed"
],
"version": "==4.3.1"
}
},
"develop": {}
}

173
app/src/androidTest/java/org/mozilla/fenix/syncintegration/SyncIntegrationTest.kt

@ -0,0 +1,173 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix.syncintegration
import android.os.SystemClock.sleep
import android.widget.Button
import android.widget.EditText
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.action.ViewActions.replaceText
import androidx.test.espresso.action.ViewActions.pressImeActionButton
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import org.junit.Rule
import org.junit.Test
import org.mozilla.fenix.helpers.HomeActivityTestRule
import org.mozilla.fenix.ui.robots.homeScreen
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiSelector
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import org.hamcrest.Matchers.allOf
import org.mozilla.fenix.R
@Suppress("RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS")
class SyncIntegrationTest {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
@get:Rule
val activityTestRule = HomeActivityTestRule()
// History item Desktop -> Fenix
@Test
fun checkHistoryFromDesktopTest() {
signInFxSync()
tapReturnToPreviousApp()
homeScreen {
}.openThreeDotMenu {}
libraryButton()
historyButton()
historyAfterSyncIsShown()
}
/* These tests will be running in the future
// once the test above runs successfully and
// the environment is stable
// Bookmark item Desktop -> Fenix
@Test
fun checkBookmarkFromDesktopTest() {
signInFxSync()
tapReturnToPreviousApp()
sleep(5000)
homeScreen {
}.openThreeDotMenu {}
libraryButton()
bookmarkButton()
bookmarkAfterSyncIsShown()
}
// History item Fenix -> Desktop
@Test
fun checkBookmarkFromDeviceTest() {
tapInToolBar()
typeInToolBar()
seeBookmark()
mDevice.pressBack()
signInFxSync()
}
// Bookmark item Fenix -> Desktop
@Test
fun checkHistoryFromDeviceTest() {
tapInToolBar()
typeInToolBar()
sleep(3000)
mDevice.pressBack()
signInFxSync()
}
*/
// Useful functions for the tests
fun typeEmail() {
val emailInput = mDevice.findObject(UiSelector()
.instance(0)
.className(EditText::class.java))
emailInput.waitForExists(1000)
val emailAddress = javaClass.classLoader.getResource("email.txt").readText()
emailInput.setText(emailAddress)
}
fun tapOnContinueButton() {
val continueButton = mDevice.findObject(By.res("submit-btn"))
continueButton.clickAndWait(Until.newWindow(), 50000)
}
fun typePassowrd() {
val passwordInput = mDevice.findObject(UiSelector()
.instance(0)
.className(EditText::class.java))
val passwordValue = javaClass.classLoader.getResource("password.txt").readText()
passwordInput.setText(passwordValue)
}
fun tapOnSygIn() {
mDevice.pressEnter()
mDevice.wait(Until.findObjects(By.text("Sign in")), 3000)
val signInButton = mDevice.findObject(UiSelector()
.instance(0)
.className(Button::class.java))
signInButton.waitForExists(10000)
signInButton.click()
}
fun typeInToolBar() {
awesomeBar().perform(replaceText("example.com"),
pressImeActionButton())
}
fun historyAfterSyncIsShown() {
val historyEntry = mDevice.findObject(By.text("http://www.example.com/"))
historyEntry.isEnabled()
}
fun bookmarkAfterSyncIsShown() {
val bookmarkyEntry = mDevice.findObject(By.text("Example Domain"))
bookmarkyEntry.isEnabled()
}
fun seeBookmark() {
mDevice.wait(Until.findObjects(By.text("Bookmark")), 3000)
val bookmarkButton = mDevice.findObject(By.text("Bookmark"))
bookmarkButton.click()
}
fun tapReturnToPreviousApp() {
mDevice.wait(Until.findObjects(By.text("Connected")), 2000)
val settingsLabel = mDevice.wait(Until.findObject(By.text("Settings")), 20000)
settingsLabel.isClickable()
mDevice.pressBack()
}
fun signInFxSync() {
homeScreen {
}.openThreeDotMenu {
verifySettingsButton()
}.openSettings {}
settingsAccount()
useEmailInsteadButton()
typeEmail()
tapOnContinueButton()
typePassowrd()
sleep(3000)
tapOnSygIn()
}
}
fun settingsAccount() = onView(allOf(withText("Turn on Sync"))).perform(click())
fun tapInToolBar() = onView(withId(org.mozilla.fenix.R.id.toolbar_wrapper))
fun awesomeBar() = onView(withId(org.mozilla.fenix.R.id.mozac_browser_toolbar_edit_url_view))
fun libraryButton() = onView(allOf(withText(R.string.browser_menu_your_library))).perform(click())
fun historyButton() = onView(allOf(withText("History"))).perform(click())
fun bookmarkButton() = onView(allOf(withText("Bookmarks"))).perform(click())
fun useEmailInsteadButton() = onView(withId(R.id.signInEmailButton)).perform(click())

0
app/src/androidTest/java/org/mozilla/fenix/syncintegration/__init__.py

16
app/src/androidTest/java/org/mozilla/fenix/syncintegration/adbrun.py

@ -0,0 +1,16 @@
import logging
import subprocess
import os
logging.getLogger(__name__).addHandler(logging.NullHandler())
class ADBrun(object):
binary = 'adbrun'
logger = logging.getLogger()
def launch(self):
# First close sim if any then launch
os.system('~/Library/Android/sdk/platform-tools/adb devices | grep emulator | cut -f1 | while read line; do ~/Library/Android/sdk/platform-tools/adb -s $line emu kill; done')
# Then launch sim
os.system("sh launchSimScript.sh")

166
app/src/androidTest/java/org/mozilla/fenix/syncintegration/conftest.py

@ -0,0 +1,166 @@
import io
import json
import os
import time
from mozdownload import DirectScraper, FactoryScraper
from mozprofile import Profile
import mozinstall
import mozversion
import pytest
import requests
from tps import TPS
from gradlewbuild import GradlewBuild
here = os.path.dirname(__file__)
@pytest.fixture(scope='session')
def firefox(pytestconfig, tmpdir_factory):
binary = os.getenv('MOZREGRESSION_BINARY',
pytestconfig.getoption('firefox'))
if binary is None:
cache_dir = str(pytestconfig.cache.makedir('firefox'))
scraper = FactoryScraper('daily', destination=cache_dir)
build_path = scraper.download()
install_path = str(tmpdir_factory.mktemp('firefox'))
install_dir = mozinstall.install(src=build_path, dest=install_path)
binary = mozinstall.get_binary(install_dir, 'firefox')
version = mozversion.get_version(binary)
if hasattr(pytestconfig, '_metadata'):
pytestconfig._metadata.update(version)
return binary
@pytest.fixture
def firefox_log(pytestconfig, tmpdir):
firefox_log = str(tmpdir.join('firefox.log'))
pytestconfig._firefox_log = firefox_log
yield firefox_log
@pytest.fixture(scope='session')
def tps_addon(pytestconfig, tmpdir_factory):
path = pytestconfig.getoption('tps')
if path is not None:
return path
task_url = 'https://index.taskcluster.net/v1/task/' \
'gecko.v2.mozilla-central.latest.firefox.addons.tps'
task_id = requests.get(task_url).json().get('taskId')
cache_dir = str(pytestconfig.cache.makedir('tps-{}'.format(task_id)))
addon_url = 'https://queue.taskcluster.net/v1/task/' \
'{}/artifacts/public/tps.xpi'.format(task_id)
scraper = DirectScraper(addon_url, destination=cache_dir)
return scraper.download()
@pytest.fixture
def tps_config(fxa_account, monkeypatch):
monkeypatch.setenv('FXA_EMAIL', fxa_account.email)
monkeypatch.setenv('FXA_PASSWORD', fxa_account.password)
f= open("/Users/synctesting/.jenkins/workspace/fenix@2/app/src/androidTest/resources/email.txt","w+")
f.write(fxa_account.email)
f= open("/Users/synctesting/.jenkins/workspace/fenix@2/app/src/androidTest/resources/password.txt","w+")
f.write(fxa_account.password)
yield {'fx_account': {
'username': fxa_account.email,
'password': fxa_account.password}
}
@pytest.fixture
def tps_log(pytestconfig, tmpdir):
tps_log = str(tmpdir.join('tps.log'))
pytestconfig._tps_log = tps_log
yield tps_log
@pytest.fixture
def tps_profile(pytestconfig, tps_addon, tps_config, tps_log, fxa_urls):
preferences = {
'app.update.enabled': False,
'browser.dom.window.dump.enabled': True,
'browser.onboarding.enabled': False,
'browser.sessionstore.resume_from_crash': False,
'browser.shell.checkDefaultBrowser': False,
'browser.startup.homepage_override.mstone': 'ignore',
'browser.startup.page': 0,
'browser.tabs.warnOnClose': False,
'browser.warnOnQuit': False,
'datareporting.policy.dataSubmissionEnabled': False,
# 'devtools.chrome.enabled': True,
# 'devtools.debugger.remote-enabled': True,
'engine.bookmarks.repair.enabled': False,
'extensions.autoDisableScopes': 10,
'extensions.legacy.enabled': True,
'extensions.update.enabled': False,
'extensions.update.notifyUser': False,
# While this line is commented prod is launched instead of stage
'identity.fxaccounts.autoconfig.uri': fxa_urls['content'],
'testing.tps.skipPingValidation': True,
'services.sync.firstSync': 'notReady',
'services.sync.lastversion': '1.0',
'services.sync.log.appender.console': 'Trace',
'services.sync.log.appender.dump': 'Trace',
'services.sync.log.appender.file.level': 'Trace',
'services.sync.log.appender.file.logOnSuccess': True,
'services.sync.log.logger': 'Trace',
'services.sync.log.logger.engine': 'Trace',
'services.sync.testing.tps': True,
'testing.tps.logFile': tps_log,
'toolkit.startup.max_resumed_crashes': -1,
'tps.config': json.dumps(tps_config),
'tps.seconds_since_epoch': int(time.time()),
'xpinstall.signatures.required': False
}
profile = Profile(addons=[tps_addon], preferences=preferences)
pytestconfig._profile = profile.profile
yield profile
@pytest.fixture
def tps(firefox, firefox_log, monkeypatch, pytestconfig, tps_log, tps_profile):
yield TPS(firefox, firefox_log, tps_log, tps_profile)
@pytest.fixture
def gradlewbuild_log(pytestconfig, tmpdir):
gradlewbuild_log = str(tmpdir.join('gradlewbuild.log'))
pytestconfig._gradlewbuild_log = gradlewbuild_log
yield gradlewbuild_log
@pytest.fixture
def gradlewbuild(fxa_account, monkeypatch, gradlewbuild_log):
monkeypatch.setenv('FXA_EMAIL', fxa_account.email)
monkeypatch.setenv('FXA_PASSWORD', fxa_account.password)
yield GradlewBuild(gradlewbuild_log)
def pytest_addoption(parser):
parser.addoption('--firefox', help='path to firefox binary (defaults to '
'downloading latest nightly build)')
parser.addoption('--tps', help='path to tps add-on (defaults to '
'downloading latest nightly build)')
@pytest.mark.hookwrapper
def pytest_runtest_makereport(item, call):
outcome = yield
report = outcome.get_result()
extra = getattr(report, 'extra', [])
pytest_html = item.config.pluginmanager.getplugin('html')
profile = getattr(item.config, '_profile', None)
if profile is not None and os.path.exists(profile):
# add sync logs to HTML report
for root, _, files in os.walk(os.path.join(profile, 'weave', 'logs')):
for f in files:
path = os.path.join(root, f)
if pytest_html is not None:
with io.open(path, 'r', encoding='utf8') as f:
extra.append(pytest_html.extras.text(f.read(), 'Sync'))
report.sections.append(('Sync', 'Log: {}'.format(path)))
for log in ('Firefox', 'TPS', 'GradlewBuild'):
attr = '_{}_log'.format(log.lower())
path = getattr(item.config, attr, None)
if path is not None and os.path.exists(path):
if pytest_html is not None:
with io.open(path, 'r', encoding='utf8') as f:
extra.append(pytest_html.extras.text(f.read(), log))
report.sections.append((log, 'Log: {}'.format(path)))
report.extra = extra

42
app/src/androidTest/java/org/mozilla/fenix/syncintegration/gradlewbuild.py

@ -0,0 +1,42 @@
import logging
import os
import subprocess
from adbrun import ADBrun
here = os.path.dirname(__file__)
logging.getLogger(__name__).addHandler(logging.NullHandler())
class GradlewBuild(object):
binary = './gradlew'
logger = logging.getLogger()
adbrun = ADBrun()
def __init__(self, log):
self.log = log
def test(self, identifier):
self.adbrun.launch()
#self.xcrun.launch()
# Change path accordingly to go to root folder to run gradlew
os.chdir('../../../../../../../..')
args = './gradlew ' + 'app:connectedGeckoNightlyDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=org.mozilla.fenix.syncintegration.SyncIntegrationTest#{}'.format(identifier)
# os.system(args)
# Whit this the logs are shown when there is a failure
# they are saved in ~/fenix/app/build/reports/androidTests/connected/flavors/X86/index.html
# output = subprocess.check_output(args, shell=True)
# This part below does not work yet...
self.logger.info('Running: {}'.format(' '.join(args)))
try:
out = subprocess.check_output(
args, shell=True)
except subprocess.CalledProcessError as e:
out = e.output
raise
finally:
with open(self.log, 'w') as f:
f.writelines(out)

26
app/src/androidTest/java/org/mozilla/fenix/syncintegration/launchSimScript.sh

@ -0,0 +1,26 @@
#!/usr/bin/env bash
set -e
echo "Waiting emulator is ready..."
~/Library/Android/sdk/emulator/emulator -avd Pixel_API_28 -wipe-data -no-boot-anim -screen no-touch &
bootanim=""
failcounter=0
timeout_in_sec=360
until [[ "$bootanim" =~ "stopped" ]]; do
bootanim=`~/Library/Android/sdk/platform-tools/adb -e shell getprop init.svc.bootanim 2>&1 &`
if [[ "$bootanim" =~ "device not found" || "$bootanim" =~ "device offline"
|| "$bootanim" =~ "running" ]]; then
let "failcounter += 1"
echo "Waiting for emulator to start"
if [[ $failcounter -gt timeout_in_sec ]]; then
echo "Timeout ($timeout_in_sec seconds) reached; failed to start emulator"
exit 1
fi
fi
sleep 1
done
echo "Emulator is ready"
sleep 10

4
app/src/androidTest/java/org/mozilla/fenix/syncintegration/pytest.ini

@ -0,0 +1,4 @@
[pytest]
addopts = --verbose --html=results/index.html
log_cli = true
log_cli_level = info

25
app/src/androidTest/java/org/mozilla/fenix/syncintegration/test_bookmark.js

@ -0,0 +1,25 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*
* The list of phases mapped to their corresponding profiles. The object
* here must be in strict JSON format, as it will get parsed by the Python
* testrunner (no single quotes, extra comma's, etc).
*/
EnableEngines(["bookmarks"]);
var phases = { "phase1": "profile1" };
// expected bookmark state
var bookmarksExpected = {
"mobile": [{
uri: "http://www.example.com/",
title: "Example Domain"}]
};
// sync and verify bookmarks
Phase("phase1", [
[Sync],
[Bookmarks.verify, bookmarksExpected],
]);

33
app/src/androidTest/java/org/mozilla/fenix/syncintegration/test_history.js

@ -0,0 +1,33 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*
* The list of phases mapped to their corresponding profiles. The object
* here must be in strict JSON format, as it will get parsed by the Python
* testrunner (no single quotes, extra comma's, etc).
*/
EnableEngines(["history"]);
var phases = { "phase1": "profile1" };
// expected history state
var historyCreated = [
{ uri: "http://www.example.com/",
visits: [
{ type: 1 ,
date: 0
},
{ type: 2,
date: -1
}
]
}
];
// sync and verify history
Phase("phase1", [
[Sync],
[History.add, historyCreated],
[Sync]
]);

14
app/src/androidTest/java/org/mozilla/fenix/syncintegration/test_integration.py

@ -0,0 +1,14 @@
import os
import sys
def test_sync_history_from_desktop(tps, gradlewbuild):
# Running tests
tps.run('test_history.js')
gradlewbuild.test('checkHistoryFromDesktopTest')
'''
# For the future, this way we change the test to run....
def test_sync_bookmark_from_device(tps, xcodebuild):
gradlewbuild.test('checkBookmarkFromDeviceTest')
tps.run('app/src/androidTest/java/org/mozilla/fenix/ui/SyncIntegrationTests/test_bookmark.js')
'''

52
app/src/androidTest/java/org/mozilla/fenix/syncintegration/tps.py

@ -0,0 +1,52 @@
import logging
import os
from mozrunner import FirefoxRunner
logging.getLogger(__name__).addHandler(logging.NullHandler())
TIMEOUT = 60
class TPS(object):
logger = logging.getLogger()
def __init__(self, firefox, firefox_log, tps_log, profile):
self.firefox = firefox
self.firefox_log = open(firefox_log, 'w')
self.tps_log = tps_log
self.profile = profile
def _log(self, line):
self.firefox_log.write(line + '\n')
def run(self, test, phase='phase1', ignore_unused_engines=True):
self.profile.set_preferences({
'testing.tps.testFile': os.path.abspath(test),
'testing.tps.testPhase': phase,
'testing.tps.ignoreUnusedEngines': ignore_unused_engines,
})
args = ['-marionette']
process_args = {'processOutputLine': [self._log]}
self.logger.info('Running: {} {}'.format(self.firefox, ' '.join(args)))
self.logger.info('Using profile at: {}'.format(self.profile.profile))
runner = FirefoxRunner(
binary=self.firefox,
cmdargs=args,
profile=self.profile,
process_args=process_args)
runner.start(timeout=TIMEOUT)
runner.wait(timeout=TIMEOUT)
self.firefox_log.close()
with open(self.tps_log) as f:
for line in f.readlines():
if 'CROSSWEAVE ERROR: ' in line:
raise TPSError(line.partition('CROSSWEAVE ERROR: ')[-1])
with open(self.tps_log) as f:
assert 'test phase {}: PASS'.format(phase) in f.read()
class TPSError(Exception):
pass

1
app/src/androidTest/resources/email.txt

@ -0,0 +1 @@
pytest-28f90ad8b4@restmail.net

1
app/src/androidTest/resources/password.txt

@ -0,0 +1 @@
yArgpjhB

38
app/src/main/java/org/mozilla/fenix/components/BackgroundServices.kt

@ -52,34 +52,24 @@ class BackgroundServices(
historyStorage: PlacesHistoryStorage,
bookmarkStorage: PlacesBookmarksStorage
) {
companion object {
const val CLIENT_ID = "a2270f727f45f648"
fun redirectUrl(context: Context) = if (context.isInExperiment(Experiments.asFeatureWebChannelsDisabled)) {
"https://accounts.firefox.com/oauth/success/$CLIENT_ID"
} else {
"urn:ietf:wg:oauth:2.0:oob:oauth-redirect-webchannel"
}
}
// // A malformed string is causing crashes.
// This will be removed when the string is fixed. See #5552
fun defaultDeviceName(context: Context): String = try {
context.getString(
R.string.default_device_name,
context.getString(R.string.app_name),
Build.MANUFACTURER,
Build.MODEL
)
} catch (ex: FormatFlagsConversionMismatchException) {
"%s on %s %s".format(
context.getString(R.string.app_name),
Build.MANUFACTURER,
Build.MODEL
)
}
context.getString(
R.string.default_device_name,
context.getString(R.string.app_name),
Build.MANUFACTURER,
Build.MODEL
)
} catch (ex: FormatFlagsConversionMismatchException) {
"%s on %s %s".format(
context.getString(R.string.app_name),
Build.MANUFACTURER,
Build.MODEL
)
}
private val serverConfig = ServerConfig.release(CLIENT_ID, redirectUrl(context))
private val serverConfig = FxaServer.config(context)
private val deviceConfig = DeviceConfig(
name = defaultDeviceName(context),
type = DeviceType.MOBILE,

21
app/src/main/java/org/mozilla/fenix/components/FxaServer.kt

@ -0,0 +1,21 @@
package org.mozilla.fenix.components
import android.content.Context
import mozilla.components.service.fxa.ServerConfig
import org.mozilla.fenix.Experiments
import org.mozilla.fenix.isInExperiment
object FxaServer {
const val CLIENT_ID = "a2270f727f45f648"
const val REDIRECT_URL = "https://accounts.firefox.com/oauth/success/$CLIENT_ID"
fun redirectUrl(context: Context) = if (context.isInExperiment(Experiments.asFeatureWebChannelsDisabled)) {
REDIRECT_URL
} else {
"urn:ietf:wg:oauth:2.0:oob:oauth-redirect-webchannel"
}
fun config(context: Context): ServerConfig {
return ServerConfig.release(CLIENT_ID, redirectUrl(context))
}
}

4
app/src/main/java/org/mozilla/fenix/components/Services.kt

@ -28,10 +28,12 @@ class Services(
private val context: Context,
private val accountManager: FxaAccountManager
) {
val fxaRedirectUrl = FxaServer.redirectUrl(context)
val accountsAuthFeature by lazy {
FirefoxAccountsAuthFeature(
accountManager,
redirectUrl = BackgroundServices.redirectUrl(context)
redirectUrl = fxaRedirectUrl
) { context, authUrl ->
CoroutineScope(Dispatchers.Main).launch {
val intent = SupportUtils.createAuthCustomTabIntent(context, authUrl)

2
app/src/main/res/values/preference_keys.xml

@ -105,6 +105,6 @@
<!-- Quick Action Sheet -->
<string name="pref_key_bounce_quick_action" translatable="false">pref_key_bounce_quick_action</string>
<string name="pref_key_reader_mode_notification" translatable="false">pref_key_reader_mode_notification</string>
<string name="pref_key_adjust_campaign" translatable="false">pref_key_adjust_campaign</string>
<string name="pref_key_testing_stage" translatable="false">pref_key_testing_stage</string>
</resources>

26
docs/syncIntegrationTests.md

@ -0,0 +1,26 @@
### Sync Integration Tests
The aim of these tests is to check that the synchronization is working between Fenix and Desktop. The intention is to add tests for History, Bookmarks, Tabs and Logins.
At this moment only tests for History and Bookmarks are defined.
### Steps to Run
To run these tests you will need Python 2 and pipenv installed. Once you have these, make sure you're in the `syncintegration` directory and run the following:
`$ pipenv install`
`$ pipenv run pytest`
When a test is launched a stage account is created. That will be used both in Desktop and Fenix to be sure that what is saved in one place is shown in the other.
The process for example for History item Desktop -> Fenix, would be:
- Desktop is launched, user signed in and history item created.
- Android sim is launched (Pixel 3 API28), Fenix app starts and same user is signed in, then we go to History list and verify that the item is there.
### Results
Due to the set up necessary these tests do not run as part of the regular CI, via Taskcluster.
The idea is to have them running on Jenkins periodically (TBD how often).
Once they finish there is a slack notificattion received informing about the result (so far that is configured for #firefox-ios-alerts)
A html file is generated with all the info, for each step to make it easy to debug in case of failure.
## Notes
More detailed info can be found [`here`](https://docs.google.com/document/d/1dhxlbGQBA6aJi2Xz-CsJZuGJPRReoL7nfm9cYu4HcZI/edit?usp=sharing)
Loading…
Cancel
Save