package telegram.files; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; class AvgSpeedTest { private AvgSpeed avgSpeed; private static final int TEST_INTERVAL = 100; // 100 seconds for testing private static final int SMOOTHING_WINDOW = 3; @BeforeEach void setUp() { avgSpeed = new AvgSpeed(TEST_INTERVAL, SMOOTHING_WINDOW); } @Test void testInitialState() { assertEquals(0, avgSpeed.getSpeed()); assertEquals(0, avgSpeed.getMedianSpeed()); assertEquals(0, avgSpeed.getMaxSpeed()); assertEquals(0, avgSpeed.getMinSpeed()); } @Test void testConstantSpeed() { // Simulate constant download speed of 100 bytes per second long baseTime = System.currentTimeMillis(); avgSpeed.update(0L, baseTime); avgSpeed.update(1000L, baseTime + 10000); // 100 bytes/sec for 10 seconds avgSpeed.update(2000L, baseTime + 20000); // 100 bytes/sec for another 10 seconds AvgSpeed.SpeedStats stats = avgSpeed.getSpeedStats(); assertEquals(100, stats.avgSpeed(), 1.0, "Average speed should be 100 bytes/sec"); } @Test void testSpeedWithPause() { long baseTime = System.currentTimeMillis(); // Download at 100 bytes/sec avgSpeed.update(1L, baseTime); avgSpeed.update(1001L, baseTime + 10000); // 100 bytes/sec // Pause for 10 seconds avgSpeed.update(1000L, baseTime + 20000); // Resume at 100 bytes/sec avgSpeed.update(2000L, baseTime + 30000); // Average speed should be: 2000 bytes / 30 seconds = 66.67 bytes/sec assertEquals(67, avgSpeed.getSpeed(), 1.0, "Speed should account for pause period"); } @Test void testDownloadRestart() { long baseTime = System.currentTimeMillis(); // Initial download avgSpeed.update(1L, baseTime); avgSpeed.update(1001L, baseTime + 10000); // 100 bytes/sec // Restart download avgSpeed.update(1L, baseTime + 15000); avgSpeed.update(501L, baseTime + 20000); // 100 bytes/sec after restart AvgSpeed.SpeedStats stats = avgSpeed.getSpeedStats(); assertTrue(stats.maxSpeed() >= 100, "Max speed should capture the highest speed segment"); } @Test void testSpeedFluctuation() { long baseTime = System.currentTimeMillis(); avgSpeed.update(0L, baseTime); avgSpeed.update(500L, baseTime + 5000); // 100 bytes/sec avgSpeed.update(2500L, baseTime + 10000); // 400 bytes/sec avgSpeed.update(3000L, baseTime + 15000); // 100 bytes/sec AvgSpeed.SpeedStats stats = avgSpeed.getSpeedStats(); assertTrue(stats.maxSpeed() >= 300, "Max speed should capture high speed period"); assertTrue(stats.minSpeed() == 250, "Min speed should capture low speed period"); } @Test void testDataSmoothing() { long baseTime = System.currentTimeMillis(); avgSpeed.update(0L, baseTime); avgSpeed.update(1000L, baseTime + 10000); // 100 bytes/sec avgSpeed.update(2000L, baseTime + 20000); // 100 bytes/sec avgSpeed.update(7000L, baseTime + 30000); // 500 bytes/sec (spike) avgSpeed.update(8000L, baseTime + 40000); // 100 bytes/sec AvgSpeed.SpeedStats stats = avgSpeed.getSpeedStats(); assertTrue(stats.avgSpeed() < 300, "Smoothed speed should be less than the spike value"); } @Test void testOldDataRemoval() { long baseTime = System.currentTimeMillis(); // Add initial points avgSpeed.update(0L, baseTime); avgSpeed.update(1000L, baseTime + 10000); // 100 bytes/sec // Add point beyond interval // Note: Need to move forward by interval milliseconds plus a buffer avgSpeed.update(2000L, baseTime + (TEST_INTERVAL * 1000L) + 20000); long speed = avgSpeed.getSpeed(); assertTrue(speed < 50, "Speed should be very low when most points are outside the interval"); } @Test void testMedianCalculation() { long baseTime = System.currentTimeMillis(); // Create a sequence of very distinct speeds for clear median avgSpeed.update(0L, baseTime); avgSpeed.update(1000L, baseTime + 5000); // 200 bytes/sec avgSpeed.update(1500L, baseTime + 10000); // 100 bytes/sec avgSpeed.update(3500L, baseTime + 15000); // 400 bytes/sec long medianSpeed = avgSpeed.getMedianSpeed(); assertTrue(medianSpeed >= 100 && medianSpeed <= 400, "Median speed should be between the lowest and highest speeds"); } @Test void testExtremeCases() { long baseTime = System.currentTimeMillis(); // Test with zero time difference avgSpeed.update(0L, baseTime); avgSpeed.update(100L, baseTime); assertEquals(0, avgSpeed.getSpeed(), "Speed should be 0 when time difference is 0"); // Test with large downloads avgSpeed.update(0L, baseTime + 1000); avgSpeed.update(500000L, baseTime + 6000); // 100,000 bytes/sec assertTrue(avgSpeed.getSpeed() > 0, "Speed should be calculated correctly with large numbers"); } @Test void shouldShowDifferentSpeedsOverTime() { // Given AvgSpeed avgSpeed = new AvgSpeed(60); // 1 minute interval long baseTime = System.currentTimeMillis(); // When - simulate download over 2 minutes with varying speeds // First 30 seconds - constant speed for (int i = 0; i < 30; i++) { avgSpeed.update(1024L * 1024L * i, // 1MB increments baseTime + (i * 1000L)); // 1 second intervals } // Record speeds at 30 second mark AvgSpeed.SpeedStats stats30s = avgSpeed.getSpeedStats(); // Next 30 seconds - faster speed for (int i = 30; i < 60; i++) { avgSpeed.update(1024L * 1024L * (i * 2), // 2MB increments baseTime + (i * 1000L)); // 1 second intervals } // Record speeds at 60 second mark AvgSpeed.SpeedStats stats60s = avgSpeed.getSpeedStats(); // Another 30 seconds - slower speed for (int i = 60; i < 90; i++) { avgSpeed.update(1024L * 1024L * (i + 60), // slower increments baseTime + (i * 1000L)); // 1 second intervals } // Record speeds at 90 second mark AvgSpeed.SpeedStats stats90s = avgSpeed.getSpeedStats(); // 30s with big speed changes for (int i = 90; i < 120; i++) { avgSpeed.update(1024L * 1024L * (i * 4), // 4MB increments baseTime + (i * 1000L)); // 1 second intervals } // Record speeds at 120 second mark AvgSpeed.SpeedStats stats120s = avgSpeed.getSpeedStats(); // Then System.out.println("30s stats: " + stats30s); System.out.println("60s stats: " + stats60s); System.out.println("90s stats: " + stats90s); System.out.println("120s stats: " + stats120s); } }