OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 package org.chromium.content.browser.installedapp; |
| 6 |
| 7 import android.content.pm.ApplicationInfo; |
| 8 import android.content.pm.PackageManager; |
| 9 import android.content.pm.PackageManager.NameNotFoundException; |
| 10 import android.content.res.AssetManager; |
| 11 import android.content.res.Resources; |
| 12 import android.os.Bundle; |
| 13 |
| 14 import org.junit.Assert; |
| 15 import org.junit.Before; |
| 16 import org.junit.Test; |
| 17 import org.junit.runner.RunWith; |
| 18 |
| 19 import org.robolectric.RuntimeEnvironment; |
| 20 import org.robolectric.annotation.Config; |
| 21 import org.robolectric.res.builder.DefaultPackageManager; |
| 22 |
| 23 import org.chromium.base.test.util.Feature; |
| 24 import org.chromium.installedapp.mojom.InstalledAppProvider; |
| 25 import org.chromium.installedapp.mojom.RelatedApplication; |
| 26 import org.chromium.testing.local.LocalRobolectricTestRunner; |
| 27 |
| 28 import java.net.URI; |
| 29 import java.net.URISyntaxException; |
| 30 import java.util.HashMap; |
| 31 |
| 32 /** |
| 33 * Ensure that the InstalledAppProvider returns the correct apps. |
| 34 */ |
| 35 @RunWith(LocalRobolectricTestRunner.class) |
| 36 @Config(manifest = Config.NONE) |
| 37 public class InstalledAppProviderTest { |
| 38 private static final String ASSET_STATEMENTS_KEY = |
| 39 InstalledAppProviderImpl.ASSET_STATEMENTS_KEY; |
| 40 private static final String RELATION_HANDLE_ALL_URLS = |
| 41 "delegate_permission/common.handle_all_urls"; |
| 42 private static final String NAMESPACE_WEB = |
| 43 InstalledAppProviderImpl.ASSET_STATEMENT_NAMESPACE_WEB; |
| 44 private static final String PLATFORM_ANDROID = |
| 45 InstalledAppProviderImpl.RELATED_APP_PLATFORM_ANDROID; |
| 46 private static final String PLATFORM_OTHER = "itunes"; |
| 47 // Note: Android package name and origin deliberately unrelated (there is no
requirement that |
| 48 // they be the same). |
| 49 private static final String PACKAGE_NAME_1 = "com.app1.package"; |
| 50 private static final String PACKAGE_NAME_2 = "com.app2.package"; |
| 51 private static final String PACKAGE_NAME_3 = "com.app3.package"; |
| 52 private static final String URL_UNRELATED = "https://appstore.example.com/ap
p1"; |
| 53 private static final String ORIGIN = "https://example.com:8000"; |
| 54 private static final String URL_ON_ORIGIN = |
| 55 "https://example.com:8000/path/to/page.html?key=value#fragment"; |
| 56 private static final String ORIGIN_SYNTAX_ERROR = "https:{"; |
| 57 private static final String ORIGIN_MISSING_SCHEME = "path/only"; |
| 58 private static final String ORIGIN_MISSING_HOST = "file:///path/piece"; |
| 59 private static final String ORIGIN_MISSING_PORT = "http://example.com"; |
| 60 private static final String ORIGIN_DIFFERENT_SCHEME = "http://example.com:80
00"; |
| 61 private static final String ORIGIN_DIFFERENT_HOST = "https://example.org:800
0"; |
| 62 private static final String ORIGIN_DIFFERENT_PORT = "https://example.com:800
1"; |
| 63 |
| 64 private FakePackageManager mPackageManager; |
| 65 private FakeFrameUrlDelegate mFrameUrlDelegate; |
| 66 private InstalledAppProviderImpl mInstalledAppProvider; |
| 67 |
| 68 /** |
| 69 * FakePackageManager allows for the "installation" of Android package names
and setting up |
| 70 * Resources for installed packages. |
| 71 */ |
| 72 private static class FakePackageManager extends DefaultPackageManager { |
| 73 private final HashMap<String, Bundle> mMetaDataMap; |
| 74 private final HashMap<String, Resources> mResourceMap; |
| 75 |
| 76 public FakePackageManager() { |
| 77 super(); |
| 78 mMetaDataMap = new HashMap<String, Bundle>(); |
| 79 mResourceMap = new HashMap<String, Resources>(); |
| 80 } |
| 81 |
| 82 @Override |
| 83 public ApplicationInfo getApplicationInfo(String packageName, int flags) |
| 84 throws NameNotFoundException { |
| 85 if (packageName == null) throw new NullPointerException(); |
| 86 |
| 87 Bundle metaData = mMetaDataMap.get(packageName); |
| 88 if (metaData == null) throw new NameNotFoundException(packageName); |
| 89 |
| 90 // Create an application with this metadata (but only if |flags| all
ows). Doing it this |
| 91 // way (rather than simply storing the ApplicationInfo in a map) ens
ures that the |
| 92 // |flags| is set correctly. |
| 93 ApplicationInfo appInfo = new ApplicationInfo(); |
| 94 appInfo.packageName = packageName; |
| 95 if ((flags & PackageManager.GET_META_DATA) != 0) { |
| 96 appInfo.metaData = metaData; |
| 97 } |
| 98 return appInfo; |
| 99 } |
| 100 |
| 101 @Override |
| 102 public Resources getResourcesForApplication(ApplicationInfo app) |
| 103 throws NameNotFoundException { |
| 104 if (app == null) throw new NullPointerException(); |
| 105 |
| 106 Resources result = mResourceMap.get(app.packageName); |
| 107 if (result == null) throw new NameNotFoundException(app.packageName)
; |
| 108 |
| 109 return result; |
| 110 } |
| 111 |
| 112 public void setMetaDataAndResourcesForTest( |
| 113 String packageName, Bundle metaData, Resources resources) { |
| 114 mMetaDataMap.put(packageName, metaData); |
| 115 mResourceMap.put(packageName, resources); |
| 116 } |
| 117 } |
| 118 |
| 119 /** |
| 120 * Fakes the Resources object, allowing lookup of a single String value. |
| 121 * |
| 122 * Note: The real Resources object defines a mapping to many values. This fa
ke object only |
| 123 * allows a single value in the mapping, and it must be a String (which is a
ll that is required |
| 124 * for these tests). |
| 125 */ |
| 126 private static class FakeResources extends Resources { |
| 127 private final int mId; |
| 128 private final String mValue; |
| 129 |
| 130 // Do not warn about deprecated call to Resources(); the documentation s
ays code is not |
| 131 // supposed to create its own Resources object, but we are using it to f
ake out the |
| 132 // Resources, and there is no other way to do that. |
| 133 @SuppressWarnings("deprecation") |
| 134 public FakeResources(int identifier, String value) { |
| 135 super(new AssetManager(), null, null); |
| 136 mId = identifier; |
| 137 mValue = value; |
| 138 } |
| 139 |
| 140 @Override |
| 141 public int getIdentifier(String name, String defType, String defPackage)
{ |
| 142 if (name == null) throw new NullPointerException(); |
| 143 |
| 144 // There is *no guarantee* (in the Digital Asset Links spec) about w
hat the string |
| 145 // resource should be called ("asset_statements" is just an example)
. Therefore, |
| 146 // getIdentifier cannot be used to get the asset statements string.
Always fail the |
| 147 // lookup here, to ensure the implementation isn't relying on any pa
rticular hard-coded |
| 148 // string. |
| 149 return 0; |
| 150 } |
| 151 |
| 152 @Override |
| 153 public String getString(int id) { |
| 154 if (id != mId) { |
| 155 throw new Resources.NotFoundException("id 0x" + Integer.toHexStr
ing(id)); |
| 156 } |
| 157 |
| 158 return mValue; |
| 159 } |
| 160 } |
| 161 |
| 162 private static final class FakeFrameUrlDelegate |
| 163 implements InstalledAppProviderImpl.FrameUrlDelegate { |
| 164 private URI mFrameUrl; |
| 165 |
| 166 public FakeFrameUrlDelegate(String frameUrl) { |
| 167 setFrameUrl(frameUrl); |
| 168 } |
| 169 |
| 170 public void setFrameUrl(String frameUrl) { |
| 171 if (frameUrl == null) { |
| 172 mFrameUrl = null; |
| 173 return; |
| 174 } |
| 175 |
| 176 try { |
| 177 mFrameUrl = new URI(frameUrl); |
| 178 } catch (URISyntaxException e) { |
| 179 throw new AssertionError(e); |
| 180 } |
| 181 } |
| 182 |
| 183 @Override |
| 184 public URI getUrl() { |
| 185 return mFrameUrl; |
| 186 } |
| 187 } |
| 188 |
| 189 /** |
| 190 * Creates a metaData bundle with a single resource-id key. |
| 191 */ |
| 192 private static Bundle createMetaData(String metaDataName, int metaDataResour
ceId) { |
| 193 Bundle metaData = new Bundle(); |
| 194 metaData.putInt(metaDataName, metaDataResourceId); |
| 195 return metaData; |
| 196 } |
| 197 |
| 198 /** |
| 199 * Sets a resource with a single key-value pair in an Android package's mani
fest. |
| 200 * |
| 201 * The value is always a string. |
| 202 */ |
| 203 private void setStringResource(String packageName, String key, String value)
{ |
| 204 int identifier = 0x1234; |
| 205 Bundle metaData = createMetaData(key, identifier); |
| 206 FakeResources resources = new FakeResources(identifier, value); |
| 207 mPackageManager.setMetaDataAndResourcesForTest(packageName, metaData, re
sources); |
| 208 } |
| 209 |
| 210 /** |
| 211 * Creates a valid Android asset statement string. |
| 212 */ |
| 213 private String createAssetStatement(String platform, String relation, String
url) { |
| 214 return String.format( |
| 215 "{\"relation\": [\"%s\"], \"target\": {\"namespace\": \"%s\", \"
site\": \"%s\"}}", |
| 216 relation, platform, url); |
| 217 } |
| 218 |
| 219 /** |
| 220 * Sets an asset statement to an Android package's manifest (in the fake pac
kage manager). |
| 221 * |
| 222 * Only one asset statement can be set for a given package (if this is calle
d twice on the same |
| 223 * package, overwrites the previous asset statement). |
| 224 * |
| 225 * This corresponds to a Statement List in the Digital Asset Links spec v1. |
| 226 */ |
| 227 private void setAssetStatement( |
| 228 String packageName, String platform, String relation, String url) { |
| 229 String statements = "[" + createAssetStatement(platform, relation, url)
+ "]"; |
| 230 setStringResource(packageName, ASSET_STATEMENTS_KEY, statements); |
| 231 } |
| 232 |
| 233 /** |
| 234 * Creates a RelatedApplication to put in the web app manifest. |
| 235 */ |
| 236 private RelatedApplication createRelatedApplication(String platform, String
id, String url) { |
| 237 RelatedApplication application = new RelatedApplication(); |
| 238 application.platform = platform; |
| 239 application.id = id; |
| 240 application.url = url; |
| 241 return application; |
| 242 } |
| 243 |
| 244 /** |
| 245 * Calls filterInstalledApps with the given inputs, and tests that the expec
ted result is |
| 246 * returned. |
| 247 */ |
| 248 private void verifyInstalledApps(RelatedApplication[] manifestRelatedApps, |
| 249 final RelatedApplication[] expectedInstalledRelatedApps) { |
| 250 mInstalledAppProvider.filterInstalledApps( |
| 251 manifestRelatedApps, new InstalledAppProvider.FilterInstalledApp
sResponse() { |
| 252 @Override |
| 253 public void call(RelatedApplication[] installedRelatedApps)
{ |
| 254 Assert.assertEquals( |
| 255 expectedInstalledRelatedApps.length, installedRe
latedApps.length); |
| 256 |
| 257 for (int i = 0; i < installedRelatedApps.length; i++) { |
| 258 Assert.assertEquals( |
| 259 expectedInstalledRelatedApps[i], installedRe
latedApps[i]); |
| 260 } |
| 261 } |
| 262 }); |
| 263 } |
| 264 |
| 265 @Before |
| 266 public void setUp() { |
| 267 mPackageManager = new FakePackageManager(); |
| 268 RuntimeEnvironment.setRobolectricPackageManager(mPackageManager); |
| 269 mFrameUrlDelegate = new FakeFrameUrlDelegate(URL_ON_ORIGIN); |
| 270 mInstalledAppProvider = |
| 271 new InstalledAppProviderImpl(mFrameUrlDelegate, RuntimeEnvironme
nt.application); |
| 272 } |
| 273 |
| 274 /** |
| 275 * Origin of the page using the API is missing certain parts of the URI. |
| 276 */ |
| 277 @Test |
| 278 @Feature({"InstalledApp"}) |
| 279 public void testOriginMissingParts() { |
| 280 RelatedApplication manifestRelatedApps[] = new RelatedApplication[] { |
| 281 createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)
}; |
| 282 setAssetStatement(PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URL
S, ORIGIN); |
| 283 RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplicati
on[] {}; |
| 284 |
| 285 mFrameUrlDelegate.setFrameUrl(ORIGIN_MISSING_SCHEME); |
| 286 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 287 |
| 288 mFrameUrlDelegate.setFrameUrl(ORIGIN_MISSING_HOST); |
| 289 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 290 } |
| 291 |
| 292 /** |
| 293 * No related Android apps. |
| 294 * |
| 295 * An Android app relates to the web app, but not mutual. |
| 296 */ |
| 297 @Test |
| 298 @Feature({"InstalledApp"}) |
| 299 public void testNoRelatedApps() { |
| 300 // The web manifest has no related apps. |
| 301 RelatedApplication manifestRelatedApps[] = new RelatedApplication[] {}; |
| 302 |
| 303 // One Android app is installed named |PACKAGE_NAME_1|. It has a related
web app with origin |
| 304 // |ORIGIN|. |
| 305 setAssetStatement(PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URL
S, ORIGIN); |
| 306 |
| 307 RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplicati
on[] {}; |
| 308 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 309 } |
| 310 |
| 311 /** |
| 312 * One related Android app with no id (package name). |
| 313 * |
| 314 * An Android app relates to the web app, but not mutual. |
| 315 */ |
| 316 @Test |
| 317 @Feature({"InstalledApp"}) |
| 318 public void testOneRelatedAppNoId() { |
| 319 RelatedApplication manifestRelatedApps[] = |
| 320 new RelatedApplication[] {createRelatedApplication(PLATFORM_ANDR
OID, null, null)}; |
| 321 |
| 322 setAssetStatement(PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URL
S, ORIGIN); |
| 323 |
| 324 RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplicati
on[] {}; |
| 325 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 326 } |
| 327 |
| 328 /** |
| 329 * One related app (from a non-Android platform). |
| 330 * |
| 331 * An Android app with the same id relates to the web app. This should be ig
nored since the |
| 332 * manifest doesn't mention the Android app. |
| 333 */ |
| 334 @Test |
| 335 @Feature({"InstalledApp"}) |
| 336 public void testOneRelatedNonAndroidApp() { |
| 337 RelatedApplication manifestRelatedApps[] = new RelatedApplication[] { |
| 338 createRelatedApplication(PLATFORM_OTHER, PACKAGE_NAME_1, null)}; |
| 339 |
| 340 setAssetStatement(PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URL
S, ORIGIN); |
| 341 |
| 342 RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplicati
on[] {}; |
| 343 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 344 } |
| 345 |
| 346 /** |
| 347 * One related Android app; Android app is not installed. |
| 348 * |
| 349 * Another Android app relates to the web app, but not mutual. |
| 350 */ |
| 351 @Test |
| 352 @Feature({"InstalledApp"}) |
| 353 public void testOneRelatedAppNotInstalled() { |
| 354 // The web manifest has a related Android app named |PACKAGE_NAME_1|. |
| 355 RelatedApplication manifestRelatedApps[] = new RelatedApplication[] { |
| 356 createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)
}; |
| 357 |
| 358 // One Android app is installed named |PACKAGE_NAME_2|. It has a related
web app with origin |
| 359 // |ORIGIN|. |
| 360 setAssetStatement(PACKAGE_NAME_2, NAMESPACE_WEB, RELATION_HANDLE_ALL_URL
S, ORIGIN); |
| 361 |
| 362 RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplicati
on[] {}; |
| 363 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 364 } |
| 365 |
| 366 /** |
| 367 * Android app manifest has an asset_statements key, but the resource it lin
ks to is missing. |
| 368 */ |
| 369 @Test |
| 370 @Feature({"InstalledApp"}) |
| 371 public void testOneRelatedAppBrokenAssetStatementsResource() { |
| 372 RelatedApplication manifestRelatedApps[] = new RelatedApplication[] { |
| 373 createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)
}; |
| 374 |
| 375 Bundle metaData = createMetaData(ASSET_STATEMENTS_KEY, 0x1234); |
| 376 String statements = |
| 377 "[" + createAssetStatement(NAMESPACE_WEB, RELATION_HANDLE_ALL_UR
LS, ORIGIN) + "]"; |
| 378 FakeResources resources = new FakeResources(0x4321, statements); |
| 379 mPackageManager.setMetaDataAndResourcesForTest(PACKAGE_NAME_1, metaData,
resources); |
| 380 RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplicati
on[] {}; |
| 381 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 382 } |
| 383 |
| 384 /** |
| 385 * One related Android app; Android app is not mutually related (has no asse
t_statements). |
| 386 */ |
| 387 @Test |
| 388 @Feature({"InstalledApp"}) |
| 389 public void testOneRelatedAppNoAssetStatements() { |
| 390 RelatedApplication manifestRelatedApps[] = new RelatedApplication[] { |
| 391 createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)
}; |
| 392 |
| 393 setStringResource(PACKAGE_NAME_1, null, null); |
| 394 RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplicati
on[] {}; |
| 395 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 396 } |
| 397 |
| 398 /** |
| 399 * One related Android app; Android app is related to other origins. |
| 400 * |
| 401 * Tests three cases: |
| 402 * - The Android app is related to a web app with a different scheme. |
| 403 * - The Android app is related to a web app with a different host. |
| 404 * - The Android app is related to a web app with a different port. |
| 405 */ |
| 406 @Test |
| 407 @Feature({"InstalledApp"}) |
| 408 public void testOneRelatedAppRelatedToDifferentOrigins() { |
| 409 RelatedApplication manifestRelatedApps[] = new RelatedApplication[] { |
| 410 createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)
}; |
| 411 |
| 412 setAssetStatement( |
| 413 PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN_
DIFFERENT_SCHEME); |
| 414 RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplicati
on[] {}; |
| 415 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 416 |
| 417 setAssetStatement( |
| 418 PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN_
DIFFERENT_HOST); |
| 419 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 420 |
| 421 setAssetStatement( |
| 422 PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN_
DIFFERENT_PORT); |
| 423 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 424 } |
| 425 |
| 426 /** |
| 427 * One related Android app; Android app is installed and mutually related. |
| 428 */ |
| 429 @Test |
| 430 @Feature({"InstalledApp"}) |
| 431 public void testOneInstalledRelatedApp() { |
| 432 RelatedApplication manifestRelatedApps[] = new RelatedApplication[] { |
| 433 createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)
}; |
| 434 |
| 435 setAssetStatement(PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URL
S, ORIGIN); |
| 436 |
| 437 RelatedApplication[] expectedInstalledRelatedApps = manifestRelatedApps; |
| 438 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 439 } |
| 440 |
| 441 /** |
| 442 * Change the frame URL and ensure the app relates to the new URL, not the o
ld one. |
| 443 * |
| 444 * This simulates navigating the frame while keeping the same Mojo service o
pen. |
| 445 */ |
| 446 @Test |
| 447 @Feature({"InstalledApp"}) |
| 448 public void testDynamicallyChangingUrl() { |
| 449 RelatedApplication manifestRelatedApps[] = new RelatedApplication[] { |
| 450 createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)
}; |
| 451 |
| 452 setAssetStatement( |
| 453 PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN_
DIFFERENT_SCHEME); |
| 454 |
| 455 // Should be empty, since Android app does not relate to this frame's or
igin. |
| 456 RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplicati
on[] {}; |
| 457 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 458 |
| 459 // Simulate a navigation to a different origin. |
| 460 mFrameUrlDelegate.setFrameUrl(ORIGIN_DIFFERENT_SCHEME); |
| 461 |
| 462 // Now the result should include the Android app that relates to the new
origin. |
| 463 expectedInstalledRelatedApps = manifestRelatedApps; |
| 464 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 465 |
| 466 // Simulate the native RenderFrameHost disappearing. |
| 467 mFrameUrlDelegate.setFrameUrl(null); |
| 468 |
| 469 expectedInstalledRelatedApps = new RelatedApplication[] {}; |
| 470 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 471 } |
| 472 |
| 473 /** |
| 474 * One related Android app (installed and mutually related), with a non-null
URL field. |
| 475 */ |
| 476 @Test |
| 477 @Feature({"InstalledApp"}) |
| 478 public void testInstalledRelatedAppWithUrl() { |
| 479 RelatedApplication manifestRelatedApps[] = new RelatedApplication[] { |
| 480 createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, URL_U
NRELATED)}; |
| 481 |
| 482 setAssetStatement(PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URL
S, ORIGIN); |
| 483 |
| 484 RelatedApplication[] expectedInstalledRelatedApps = manifestRelatedApps; |
| 485 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 486 } |
| 487 |
| 488 /** |
| 489 * One related Android app; Android app is related to multiple origins. |
| 490 */ |
| 491 @Test |
| 492 @Feature({"InstalledApp"}) |
| 493 public void testMultipleAssetStatements() { |
| 494 RelatedApplication manifestRelatedApps[] = new RelatedApplication[] { |
| 495 createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)
}; |
| 496 |
| 497 // Create an asset_statements field with multiple statements. The second
one matches the web |
| 498 // app. |
| 499 String statements = "[" |
| 500 + createAssetStatement( |
| 501 NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN_DIFFER
ENT_HOST) |
| 502 + ", " + createAssetStatement(NAMESPACE_WEB, RELATION_HANDLE_ALL
_URLS, ORIGIN) |
| 503 + "]"; |
| 504 setStringResource(PACKAGE_NAME_1, ASSET_STATEMENTS_KEY, statements); |
| 505 |
| 506 RelatedApplication[] expectedInstalledRelatedApps = manifestRelatedApps; |
| 507 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 508 } |
| 509 |
| 510 /** |
| 511 * A JSON syntax error in the Android app's asset statement. |
| 512 */ |
| 513 @Test |
| 514 @Feature({"InstalledApp"}) |
| 515 public void testAssetStatementSyntaxError() { |
| 516 RelatedApplication manifestRelatedApps[] = new RelatedApplication[] { |
| 517 createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)
}; |
| 518 |
| 519 String statements = "[{\"target\" {}}]"; |
| 520 setStringResource(PACKAGE_NAME_1, ASSET_STATEMENTS_KEY, statements); |
| 521 |
| 522 RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplicati
on[] {}; |
| 523 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 524 } |
| 525 |
| 526 /** |
| 527 * The Android app's asset statement is not an array. |
| 528 */ |
| 529 @Test |
| 530 @Feature({"InstalledApp"}) |
| 531 public void testAssetStatementNotArray() { |
| 532 RelatedApplication manifestRelatedApps[] = new RelatedApplication[] { |
| 533 createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)
}; |
| 534 |
| 535 String statement = createAssetStatement(NAMESPACE_WEB, RELATION_HANDLE_A
LL_URLS, ORIGIN); |
| 536 setStringResource(PACKAGE_NAME_1, ASSET_STATEMENTS_KEY, statement); |
| 537 |
| 538 RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplicati
on[] {}; |
| 539 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 540 } |
| 541 |
| 542 /** |
| 543 * The Android app's asset statement array contains non-objects. |
| 544 */ |
| 545 @Test |
| 546 @Feature({"InstalledApp"}) |
| 547 public void testAssetStatementArrayNoObjects() { |
| 548 RelatedApplication manifestRelatedApps[] = new RelatedApplication[] { |
| 549 createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)
}; |
| 550 |
| 551 String statements = "[" |
| 552 + createAssetStatement(NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS,
ORIGIN) + ", 4]"; |
| 553 setStringResource(PACKAGE_NAME_1, ASSET_STATEMENTS_KEY, statements); |
| 554 |
| 555 // Expect it to ignore the integer and successfully parse the valid obje
ct. |
| 556 RelatedApplication[] expectedInstalledRelatedApps = manifestRelatedApps; |
| 557 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 558 } |
| 559 |
| 560 /** |
| 561 * Android app has no "relation" in the asset statement. |
| 562 * |
| 563 * Currently, the relation string (in the Android package's asset statement)
is ignored, so the |
| 564 * app is still returned as "installed". |
| 565 */ |
| 566 @Test |
| 567 @Feature({"InstalledApp"}) |
| 568 public void testAssetStatementNoRelation() { |
| 569 RelatedApplication manifestRelatedApps[] = new RelatedApplication[] { |
| 570 createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)
}; |
| 571 |
| 572 String statements = String.format( |
| 573 "[{\"target\": {\"namespace\": \"%s\", \"site\": \"%s\"}}]", NAM
ESPACE_WEB, ORIGIN); |
| 574 setStringResource(PACKAGE_NAME_1, ASSET_STATEMENTS_KEY, statements); |
| 575 |
| 576 // TODO(mgiuca): [Spec issue] Should we require a specific relation stri
ng, rather than any |
| 577 // or no relation? |
| 578 RelatedApplication[] expectedInstalledRelatedApps = manifestRelatedApps; |
| 579 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 580 } |
| 581 |
| 582 /** |
| 583 * Android app is related with a non-standard relation. |
| 584 * |
| 585 * Currently, the relation string (in the Android package's asset statement)
is ignored, so any |
| 586 * will do. Is this desirable, or do we want to require a specific relation
string? |
| 587 */ |
| 588 @Test |
| 589 @Feature({"InstalledApp"}) |
| 590 public void testAssetStatementNonStandardRelation() { |
| 591 RelatedApplication manifestRelatedApps[] = new RelatedApplication[] { |
| 592 createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)
}; |
| 593 |
| 594 setAssetStatement(PACKAGE_NAME_1, NAMESPACE_WEB, "nonstandard/relation",
ORIGIN); |
| 595 |
| 596 // TODO(mgiuca): [Spec issue] Should we require a specific relation stri
ng, rather than any |
| 597 // or no relation? |
| 598 RelatedApplication[] expectedInstalledRelatedApps = manifestRelatedApps; |
| 599 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 600 } |
| 601 |
| 602 /** |
| 603 * Android app has no "target" in the asset statement. |
| 604 */ |
| 605 @Test |
| 606 @Feature({"InstalledApp"}) |
| 607 public void testAssetStatementNoTarget() { |
| 608 RelatedApplication manifestRelatedApps[] = new RelatedApplication[] { |
| 609 createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)
}; |
| 610 |
| 611 String statements = String.format("[{\"relation\": [\"%s\"]}]", RELATION
_HANDLE_ALL_URLS); |
| 612 setStringResource(PACKAGE_NAME_1, ASSET_STATEMENTS_KEY, statements); |
| 613 |
| 614 RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplicati
on[] {}; |
| 615 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 616 } |
| 617 |
| 618 /** |
| 619 * Android app has no "namespace" in the asset statement. |
| 620 */ |
| 621 @Test |
| 622 @Feature({"InstalledApp"}) |
| 623 public void testAssetStatementNoNamespace() { |
| 624 RelatedApplication manifestRelatedApps[] = new RelatedApplication[] { |
| 625 createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)
}; |
| 626 |
| 627 String statements = |
| 628 String.format("[{\"relation\": [\"%s\"], \"target\": {\"site\":
\"%s\"}}]", |
| 629 RELATION_HANDLE_ALL_URLS, ORIGIN); |
| 630 setStringResource(PACKAGE_NAME_1, ASSET_STATEMENTS_KEY, statements); |
| 631 |
| 632 RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplicati
on[] {}; |
| 633 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 634 } |
| 635 |
| 636 /** |
| 637 * Android app is related, but not to the web namespace. |
| 638 */ |
| 639 @Test |
| 640 @Feature({"InstalledApp"}) |
| 641 public void testNonWebAssetStatement() { |
| 642 RelatedApplication manifestRelatedApps[] = new RelatedApplication[] { |
| 643 createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)
}; |
| 644 |
| 645 setAssetStatement(PACKAGE_NAME_1, "play", RELATION_HANDLE_ALL_URLS, ORIG
IN); |
| 646 |
| 647 RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplicati
on[] {}; |
| 648 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 649 } |
| 650 |
| 651 /** |
| 652 * Android app has no "site" in the asset statement. |
| 653 */ |
| 654 @Test |
| 655 @Feature({"InstalledApp"}) |
| 656 public void testAssetStatementNoSite() { |
| 657 RelatedApplication manifestRelatedApps[] = new RelatedApplication[] { |
| 658 createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)
}; |
| 659 |
| 660 String statements = |
| 661 String.format("[{\"relation\": [\"%s\"], \"target\": {\"namespac
e\": \"%s\"}}]", |
| 662 RELATION_HANDLE_ALL_URLS, NAMESPACE_WEB); |
| 663 setStringResource(PACKAGE_NAME_1, ASSET_STATEMENTS_KEY, statements); |
| 664 |
| 665 RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplicati
on[] {}; |
| 666 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 667 } |
| 668 |
| 669 /** |
| 670 * Android app has a syntax error in the "site" field of the asset statement
. |
| 671 */ |
| 672 @Test |
| 673 @Feature({"InstalledApp"}) |
| 674 public void testAssetStatementSiteSyntaxError() { |
| 675 RelatedApplication manifestRelatedApps[] = new RelatedApplication[] { |
| 676 createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)
}; |
| 677 |
| 678 setAssetStatement( |
| 679 PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN_
SYNTAX_ERROR); |
| 680 |
| 681 RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplicati
on[] {}; |
| 682 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 683 } |
| 684 |
| 685 /** |
| 686 * Android app has a "site" field missing certain parts of the URI (scheme,
host, port). |
| 687 */ |
| 688 @Test |
| 689 @Feature({"InstalledApp"}) |
| 690 public void testAssetStatementSiteMissingParts() { |
| 691 RelatedApplication manifestRelatedApps[] = new RelatedApplication[] { |
| 692 createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)
}; |
| 693 |
| 694 setAssetStatement( |
| 695 PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN_
MISSING_SCHEME); |
| 696 RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplicati
on[] {}; |
| 697 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 698 |
| 699 setAssetStatement( |
| 700 PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN_
MISSING_HOST); |
| 701 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 702 |
| 703 setAssetStatement( |
| 704 PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN_
MISSING_PORT); |
| 705 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 706 } |
| 707 |
| 708 /** |
| 709 * One related Android app; Android app is related with a path part in the "
site" field. |
| 710 * |
| 711 * The path part shouldn't really be there (according to the Digital Asset L
inks spec), but if |
| 712 * it is, we are lenient and just ignore it (matching only the origin). |
| 713 */ |
| 714 @Test |
| 715 @Feature({"InstalledApp"}) |
| 716 public void testAssetStatementSiteHasPath() { |
| 717 RelatedApplication manifestRelatedApps[] = new RelatedApplication[] { |
| 718 createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)
}; |
| 719 |
| 720 String site = ORIGIN + "/path"; |
| 721 setAssetStatement(PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URL
S, site); |
| 722 |
| 723 RelatedApplication[] expectedInstalledRelatedApps = manifestRelatedApps; |
| 724 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 725 } |
| 726 |
| 727 /** |
| 728 * One related Android app; Android app is installed and mutually related. |
| 729 * |
| 730 * Another Android app relates to the web app, but not mutual. |
| 731 */ |
| 732 @Test |
| 733 @Feature({"InstalledApp"}) |
| 734 public void testExtraInstalledApp() { |
| 735 RelatedApplication manifestRelatedApps[] = new RelatedApplication[] { |
| 736 createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)
}; |
| 737 |
| 738 setAssetStatement(PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URL
S, ORIGIN); |
| 739 setAssetStatement(PACKAGE_NAME_2, NAMESPACE_WEB, RELATION_HANDLE_ALL_URL
S, ORIGIN); |
| 740 |
| 741 RelatedApplication[] expectedInstalledRelatedApps = manifestRelatedApps; |
| 742 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 743 } |
| 744 |
| 745 /** |
| 746 * Two related Android apps; Android apps both installed and mutually relate
d. |
| 747 * |
| 748 * Web app also related to an app with the same name on another platform, an
d another Android |
| 749 * app which is not installed. |
| 750 */ |
| 751 @Test |
| 752 @Feature({"InstalledApp"}) |
| 753 public void testMultipleInstalledRelatedApps() { |
| 754 RelatedApplication[] manifestRelatedApps = new RelatedApplication[] { |
| 755 createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)
, |
| 756 createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_2, null)
, |
| 757 createRelatedApplication(PLATFORM_OTHER, PACKAGE_NAME_2, null), |
| 758 createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_3, null)
}; |
| 759 |
| 760 setAssetStatement(PACKAGE_NAME_2, NAMESPACE_WEB, RELATION_HANDLE_ALL_URL
S, ORIGIN); |
| 761 setAssetStatement(PACKAGE_NAME_3, NAMESPACE_WEB, RELATION_HANDLE_ALL_URL
S, ORIGIN); |
| 762 |
| 763 RelatedApplication[] expectedInstalledRelatedApps = |
| 764 new RelatedApplication[] {manifestRelatedApps[1], manifestRelate
dApps[3]}; |
| 765 verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps); |
| 766 } |
| 767 } |
OLD | NEW |