Skip to content

Commit a2b59b4

Browse files
committed
add integrate test for probe
1 parent 0aaf844 commit a2b59b4

File tree

4 files changed

+194
-2
lines changed

4 files changed

+194
-2
lines changed

metrics/probe/README.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ It showcases how to expose dedicated probe endpoints and how Kubernetes reacts d
1212

1313
```
1414
metrics/probe/
15+
├── go-client/
16+
│ └── cmd/main.go # Integration checker for ports/probes/RPC
1517
├── go-server/
1618
│ ├── cmd/main.go # Application entrypoint
1719
│ ├── build.sh # Docker build script
@@ -50,7 +52,21 @@ metrics/probe/
5052
go run ./metrics/probe/go-server/cmd/main.go
5153
```
5254

53-
### 2️Monitor probe endpoints
55+
### 2️Run the go-client integration checks
56+
57+
```bash
58+
go run ./metrics/probe/go-client/cmd/main.go
59+
```
60+
61+
The `go-client` validates:
62+
63+
* Triple port `20000` is reachable.
64+
* Probe port `22222` is reachable.
65+
* `/live` returns `200`.
66+
* `/ready` and `/startup` eventually return `200` after warm-up.
67+
* One `Greet` RPC call succeeds.
68+
69+
### 3️Monitor probe endpoints
5470

