diff --git a/closure/goog/labs/useragent/browser.js b/closure/goog/labs/useragent/browser.js index aa3fe5f031..2831f8562a 100644 --- a/closure/goog/labs/useragent/browser.js +++ b/closure/goog/labs/useragent/browser.js @@ -19,7 +19,7 @@ const googAsserts = goog.require('goog.asserts'); const util = goog.require('goog.labs.userAgent.util'); const {AsyncValue, Version} = goog.require('goog.labs.userAgent.highEntropy.highEntropyValue'); const {compareVersions} = goog.require('goog.string.internal'); -const {fullVersionList} = goog.require('goog.labs.userAgent.highEntropy.highEntropyData'); +const {fullVersionList, hasFullVersionList} = goog.require('goog.labs.userAgent.highEntropy.highEntropyData'); // TODO(nnaze): Refactor to remove excessive exclusion logic in matching // functions. @@ -624,6 +624,23 @@ class UserAgentStringFallbackBrandVersion { } } +/** + * Requests all full browser versions to be cached. When the returned promise + * resolves, subsequent calls to `fullVersionOf(...).getIfLoaded()` will return + * a value. + * + * This method should be avoided in favor of directly awaiting + * `fullVersionOf(...).load()` where it is used. + * + * @return {!Promise} + */ +async function loadFullVersions() { + if (useUserAgentBrand() && hasFullVersionList()) { + await fullVersionList.load(); + } +} +exports.loadFullVersions = loadFullVersions; + /** * Returns an object that provides access to the full version string of the * current browser -- or undefined, based on whether the current browser matches @@ -636,15 +653,9 @@ class UserAgentStringFallbackBrandVersion { * undefined if the current browser doesn't match the given brand. */ function fullVersionOf(browser) { - // fullVersionList is currently not implemented in Chromium. Therefore, don't - // check fullVersionList until Chromium 101. We choose 101 as a reasonable - // upper bound for when fullVersionList is estimated to have been implemented. - // TODO(user): If fullVersionList is implemented in an earlier version - // of Chromium, lower this value to compare against that major version. - // Additionally, Silk currently does not identify itself in its - // userAgentData.brands array, so if checking its version, always fall back to - // the user agent string. - if (useUserAgentBrand() && !(versionOf(Brand.CHROMIUM) < 101)) { + // Silk currently does not identify itself in its userAgentData.brands array, + // so if checking its version, always fall back to the user agent string. + if (useUserAgentBrand() && hasFullVersionList()) { const data = util.getUserAgentData(); // Operate under the assumption that the low-entropy and high-entropy lists // of brand/version pairs contain an identical set of brands. Therefore, if diff --git a/closure/goog/labs/useragent/browser_test.js b/closure/goog/labs/useragent/browser_test.js index fa3000adc4..6fd8fae7e5 100644 --- a/closure/goog/labs/useragent/browser_test.js +++ b/closure/goog/labs/useragent/browser_test.js @@ -273,6 +273,7 @@ testSuite({ util.setUserAgent(''); util.setUserAgentData(null); highEntropyData.resetAllForTesting(); + highEntropyData.setHasFullVersionListForTesting(false); }, async testOpera10() { @@ -947,6 +948,7 @@ testSuite({ ] }); util.setUserAgentData(userAgentDataWithVersion); + highEntropyData.setHasFullVersionListForTesting(true); assertBrowser(Browser.CHROME); assertNonChromeChromiumBrowser(NonChromeChromiumBrowser.OPERA_CHROMIUM); @@ -984,6 +986,7 @@ testSuite({ ] }); util.setUserAgentData(userAgentDataWithVersion); + highEntropyData.setHasFullVersionListForTesting(true); assertBrowser(Browser.CHROME); assertNonChromeChromiumBrowser(NonChromeChromiumBrowser.EDGE_CHROMIUM); @@ -1055,6 +1058,7 @@ testSuite({ testAgentData.CHROME_USERAGENT_DATA, {fullVersionList: [{brand: 'Chromium', version: '101.0.4472.77'}]}); util.setUserAgentData(userAgentDataWithVersion); + highEntropyData.setHasFullVersionListForTesting(true); assertBrowser(Browser.CHROME); assertTrue(userAgentBrowser.isChrome()); @@ -1105,6 +1109,7 @@ testSuite({ async testChromeUserAgentDataWithRejectedHighEntropyValues() { util.setUserAgentData(testAgentData.CHROME_USERAGENT_DATA); + highEntropyData.setHasFullVersionListForTesting(true); const fullChromeVersion = userAgentBrowser.fullVersionOf(userAgentBrowser.Brand.CHROMIUM); @@ -1118,4 +1123,45 @@ testSuite({ userAgentBrowser.Brand.CHROMIUM, '101', '101'); await assertGetVersionStringForLogging(DEFINITELY_NOT_A_BROWSER, '', ''); }, + + async testChromeUserAgentDataPreloadedFullVersion() { + // Note: The full versions listed here are fictional, made up by bumping + // a legitimate version's major version number by 10 (e.g. 91.* -> 101.*). + const userAgentDataWithVersion = testAgentData.withHighEntropyData( + testAgentData.CHROME_USERAGENT_DATA, + {fullVersionList: [{brand: 'Chromium', version: '101.0.4472.77'}]}); + util.setUserAgentData(userAgentDataWithVersion); + highEntropyData.setHasFullVersionListForTesting(true); + + const fullChromeVersion = + userAgentBrowser.fullVersionOf(userAgentBrowser.Brand.CHROMIUM); + assertNotNullNorUndefined(fullChromeVersion); + assertEquals(undefined, fullChromeVersion.getIfLoaded()); + + // Preload the full version list. + await userAgentBrowser.loadFullVersions(); + assertEquals( + '101.0.4472.77', + fullChromeVersion.getIfLoaded().toVersionStringForLogging()); + }, + + async testChromeNoFullVersionUserAgentDataPreloadedFullVersion() { + util.setUserAgent(testAgents.CHROME_LINUX_91); + util.setUserAgentData( + testAgentData.CHROME_NO_FULLVERSIONLIST_USERAGENT_DATA); + + const fullChromeVersion = + userAgentBrowser.fullVersionOf(userAgentBrowser.Brand.CHROMIUM); + assertNotNullNorUndefined(fullChromeVersion); + assertEquals( + '91.0.4472.77', + fullChromeVersion.getIfLoaded().toVersionStringForLogging()); + + // Preload the full version list. + await userAgentBrowser.loadFullVersions(); + // This should have no effect. + assertEquals( + '91.0.4472.77', + fullChromeVersion.getIfLoaded().toVersionStringForLogging()); + }, }); diff --git a/closure/goog/labs/useragent/highentropy/highentropydata.js b/closure/goog/labs/useragent/highentropy/highentropydata.js index 14c76cc0b7..c1ff63fc81 100644 --- a/closure/goog/labs/useragent/highentropy/highentropydata.js +++ b/closure/goog/labs/useragent/highentropy/highentropydata.js @@ -12,6 +12,39 @@ goog.module('goog.labs.userAgent.highEntropy.highEntropyData'); const {HighEntropyValue} = goog.require('goog.labs.userAgent.highEntropy.highEntropyValue'); +/** + * fullVersionList is currently not implemented in Chromium. + * TODO(user): When fullVersionList is added, remove this value. + */ +let fullVersionListAvailable = false; + +/** + * A helper function to check whether fullVersionList is available in the + * current browser. + * TODO(user): When fullVersionList is added, move hasFullVersionList() + * to browser.js, and inline the browser version check. For example, if it is + * implemented in Chromium 101, have hasFullVersionList simply return + * `browser.versionOf(CHROMIUM) >= 101`. + * @return {boolean} + */ +function hasFullVersionList() { + return fullVersionListAvailable; +} +exports.hasFullVersionList = hasFullVersionList; + +/** + * A test-only function to set whether it should be assumed fullVersionList is + * available in the browser. + * TODO(user): When fullVersionList is added, remove this function, as + * behavior when fullVersionList is either present or absent would be testable + * by setting the user agent and user agent data accordingly. + * @param {boolean} value + */ +function setHasFullVersionListForTesting(value) { + fullVersionListAvailable = value; +} +exports.setHasFullVersionListForTesting = setHasFullVersionListForTesting; + /** * @type {!HighEntropyValue>} */