github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/sys/it/bug_test.go (about) 1 /* 2 * Copyright (c) 2022-present unTill Pro, Ltd. 3 */ 4 5 package sys_it 6 7 import ( 8 "context" 9 "errors" 10 "io" 11 "net/http" 12 "testing" 13 14 "github.com/stretchr/testify/require" 15 16 "github.com/voedger/voedger/pkg/appdef" 17 "github.com/voedger/voedger/pkg/istructs" 18 "github.com/voedger/voedger/pkg/state" 19 coreutils "github.com/voedger/voedger/pkg/utils" 20 it "github.com/voedger/voedger/pkg/vit" 21 ) 22 23 type rr struct { 24 istructs.NullObject 25 res string 26 } 27 28 func (r *rr) AsString(string) string { 29 return r.res 30 } 31 32 func TestBug_QueryProcessorMustStopOnClientDisconnect(t *testing.T) { 33 if testing.Short() { 34 t.Skip() 35 } 36 require := require.New(t) 37 goOn := make(chan interface{}) 38 it.MockQryExec = func(input string, callback istructs.ExecQueryCallback) (err error) { 39 rr := &rr{res: input} 40 require.NoError(callback(rr)) 41 <-goOn // ждем, пока http клиент примет первый элемент и отключится 42 // теперь ждем ошибку context.Cancelled. Она выйдет не сразу, т.к. в queryprocessor работает асинхронный конвейер 43 for err == nil { 44 err = callback(rr) 45 } 46 require.Equal(context.Canceled, err) 47 defer func() { goOn <- nil }() // отсигналим, что поймали ошибку context.Cancelled 48 return err 49 } 50 vit := it.NewVIT(t, &it.SharedConfig_App1) 51 defer vit.TearDown() 52 53 // отправим POST-запрос 54 body := `{"args": {"Input": "world"},"elements": [{"fields": ["Res"]}]}` 55 ws := vit.WS(istructs.AppQName_test1_app1, "test_ws") 56 vit.PostWS(ws, "q.app1pkg.MockQry", body, coreutils.WithResponseHandler(func(httpResp *http.Response) { 57 // прочтем первую часть ответа (сервер не отдаст вторую, пока в goOn не запишем чего-нибудь) 58 entireResp := []byte{} 59 var err error 60 n := 0 61 for string(entireResp) != `{"sections":[{"type":"","elements":[[[["world"]]]` { 62 if n == 0 && errors.Is(err, io.EOF) { 63 t.Fatal() 64 } 65 buf := make([]byte, 512) 66 n, err = httpResp.Body.Read(buf) 67 entireResp = append(entireResp, buf[:n]...) 68 } 69 70 // порвем соединение в середине обработки запроса 71 httpResp.Request.Body.Close() 72 httpResp.Body.Close() 73 goOn <- nil // функция начнет передавать вторую часть, но это не получится, т.к. request context закрыт 74 })) 75 76 <-goOn // подождем, пока ошибки проверятся 77 // ожидаем, что никаких посторонних ошибок нет: ничего не повисло, queryprocessor отдал управление, роутер не пытается писать в закрытую коннекцию и т.п. 78 } 79 80 func Test409OnRepeatedlyUsedRawIDsInResultCUDs_(t *testing.T) { 81 vit := it.NewVIT(t, &it.SharedConfig_App1) 82 defer vit.TearDown() 83 it.MockCmdExec = func(_ string, args istructs.ExecCommandArgs) error { 84 // 2 раза используем один и тот же rawID -> 500 internal server error 85 kb, err := args.State.KeyBuilder(state.Record, it.QNameApp1_CDocCategory) 86 if err != nil { 87 return err 88 } 89 sv, err := args.Intents.NewValue(kb) 90 if err != nil { 91 return err 92 } 93 sv.PutRecordID(appdef.SystemField_ID, 1) 94 95 kb, err = args.State.KeyBuilder(state.Record, it.QNameApp1_CDocCategory) 96 if err != nil { 97 return err 98 } 99 sv, err = args.Intents.NewValue(kb) 100 if err != nil { 101 return err 102 } 103 sv.PutRecordID(appdef.SystemField_ID, 1) 104 return nil 105 } 106 ws := vit.WS(istructs.AppQName_test1_app1, "test_ws") 107 vit.PostWS(ws, "c.app1pkg.MockCmd", `{"args":{"Input":"Str"}}`, coreutils.Expect409()).Println() 108 }