package greenledsocket import ( "context" "encoding/json" "io" "net" "os" "path/filepath" "testing" "time" "tera-clone/services/tera-api/internal/hardware/greenled" ) func TestServerRespondsToNewlineFramedRequestWithoutWaitingForEOF(t *testing.T) { serverConnection, clientConnection := net.Pipe() defer clientConnection.Close() done := make(chan struct{}) go func() { (Server{}).handleConnection(serverConnection) close(done) }() if err := clientConnection.SetDeadline(time.Now().Add(time.Second)); err != nil { t.Fatal(err) } if _, err := io.WriteString(clientConnection, "{\"action\":\"unsupported\"}\n"); err != nil { t.Fatal(err) } var result response if err := json.NewDecoder(clientConnection).Decode(&result); err != nil { t.Fatalf("decode response before client EOF: %v", err) } if result.Code != "validation_failed" || result.Error != "hardware control action is not supported" { t.Fatalf("response = %#v", result) } select { case <-done: case <-time.After(time.Second): t.Fatal("server did not close the completed request") } } func TestClientAndServerControlOnlyMappedGPIOLEDs(t *testing.T) { root := t.TempDir() for channel := 1; channel <= greenled.ChannelCount; channel++ { name := "ch" + twoDigits(channel) + "-green-led-force" if err := os.MkdirAll(filepath.Join(root, name), 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(root, name, "brightness"), []byte("0\n"), 0o644); err != nil { t.Fatal(err) } } socketPath := filepath.Join(t.TempDir(), "green-leds.sock") listener, err := net.Listen("unix", socketPath) if err != nil { t.Skipf("unix sockets unavailable: %v", err) } defer listener.Close() server := Server{Controller: greenled.NewSysfsController(root)} done := make(chan error, 1) go func() { done <- server.Serve(listener) }() client := NewClient(socketPath) states, err := client.States(context.Background()) if err != nil || len(states) != greenled.ChannelCount || states[8].Channel != "CH09" || states[8].I2CAddress != "0x21" || states[8].GPIOOffset != 0 { t.Fatalf("states = %#v, %v", states, err) } state, err := client.SetForce(context.Background(), "CH09", true) if err != nil || !state.Forced { t.Fatalf("set force = %#v, %v", state, err) } state, err = client.Pulse(context.Background(), "CH09", greenled.MinPulseDuration) if err != nil || state.Forced { t.Fatalf("pulse = %#v, %v", state, err) } if err := listener.Close(); err != nil { t.Fatal(err) } select { case err := <-done: if err != nil { t.Fatal(err) } case <-time.After(time.Second): t.Fatal("server did not stop") } } func twoDigits(value int) string { return string(rune('0'+value/10)) + string(rune('0'+value%10)) }