package eq2net import ( "net" "testing" "time" ) func TestStreamCreation(t *testing.T) { config := DefaultStreamConfig() stream := NewEQStream(config) if stream == nil { t.Fatal("Failed to create stream") } if stream.GetState() != StreamStateDisconnected { t.Errorf("Expected disconnected state, got %v", stream.GetState()) } // Test state transitions if !stream.compareAndSwapState(StreamStateDisconnected, StreamStateConnecting) { t.Error("Failed to transition to connecting state") } if stream.GetState() != StreamStateConnecting { t.Errorf("Expected connecting state, got %v", stream.GetState()) } // Clean up stream.Close() } func TestStreamConfig(t *testing.T) { config := DefaultStreamConfig() if config.MaxPacketSize != 512 { t.Errorf("Expected max packet size 512, got %d", config.MaxPacketSize) } if config.WindowSize != 2048 { t.Errorf("Expected window size 2048, got %d", config.WindowSize) } if config.RetransmitTimeMs != 500 { t.Errorf("Expected retransmit time 500ms, got %d", config.RetransmitTimeMs) } } func TestRTTCalculation(t *testing.T) { stream := NewEQStream(nil) // Test first RTT sample stream.updateRTT(100000) // 100ms in microseconds if stream.rtt.Load() != 100000 { t.Errorf("Expected RTT 100000, got %d", stream.rtt.Load()) } // Test subsequent samples stream.updateRTT(120000) // 120ms stream.updateRTT(80000) // 80ms // RTT should be smoothed rtt := stream.rtt.Load() if rtt < 80000 || rtt > 120000 { t.Errorf("RTT outside expected range: %d", rtt) } // RTO should be set rto := stream.rto.Load() if rto < 200000 { // Minimum 200ms t.Errorf("RTO below minimum: %d", rto) } } func TestPacketSequencing(t *testing.T) { stream := NewEQStream(nil) // Test sequence number generation seq1 := stream.nextSeqOut.Add(1) seq2 := stream.nextSeqOut.Add(1) seq3 := stream.nextSeqOut.Add(1) if seq1 != 1 || seq2 != 2 || seq3 != 3 { t.Errorf("Sequence numbers not incrementing correctly: %d, %d, %d", seq1, seq2, seq3) } } func TestSendWindow(t *testing.T) { stream := NewEQStream(nil) // Add packet to send window packet := NewEQProtocolPacket(OPPacket, []byte("test")) packet.Sequence = 1 stream.sendWindowMu.Lock() stream.sendWindow[1] = &sendPacket{ packet: packet, sentTime: time.Now(), attempts: 1, nextRetry: time.Now().Add(500 * time.Millisecond), } stream.sendWindowMu.Unlock() // Process ACK stream.processAck(1) // Verify packet removed from window stream.sendWindowMu.RLock() _, exists := stream.sendWindow[1] stream.sendWindowMu.RUnlock() if exists { t.Error("Packet not removed from send window after ACK") } } func TestFragmentation(t *testing.T) { stream := NewEQStream(nil) // Create large data that needs fragmentation largeData := make([]byte, 1000) for i := range largeData { largeData[i] = byte(i % 256) } // Fragment the data fragments := stream.FragmentPacket(largeData, 100) if len(fragments) == 0 { t.Fatal("No fragments created") } // Verify fragments expectedFragments := (len(largeData) + 93) / 94 // 100 - 6 header bytes if len(fragments) != expectedFragments { t.Errorf("Expected %d fragments, got %d", expectedFragments, len(fragments)) } // Verify each fragment has correct opcode for _, frag := range fragments { if frag.Opcode != OPFragment { t.Errorf("Fragment has wrong opcode: %04x", frag.Opcode) } } } // TestMockConnection tests basic packet flow without real network func TestMockConnection(t *testing.T) { // Create mock packet conn clientConn, serverConn := net.Pipe() defer clientConn.Close() defer serverConn.Close() // Note: net.Pipe creates a stream connection, not packet-based // For a real test, we'd need to use actual UDP sockets // This is just to verify compilation config := DefaultStreamConfig() stream := NewEQStream(config) // Verify stream creation if stream == nil { t.Fatal("Failed to create stream") } stream.Close() } func TestServerCreation(t *testing.T) { config := DefaultServerConfig() server := NewEQ2Server(config) if server == nil { t.Fatal("Failed to create server") } // Set callbacks connectCount := 0 disconnectCount := 0 server.SetCallbacks( func(s *EQStream) { connectCount++ }, func(s *EQStream, reason string) { disconnectCount++ }, ) // Note: We don't actually start the server in unit tests // as it would require binding to a real port }