@umituz/react-native-design-system 2.8.7 → 2.8.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -6
- package/src/device/infrastructure/repositories/LegacyDeviceIdRepository.ts +1 -1
- package/src/device/infrastructure/services/DeviceFeatureService.ts +1 -1
- package/src/exception/infrastructure/services/ExceptionLogger.ts +1 -1
- package/src/exception/infrastructure/storage/ExceptionStore.ts +1 -1
- package/src/exports/filesystem.ts +1 -0
- package/src/exports/storage.ts +1 -0
- package/src/filesystem/domain/constants/FileConstants.ts +20 -0
- package/src/filesystem/domain/entities/File.ts +20 -0
- package/src/filesystem/domain/types/FileTypes.ts +43 -0
- package/src/filesystem/domain/utils/FileUtils.ts +86 -0
- package/src/filesystem/index.ts +23 -0
- package/src/filesystem/infrastructure/services/FileSystemService.ts +45 -0
- package/src/filesystem/infrastructure/services/cache.service.ts +48 -0
- package/src/filesystem/infrastructure/services/directory.service.ts +66 -0
- package/src/filesystem/infrastructure/services/download.constants.ts +6 -0
- package/src/filesystem/infrastructure/services/download.service.ts +74 -0
- package/src/filesystem/infrastructure/services/download.types.ts +7 -0
- package/src/filesystem/infrastructure/services/encoding.service.ts +25 -0
- package/src/filesystem/infrastructure/services/file-info.service.ts +52 -0
- package/src/filesystem/infrastructure/services/file-manager.service.ts +81 -0
- package/src/filesystem/infrastructure/services/file-path.service.ts +22 -0
- package/src/filesystem/infrastructure/services/file-reader.service.ts +52 -0
- package/src/filesystem/infrastructure/services/file-writer.service.ts +32 -0
- package/src/filesystem/infrastructure/utils/blob.utils.ts +20 -0
- package/src/image/infrastructure/services/ImageStorageService.ts +1 -1
- package/src/index.ts +9 -0
- package/src/molecules/alerts/AlertStore.ts +1 -1
- package/src/molecules/calendar/infrastructure/storage/EventActions.ts +1 -1
- package/src/molecules/calendar/infrastructure/stores/storageAdapter.ts +1 -1
- package/src/offline/infrastructure/storage/OfflineStore.ts +1 -1
- package/src/onboarding/infrastructure/storage/OnboardingStore.ts +2 -2
- package/src/onboarding/infrastructure/storage/__tests__/OnboardingStore.test.ts +1 -1
- package/src/onboarding/infrastructure/storage/actions/answerActions.ts +1 -1
- package/src/onboarding/infrastructure/storage/actions/storageHelpers.ts +1 -1
- package/src/storage/README.md +185 -0
- package/src/storage/__tests__/integration.test.ts +391 -0
- package/src/storage/__tests__/mocks/asyncStorage.mock.ts +52 -0
- package/src/storage/__tests__/performance.test.tsx +352 -0
- package/src/storage/__tests__/setup.ts +63 -0
- package/src/storage/application/README.md +158 -0
- package/src/storage/application/ports/IStorageRepository.ts +61 -0
- package/src/storage/application/ports/README.md +127 -0
- package/src/storage/cache/README.md +154 -0
- package/src/storage/cache/__tests__/PerformanceAndMemory.test.ts +387 -0
- package/src/storage/cache/__tests__/setup.ts +19 -0
- package/src/storage/cache/domain/Cache.ts +146 -0
- package/src/storage/cache/domain/CacheManager.md +83 -0
- package/src/storage/cache/domain/CacheManager.ts +48 -0
- package/src/storage/cache/domain/CacheStatsTracker.md +169 -0
- package/src/storage/cache/domain/CacheStatsTracker.ts +49 -0
- package/src/storage/cache/domain/CachedValue.md +97 -0
- package/src/storage/cache/domain/ErrorHandler.md +99 -0
- package/src/storage/cache/domain/ErrorHandler.ts +42 -0
- package/src/storage/cache/domain/PatternMatcher.md +122 -0
- package/src/storage/cache/domain/PatternMatcher.ts +30 -0
- package/src/storage/cache/domain/README.md +118 -0
- package/src/storage/cache/domain/__tests__/Cache.test.ts +293 -0
- package/src/storage/cache/domain/__tests__/CacheManager.test.ts +276 -0
- package/src/storage/cache/domain/__tests__/ErrorHandler.test.ts +303 -0
- package/src/storage/cache/domain/__tests__/PatternMatcher.test.ts +261 -0
- package/src/storage/cache/domain/strategies/EvictionStrategy.ts +9 -0
- package/src/storage/cache/domain/strategies/FIFOStrategy.ts +12 -0
- package/src/storage/cache/domain/strategies/LFUStrategy.ts +22 -0
- package/src/storage/cache/domain/strategies/LRUStrategy.ts +22 -0
- package/src/storage/cache/domain/strategies/README.md +117 -0
- package/src/storage/cache/domain/strategies/TTLStrategy.ts +23 -0
- package/src/storage/cache/domain/strategies/__tests__/EvictionStrategies.test.ts +293 -0
- package/src/storage/cache/domain/types/Cache.ts +28 -0
- package/src/storage/cache/domain/types/README.md +107 -0
- package/src/storage/cache/index.ts +28 -0
- package/src/storage/cache/infrastructure/README.md +126 -0
- package/src/storage/cache/infrastructure/TTLCache.ts +103 -0
- package/src/storage/cache/infrastructure/__tests__/TTLCache.test.ts +303 -0
- package/src/storage/cache/presentation/README.md +123 -0
- package/src/storage/cache/presentation/__tests__/ReactHooks.test.ts +514 -0
- package/src/storage/cache/presentation/useCache.ts +76 -0
- package/src/storage/cache/presentation/useCachedValue.ts +88 -0
- package/src/storage/cache/types.d.ts +3 -0
- package/src/storage/domain/README.md +128 -0
- package/src/storage/domain/constants/CacheDefaults.ts +64 -0
- package/src/storage/domain/constants/README.md +105 -0
- package/src/storage/domain/entities/CachedValue.ts +86 -0
- package/src/storage/domain/entities/README.md +109 -0
- package/src/storage/domain/entities/StorageResult.ts +75 -0
- package/src/storage/domain/entities/__tests__/CachedValue.test.ts +149 -0
- package/src/storage/domain/entities/__tests__/StorageResult.test.ts +122 -0
- package/src/storage/domain/errors/README.md +126 -0
- package/src/storage/domain/errors/StorageError.ts +81 -0
- package/src/storage/domain/errors/__tests__/StorageError.test.ts +127 -0
- package/src/storage/domain/factories/README.md +138 -0
- package/src/storage/domain/factories/StoreFactory.ts +59 -0
- package/src/storage/domain/types/README.md +522 -0
- package/src/storage/domain/types/Store.ts +44 -0
- package/src/storage/domain/utils/CacheKeyGenerator.ts +66 -0
- package/src/storage/domain/utils/README.md +127 -0
- package/src/storage/domain/utils/__tests__/devUtils.test.ts +97 -0
- package/src/storage/domain/utils/devUtils.ts +37 -0
- package/src/storage/domain/value-objects/README.md +120 -0
- package/src/storage/domain/value-objects/StorageKey.ts +60 -0
- package/src/storage/index.ts +175 -0
- package/src/storage/infrastructure/README.md +165 -0
- package/src/storage/infrastructure/adapters/README.md +175 -0
- package/src/storage/infrastructure/adapters/StorageService.md +103 -0
- package/src/storage/infrastructure/adapters/StorageService.ts +49 -0
- package/src/storage/infrastructure/repositories/AsyncStorageRepository.ts +98 -0
- package/src/storage/infrastructure/repositories/BaseStorageOperations.ts +100 -0
- package/src/storage/infrastructure/repositories/BatchStorageOperations.ts +42 -0
- package/src/storage/infrastructure/repositories/README.md +121 -0
- package/src/storage/infrastructure/repositories/StringStorageOperations.ts +44 -0
- package/src/storage/infrastructure/repositories/__tests__/AsyncStorageRepository.test.ts +170 -0
- package/src/storage/infrastructure/repositories/__tests__/BaseStorageOperations.test.ts +201 -0
- package/src/storage/presentation/README.md +181 -0
- package/src/storage/presentation/hooks/CacheStorageOperations.ts +94 -0
- package/src/storage/presentation/hooks/README.md +128 -0
- package/src/storage/presentation/hooks/__tests__/usePersistentCache.test.ts +405 -0
- package/src/storage/presentation/hooks/__tests__/useStorage.test.ts +247 -0
- package/src/storage/presentation/hooks/__tests__/useStorageState.test.ts +293 -0
- package/src/storage/presentation/hooks/useCacheState.ts +53 -0
- package/src/storage/presentation/hooks/usePersistentCache.ts +154 -0
- package/src/storage/presentation/hooks/useStorage.ts +102 -0
- package/src/storage/presentation/hooks/useStorageState.ts +71 -0
- package/src/storage/presentation/hooks/useStore.ts +15 -0
- package/src/storage/types/README.md +103 -0
- package/src/theme/infrastructure/globalThemeStore.ts +1 -1
- package/src/theme/infrastructure/storage/ThemeStorage.ts +1 -1
- package/src/theme/infrastructure/stores/themeStore.ts +1 -1
- package/src/utilities/sharing/infrastructure/services/SharingService.ts +1 -1
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Application Ports
|
|
2
|
+
|
|
3
|
+
Repository interfaces for dependency inversion and testability.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Ports define contracts between application and infrastructure layers using dependency inversion principle. Located at `src/application/ports/`.
|
|
8
|
+
|
|
9
|
+
## Strategies
|
|
10
|
+
|
|
11
|
+
### Dependency Inversion
|
|
12
|
+
- Define interfaces in application layer
|
|
13
|
+
- Implement interfaces in infrastructure layer
|
|
14
|
+
- Depend on abstractions, not concretions
|
|
15
|
+
- Enable swapping implementations without business logic changes
|
|
16
|
+
|
|
17
|
+
### Testability Strategy
|
|
18
|
+
- Design interfaces for easy mocking
|
|
19
|
+
- Use constructor injection for dependencies
|
|
20
|
+
- Create fake implementations for testing
|
|
21
|
+
- Separate unit tests from integration tests
|
|
22
|
+
|
|
23
|
+
### Contract Design
|
|
24
|
+
- Define clear method signatures
|
|
25
|
+
- Use Result pattern for error handling
|
|
26
|
+
- Include type parameters for flexibility
|
|
27
|
+
- Document interface contracts
|
|
28
|
+
|
|
29
|
+
### Implementation Strategy
|
|
30
|
+
- Provide production implementation (AsyncStorage)
|
|
31
|
+
- Provide mock implementation for testing
|
|
32
|
+
- Support custom implementations (MMKV, SecureStore)
|
|
33
|
+
- Allow platform-specific implementations
|
|
34
|
+
|
|
35
|
+
## Restrictions
|
|
36
|
+
|
|
37
|
+
### Interface Design
|
|
38
|
+
- DO NOT include implementation details in interfaces
|
|
39
|
+
- DO NOT change interface signatures without major version bump
|
|
40
|
+
- DO NOT add optional parameters to existing methods
|
|
41
|
+
- DO NOT remove methods from interfaces
|
|
42
|
+
|
|
43
|
+
### Usage
|
|
44
|
+
- DO NOT use concrete implementations in business logic
|
|
45
|
+
- DO NOT instantiate dependencies inside services
|
|
46
|
+
- DO NOT couple services to specific storage technologies
|
|
47
|
+
- DO NOT bypass interface for performance
|
|
48
|
+
|
|
49
|
+
### Implementation
|
|
50
|
+
- DO NOT throw exceptions from interface methods
|
|
51
|
+
- DO NOT return undefined (use null or Result)
|
|
52
|
+
- DO NOT ignore type parameters
|
|
53
|
+
- DO NOT mix sync and async patterns
|
|
54
|
+
|
|
55
|
+
### Testing
|
|
56
|
+
- DO NOT use real storage in unit tests
|
|
57
|
+
- DO NOT share mock instances between tests
|
|
58
|
+
- DO NOT forget to reset mock state
|
|
59
|
+
- DO NOT test interfaces directly
|
|
60
|
+
|
|
61
|
+
## Rules
|
|
62
|
+
|
|
63
|
+
### Interface Definition
|
|
64
|
+
- MUST define all required methods
|
|
65
|
+
- MUST use generic type parameters for flexibility
|
|
66
|
+
- MUST return Promise for async operations
|
|
67
|
+
- MUST use Result pattern for error handling
|
|
68
|
+
|
|
69
|
+
### Method Signatures
|
|
70
|
+
- MUST include type parameter <T> for data operations
|
|
71
|
+
- MUST accept key parameter for storage operations
|
|
72
|
+
- MUST provide defaultValue for getItem methods
|
|
73
|
+
- MUST return StorageResult for operations that can fail
|
|
74
|
+
|
|
75
|
+
### Constructor Injection
|
|
76
|
+
- MUST inject interfaces through constructors
|
|
77
|
+
- MUST store interface reference as private field
|
|
78
|
+
- MUST mark constructor parameter as readonly
|
|
79
|
+
- MUST not create instances inside class
|
|
80
|
+
|
|
81
|
+
### Implementation Classes
|
|
82
|
+
- MUST implement complete interface
|
|
83
|
+
- MUST handle all error cases internally
|
|
84
|
+
- MUST return appropriate error types
|
|
85
|
+
- MUST log errors for debugging
|
|
86
|
+
|
|
87
|
+
### Mock Implementations
|
|
88
|
+
- MUST implement all interface methods
|
|
89
|
+
- MUST provide methods to set mock behavior
|
|
90
|
+
- MUST track method calls for assertions
|
|
91
|
+
- MUST reset state between tests
|
|
92
|
+
|
|
93
|
+
### Custom Implementations
|
|
94
|
+
- MUST implement IStorageRepository interface
|
|
95
|
+
- MUST handle serialization consistently
|
|
96
|
+
- MUST provide error details in results
|
|
97
|
+
- MUST document platform limitations
|
|
98
|
+
|
|
99
|
+
### Dependency Injection
|
|
100
|
+
- MUST use interface types in constructors
|
|
101
|
+
- MUST not depend on concrete classes
|
|
102
|
+
- MUST support different implementations
|
|
103
|
+
- MUST validate dependencies at construction time
|
|
104
|
+
|
|
105
|
+
### Type Safety
|
|
106
|
+
- MUST specify type parameters for all operations
|
|
107
|
+
- MUST enforce type consistency
|
|
108
|
+
- MUST use type guards for validation
|
|
109
|
+
- MUST avoid type assertions
|
|
110
|
+
|
|
111
|
+
### Error Handling
|
|
112
|
+
- MUST return failure Result for errors
|
|
113
|
+
- MUST include error context (key, operation)
|
|
114
|
+
- MUST preserve original error as cause
|
|
115
|
+
- MUST not throw exceptions from interface methods
|
|
116
|
+
|
|
117
|
+
### Testing Strategy
|
|
118
|
+
- MUST use mock implementations for unit tests
|
|
119
|
+
- MUST use real implementations for integration tests
|
|
120
|
+
- MUST reset state in test setup
|
|
121
|
+
- MUST test error scenarios
|
|
122
|
+
|
|
123
|
+
### Documentation
|
|
124
|
+
- MUST document interface contracts
|
|
125
|
+
- MUST specify error types for each method
|
|
126
|
+
- MUST include parameter descriptions
|
|
127
|
+
- MUST provide usage examples in tests
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Cache Module
|
|
2
|
+
|
|
3
|
+
High-performance in-memory cache system with TTL and multiple eviction strategies.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The cache module provides a comprehensive in-memory caching solution with TTL (Time To Live), LRU, LFU, and FIFO eviction strategies. Located at `src/cache/`.
|
|
8
|
+
|
|
9
|
+
## Architecture
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
cache/
|
|
13
|
+
├── domain/ # Business logic and entities
|
|
14
|
+
│ ├── Cache.ts # Main Cache class
|
|
15
|
+
│ ├── CacheManager.ts # Singleton cache manager
|
|
16
|
+
│ ├── CacheStatsTracker.ts
|
|
17
|
+
│ ├── PatternMatcher.ts
|
|
18
|
+
│ ├── ErrorHandler.ts
|
|
19
|
+
│ ├── strategies/ # Eviction strategies
|
|
20
|
+
│ └── types/ # TypeScript types
|
|
21
|
+
├── infrastructure/ # Infrastructure implementation
|
|
22
|
+
│ └── TTLCache.ts
|
|
23
|
+
└── presentation/ # React integration
|
|
24
|
+
├── useCache.ts
|
|
25
|
+
└── useCachedValue.ts
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Strategies
|
|
29
|
+
|
|
30
|
+
### Cache Organization
|
|
31
|
+
- Use CacheManager for multiple named caches
|
|
32
|
+
- Create separate caches for different data types
|
|
33
|
+
- Use environment-specific configurations
|
|
34
|
+
- Implement cache hierarchy for performance
|
|
35
|
+
|
|
36
|
+
### Eviction Strategy Selection
|
|
37
|
+
- Use LRU for frequently accessed recent data
|
|
38
|
+
- Use LFU for popularity-based caching
|
|
39
|
+
- Use FIFO for simple queue-based caching
|
|
40
|
+
- Use TTL for time-based expiration
|
|
41
|
+
|
|
42
|
+
### React Integration
|
|
43
|
+
- Use useCache hook for manual cache management
|
|
44
|
+
- Use useCachedValue for automatic value caching
|
|
45
|
+
- Share cache instances across components
|
|
46
|
+
- Implement cleanup on component unmount
|
|
47
|
+
|
|
48
|
+
### Performance Optimization
|
|
49
|
+
- Monitor cache hit rates and adjust sizes
|
|
50
|
+
- Use appropriate TTL based on data change frequency
|
|
51
|
+
- Implement cache warmup for critical data
|
|
52
|
+
- Use pattern-based invalidation for bulk operations
|
|
53
|
+
|
|
54
|
+
## Restrictions
|
|
55
|
+
|
|
56
|
+
### Cache Creation
|
|
57
|
+
- DO NOT create unlimited cache sizes without max limit
|
|
58
|
+
- DO NOT use zero or negative TTL values
|
|
59
|
+
- DO NOT mix unrelated data types in same cache
|
|
60
|
+
- DO NOT create caches without considering eviction strategy
|
|
61
|
+
|
|
62
|
+
### Memory Management
|
|
63
|
+
- DO NOT cache large objects (> 100KB) without size limits
|
|
64
|
+
- DO NOT cache frequently changing data with long TTL
|
|
65
|
+
- DO NOT ignore memory warnings from cache statistics
|
|
66
|
+
- DO NOT let caches grow unbounded
|
|
67
|
+
|
|
68
|
+
### Pattern Usage
|
|
69
|
+
- DO NOT use broad patterns (e.g., `*`) for invalidation
|
|
70
|
+
- DO NOT mix different separators in cache keys
|
|
71
|
+
- DO NOT create ambiguous key structures
|
|
72
|
+
- DO NOT use patterns without documenting structure
|
|
73
|
+
|
|
74
|
+
### React Integration
|
|
75
|
+
- DO NOT create new cache instances on every render
|
|
76
|
+
- DO NOT use cache hooks without proper cleanup
|
|
77
|
+
- DO NOT share cache state between unrelated components
|
|
78
|
+
- DO NOT ignore loading and error states
|
|
79
|
+
|
|
80
|
+
## Rules
|
|
81
|
+
|
|
82
|
+
### Cache Configuration
|
|
83
|
+
- MUST specify maxSize for all caches
|
|
84
|
+
- MUST set defaultTTL based on data characteristics
|
|
85
|
+
- MUST provide onEvict callback in development
|
|
86
|
+
- MUST document cache purpose and data type
|
|
87
|
+
|
|
88
|
+
### Cache Operations
|
|
89
|
+
- MUST use get() for retrieving values
|
|
90
|
+
- MUST use set() for storing values with optional TTL
|
|
91
|
+
- MUST use has() to check key existence
|
|
92
|
+
- MUST use delete() to remove specific keys
|
|
93
|
+
- MUST use clear() to remove all entries
|
|
94
|
+
|
|
95
|
+
### Cache Keys
|
|
96
|
+
- MUST use consistent key structure (e.g., `entity:id:attribute`)
|
|
97
|
+
- MUST use descriptive key names
|
|
98
|
+
- MUST document key patterns in code comments
|
|
99
|
+
- MUST avoid key collisions across different data types
|
|
100
|
+
|
|
101
|
+
### Eviction Strategy
|
|
102
|
+
- MUST choose appropriate strategy for use case
|
|
103
|
+
- MUST configure strategy parameters correctly
|
|
104
|
+
- MUST monitor eviction statistics
|
|
105
|
+
- MUST test eviction behavior under load
|
|
106
|
+
|
|
107
|
+
### TTL Management
|
|
108
|
+
- MUST set TTL based on data freshness requirements
|
|
109
|
+
- MUST use TIME_MS constants for time values
|
|
110
|
+
- MUST consider stale data impact
|
|
111
|
+
- MUST implement refresh mechanisms for critical data
|
|
112
|
+
|
|
113
|
+
### Error Handling
|
|
114
|
+
- MUST handle cache errors gracefully
|
|
115
|
+
- MUST log cache operation failures
|
|
116
|
+
- MUST provide fallback for cache misses
|
|
117
|
+
- MUST not throw exceptions from cache operations
|
|
118
|
+
|
|
119
|
+
### Statistics Tracking
|
|
120
|
+
- MUST track hits, misses, and evictions
|
|
121
|
+
- MUST calculate hit rate correctly
|
|
122
|
+
- MUST provide getStats() method
|
|
123
|
+
- MUST reset statistics in tests
|
|
124
|
+
|
|
125
|
+
### Pattern-Based Operations
|
|
126
|
+
- MUST use `invalidatePattern()` for bulk invalidation
|
|
127
|
+
- MUST use `:` as default separator
|
|
128
|
+
- MUST support `*` wildcard
|
|
129
|
+
- MUST return count of invalidated keys
|
|
130
|
+
|
|
131
|
+
### React Hooks
|
|
132
|
+
- MUST follow React rules of hooks
|
|
133
|
+
- MUST cleanup cache on unmount
|
|
134
|
+
- MUST provide loading states for async operations
|
|
135
|
+
- MUST handle errors in fetcher functions
|
|
136
|
+
|
|
137
|
+
### Testing Requirements
|
|
138
|
+
- MUST clear cache before each test
|
|
139
|
+
- MUST test hit/miss scenarios
|
|
140
|
+
- MUST test eviction behavior
|
|
141
|
+
- MUST test TTL expiration
|
|
142
|
+
- MUST test pattern matching
|
|
143
|
+
|
|
144
|
+
### Type Safety
|
|
145
|
+
- MUST use generic type parameter for cached values
|
|
146
|
+
- MUST enforce type consistency
|
|
147
|
+
- MUST provide type inference
|
|
148
|
+
- MUST avoid `any` types
|
|
149
|
+
|
|
150
|
+
### Performance Monitoring
|
|
151
|
+
- MUST monitor cache hit rate
|
|
152
|
+
- MUST alert on low hit rates (< 50%)
|
|
153
|
+
- MUST track memory usage
|
|
154
|
+
- MUST log performance anomalies
|
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
+
/**
|
|
3
|
+
* Performance and Memory Leak Tests
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Cache } from '../Cache';
|
|
7
|
+
import { TTLCache } from '../TTLCache';
|
|
8
|
+
import { cacheManager } from '../CacheManager';
|
|
9
|
+
import { PatternMatcher } from '../PatternMatcher';
|
|
10
|
+
import { renderHook, act } from '@testing-library/react';
|
|
11
|
+
import { useCache } from '../../presentation/useCache';
|
|
12
|
+
|
|
13
|
+
describe('Performance and Memory Leak Tests', () => {
|
|
14
|
+
describe('Cache Performance', () => {
|
|
15
|
+
test('should handle large number of entries efficiently', () => {
|
|
16
|
+
const cache = new Cache<string>({ maxSize: 10000 });
|
|
17
|
+
const startTime = performance.now();
|
|
18
|
+
|
|
19
|
+
// Add 10,000 entries
|
|
20
|
+
for (let i = 0; i < 10000; i++) {
|
|
21
|
+
cache.set(`key${i}`, `value${i}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const insertTime = performance.now() - startTime;
|
|
25
|
+
|
|
26
|
+
// Test retrieval performance
|
|
27
|
+
const retrieveStart = performance.now();
|
|
28
|
+
for (let i = 0; i < 10000; i++) {
|
|
29
|
+
cache.get(`key${i}`);
|
|
30
|
+
}
|
|
31
|
+
const retrieveTime = performance.now() - retrieveStart;
|
|
32
|
+
|
|
33
|
+
expect(cache.getStats().size).toBe(10000);
|
|
34
|
+
expect(insertTime).toBeLessThan(1000); // 1 second for 10k inserts
|
|
35
|
+
expect(retrieveTime).toBeLessThan(500); // 0.5 second for 10k retrievals
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('should handle rapid eviction without performance degradation', () => {
|
|
39
|
+
const cache = new Cache<string>({ maxSize: 100 });
|
|
40
|
+
const startTime = performance.now();
|
|
41
|
+
|
|
42
|
+
// Add and rapidly evict entries
|
|
43
|
+
for (let i = 0; i < 1000; i++) {
|
|
44
|
+
cache.set(`key${i}`, `value${i}`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const endTime = performance.now();
|
|
48
|
+
const duration = endTime - startTime;
|
|
49
|
+
|
|
50
|
+
expect(cache.getStats().size).toBe(100); // Should maintain max size
|
|
51
|
+
expect(cache.getStats().evictions).toBeGreaterThan(800); // Many evictions
|
|
52
|
+
expect(duration).toBeLessThan(1000); // Should complete quickly
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('should handle pattern invalidation efficiently', () => {
|
|
56
|
+
const cache = new Cache<string>();
|
|
57
|
+
|
|
58
|
+
// Add entries with different patterns
|
|
59
|
+
for (let i = 0; i < 1000; i++) {
|
|
60
|
+
cache.set(`user:${i}:profile`, `profile${i}`);
|
|
61
|
+
cache.set(`user:${i}:settings`, `settings${i}`);
|
|
62
|
+
cache.set(`post:${i}`, `post${i}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const startTime = performance.now();
|
|
66
|
+
const invalidatedCount = cache.invalidatePattern('user:*:profile');
|
|
67
|
+
const endTime = performance.now();
|
|
68
|
+
|
|
69
|
+
const duration = endTime - startTime;
|
|
70
|
+
|
|
71
|
+
expect(invalidatedCount).toBe(1000);
|
|
72
|
+
expect(duration).toBeLessThan(100); // Should be very fast
|
|
73
|
+
expect(cache.getStats().size).toBe(2000); // posts + settings remain
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe('Memory Management', () => {
|
|
78
|
+
test('should not memory leak with cache destruction', () => {
|
|
79
|
+
const caches: TTLCache<string>[] = [];
|
|
80
|
+
|
|
81
|
+
// Create many caches
|
|
82
|
+
for (let i = 0; i < 100; i++) {
|
|
83
|
+
const cache = new TTLCache<string>({ cleanupIntervalMs: 100 });
|
|
84
|
+
cache.set(`key${i}`, `value${i}`);
|
|
85
|
+
caches.push(cache);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Destroy all caches
|
|
89
|
+
const startTime = performance.now();
|
|
90
|
+
caches.forEach(cache => cache.destroy());
|
|
91
|
+
const endTime = performance.now();
|
|
92
|
+
|
|
93
|
+
const duration = endTime - startTime;
|
|
94
|
+
|
|
95
|
+
expect(duration).toBeLessThan(1000); // Should destroy quickly
|
|
96
|
+
|
|
97
|
+
// Operations on destroyed caches should be safe
|
|
98
|
+
caches.forEach(cache => {
|
|
99
|
+
expect(() => cache.set('test', 'value')).not.toThrow();
|
|
100
|
+
expect(cache.get('test')).toBeUndefined();
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('should handle cache manager memory efficiently', () => {
|
|
105
|
+
const cacheNames: string[] = [];
|
|
106
|
+
|
|
107
|
+
// Create many caches through manager
|
|
108
|
+
for (let i = 0; i < 1000; i++) {
|
|
109
|
+
const name = `cache-${i}`;
|
|
110
|
+
cacheNames.push(name);
|
|
111
|
+
const cache = cacheManager.getCache<string>(name);
|
|
112
|
+
cache.set(`key${i}`, `value${i}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
expect(cacheManager.getCacheNames()).toHaveLength(1000);
|
|
116
|
+
|
|
117
|
+
// Delete all caches
|
|
118
|
+
const startTime = performance.now();
|
|
119
|
+
cacheNames.forEach(name => cacheManager.deleteCache(name));
|
|
120
|
+
const endTime = performance.now();
|
|
121
|
+
|
|
122
|
+
const duration = endTime - startTime;
|
|
123
|
+
|
|
124
|
+
expect(duration).toBeLessThan(1000);
|
|
125
|
+
expect(cacheManager.getCacheNames()).toHaveLength(0);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test('should cleanup pattern matcher cache', () => {
|
|
129
|
+
// Create many unique patterns to fill cache
|
|
130
|
+
for (let i = 0; i < 1000; i++) {
|
|
131
|
+
PatternMatcher.convertPatternToRegex(`pattern-${i}-*`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Clear cache and verify memory is freed
|
|
135
|
+
PatternMatcher.clearCache();
|
|
136
|
+
|
|
137
|
+
// Should still work after clear
|
|
138
|
+
expect(PatternMatcher.matchesPattern('test-key', 'test-*')).toBe(true);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
describe('React Hooks Performance', () => {
|
|
143
|
+
test('should handle many hook instances without memory leaks', () => {
|
|
144
|
+
const hooks: Array<ReturnType<typeof useCache<string>>> = [];
|
|
145
|
+
|
|
146
|
+
// Create many hook instances
|
|
147
|
+
for (let i = 0; i < 100; i++) {
|
|
148
|
+
const { result } = renderHook(() => useCache<string>(`test-cache-${i}`));
|
|
149
|
+
hooks.push(result.current);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Perform operations on all hooks
|
|
153
|
+
const startTime = performance.now();
|
|
154
|
+
hooks.forEach((hook, index) => {
|
|
155
|
+
act(() => {
|
|
156
|
+
hook.set(`key${index}`, `value${index}`);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
const endTime = performance.now();
|
|
160
|
+
|
|
161
|
+
const duration = endTime - startTime;
|
|
162
|
+
|
|
163
|
+
expect(duration).toBeLessThan(2000); // Should complete within 2 seconds
|
|
164
|
+
|
|
165
|
+
// Verify all operations worked
|
|
166
|
+
hooks.forEach((hook, index) => {
|
|
167
|
+
expect(hook.get(`key${index}`)).toBe(`value${index}`);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Cleanup all hooks
|
|
171
|
+
hooks.forEach(() => {
|
|
172
|
+
// Hooks will be automatically cleaned up when unmounted
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
test('should handle rapid hook re-renders efficiently', () => {
|
|
177
|
+
const { result, rerender } = renderHook(() => useCache<string>('rapid-cache'));
|
|
178
|
+
|
|
179
|
+
const startTime = performance.now();
|
|
180
|
+
|
|
181
|
+
// Perform many rapid operations
|
|
182
|
+
for (let i = 0; i < 1000; i++) {
|
|
183
|
+
act(() => {
|
|
184
|
+
result.current.set(`key${i}`, `value${i}`);
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const endTime = performance.now();
|
|
189
|
+
const duration = endTime - startTime;
|
|
190
|
+
|
|
191
|
+
expect(duration).toBeLessThan(3000); // Should complete within 3 seconds
|
|
192
|
+
expect(result.current.getStats().size).toBeLessThanOrEqual(100); // Limited by eviction
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
describe('Stress Tests', () => {
|
|
197
|
+
test('should handle concurrent operations safely', async () => {
|
|
198
|
+
const cache = new Cache<string>({ maxSize: 1000 });
|
|
199
|
+
const promises: Promise<void>[] = [];
|
|
200
|
+
|
|
201
|
+
// Create concurrent operations
|
|
202
|
+
for (let i = 0; i < 100; i++) {
|
|
203
|
+
promises.push(
|
|
204
|
+
new Promise<void>((resolve) => {
|
|
205
|
+
setTimeout(() => {
|
|
206
|
+
for (let j = 0; j < 10; j++) {
|
|
207
|
+
const key = `concurrent-${i}-${j}`;
|
|
208
|
+
const value = `value-${i}-${j}`;
|
|
209
|
+
cache.set(key, value);
|
|
210
|
+
cache.get(key);
|
|
211
|
+
}
|
|
212
|
+
resolve();
|
|
213
|
+
}, Math.random() * 100);
|
|
214
|
+
})
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Wait for all operations to complete
|
|
219
|
+
await Promise.all(promises);
|
|
220
|
+
|
|
221
|
+
// Verify cache is in consistent state
|
|
222
|
+
const stats = cache.getStats();
|
|
223
|
+
expect(stats.size).toBeLessThanOrEqual(1000);
|
|
224
|
+
expect(stats.hits + stats.misses).toBeGreaterThan(0);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
test('should handle TTL cache under stress', async () => {
|
|
228
|
+
jest.useFakeTimers();
|
|
229
|
+
|
|
230
|
+
const cache = new TTLCache<string>({
|
|
231
|
+
maxSize: 500,
|
|
232
|
+
defaultTTL: 100,
|
|
233
|
+
cleanupIntervalMs: 50
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// Add many entries with short TTL
|
|
237
|
+
for (let i = 0; i < 1000; i++) {
|
|
238
|
+
cache.set(`stress-key${i}`, `stress-value${i}`);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Advance time to trigger multiple cleanup cycles
|
|
242
|
+
for (let i = 0; i < 10; i++) {
|
|
243
|
+
jest.advanceTimersByTime(50);
|
|
244
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Cache should handle stress without errors
|
|
248
|
+
expect(() => cache.get('any-key')).not.toThrow();
|
|
249
|
+
|
|
250
|
+
const stats = cache.getStats();
|
|
251
|
+
expect(stats.expirations).toBeGreaterThan(0);
|
|
252
|
+
|
|
253
|
+
cache.destroy();
|
|
254
|
+
jest.useRealTimers();
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
test('should handle pattern matching stress test', () => {
|
|
258
|
+
const patterns: string[] = [];
|
|
259
|
+
const keys: string[] = [];
|
|
260
|
+
|
|
261
|
+
// Generate many patterns and keys
|
|
262
|
+
for (let i = 0; i < 1000; i++) {
|
|
263
|
+
patterns.push(`pattern-${i}-*`);
|
|
264
|
+
keys.push(`pattern-${i}-value`);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const startTime = performance.now();
|
|
268
|
+
|
|
269
|
+
// Test all pattern matches
|
|
270
|
+
patterns.forEach((pattern, index) => {
|
|
271
|
+
PatternMatcher.matchesPattern(keys[index], pattern);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
const endTime = performance.now();
|
|
275
|
+
const duration = endTime - startTime;
|
|
276
|
+
|
|
277
|
+
expect(duration).toBeLessThan(100); // Should be very fast with caching
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
describe('Memory Leak Detection', () => {
|
|
282
|
+
test('should not leak memory with repeated cache operations', () => {
|
|
283
|
+
const cache = new Cache<string>();
|
|
284
|
+
const initialMemory = process.memoryUsage().heapUsed;
|
|
285
|
+
|
|
286
|
+
// Perform many operations
|
|
287
|
+
for (let cycle = 0; cycle < 100; cycle++) {
|
|
288
|
+
// Add many entries
|
|
289
|
+
for (let i = 0; i < 100; i++) {
|
|
290
|
+
cache.set(`cycle-${cycle}-key-${i}`, `value-${i}`);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Clear cache
|
|
294
|
+
cache.clear();
|
|
295
|
+
|
|
296
|
+
// Force garbage collection if available
|
|
297
|
+
if (global.gc) {
|
|
298
|
+
global.gc();
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const finalMemory = process.memoryUsage().heapUsed;
|
|
303
|
+
const memoryIncrease = finalMemory - initialMemory;
|
|
304
|
+
|
|
305
|
+
// Memory increase should be minimal (allowing for some variance)
|
|
306
|
+
expect(memoryIncrease).toBeLessThan(10 * 1024 * 1024); // Less than 10MB
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
test('should not leak memory with repeated hook mount/unmount', () => {
|
|
310
|
+
const initialMemory = process.memoryUsage().heapUsed;
|
|
311
|
+
|
|
312
|
+
// Mount and unmount hooks repeatedly
|
|
313
|
+
for (let i = 0; i < 100; i++) {
|
|
314
|
+
const { unmount } = renderHook(() => useCache<string>(`test-cache-${i}`));
|
|
315
|
+
|
|
316
|
+
act(() => {
|
|
317
|
+
// Perform some operations
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
unmount();
|
|
321
|
+
|
|
322
|
+
// Force garbage collection if available
|
|
323
|
+
if (global.gc) {
|
|
324
|
+
global.gc();
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const finalMemory = process.memoryUsage().heapUsed;
|
|
329
|
+
const memoryIncrease = finalMemory - initialMemory;
|
|
330
|
+
|
|
331
|
+
// Memory increase should be minimal
|
|
332
|
+
expect(memoryIncrease).toBeLessThan(5 * 1024 * 1024); // Less than 5MB
|
|
333
|
+
});
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
describe('Performance Regression Tests', () => {
|
|
337
|
+
test('should maintain performance with large cache sizes', () => {
|
|
338
|
+
const sizes = [100, 1000, 5000, 10000];
|
|
339
|
+
|
|
340
|
+
sizes.forEach(size => {
|
|
341
|
+
const cache = new Cache<string>({ maxSize: size });
|
|
342
|
+
const startTime = performance.now();
|
|
343
|
+
|
|
344
|
+
// Fill cache
|
|
345
|
+
for (let i = 0; i < size; i++) {
|
|
346
|
+
cache.set(`key${i}`, `value${i}`);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Random access pattern
|
|
350
|
+
for (let i = 0; i < size; i++) {
|
|
351
|
+
const randomIndex = Math.floor(Math.random() * size);
|
|
352
|
+
cache.get(`key${randomIndex}`);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const endTime = performance.now();
|
|
356
|
+
const duration = endTime - startTime;
|
|
357
|
+
|
|
358
|
+
// Performance should scale reasonably
|
|
359
|
+
const opsPerMs = (size * 2) / duration; // inserts + gets
|
|
360
|
+
expect(opsPerMs).toBeGreaterThan(10); // At least 10 ops per ms
|
|
361
|
+
});
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
test('should maintain pattern matching performance', () => {
|
|
365
|
+
const patternComplexities = [
|
|
366
|
+
'simple:*',
|
|
367
|
+
'complex:*:pattern:*:here',
|
|
368
|
+
'very:complex:pattern:*:with:many:parts:*:and:sections',
|
|
369
|
+
];
|
|
370
|
+
|
|
371
|
+
patternComplexities.forEach(pattern => {
|
|
372
|
+
const startTime = performance.now();
|
|
373
|
+
|
|
374
|
+
// Test many matches
|
|
375
|
+
for (let i = 0; i < 1000; i++) {
|
|
376
|
+
PatternMatcher.matchesPattern(`test:${i}:value`, pattern);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const endTime = performance.now();
|
|
380
|
+
const duration = endTime - startTime;
|
|
381
|
+
|
|
382
|
+
// Even complex patterns should be fast
|
|
383
|
+
expect(duration).toBeLessThan(50); // Less than 50ms for 1000 matches
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test Setup
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Mock console methods in test environment
|
|
6
|
+
(global as any).console = {
|
|
7
|
+
...console,
|
|
8
|
+
log: jest.fn(),
|
|
9
|
+
warn: jest.fn(),
|
|
10
|
+
error: jest.fn(),
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// Mock __DEV__ for testing
|
|
14
|
+
(global as any).__DEV__ = true;
|
|
15
|
+
|
|
16
|
+
// Mock timers globally
|
|
17
|
+
jest.useFakeTimers({
|
|
18
|
+
doNotFake: ['nextTick', 'setImmediate']
|
|
19
|
+
});
|