Skip to main content
Glama

MCP Clipboard Server

MIT License
8
3
  • Apple
  • Linux
race_test.go3.53 kB
package main import ( "context" "fmt" "sync" "sync/atomic" "testing" "time" ) // Test for race condition in updateClipboard method func TestUpdateClipboardRace(t *testing.T) { cs := NewClipboardServer() var wg sync.WaitGroup numGoroutines := 100 // Start multiple goroutines calling updateClipboard concurrently for i := 0; i < numGoroutines; i++ { wg.Add(1) go func(id int) { defer wg.Done() for j := 0; j < 10; j++ { content := fmt.Sprintf("content-%d-%d", id, j) cs.updateClipboard(content) time.Sleep(time.Microsecond) // Small delay to increase race window } }(i) } wg.Wait() // If no race detector warnings, the test passes // But the race condition still exists in the logic t.Log("Concurrent updateClipboard calls completed") } // Test for race condition in cancel field access func TestCancelFieldRace(t *testing.T) { cs := NewClipboardServer() var wg sync.WaitGroup // Goroutine 1: Repeatedly set cancel field wg.Add(1) go func() { defer wg.Done() for i := 0; i < 1000; i++ { cancel := context.CancelFunc(func() {}) // Dummy cancel function cs.cancel.Store(&cancel) // FIXED: Use atomic store time.Sleep(time.Microsecond) } }() // Goroutine 2: Repeatedly read cancel field wg.Add(1) go func() { defer wg.Done() for i := 0; i < 1000; i++ { if cancelPtr := cs.cancel.Load(); cancelPtr != nil { // FIXED: Use atomic load // Access cancel field } time.Sleep(time.Microsecond) } }() wg.Wait() t.Log("Concurrent cancel field access completed") } // Test proper atomic operations func TestAtomicOperations(t *testing.T) { cs := NewClipboardServer() var wg sync.WaitGroup numGoroutines := 50 // Test atomic running flag for i := 0; i < numGoroutines; i++ { wg.Add(1) go func() { defer wg.Done() // Try to set running state if atomic.CompareAndSwapInt32(&cs.running, 0, 1) { // Simulate work time.Sleep(time.Millisecond) atomic.StoreInt32(&cs.running, 0) } }() } wg.Wait() t.Log("Atomic operations test completed") } // Test CAS retry limit functionality func TestUpdateClipboardRetryLimit(t *testing.T) { cs := NewClipboardServer() // Initialize with some content cs.updateClipboard("initial-content") // Test that normal operation still works updated := cs.updateClipboard("new-content") if !updated { t.Error("Expected content update to succeed") } content, _ := cs.getLastClipboard() if content != "new-content" { t.Errorf("Expected 'new-content', got '%s'", content) } t.Log("CAS retry limit functionality verified") } // Test session file tracking during shutdown func TestSessionFileTrackingDuringShutdown(t *testing.T) { cs := NewClipboardServer() // Set running state atomic.StoreInt32(&cs.running, 1) // Should track file when running cs.addSessionFile("/tmp/test1.txt") // Stop the server atomic.StoreInt32(&cs.running, 0) // Should not track file when stopped cs.addSessionFile("/tmp/test2.txt") cs.filesMutex.Lock() fileCount := len(cs.sessionFiles) cs.filesMutex.Unlock() if fileCount != 1 { t.Errorf("Expected 1 tracked file, got %d", fileCount) } t.Log("Session file tracking during shutdown test passed") } // Benchmark updateClipboard to show race impact func BenchmarkUpdateClipboardConcurrent(b *testing.B) { cs := NewClipboardServer() b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { content := fmt.Sprintf("benchmark-content-%d", i) cs.updateClipboard(content) i++ } }) }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/standardbeagle/mcp-clip'

If you have feedback or need assistance with the MCP directory API, please join our Discord server