mirror of https://github.com/buster-so/buster.git
231 lines
8.0 KiB
TypeScript
231 lines
8.0 KiB
TypeScript
import { beforeEach, describe, expect, it } from 'vitest';
|
|
import type { PermissionedDataset } from '../types/dataset-permissions';
|
|
import {
|
|
clearAllCaches,
|
|
getCachedDatasetAccess,
|
|
getCachedPermissionedDatasets,
|
|
getCacheStats,
|
|
invalidateDataset,
|
|
invalidateOnPermissionChange,
|
|
invalidateUser,
|
|
resetCacheStats,
|
|
setCachedDatasetAccess,
|
|
setCachedPermissionedDatasets,
|
|
} from './cache';
|
|
|
|
describe('Dataset Permission Cache', () => {
|
|
beforeEach(() => {
|
|
clearAllCaches();
|
|
resetCacheStats();
|
|
});
|
|
|
|
describe('Dataset List Cache', () => {
|
|
const mockDatasets: PermissionedDataset[] = [
|
|
{
|
|
id: 'ds1',
|
|
name: 'Dataset 1',
|
|
organizationId: 'org1',
|
|
dataSourceId: 'source1',
|
|
ymlContent: {},
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
},
|
|
{
|
|
id: 'ds2',
|
|
name: 'Dataset 2',
|
|
organizationId: 'org1',
|
|
dataSourceId: 'source1',
|
|
ymlContent: {},
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
},
|
|
];
|
|
|
|
it('should cache and retrieve dataset lists', () => {
|
|
const result = { datasets: mockDatasets, total: 2 };
|
|
|
|
// Should return undefined for uncached
|
|
expect(getCachedPermissionedDatasets('user1', 0, 20)).toBeUndefined();
|
|
|
|
// Set cache
|
|
setCachedPermissionedDatasets('user1', 0, 20, result);
|
|
|
|
// Should retrieve cached result
|
|
const cached = getCachedPermissionedDatasets('user1', 0, 20);
|
|
expect(cached).toEqual(result);
|
|
});
|
|
|
|
it('should handle different pagination keys', () => {
|
|
const page1 = { datasets: [mockDatasets[0]], total: 2 };
|
|
const page2 = { datasets: [mockDatasets[1]], total: 2 };
|
|
|
|
setCachedPermissionedDatasets('user1', 0, 1, page1);
|
|
setCachedPermissionedDatasets('user1', 1, 1, page2);
|
|
|
|
expect(getCachedPermissionedDatasets('user1', 0, 1)).toEqual(page1);
|
|
expect(getCachedPermissionedDatasets('user1', 1, 1)).toEqual(page2);
|
|
expect(getCachedPermissionedDatasets('user1', 0, 2)).toBeUndefined();
|
|
});
|
|
|
|
it('should track cache stats', () => {
|
|
const result = { datasets: mockDatasets, total: 2 };
|
|
|
|
// Miss
|
|
getCachedPermissionedDatasets('user1', 0, 20);
|
|
let stats = getCacheStats();
|
|
expect(stats.datasets.misses).toBe(1);
|
|
|
|
// Set and hit
|
|
setCachedPermissionedDatasets('user1', 0, 20, result);
|
|
getCachedPermissionedDatasets('user1', 0, 20);
|
|
stats = getCacheStats();
|
|
expect(stats.datasets.hits).toBe(1);
|
|
expect(stats.datasets.hitRate).toBe('50.00%');
|
|
});
|
|
});
|
|
|
|
describe('Dataset Access Cache', () => {
|
|
it('should cache and retrieve access results', () => {
|
|
// Should return undefined for uncached
|
|
expect(getCachedDatasetAccess('user1', 'ds1')).toBeUndefined();
|
|
|
|
// Set cache
|
|
setCachedDatasetAccess('user1', 'ds1', true);
|
|
setCachedDatasetAccess('user1', 'ds2', false);
|
|
|
|
// Should retrieve cached results
|
|
expect(getCachedDatasetAccess('user1', 'ds1')).toBe(true);
|
|
expect(getCachedDatasetAccess('user1', 'ds2')).toBe(false);
|
|
});
|
|
|
|
it('should track access cache stats separately', () => {
|
|
// Miss
|
|
getCachedDatasetAccess('user1', 'ds1');
|
|
let stats = getCacheStats();
|
|
expect(stats.access.misses).toBe(1);
|
|
expect(stats.datasets.misses).toBe(0); // Different cache
|
|
|
|
// Set and hit
|
|
setCachedDatasetAccess('user1', 'ds1', true);
|
|
getCachedDatasetAccess('user1', 'ds1');
|
|
stats = getCacheStats();
|
|
expect(stats.access.hits).toBe(1);
|
|
expect(stats.access.hitRate).toBe('50.00%');
|
|
});
|
|
});
|
|
|
|
describe('Cache Invalidation', () => {
|
|
beforeEach(() => {
|
|
// Set up some cached data
|
|
setCachedPermissionedDatasets('user1', 0, 20, { datasets: [], total: 0 });
|
|
setCachedPermissionedDatasets('user1', 1, 20, { datasets: [], total: 0 });
|
|
setCachedPermissionedDatasets('user2', 0, 20, { datasets: [], total: 0 });
|
|
|
|
setCachedDatasetAccess('user1', 'ds1', true);
|
|
setCachedDatasetAccess('user1', 'ds2', true);
|
|
setCachedDatasetAccess('user2', 'ds1', true);
|
|
});
|
|
|
|
it('should invalidate all caches for a user', () => {
|
|
invalidateUser('user1');
|
|
|
|
// User1 caches should be cleared
|
|
expect(getCachedPermissionedDatasets('user1', 0, 20)).toBeUndefined();
|
|
expect(getCachedPermissionedDatasets('user1', 1, 20)).toBeUndefined();
|
|
expect(getCachedDatasetAccess('user1', 'ds1')).toBeUndefined();
|
|
expect(getCachedDatasetAccess('user1', 'ds2')).toBeUndefined();
|
|
|
|
// User2 caches should remain
|
|
expect(getCachedPermissionedDatasets('user2', 0, 20)).toBeDefined();
|
|
expect(getCachedDatasetAccess('user2', 'ds1')).toBeDefined();
|
|
});
|
|
|
|
it('should invalidate all caches for a dataset', () => {
|
|
invalidateDataset('ds1');
|
|
|
|
// All dataset list caches cleared (broad invalidation)
|
|
expect(getCachedPermissionedDatasets('user1', 0, 20)).toBeUndefined();
|
|
expect(getCachedPermissionedDatasets('user2', 0, 20)).toBeUndefined();
|
|
|
|
// Specific dataset access cleared
|
|
expect(getCachedDatasetAccess('user1', 'ds1')).toBeUndefined();
|
|
expect(getCachedDatasetAccess('user2', 'ds1')).toBeUndefined();
|
|
|
|
// Other dataset access remains
|
|
expect(getCachedDatasetAccess('user1', 'ds2')).toBeDefined();
|
|
});
|
|
|
|
it('should handle user permission changes', () => {
|
|
invalidateOnPermissionChange('ds1', 'user1', 'user');
|
|
|
|
// Should invalidate the dataset
|
|
expect(getCachedDatasetAccess('user1', 'ds1')).toBeUndefined();
|
|
expect(getCachedDatasetAccess('user2', 'ds1')).toBeUndefined();
|
|
|
|
// Should invalidate all dataset lists (broad invalidation)
|
|
expect(getCachedPermissionedDatasets('user1', 0, 20)).toBeUndefined();
|
|
expect(getCachedPermissionedDatasets('user2', 0, 20)).toBeUndefined();
|
|
});
|
|
|
|
it('should clear all caches for team/group permission changes', () => {
|
|
const initialDatasets = getCachedPermissionedDatasets('user1', 0, 20);
|
|
const initialAccess = getCachedDatasetAccess('user1', 'ds1');
|
|
expect(initialDatasets).toBeDefined();
|
|
expect(initialAccess).toBeDefined();
|
|
|
|
// Team permission change
|
|
invalidateOnPermissionChange('ds1', 'team1', 'team');
|
|
|
|
// All caches should be cleared
|
|
expect(getCachedPermissionedDatasets('user1', 0, 20)).toBeUndefined();
|
|
expect(getCachedDatasetAccess('user1', 'ds1')).toBeUndefined();
|
|
|
|
// Set up new data
|
|
setCachedPermissionedDatasets('user1', 0, 20, { datasets: [], total: 0 });
|
|
setCachedDatasetAccess('user1', 'ds1', true);
|
|
|
|
// Permission group change
|
|
invalidateOnPermissionChange('ds1', 'group1', 'permission_group');
|
|
|
|
// All caches should be cleared again
|
|
expect(getCachedPermissionedDatasets('user1', 0, 20)).toBeUndefined();
|
|
expect(getCachedDatasetAccess('user1', 'ds1')).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe('Cache Management', () => {
|
|
it('should clear all caches', () => {
|
|
setCachedPermissionedDatasets('user1', 0, 20, { datasets: [], total: 0 });
|
|
setCachedDatasetAccess('user1', 'ds1', true);
|
|
|
|
clearAllCaches();
|
|
|
|
expect(getCachedPermissionedDatasets('user1', 0, 20)).toBeUndefined();
|
|
expect(getCachedDatasetAccess('user1', 'ds1')).toBeUndefined();
|
|
});
|
|
|
|
it('should reset stats but keep cache data', () => {
|
|
// Generate stats
|
|
getCachedPermissionedDatasets('user1', 0, 20);
|
|
setCachedPermissionedDatasets('user1', 0, 20, { datasets: [], total: 0 });
|
|
getCachedPermissionedDatasets('user1', 0, 20);
|
|
|
|
let stats = getCacheStats();
|
|
expect(stats.datasets.hits).toBe(1);
|
|
expect(stats.datasets.misses).toBe(1);
|
|
|
|
resetCacheStats();
|
|
stats = getCacheStats();
|
|
expect(stats.datasets.hits).toBe(0);
|
|
expect(stats.datasets.misses).toBe(0);
|
|
expect(stats.datasets.size).toBe(1); // Data still cached
|
|
});
|
|
|
|
it('should respect cache size limits', () => {
|
|
const stats = getCacheStats();
|
|
expect(stats.datasets.maxSize).toBe(1000);
|
|
expect(stats.access.maxSize).toBe(5000);
|
|
});
|
|
});
|
|
});
|