|
14 | 14 | * See the License for the specific language governing permissions and |
15 | 15 | * limitations under the License. |
16 | 16 | */ |
| 17 | +import { readFileSync, readdirSync } from 'fs'; |
| 18 | +import { parse, resolve } from 'path'; |
| 19 | + |
17 | 20 | import { expect } from 'chai'; |
18 | 21 |
|
19 | 22 | import { BloomFilter } from '../../../src/remote/bloom_filter'; |
20 | 23 |
|
21 | | -import testData from './bloom_filter_test_data.json'; |
22 | | - |
23 | 24 | describe('BloomFilter', () => { |
24 | 25 | it('can initiate an empty BloomFilter', () => { |
25 | 26 | const bloomFilter = new BloomFilter( |
@@ -95,35 +96,63 @@ describe('BloomFilter', () => { |
95 | 96 | expect(nonEmptyBloomFilter.mightContain('')).to.be.false; |
96 | 97 | }); |
97 | 98 |
|
| 99 | + /** |
| 100 | + * Golden tests are generated by backend based on inserting n number of |
| 101 | + * documents path into Bloom filter. |
| 102 | + * |
| 103 | + * Full documents path is generated by concating documentPrefix and n, ie, |
| 104 | + * projects/project-1/databases/database-1/documents/coll/doc11 |
| 105 | + * |
| 106 | + * The test result is generated by checking the membership of documents from |
| 107 | + * documentPrefix+0 to documentPrefix+2n. The membership results from 0 to n |
| 108 | + * is expected to be 1, and from n to 2n to be 0 with some false positive results. |
| 109 | + * |
| 110 | + * The test result of BloomFilter.mightContain() should match the backend result |
| 111 | + * exactly. |
| 112 | + */ |
98 | 113 | describe('BloomFilter membership test', () => { |
99 | | - const prefix = 'projects/project-1/databases/database-1/documents/coll/doc'; |
| 114 | + const documentPrefix = |
| 115 | + 'projects/project-1/databases/database-1/documents/coll/doc'; |
| 116 | + const testDataFolder = 'test/unit/remote/bloom_filter_golden_test_data'; |
100 | 117 |
|
101 | 118 | interface TestDataType { |
102 | | - // Bloom filter result created by backend based on documents: prefix+(0 ~i) |
103 | 119 | bits: { |
104 | | - bitmap: number[]; |
| 120 | + bitmap: string; |
105 | 121 | padding: number; |
106 | 122 | }; |
107 | 123 | hashCount: number; |
108 | | - // Check membership of documents prefix+(0 ~2i) |
109 | | - membershipCheckCount: number; |
110 | | - // Membership result on docs from 0~i are always postive, i~2i might have false positive |
111 | | - membershipTestResult: string; |
| 124 | + } |
| 125 | + |
| 126 | + function convertBase64ToUint8Array(base64: string = ''): Uint8Array { |
| 127 | + return Uint8Array.from(atob(base64), item => item.charCodeAt(0)); |
112 | 128 | } |
113 | 129 |
|
114 | 130 | it('mightContain result should match backend result', () => { |
115 | | - testData.forEach((data: TestDataType) => { |
116 | | - const { bits, hashCount, membershipCheckCount, membershipTestResult } = |
117 | | - data; |
118 | | - const bloomFilter = new BloomFilter( |
119 | | - Uint8Array.from(bits.bitmap), |
120 | | - bits.padding, |
121 | | - hashCount |
122 | | - ); |
123 | | - for (let i = 0; i < membershipCheckCount; i++) { |
124 | | - const isMember = membershipTestResult[i] === '1' ? true : false; |
125 | | - const mightContain = bloomFilter.mightContain(prefix + i); |
126 | | - expect(mightContain).to.equal(isMember); |
| 131 | + readdirSync(testDataFolder).forEach(filename => { |
| 132 | + const ext = parse(filename).ext; |
| 133 | + |
| 134 | + if (ext === '.json') { |
| 135 | + const testDataPath = resolve(testDataFolder, filename); |
| 136 | + const testResultPath = testDataPath.replace( |
| 137 | + 'bloom_filter_proto.json', |
| 138 | + 'membership_test_result.txt' |
| 139 | + ); |
| 140 | + const testData: TestDataType = JSON.parse( |
| 141 | + readFileSync(testDataPath, 'utf8') |
| 142 | + ); |
| 143 | + const testResult: string = readFileSync(testResultPath, 'utf8'); |
| 144 | + const { bits = { bitmap: '', padding: 0 }, hashCount = 0 } = testData; |
| 145 | + const bloomFilter = new BloomFilter( |
| 146 | + convertBase64ToUint8Array(bits.bitmap), |
| 147 | + bits.padding || 0, |
| 148 | + hashCount || 0 |
| 149 | + ); |
| 150 | + for (let i = 0; i < testResult.length; i++) { |
| 151 | + const backendMembershipResult = |
| 152 | + testResult[i] === '1' ? true : false; |
| 153 | + const mightContain = bloomFilter.mightContain(documentPrefix + i); |
| 154 | + expect(mightContain).to.equal(backendMembershipResult); |
| 155 | + } |
127 | 156 | } |
128 | 157 | }); |
129 | 158 | }); |
|
0 commit comments