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  }