1package selection
2
3import (
4 "bufio"
5 "context"
6 "fmt"
7 "os"
8 "strconv"
9 "strings"
10 "testing"
11 "time"
12
13 "github.com/stretchr/testify/assert"
14 "github.com/stretchr/testify/require"
15
16 "github.com/bnema/nefercap/internal/ports"
17)
18
19// TestSmokeSelect opens the real overlays. It needs a Wayland compositor with
20// layer-shell and Vulkan plus an input driver, so it runs only when
21// NEFERCAP_SELECTION_SMOKE names the expected result: "region" (on the first
22// output), "monitor" (whole monitor of output number NEFERCAP_SELECTION_WANT,
23// default 1) or "abort". NEFERCAP_SELECTION_OUTPUTS lists output names,
24// comma-separated; output IDs are their 1-based positions.
25func TestSmokeSelect(t *testing.T) {
26 want := os.Getenv("NEFERCAP_SELECTION_SMOKE")
27 if want == "" {
28 t.Skip("set NEFERCAP_SELECTION_SMOKE=region|monitor|abort on a Wayland session")
29 }
30 var outs []ports.Output
31 for i, name := range strings.Split(os.Getenv("NEFERCAP_SELECTION_OUTPUTS"), ",") {
32 outs = append(outs, ports.Output{ID: uint32(i + 1), Name: name})
33 }
34 ctx, cancel := context.WithTimeout(context.Background(), 40*time.Second)
35 defer cancel()
36 peak := samplePeakRSS(ctx)
37 sel, ok, err := New(ports.Record, ports.VideoSettings{}, nil, false).Select(ctx, outs)
38 cancel()
39 fmt.Printf("SMOKE outputs=%d peak_rss_kib=%d\n", len(outs), <-peak)
40 require.NoError(t, err)
41 switch want {
42 case "abort":
43 assert.False(t, ok)
44 case "monitor":
45 n, _ := strconv.Atoi(os.Getenv("NEFERCAP_SELECTION_WANT"))
46 n = max(n, 1)
47 require.True(t, ok)
48 assert.Equal(t, ports.Target{OutputID: uint32(n)}, sel.Target)
49 assert.Equal(t, DefaultFPS, sel.Video.FPS)
50 case "region":
51 require.True(t, ok)
52 assert.Equal(t, ports.Target{OutputID: 1, Region: ports.Region{X: 100, Y: 80, Width: 200, Height: 120}}, sel.Target)
53 }
54}
55
56// samplePeakRSS reports the highest VmRSS of this process seen until ctx ends.
57func samplePeakRSS(ctx context.Context) <-chan int {
58 out := make(chan int, 1)
59 go func() {
60 peak := 0
61 for t := time.NewTicker(50 * time.Millisecond); ; {
62 select {
63 case <-ctx.Done():
64 out <- peak
65 return
66 case <-t.C:
67 peak = max(peak, vmRSS())
68 }
69 }
70 }()
71 return out
72}
73
74func vmRSS() int {
75 f, err := os.Open("/proc/self/status")
76 if err != nil {
77 return 0
78 }
79 defer f.Close()
80 sc := bufio.NewScanner(f)
81 for sc.Scan() {
82 if v, ok := strings.CutPrefix(sc.Text(), "VmRSS:"); ok {
83 n, _ := strconv.Atoi(strings.Fields(v)[0])
84 return n
85 }
86 }
87 return 0
88}