performance-monitor.test.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
  2. describe('Performance Monitor', () => {
  3. let PerformanceMonitor
  4. let monitor
  5. beforeEach(async () => {
  6. // Mock os module
  7. vi.mock('os', () => ({
  8. cpus: () => [
  9. {
  10. times: { idle: 1000, user: 500, sys: 300, nice: 0, irq: 0 }
  11. },
  12. {
  13. times: { idle: 1100, user: 450, sys: 250, nice: 0, irq: 0 }
  14. },
  15. {
  16. times: { idle: 900, user: 600, sys: 350, nice: 0, irq: 0 }
  17. },
  18. {
  19. times: { idle: 950, user: 550, sys: 300, nice: 0, irq: 0 }
  20. }
  21. ]
  22. }))
  23. // Dynamically import after mock is set up
  24. PerformanceMonitor = (await import('../scripts/utils/performance-monitor.js')).default
  25. monitor = new PerformanceMonitor()
  26. })
  27. afterEach(() => {
  28. if (monitor) {
  29. monitor.stop()
  30. }
  31. vi.clearAllMocks()
  32. })
  33. it('should initialize correctly', () => {
  34. expect(monitor).toBeDefined()
  35. expect(monitor.metrics).toBeDefined()
  36. expect(monitor.metrics.downloads).toEqual([])
  37. expect(monitor.metrics.conversions).toEqual([])
  38. expect(monitor.metrics.cpuSamples).toEqual([])
  39. expect(monitor.metrics.memorySamples).toEqual([])
  40. expect(monitor.startTime).toBeGreaterThan(0)
  41. })
  42. it('should sample system metrics', () => {
  43. monitor.sampleSystemMetrics()
  44. expect(monitor.metrics.cpuSamples.length).toBeGreaterThan(0)
  45. expect(monitor.metrics.memorySamples.length).toBeGreaterThan(0)
  46. const cpuSample = monitor.metrics.cpuSamples[0]
  47. expect(cpuSample).toHaveProperty('timestamp')
  48. expect(cpuSample).toHaveProperty('usage')
  49. expect(cpuSample).toHaveProperty('cores')
  50. expect(cpuSample.cores).toBeGreaterThan(0) // At least 1 core
  51. const memSample = monitor.metrics.memorySamples[0]
  52. expect(memSample).toHaveProperty('timestamp')
  53. expect(memSample).toHaveProperty('heapUsed')
  54. expect(memSample).toHaveProperty('heapTotal')
  55. })
  56. it('should record downloads', () => {
  57. const downloadData = {
  58. videoId: 'test-video-1',
  59. duration: 5000,
  60. status: 'completed'
  61. }
  62. monitor.recordDownload(downloadData)
  63. expect(monitor.metrics.downloads.length).toBe(1)
  64. expect(monitor.metrics.downloads[0].videoId).toBe('test-video-1')
  65. expect(monitor.metrics.downloads[0].duration).toBe(5000)
  66. expect(monitor.metrics.downloads[0].success).toBe(true)
  67. })
  68. it('should record failed downloads', () => {
  69. const downloadData = {
  70. videoId: 'test-video-2',
  71. duration: 2000,
  72. status: 'error'
  73. }
  74. monitor.recordDownload(downloadData)
  75. expect(monitor.metrics.downloads.length).toBe(1)
  76. expect(monitor.metrics.downloads[0].success).toBe(false)
  77. })
  78. it('should record conversions', () => {
  79. const conversionData = {
  80. videoId: 'test-video-3',
  81. duration: 8000,
  82. usedGPU: true
  83. }
  84. monitor.recordConversion(conversionData)
  85. expect(monitor.metrics.conversions.length).toBe(1)
  86. expect(monitor.metrics.conversions[0].videoId).toBe('test-video-3')
  87. expect(monitor.metrics.conversions[0].duration).toBe(8000)
  88. expect(monitor.metrics.conversions[0].usedGPU).toBe(true)
  89. })
  90. it('should get comprehensive stats', () => {
  91. // Add some data
  92. monitor.recordDownload({ videoId: 'v1', duration: 5000, status: 'completed' })
  93. monitor.recordDownload({ videoId: 'v2', duration: 3000, status: 'completed' })
  94. monitor.recordDownload({ videoId: 'v3', duration: 2000, status: 'error' })
  95. monitor.recordConversion({ videoId: 'v1', duration: 8000, usedGPU: true })
  96. monitor.recordConversion({ videoId: 'v2', duration: 6000, usedGPU: false })
  97. const stats = monitor.getStats()
  98. expect(stats).toHaveProperty('downloads')
  99. expect(stats.downloads.total).toBe(3)
  100. expect(stats.downloads.successful).toBe(2)
  101. expect(stats.downloads.failed).toBe(1)
  102. expect(stats).toHaveProperty('conversions')
  103. expect(stats.conversions.total).toBe(2)
  104. expect(stats.conversions.gpu).toBe(1)
  105. expect(stats.conversions.cpu).toBe(1)
  106. expect(stats).toHaveProperty('system')
  107. expect(stats.system).toHaveProperty('currentCPU')
  108. expect(stats.system).toHaveProperty('currentMemory')
  109. expect(stats.system).toHaveProperty('uptime')
  110. })
  111. it('should limit CPU sample history to 100', () => {
  112. // Add more than 100 samples
  113. for (let i = 0; i < 150; i++) {
  114. monitor.sampleSystemMetrics()
  115. }
  116. expect(monitor.metrics.cpuSamples.length).toBeLessThanOrEqual(100)
  117. expect(monitor.metrics.memorySamples.length).toBeLessThanOrEqual(100)
  118. })
  119. it('should limit download history to 1000', () => {
  120. // Add more than 1000 downloads
  121. for (let i = 0; i < 1050; i++) {
  122. monitor.recordDownload({
  123. videoId: `video-${i}`,
  124. duration: 1000,
  125. status: 'completed'
  126. })
  127. }
  128. expect(monitor.metrics.downloads.length).toBeLessThanOrEqual(1000)
  129. })
  130. it('should limit conversion history to 1000', () => {
  131. // Add more than 1000 conversions
  132. for (let i = 0; i < 1050; i++) {
  133. monitor.recordConversion({
  134. videoId: `video-${i}`,
  135. duration: 1000,
  136. usedGPU: i % 2 === 0
  137. })
  138. }
  139. expect(monitor.metrics.conversions.length).toBeLessThanOrEqual(1000)
  140. })
  141. it('should get current CPU usage', () => {
  142. monitor.sampleSystemMetrics()
  143. const currentCPU = monitor.getCurrentCPU()
  144. expect(currentCPU).toBeDefined()
  145. expect(typeof currentCPU).toBe('string')
  146. expect(parseFloat(currentCPU)).toBeGreaterThanOrEqual(0)
  147. expect(parseFloat(currentCPU)).toBeLessThanOrEqual(100)
  148. })
  149. it('should get current memory usage', () => {
  150. monitor.sampleSystemMetrics()
  151. const currentMemory = monitor.getCurrentMemory()
  152. expect(currentMemory).toBeDefined()
  153. expect(currentMemory).toHaveProperty('used')
  154. expect(currentMemory).toHaveProperty('total')
  155. expect(parseFloat(currentMemory.used)).toBeGreaterThan(0)
  156. expect(parseFloat(currentMemory.total)).toBeGreaterThan(0)
  157. })
  158. it('should calculate average CPU usage', () => {
  159. // Add some samples
  160. for (let i = 0; i < 20; i++) {
  161. monitor.sampleSystemMetrics()
  162. }
  163. const avgCPU = monitor.getAverageCPU(10)
  164. expect(avgCPU).toBeDefined()
  165. expect(typeof avgCPU).toBe('number')
  166. expect(avgCPU).toBeGreaterThanOrEqual(0)
  167. expect(avgCPU).toBeLessThanOrEqual(100)
  168. })
  169. it('should reset metrics', () => {
  170. // Add some data
  171. monitor.recordDownload({ videoId: 'v1', duration: 5000, status: 'completed' })
  172. monitor.recordConversion({ videoId: 'v1', duration: 8000, usedGPU: true })
  173. monitor.sampleSystemMetrics()
  174. // Reset
  175. monitor.reset()
  176. expect(monitor.metrics.downloads).toEqual([])
  177. expect(monitor.metrics.conversions).toEqual([])
  178. expect(monitor.metrics.cpuSamples).toEqual([])
  179. expect(monitor.metrics.memorySamples).toEqual([])
  180. })
  181. it('should stop monitoring', () => {
  182. expect(monitor.monitorInterval).not.toBeNull()
  183. monitor.stop()
  184. expect(monitor.monitorInterval).toBeNull()
  185. })
  186. it('should handle multiple stop calls gracefully', () => {
  187. monitor.stop()
  188. monitor.stop() // Should not throw
  189. expect(monitor.monitorInterval).toBeNull()
  190. })
  191. it('should return default values when no samples exist', () => {
  192. const newMonitor = new PerformanceMonitor()
  193. newMonitor.stop() // Stop sampling
  194. const currentCPU = newMonitor.getCurrentCPU()
  195. expect(currentCPU).toBe('0.0')
  196. const currentMemory = newMonitor.getCurrentMemory()
  197. expect(currentMemory.used).toBe('0.0')
  198. expect(currentMemory.total).toBe('0.0')
  199. newMonitor.stop()
  200. })
  201. it('should sample metrics automatically every 2 seconds', (done) => {
  202. const newMonitor = new PerformanceMonitor()
  203. // Wait for some automatic sampling
  204. setTimeout(() => {
  205. expect(newMonitor.metrics.cpuSamples.length).toBeGreaterThan(0)
  206. expect(newMonitor.metrics.memorySamples.length).toBeGreaterThan(0)
  207. newMonitor.stop()
  208. done()
  209. }, 2500)
  210. }, 3000)
  211. })