package graphvent import ( "bytes" "crypto/tls" "encoding/json" "fmt" "io" "net" "net/http" "reflect" "testing" "time" "github.com/google/uuid" "golang.org/x/net/websocket" ) func TestGQLSubscribe(t *testing.T) { ctx := logTestContext(t, []string{"test"}) n1, err := NewNode(ctx, nil, "Lockable", 10, NewLockableExt(nil)) fatalErr(t, err) listener_ext := NewListenerExt(10) gql_ext, err := NewGQLExt(ctx, ":0", nil, nil) fatalErr(t, err) gql, err := NewNode(ctx, nil, "Lockable", 10, NewLockableExt([]NodeID{n1.ID}), gql_ext, listener_ext) fatalErr(t, err) ctx.Log.Logf("test", "GQL: %s", gql.ID) ctx.Log.Logf("test", "NODE: %s", n1.ID) sub_1 := GQLPayload{ Query: "subscription Self { Self { ID, Type } }", } port := gql_ext.tcp_listener.Addr().(*net.TCPAddr).Port url := fmt.Sprintf("http://localhost:%d/gql", port) ws_url := fmt.Sprintf("ws://127.0.0.1:%d/gqlws", port) SubGQL := func(payload GQLPayload) { config, err := websocket.NewConfig(ws_url, url) fatalErr(t, err) config.Protocol = append(config.Protocol, "graphql-ws") config.TlsConfig = &tls.Config{InsecureSkipVerify: true} ws, err := websocket.DialConfig(config) fatalErr(t, err) type payload_struct struct { Token string `json:"token"` } init := struct{ ID uuid.UUID `json:"id"` Type string `json:"type"` }{ uuid.New(), "connection_init", } ser, err := json.Marshal(&init) fatalErr(t, err) _, err = ws.Write(ser) fatalErr(t, err) resp := make([]byte, 1024) n, err := ws.Read(resp) var init_resp GQLWSMsg err = json.Unmarshal(resp[:n], &init_resp) fatalErr(t, err) if init_resp.Type != "connection_ack" { t.Fatal("Didn't receive connection_ack") } sub := GQLWSMsg{ ID: uuid.New().String(), Type: "subscribe", Payload: sub_1, } ser, err = json.Marshal(&sub) fatalErr(t, err) _, err = ws.Write(ser) fatalErr(t, err) n, err = ws.Read(resp) fatalErr(t, err) ctx.Log.Logf("test", "SUB: %s", resp[:n]) err = ctx.Send(gql, []SendMsg{{ Dest: gql.ID, Signal: NewStatusSignal(gql.ID, map[ExtType]Changes{ ExtTypeFor[GQLExt](): {"state"}, }), }}) fatalErr(t, err) n, err = ws.Read(resp) fatalErr(t, err) ctx.Log.Logf("test", "SUB: %s", resp[:n]) // TODO: check that there are no more messages sent to ws within a timeout } SubGQL(sub_1) } func TestGQLQuery(t *testing.T) { ctx := logTestContext(t, []string{"test", "lockable"}) n1_listener := NewListenerExt(10) n1, err := NewNode(ctx, nil, "Lockable", 10, NewLockableExt(nil), n1_listener) fatalErr(t, err) gql_listener := NewListenerExt(10) gql_ext, err := NewGQLExt(ctx, ":0", nil, nil) fatalErr(t, err) gql, err := NewNode(ctx, nil, "Lockable", 10, NewLockableExt([]NodeID{n1.ID}), gql_ext, gql_listener) fatalErr(t, err) ctx.Log.Logf("test", "GQL: %s", gql.ID) ctx.Log.Logf("test", "NODE: %s", n1.ID) skipVerifyTransport := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, } client := &http.Client{Transport: skipVerifyTransport} port := gql_ext.tcp_listener.Addr().(*net.TCPAddr).Port url := fmt.Sprintf("http://localhost:%d/gql", port) req_1 := GQLPayload{ Query: "query Node($id:graphvent_NodeID) { Node(id:$id) { ID, Type, ... on Lockable { lockable_state } } }", Variables: map[string]interface{}{ "id": n1.ID.String(), }, } req_2 := GQLPayload{ Query: "query Self { Self { ID, Type, ... on Lockable { lockable_state, requirements { Key { ID ... on Lockable { lockable_state } } } } } }", } SendGQL := func(payload GQLPayload) []byte { ser, err := json.MarshalIndent(&payload, "", " ") fatalErr(t, err) req_data := bytes.NewBuffer(ser) req, err := http.NewRequest("GET", url, req_data) fatalErr(t, err) resp, err := client.Do(req) fatalErr(t, err) body, err := io.ReadAll(resp.Body) fatalErr(t, err) resp.Body.Close() return body } resp_1 := SendGQL(req_1) ctx.Log.Logf("test", "RESP_1: %s", resp_1) resp_2 := SendGQL(req_2) ctx.Log.Logf("test", "RESP_2: %s", resp_2) lock_id, err := LockLockable(ctx, n1) fatalErr(t, err) response, _, err := WaitForResponse(n1_listener.Chan, 100*time.Millisecond, lock_id) fatalErr(t, err) switch response := response.(type) { case *SuccessSignal: default: t.Fatalf("Wrong response: %s", reflect.TypeOf(response)) } resp_3 := SendGQL(req_1) ctx.Log.Logf("test", "RESP_3: %s", resp_3) resp_4 := SendGQL(req_2) ctx.Log.Logf("test", "RESP_4: %s", resp_4) } func TestGQLDB(t *testing.T) { ctx := logTestContext(t, []string{"test", "db", "node"}) gql_ext, err := NewGQLExt(ctx, ":0", nil, nil) fatalErr(t, err) listener_ext := NewListenerExt(10) gql, err := NewNode(ctx, nil, "Base", 10, gql_ext, listener_ext) fatalErr(t, err) ctx.Log.Logf("test", "GQL_ID: %s", gql.ID) err = ctx.Unload(gql.ID) fatalErr(t, err) gql_loaded, err := ctx.Load(gql.ID) fatalErr(t, err) listener_ext, err = GetExt[ListenerExt](gql_loaded) fatalErr(t, err) }