package core import ( "encoding/json" "llmsproxy/internal/lua" "net/http" "net/http/httptest" "testing" ) func TestLobsterExchangePreservesIdentity(t *testing.T) { var calls int ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { calls++ var b map[string]string if err := json.NewDecoder(r.Body).Decode(&b); err != nil { t.Error(err) } if b["authCode"] != "quote\"&code" || len(b["uuid"]) != 36 || b["firstKeyfrom"] == "" || b["firstKeyfrom"] == "cli" { t.Errorf("invalid exchange fields: %#v", b) } if r.Header.Get("Content-Type") != "application/json" || r.Header.Get("User-Agent") != "LobsterAI/0.1.0" { t.Error("wrong headers") } w.Header().Set("Content-Type", "application/json") w.Write([]byte(`{"code":0,"data":{"accessToken":"at-test","refreshToken":"rt-test","expiresIn":3600,"user":{"id":"uid1","userId":"account1","nickname":"test"}}}`)) })) defer ts.Close() c := kernelTestCore(t) ps := c.Plugins() src, err := readBundledChannels(t) if err != nil { t.Fatal(err) } if err = ps.LoadSource("channels", src); err != nil { t.Fatal(err) } // The fixture changes only the transport destination, not the upstream contract. if _, err = ps.Call("channels", "set_endpoints", map[string]interface{}{"platform": "lobsterai", "callback": map[string]interface{}{"token_url": ts.URL}}); err != nil { t.Fatal(err) } out, err := ps.InvokeHandler("channels", "start_login", &lua.HandlerRequest{Method: "POST", Body: `{"platform":"lobsterai"}`, Role: "admin"}) if err != nil { t.Fatal(err) } nonce := out.JSON.(map[string]interface{})["session"].(map[string]interface{})["nonce"].(string) req := &lua.HandlerRequest{Method: "GET", Query: map[string]string{"state": nonce, "authCode": "quote\"&code"}} out, err = ps.InvokeHandler("channels", "oauth_callback", req) if err != nil { t.Fatal(err) } if out.Status != 200 { t.Fatalf("callback: %#v", out) } raw, ok, err := ps.GetSecret("channels", "channels:lobsterai") if err != nil || !ok { t.Fatal("missing credential", err) } var cred map[string]interface{} if err = json.Unmarshal([]byte(raw), &cred); err != nil { t.Fatal(err) } for _, k := range []string{"access_token", "refresh_token", "uuid", "first_keyfrom", "latest_keyfrom", "expires_at", "uid", "user_id"} { if cred[k] == nil || cred[k] == "" { t.Errorf("missing %s", k) } } out, err = ps.InvokeHandler("channels", "oauth_callback", req) if err != nil { t.Fatal(err) } if out.Status != 409 || calls != 1 { t.Fatalf("replay accepted: status=%d calls=%d", out.Status, calls) } }