5571
```bash
5672
watch -n 1 '
@@ -147,4 +163,4 @@ This demonstrates proper separation of:
147163

148164
* Process liveness
149165
* Service readiness
150-
* Startup lifecycle completion
166+
* Startup lifecycle completion

metrics/probe/README_CN.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
```
1515
metrics/probe/
16+
├── go-client/
17+
│ └── cmd/main.go # 集成测试客户端(端口/探针/RPC 校验)
1618
├── go-server/
1719
│ ├── cmd/main.go # 程序入口
1820
│ ├── build.sh # Docker 构建脚本
@@ -52,6 +54,20 @@ metrics/probe/
5254
go run ./metrics/probe/go-server/cmd/main.go
5355
```
5456

57+
### 运行 go-client 做集成检查
58+
59+
```bash
60+
go run ./metrics/probe/go-client/cmd/main.go
61+
```
62+
63+
`go-client` 会依次检查:
64+
65+
* Triple 端口 `20000` 可连接。
66+
* 探针端口 `22222` 可连接。
67+
* `/live` 返回 `200`
68+
* `/ready``/startup` 在预热完成后返回 `200`
69+
* 发起一次 `Greet` RPC,确认 Triple 服务可用。
70+
5571

5672
### 观察探针状态
5773

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package main
19+
20+
import (
21+
"context"
22+
"fmt"
23+
"io"
24+
"net"
25+
"net/http"
26+
"strings"
27+
"time"
28+
29+
"dubbo.apache.org/dubbo-go/v3/client"
30+
31+
_ "dubbo.apache.org/dubbo-go/v3/imports"
32+
"github.com/dubbogo/gost/log/logger"
33+
34+
greet "github.com/apache/dubbo-go-samples/direct/proto"
35+
)
36+
37+
const (
38+
tripleAddr = "127.0.0.1:20000"
39+
probeBaseURL = "http://127.0.0.1:22222"
40+
41+
tcpReadyTimeout = 20 * time.Second
42+
probeReadyTimeout = 40 * time.Second
43+
requestTimeout = 2 * time.Second
44+
)
45+
46+
func main() {
47+
ctx := context.Background()
48+
49+
if err := waitTCPReady(tripleAddr, tcpReadyTimeout); err != nil {
50+
logger.Fatalf("triple port is not ready: %v", err)
51+
panic("triple port is not ready")
52+
}
53+
logger.Infof("triple port is ready: %s", tripleAddr)
54+
55+
if err := waitTCPReady("127.0.0.1:22222", tcpReadyTimeout); err != nil {
56+
logger.Fatalf("probe port is not ready: %v", err)
57+
panic("probe port is not ready")
58+
}
59+
logger.Info("probe port is ready: 127.0.0.1:22222")
60+
61+
if err := expectHTTPStatus(probeBaseURL+"/live", http.StatusOK, requestTimeout); err != nil {
62+
logger.Fatalf("/live check failed: %v", err)
63+
panic("/live check failed")
64+
}
65+
logger.Info("/live is healthy")
66+
67+
if err := waitHTTPStatus(probeBaseURL+"/ready", http.StatusOK, probeReadyTimeout, requestTimeout); err != nil {
68+
logger.Fatalf("/ready did not become healthy: %v", err)
69+
panic("/ready did not become healthy")
70+
}
71+
logger.Info("/ready is healthy")
72+
73+
if err := waitHTTPStatus(probeBaseURL+"/startup", http.StatusOK, probeReadyTimeout, requestTimeout); err != nil {
74+
logger.Fatalf("/startup did not become healthy: %v", err)
75+
panic("/startup did not become healthy")
76+
}
77+
logger.Info("/startup is healthy")
78+
79+
if err := callGreet(ctx); err != nil {
80+
logger.Fatalf("greet rpc check failed: %v", err)
81+
panic("greet rpc check failed")
82+
}
83+
logger.Info("probe sample integration checks passed")
84+
}
85+
86+
func callGreet(ctx context.Context) error {
87+
cli, err := client.NewClient(
88+
client.WithClientURL("tri://" + tripleAddr),
89+
)
90+
if err != nil {
91+
return fmt.Errorf("create client: %w", err)
92+
}
93+
94+
svc, err := greet.NewGreetService(cli)
95+
if err != nil {
96+
return fmt.Errorf("create greet service: %w", err)
97+
}
98+
99+
rpcCtx, cancel := context.WithTimeout(ctx, 3*time.Second)
100+
defer cancel()
101+
102+
resp, err := svc.Greet(rpcCtx, &greet.GreetRequest{Name: "probe-check"})
103+
if err != nil {
104+
return fmt.Errorf("invoke greet: %w", err)
105+
}
106+
if strings.TrimSpace(resp.Greeting) == "" {
107+
return fmt.Errorf("empty greet response")
108+
}
109+
logger.Infof("greet rpc succeeded: %s", resp.Greeting)
110+
return nil
111+
}
112+
113+
func waitTCPReady(addr string, timeout time.Duration) error {
114+
deadline := time.Now().Add(timeout)
115+
for {
116+
conn, err := net.DialTimeout("tcp", addr, 1*time.Second)
117+
if err == nil {
118+
_ = conn.Close()
119+
return nil
120+
}
121+
if time.Now().After(deadline) {
122+
return fmt.Errorf("tcp %s not ready within %s: %w", addr, timeout, err)
123+
}
124+
time.Sleep(300 * time.Millisecond)
125+
}
126+
}
127+
128+
func waitHTTPStatus(url string, expected int, timeout, reqTimeout time.Duration) error {
129+
deadline := time.Now().Add(timeout)
130+
var lastErr error
131+
for {
132+
err := expectHTTPStatus(url, expected, reqTimeout)
133+
if err == nil {
134+
return nil
135+
}
136+
lastErr = err
137+
if time.Now().After(deadline) {
138+
return fmt.Errorf("url %s not ready within %s: %w", url, timeout, lastErr)
139+
}
140+
time.Sleep(500 * time.Millisecond)
141+
}
142+
}
143+
144+
func expectHTTPStatus(url string, expected int, reqTimeout time.Duration) error {
145+
client := http.Client{Timeout: reqTimeout}
146+
resp, err := client.Get(url)
147+
if err != nil {
148+
return err
149+
}
150+
defer func() { _ = resp.Body.Close() }()
151+
152+
body, _ := io.ReadAll(resp.Body)
153+
if resp.StatusCode != expected {
154+
return fmt.Errorf("expect status %d but got %d, body=%s", expected, resp.StatusCode, strings.TrimSpace(string(body)))
155+
}
156+
return nil
157+
}

start_integrate_test.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ array+=("async")
7373
# error
7474
array+=("error")
7575

76+
# metrics
77+
array+=("metrics/probe")
78+
7679
# config_center
7780
array+=("config_center/nacos")
7881
# array+=("config_center/apollo")

0 commit comments

Comments
 (0)