package relaydev import ( "context" "net/http" "net/http/httptest" "strings" "sync" "testing" ) // The pattern form: one URL pair for the whole board, {relay} substituted. func TestHTTPGenericPattern(t *testing.T) { var mu sync.Mutex var got []string srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { mu.Lock() got = append(got, r.URL.String()) mu.Unlock() })) defer srv.Close() d := NewHTTPGeneric(nil, nil, srv.URL+"/relay?n={relay}&state=on", srv.URL+"/relay?n={relay}&state=off", "", "", 4) if err := d.Set(context.Background(), 2, true); err != nil { t.Fatalf("Set on: %v", err) } if err := d.Set(context.Background(), 3, false); err != nil { t.Fatalf("Set off: %v", err) } mu.Lock() defer mu.Unlock() want := []string{"/relay?n=2&state=on", "/relay?n=3&state=off"} if strings.Join(got, " ") != strings.Join(want, " ") { t.Errorf("requested %v, want %v", got, want) } } // The per-relay form, which is the reason this driver exists: a hand-made // switch often has URLs with nothing in common between channels, and no // pattern can express that. func TestHTTPGenericPerRelayURLsWinOverThePattern(t *testing.T) { var mu sync.Mutex var got []string srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { mu.Lock() got = append(got, r.URL.Path) mu.Unlock() })) defer srv.Close() d := NewHTTPGeneric( []string{srv.URL + "/FF0101", "", srv.URL + "/weird/on"}, []string{srv.URL + "/FF0100", "", ""}, srv.URL+"/pattern/on/{relay}", srv.URL+"/pattern/off/{relay}", "", "", 3) _ = d.Set(context.Background(), 1, true) // its own URL _ = d.Set(context.Background(), 2, true) // empty → falls back to the pattern _ = d.Set(context.Background(), 3, false) // no OFF of its own → pattern mu.Lock() defer mu.Unlock() want := []string{"/FF0101", "/pattern/on/2", "/pattern/off/3"} if strings.Join(got, " ") != strings.Join(want, " ") { t.Errorf("requested %v, want %v", got, want) } } // A switch with the ON URLs filled and OFF left empty latches. The error has to // name the direction, or the operator cannot tell which half is missing. func TestHTTPGenericNamesTheMissingDirection(t *testing.T) { d := NewHTTPGeneric([]string{"http://x/on"}, nil, "", "", "", "", 1) err := d.Set(context.Background(), 1, false) if err == nil || !strings.Contains(err.Error(), "OFF") { t.Errorf("err = %v, want it to name the OFF direction", err) } } // Status reports what was commanded: these boxes have nothing to read. func TestHTTPGenericRemembersWhatItCommanded(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {})) defer srv.Close() d := NewHTTPGeneric(nil, nil, srv.URL+"/on/{relay}", srv.URL+"/off/{relay}", "", "", 3) _ = d.Set(context.Background(), 2, true) st, err := d.Status(context.Background()) if err != nil { t.Fatalf("Status: %v", err) } if len(st) != 3 || st[0] || !st[1] || st[2] { t.Errorf("state = %v, want only relay 2 on", st) } }