test_AttributionCode.js (5195B)
1 /* Any copyright is dedicated to the Public Domain. 2 * http://creativecommons.org/publicdomain/zero/1.0/ 3 */ 4 "use strict"; 5 6 const { AppConstants } = ChromeUtils.importESModule( 7 "resource://gre/modules/AppConstants.sys.mjs" 8 ); 9 10 const { sinon } = ChromeUtils.importESModule( 11 "resource://testing-common/Sinon.sys.mjs" 12 ); 13 14 add_task(async () => { 15 await setupStubs(); 16 }); 17 18 /** 19 * Test validation of attribution codes, 20 * to make sure we reject bad ones and accept good ones. 21 */ 22 add_task(async function testValidAttrCodes() { 23 let msixCampaignIdStub = sinon.stub(AttributionCode, "msixCampaignId"); 24 25 let currentCode = null; 26 for (let entry of validAttrCodes) { 27 currentCode = entry.code; 28 // Attribution for MSIX builds works quite differently than regular Windows 29 // builds: the attribution codes come from a Windows API that we've wrapped 30 // with an XPCOM class. We don't have a way to inject codes into the build, 31 // so instead we mock out our XPCOM class and return the desired values from 32 // there. (A potential alternative is to have MSIX tests rely on attribution 33 // files, but that more or less invalidates the tests.) 34 if ( 35 AppConstants.platform === "win" && 36 Services.sysinfo.getProperty("hasWinPackageId") 37 ) { 38 // In real life, the attribution codes returned from Microsoft APIs 39 // are not URI encoded, and the AttributionCode code that deals with 40 // them expects that - so we have to simulate that as well. 41 msixCampaignIdStub.callsFake(async () => decodeURIComponent(currentCode)); 42 } else if (AppConstants.platform === "macosx") { 43 const { MacAttribution } = ChromeUtils.importESModule( 44 "moz-src:///browser/components/attribution/MacAttribution.sys.mjs" 45 ); 46 47 await MacAttribution.setAttributionString(currentCode); 48 } else { 49 // non-msix windows 50 await AttributionCode.writeAttributionFile(currentCode); 51 } 52 AttributionCode._clearCache(); 53 let result = await AttributionCode.getAttrDataAsync(); 54 55 Assert.deepEqual( 56 result, 57 entry.parsed, 58 "Parsed code should match expected value, code was: " + currentCode 59 ); 60 } 61 AttributionCode._clearCache(); 62 63 // Restore the msixCampaignId stub so that other tests don't fail stubbing it 64 msixCampaignIdStub.restore(); 65 }); 66 67 /** 68 * Make sure codes with various formatting errors are not seen as valid. 69 */ 70 add_task(async function testInvalidAttrCodes() { 71 let msixCampaignIdStub = sinon.stub(AttributionCode, "msixCampaignId"); 72 let currentCode = null; 73 74 for (let code of invalidAttrCodes) { 75 currentCode = code; 76 77 if ( 78 AppConstants.platform === "win" && 79 Services.sysinfo.getProperty("hasWinPackageId") 80 ) { 81 if (code.includes("not set")) { 82 // One of the "invalid" codes that we test is an unescaped one. 83 // This is valid for most platforms, but we actually _expect_ 84 // unescaped codes for MSIX builds, so that particular test is not 85 // valid for this case. 86 continue; 87 } 88 89 msixCampaignIdStub.callsFake(async () => decodeURIComponent(currentCode)); 90 } else if (AppConstants.platform === "macosx") { 91 const { MacAttribution } = ChromeUtils.importESModule( 92 "moz-src:///browser/components/attribution/MacAttribution.sys.mjs" 93 ); 94 95 await MacAttribution.setAttributionString(currentCode); 96 } else { 97 // non-msix windows 98 await AttributionCode.writeAttributionFile(currentCode); 99 } 100 AttributionCode._clearCache(); 101 let result = await AttributionCode.getAttrDataAsync(); 102 Assert.deepEqual( 103 result, 104 {}, 105 "Code should have failed to parse: " + currentCode 106 ); 107 } 108 AttributionCode._clearCache(); 109 110 // Restore the msixCampaignId stub so that other tests don't fail stubbing it 111 msixCampaignIdStub.restore(); 112 }); 113 114 /** 115 * Test the cache by deleting the attribution data file 116 * and making sure we still get the expected code. 117 */ 118 let condition = { 119 // macOS and MSIX attribution codes are not cached by us, thus this test is 120 // unnecessary for those builds. 121 skip_if: () => 122 (AppConstants.platform === "win" && 123 Services.sysinfo.getProperty("hasWinPackageId")) || 124 AppConstants.platform === "macosx", 125 }; 126 add_task(condition, async function testDeletedFile() { 127 // Set up the test by clearing the cache and writing a valid file. 128 await AttributionCode.writeAttributionFile(validAttrCodes[0].code); 129 let result = await AttributionCode.getAttrDataAsync(); 130 Assert.deepEqual( 131 result, 132 validAttrCodes[0].parsed, 133 "The code should be readable directly from the file" 134 ); 135 136 // Delete the file and make sure we can still read the value back from cache. 137 await AttributionCode.deleteFileAsync(); 138 result = await AttributionCode.getAttrDataAsync(); 139 Assert.deepEqual( 140 result, 141 validAttrCodes[0].parsed, 142 "The code should be readable from the cache" 143 ); 144 145 // Clear the cache and check we can't read anything. 146 AttributionCode._clearCache(); 147 result = await AttributionCode.getAttrDataAsync(); 148 Assert.deepEqual( 149 result, 150 {}, 151 "Shouldn't be able to get a code after file is deleted and cache is cleared" 152 ); 153 });