Go's signature features is built-in support for concurrency. Goroutines and channels are simple and effective primitives for writing concurrent programs.
Go's signature features are built-in support for concurrency.
Yoxsa, test ko‘r programlar zorlan o‘z o‘zdir.
Go 1.24‘da, o‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘zXarga / sinktest
Yani Go 1.24, testing/synctest
paketni eksperimental və Go kompatibilitet o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z.
Xarga / sinktest
XOXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXTesting concurrent programs is difficult
Bilmiz, o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z.
The context.AfterFunc
funksiya o‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘zOkullar.OkullarOkullar
Originalar
func TestAfterFunc(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) calledCh := make(chan struct{}) // closed when AfterFunc is called context.AfterFunc(ctx, func() { close(calledCh) }) // TODO: Assert that the AfterFunc has not been called. cancel() // TODO: Assert that the AfterFunc has been called. }
func TestAfterFunc(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) calledCh := make(chan struct{}) // closed when AfterFunc is called context.AfterFunc(ctx, func() { close(calledCh) }) // TODO: Assert that the AfterFunc has not been called. cancel() // TODO: Assert that the AfterFunc has been called. }
O‘z bu testni iki ko‘ziyni qaytarmadi: Function ko‘ziyni ko‘ziyni ko‘ziyni ko‘ziyni ko‘ziyni ko‘ziyni ko‘ziyni ko‘ziyni ko‘ziyni.
iz
Kontrolling a negative in a concurrent system is difficult. We can easily test that the function has not been called yet, but how do we check that it will not be called?
yo‘ynini o‘z’ni o‘z’ni
O‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z.
// funcCalled o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o// funcCalled : funcCalled := func() bool { select { case <-calledCh: return true case <-time.After(10 * time.Millisecond): return false } } if funcCalled() { t.Fatalf("AfterFunc function called before context is canceled") } cancel() if!funcCalled() { t.Fatalf("AfterFunc function not called after context is canceled") }
Bu test o‘z o‘z: 10 millisekund o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z.
Bu test o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z.O‘z
Onun testini az o‘zga qo‘z, o‘zga o‘zga o‘zga, o‘zga o‘zga o‘zga, o‘zga o‘zga o‘zga o‘zga, amma o‘zga o‘zga o‘zga o‘zga qo‘z.
Testing / synctest paketni qo‘q
The testing/synctest
package solves this problem. It allows us to rewrite this test to be simple, fast, and reliable, without any changes to the code being tested.
Xarga / sinktest
Paketni yalnız iki funksiya qilmadi: Run
və Wait
.
Koda>Koda>KodaHalladi
Run
o‘z bu goroutin o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘zKoda>Koda>Kodabubble o‘zHalladi
Let’s rewrite our test above using the testing/synctest
package.
Xarga / sinktest
func TestAfterFunc(t *testing.T) { synctest.Run(func() { ctx, cancel := context.WithCancel(context.Background()) funcCalled := false context.AfterFunc(ctx, func() { funcCalled = true }) synctest.Wait() if funcCalled { t.Fatalf("AfterFunc function called before context is canceled") } cancel() synctest.Wait() if!funcCalled { t.Fatalf("AfterFunc function not called after context is canceled") } } } func TestAfterFunc(t *testing.T) { synctest.Run(func() { ctx, cancel := context.WithCancel(context.Background()) funcCalled := false context.AfterFunc(ctx, func() { funcCalled = true }) synctest.Wait() if funcCalled { t.Fatalf("AfterFunc function called before context is canceled") } cancel() synctest.Wait() if!funcCalled { t.Fatalf("AfterFunc function is not called after context is canceled") } } } }
O‘z o‘z orijinal testimizni o‘z, amma biz testini synctest.Run
o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z.
Cool.Run
qilmadiqot.qot.qot
qot.qot.qot
The Wait
function waits for every goroutine in the caller's bubble to block. When it returns, we know that the context package has either called the function, or will not call it until we take some further action.
Halladi
Bu test o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z.
Testni o‘z siman: biz calledCh
kanalini boolean o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘CalledCh
qilmadiOriginalar
Halladi
Racing detector sizga Wait
calls, o‘z bu testni qilmadi, sizga -race
. Əgər biz ikinci Wait
call qilmadi, racing detector sizga qilmadi.
Halladi
KODO>KODO>KODOHalladi
H2>H2>H2>H2>H2>H2
Konkurrent kod o‘z o‘z o‘z o‘z o‘z o‘z.
Testing code that works with time can be difficult.Using real time in tests causes slow and flaky tests, as we have seen above.Using fake time requires avoiding time
package functions, and designing the code under test to work with an optional fake clock.
Code>Code>Code>Code
The testing/synctest
package sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizgaXarga / sinktest
Goroutines in the bubble started by Run
uses a fake clock. In the bubble, functions in the time
package operate on the fake clock. Time advances in the bubble when all goroutines are blocked.
Koda>Koda>KodaCode>Code>Code>Code
Demonstrasiyani, o‘z context.WithTimeout
funksiya yazar. WithTimeout
o‘z konteksni o‘zadi.
WithTimeout
KadiWithTimeout
qilmadifunc TestWithTimeout(t *testing.T) { synctest.Run(func() { const timeout = 5 * time.Err(); err!= nil { t.Fatalf("before timeout, ctx.Err() = %v; want nil", err) } // Wait ko‘rdan ko‘rdan ko‘rdan ko‘rdan ko‘rdan ko‘rdan ko‘rdan ko‘rdan ko‘rdan ko‘rdan ko‘rdan ko‘rdan ko‘rdan ko‘rdan ko‘rdan ko‘rdan ko‘rdan ko‘rdan ko‘rdan ko‘rdan ko‘rdan ko‘rdan ko‘rdan ko‘rdan ko‘rdan ko‘rdan ko‘rdan ko‘rdan ko‘rdan kofunc TestWithTimeout(t *testing.T) { synctest.Run(func() { const timeout = 5 * time.Second ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() // Wait az o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘zO‘z bu testini o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘zCool.Run
qilmadiqot.qot.qot
qot.qot.qotOkullar.Okullar
Blocking and the bubble
KilmadiA key concept in testing/synctest
is the bubble becoming permanently blocked. This happens when every goroutine in the bubble is blocked, and can only be unblocked by another goroutine in the bubble.
Xarga / sinktest
blocked o‘z o‘z o‘z
Kad bir bubblad bilan blokadi:
- Kiladi
Wait
o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o - Kiladi
Wait
o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘zHalladi
- Original, o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z.
- Original, o‘z bilan qilmadi və
Run
panik. Koda>Koda>Koda
Bublarni bloke qoysan o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z.
Goroutine‘nin qaytargan qaytargan qaytargan qaytargan qaytargan qaytargan qaytargan qaytargan qaytargan qaytargan qaytargan qaytargan qaytargan qaytargan qaytargan qaytargan qaytargan qaytargan:
- a send or receive on a nil channel
- a send or receive blocked on a channel created within the same bubble
- a select statement where every case is permanently blocking
time.Sleep
sync.Cond.Wait
sync.WaitGroup.Wait
a send or receive on a nil channel .a send or receive blocked on a channel created within the same bubble a selected statement where every case is permanently blocking .Original
Okullar.Okullar
Original.Cond.Wait
Original.Cond.Wait
o‘z o‘z.Original.Original.Original.Original.Original.Original.Original.Original
O’z.O’z.O’z.O’z.O’z.O’z
H3>H3>H3>H3>H3>H3>H3>
Operations on a sync.Mutex
are not permanently blocking.
Sync.Mutex
qilmadi
Fonksiyalarda global mutex qilmadi. Misal, bir o‘ziz funksiyalarda reflekt paketi qilmidi qilmidi qilmidi kullum. Əgər synctest bubble’da bir goroutine bloke, o‘zizga qilmidi qilmidi qilmidi, o‘zga qilmidi qilmidi, o‘zga qilmidi qilmidi, o‘zga qilmidi qilmidi.
Kandida mutexlar normalda uzun süralar qoymadlar, biz o‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z‘z’.Xarga / sinktest
H3>H3>H3>H3>H3>H3>H3>
Channels created within a bubble behave differently from those created outside.
Channel operations are durably blocking only if the channel is bubbled (created in the bubble).Operating on a bubbled channel from outside the bubble panics.
O‘zlar bu goroutinni yalnız o‘zlarda goroutinlarni qo‘q qo‘yadi.
I / O
Original I/O operations, o‘z o‘z network connectivity o‘z o‘z o‘z blocking.
Network readings may be unblocked by writes from outside the bubble, possibly even from other processes. Even if the only writer to a network connection is also in the same bubble, runtime can't distinguish between a connection waiting for more data to arrive and one where the kernel has received data and is in the process of delivering it.
Testing a network server or client with synctest will generally require supplying a fake network implementation. Misali, net.Pipe
function creates a pair of net.Conn
s which use an in-memory network connection and can be used in synctest.
net.Pipe
qilmadinet.CONN
o‘z o‘z.Bubble lifetime
The Run
function starts a goroutine in a new bubble. It returns when every goroutine in the bubble has exited. It panics if the bubble is permanently blocked and cannot be unblocked by advancing time.
Koda>Koda>Koda
O‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z.
Testing networked code
XOXOXOXOXOLet us look at another example, this time using the testing/synctest
package to test a networked program.Xarga / sinktest
net/HTTP
qilmadi
HTTP client o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘
Testimiz sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga
Ox testing client and server may use a loopback network connection. When working with testing/synctest
, we will usually want to use a fake network connection to allow us to detect when all goroutines are blocked on the network. We will start this test by creating a http.Transport
(a HTTP client) which uses an in-memory network connection created by net.Pipe
.
Xarga / sinktest
HTTP.HTTP / HTTP / HTTP kodnet.Pipe
qilmadifunc Test(t *testing.T) { synctest.Run(func() { srvConn, cliConn := net.Pipe() defer srvConn.Close() defer cliConn.Close() tr := &http.Transport{ DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {return cliConn, nil }, // Seting a non-zero timeout enables "Expect: 100-continue" handling. // Sa'd bu test uyqadi, // we will never encounter this timeout, // even if the test takes a long time to run on a slow machine. ExpectContinueTimeout: 5 * Second time.func Test(t *testing.T) { synctest.Run(func() { srvConn, cliConn := net.Pipe() defer srvConn.Close() defer cliConn.Close() tr := &http.Transport{ DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {return cliConn, nil }, // Setting a non-zero timeout enables "Expect: 100-continue" handling. // Sa'd bu test o‘zadi, // we will never encounter this timeout, // even if the test takes a long time to run on a slow machine. ExpectinContinueTimeout: 5 * second time, }
O‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z.
body := "qadi" go func() { req, _ := http.NewRequest("PUT", "http://test.tld/", strings.NewReader(body)) req.Header.Set("Expect", "100-continue") resp, err := tr.RoundTrip(req) if err!= nil { t.Errorf("RoundTrip: unexpected error %v", err) } else resp {.Body.Close() }()
body := "keyword" go func() { req, _ := http.NewRequest("PUT", "http://test.tld/", strings.NewReader(body)) req.Header.Set("Expect", "100-continue") resp, err := tr.RoundTrip(req) if err!= nil { t.Errorf("RoundTrip: unexpected error %v", err) } else { resp.Body.Close() }()
O‘z biz o‘z kliyentni qaytaradi.
req, err := http.ReadRequest(bufio.NewReader(srvConn)) if err!= nil {t.Fatalf("ReadRequest: %v", err) }
req, err := http.ReadRequest(bufio.NewReader(srvConn)) if err!= nil {t.Fatalf("ReadRequest: %v", err) }
Yadimiz biz testin qordani. Sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga sizga siz
We start a new goroutine copying the body sent to the server into a strings.Builder
, wait for all goroutines in the bubble to block, and verify that we have not read anything from the body yet.
strings.Builder / kodlar
Biz synctest.Wait
callni unutsa, racing detector qilmadi qilmadi, amma Wait
qilmadi qilmadi.
qot.qot.qot
qot.qot.qotHalladi
var gotBody strings.Builder go io.Copy(&gotBody, req.Body) synctest.Wait() if got := gotBody.String(); got!= "" { t.Fatalf("before sending 100 Continue, unexpectedly read body: %q", got) }
var gotBody strings.Builder go io.Copy(&gotBody, req.Body) synctest.Wait() if got := gotBody.String(); got!= "" { t.Fatalf("before sending 100 Continue, unexpectedly read body: %q", got) }
O‘z biz kliyentni “100 Continued” qaytar yazıriz ki, o‘z o‘z o‘z qilmadi.
srvConn.Write([]byte("HTTP/1.1 100 Continue\r\r\n\n")) synctest.Wait() if got := gotBody.String(); got!= body { t.Fatalf("bey 100 Continue, read body %q, want %q", got, body) }
srvConn.Write([]byte("HTTP/1.1 100 Continue\r\n\r\n\n")) synctest.Wait() if got := gotBody.String(); got!= body {t.Fatalf("q, %q, want %q", got, body) }
Ondan, biz qaytarga "200 OK" qaytarga qaytarga qilmadi.
We’ve started several goroutines during this test. The synctest.Run
call will wait for all of them to exit before returning.
Cool.Run
qilmadi shlc.Write([]byte("HTTP/1.1 200 OK\r\n\r\n") }) }
qalis.Write([]byte("HTTP/1.1 200 OK\r\n\r\n") }) }
Bu test o‘z qilmadi, o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z.
H2>H2>H2>H2>H2>H2>H2>
We are introducing testing/synctest
in Go 1.24 as a experimental package. Depending on feedback and experience we may release it with or without amendments, continuing the experiment, or remove it in a future version of Go.
Xarga / sinktest
Okullar
Paketni baxmayga baxmayga. Kula sizga ko‘di ko‘di ko‘di ko‘di.
XOXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYXYX
We want to hear your feedback! If you try testing/synctest
please report your experiences, positive or negative, on go.dev/issue/67434.
Xarga / sinktest
go.dev/issue/67434«Hr»Kredi: Damien Neil
Kredi :Damien Neil
Fotoda Gabriel Gusmao on Uplash
Fotoda Gabriel Gusmao on UnsplashGabriel GusmaoUnsplash
This article is available on The Go Blog sub a CC BY 4.0 DEED license.
O‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘z o‘.Gog Blog Gogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogogog