Skip to content

Commit 5ac0f86

Browse files
lilyLuLiupraveenkumar
authored andcommitted
[QE]monitor cpu usage in e2e test case
1 parent 231ecf7 commit 5ac0f86

4 files changed

Lines changed: 156 additions & 34 deletions

File tree

test/e2e/features/story_microshift.feature

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@ Feature: Microshift test stories
77
And setting config property "persistent-volume-size" to value "20" succeeds
88
And ensuring network mode user
99
And executing single crc setup command succeeds
10-
And get cpu data "Before start"
11-
And get memory data "Before start"
1210
And starting CRC with default bundle succeeds
13-
And get cpu data "After start"
1411
And get memory data "After start"
1512
And ensuring oc command is available
1613
And ensuring microshift cluster is fully operational
@@ -20,8 +17,9 @@ Feature: Microshift test stories
2017

2118
# End-to-end health check
2219

23-
@microshift @testdata @linux @windows @darwin @cleanup
20+
@microshift @testdata @linux @windows @darwin @cleanup @performance
2421
Scenario: Start and expose a basic HTTP service and check after restart
22+
And record timestamp "deployment"
2523
Given executing "oc create namespace testproj" succeeds
2624
And executing "oc config set-context --current --namespace=testproj" succeeds
2725
When executing "oc apply -f httpd-example.yaml" succeeds
@@ -36,13 +34,13 @@ Feature: Microshift test stories
3634
When executing "oc expose svc httpd-example" succeeds
3735
Then stdout should contain "httpd-example exposed"
3836
When with up to "20" retries with wait period of "5s" http response from "http://httpd-example-testproj.apps.crc.testing" has status code "200"
39-
And get cpu data "After deployment"
4037
And get memory data "After deployment"
4138
Then executing "curl -s http://httpd-example-testproj.apps.crc.testing" succeeds
4239
And stdout should contain "Hello CRC!"
40+
And record timestamp "stop"
4341
When executing "crc stop" succeeds
44-
And get cpu data "After stop"
4542
And get memory data "After stop"
43+
And record timestamp "start again"
4644
And starting CRC with default bundle succeeds
4745
And checking that CRC is running
4846
And with up to "4" retries with wait period of "1m" http response from "http://httpd-example-testproj.apps.crc.testing" has status code "200"

test/e2e/features/story_openshift.feature

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ Feature: 4 Openshift stories
99

1010
# End-to-end health check
1111

12-
@darwin @linux @windows @testdata @story_health @needs_namespace
12+
@darwin @linux @windows @testdata @story_health @needs_namespace @performance
1313
Scenario: Overall cluster health
1414
Given executing "oc new-project testproj" succeeds
15-
And get cpu data "After start"
1615
And get memory data "After start"
16+
And record timestamp "deployment"
1717
When executing "oc apply -f httpd-example.yaml" succeeds
1818
And executing "oc rollout status deployment httpd-example" succeeds
1919
Then stdout should contain "successfully rolled out"
@@ -25,14 +25,14 @@ Feature: 4 Openshift stories
2525
Then stdout should contain "httpd-example exposed"
2626
When executing "oc expose svc httpd-example" succeeds
2727
Then stdout should contain "httpd-example exposed"
28-
And get cpu data "After deployment"
29-
And get memory data "After deployment"
3028
When with up to "20" retries with wait period of "5s" http response from "http://httpd-example-testproj.apps-crc.testing" has status code "200"
3129
Then executing "curl -s http://httpd-example-testproj.apps-crc.testing" succeeds
3230
And stdout should contain "Hello CRC!"
31+
And get memory data "After deployment"
32+
And record timestamp "stop"
3333
When executing "crc stop" succeeds
34-
And get cpu data "After stop"
3534
And get memory data "After stop"
35+
And record timestamp "start again"
3636
And starting CRC with default bundle succeeds
3737
And checking that CRC is running
3838
And with up to "4" retries with wait period of "1m" http response from "http://httpd-example-testproj.apps-crc.testing" has status code "200"

test/e2e/testsuite/performance.go

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package testsuite
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
"path/filepath"
8+
"sync"
9+
"time"
10+
11+
"github.com/crc-org/crc/v2/test/extended/util"
12+
"github.com/shirou/gopsutil/v4/cpu"
13+
)
14+
15+
type Monitor struct {
16+
cancelFunc context.CancelFunc
17+
isRunning bool
18+
mu sync.Mutex
19+
wg sync.WaitGroup
20+
interval time.Duration
21+
}
22+
23+
func NewMonitor(interval time.Duration) *Monitor {
24+
return &Monitor{
25+
interval: interval,
26+
}
27+
}
28+
29+
func (m *Monitor) Start() error {
30+
m.mu.Lock()
31+
defer m.mu.Unlock()
32+
33+
if m.isRunning {
34+
return fmt.Errorf("The collector is running")
35+
}
36+
37+
fmt.Printf("Attempt to start CPU collector, interval: %s\n", m.interval)
38+
39+
// create a context.WithCancel
40+
ctx, cancel := context.WithCancel(context.Background())
41+
m.cancelFunc = cancel
42+
m.isRunning = true
43+
44+
// start goroutine
45+
m.wg.Add(1)
46+
go m.collectLoop(ctx)
47+
48+
fmt.Println("CPU collector has been successfully started")
49+
return nil
50+
}
51+
52+
func (m *Monitor) Stop() error {
53+
m.mu.Lock()
54+
defer m.mu.Unlock()
55+
56+
if !m.isRunning {
57+
return fmt.Errorf("The collector is not running")
58+
}
59+
if m.cancelFunc != nil {
60+
m.cancelFunc()
61+
}
62+
m.isRunning = false
63+
m.wg.Wait()
64+
fmt.Println("CPU collector has sent a stop signal")
65+
// may need wait a while to stop
66+
return nil
67+
}
68+
69+
func (m *Monitor) collectLoop(ctx context.Context) {
70+
defer m.wg.Done()
71+
72+
fmt.Println("--> collect goroutine start...")
73+
calcInterval := m.interval
74+
75+
// Prime cpu.Percent so the subsequent calls with interval=0 return usage
76+
// since this priming call. We discard the returned value.
77+
_, _ = cpu.Percent(0, false)
78+
79+
ticker := time.NewTicker(calcInterval)
80+
defer ticker.Stop()
81+
82+
for {
83+
select {
84+
case <-ctx.Done():
85+
fmt.Println("<-- collect goroutine receive stop signal")
86+
return // exit goroutine
87+
case <-ticker.C:
88+
// cpu.Percent with interval=0 returns percent since the last call.
89+
totalPercent, err := cpu.Percent(0, false)
90+
if err != nil {
91+
fmt.Printf("Error: fail to collect CPU data: %v\n", err)
92+
// do not block here; wait for next tick or cancellation
93+
continue
94+
}
95+
96+
if len(totalPercent) > 0 {
97+
data := fmt.Sprintf("[%s], cpu percent: %.2f%%\n",
98+
time.Now().Format("15:04:05"), totalPercent[0])
99+
wd, err := os.Getwd()
100+
if err != nil {
101+
fmt.Printf("Error: failed to get working directory: %v\n", err)
102+
continue
103+
}
104+
file := filepath.Join(wd, "../test-results/cpu-consume.txt")
105+
err = util.WriteToFile(data, file)
106+
if err != nil {
107+
fmt.Printf("Error: fail to write to %s: %v\n", file, err)
108+
}
109+
}
110+
}
111+
}
112+
}

test/e2e/testsuite/testsuite.go

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import (
2828
crcCmd "github.com/crc-org/crc/v2/test/extended/crc/cmd"
2929
"github.com/crc-org/crc/v2/test/extended/util"
3030
"github.com/cucumber/godog"
31-
"github.com/shirou/gopsutil/v4/cpu"
3231
"github.com/shirou/gopsutil/v4/mem"
3332
"github.com/spf13/pflag"
3433
)
@@ -153,7 +152,7 @@ func InitializeTestSuite(tctx *godog.TestSuiteContext) {
153152

154153
err := crcCmd.DeleteCRC()
155154
if err != nil {
156-
fmt.Printf("Could not delete CRC VM: %s.", err)
155+
fmt.Printf("Could not delete CRC VM: %s.\n", err)
157156
}
158157

159158
err = util.LogMessage("info", "----- Cleaning Up -----")
@@ -169,6 +168,7 @@ func InitializeTestSuite(tctx *godog.TestSuiteContext) {
169168
}
170169

171170
func InitializeScenario(s *godog.ScenarioContext) {
171+
monitor := NewMonitor(1 * time.Second)
172172

173173
s.Before(func(ctx context.Context, sc *godog.Scenario) (context.Context, error) {
174174

@@ -264,12 +264,17 @@ func InitializeScenario(s *godog.ScenarioContext) {
264264
}
265265
}
266266

267-
if tag.Name == "@story_health" {
268-
if err := getCPUdata("Before start"); err != nil {
269-
fmt.Printf("Failed to collect CPU data: %v\n", err)
267+
if tag.Name == "@performance" {
268+
if err := monitor.Start(); err != nil {
269+
fmt.Printf("Failed to start monitor: %v\n", err)
270270
}
271-
if err := getMemoryData("Before start"); err != nil {
272-
fmt.Printf("Failed to collect memory data: %v\n", err)
271+
err := getTimestamp("start")
272+
if err != nil {
273+
fmt.Printf("Failed to get finish getTimestamp: %v\n", err)
274+
}
275+
err = getMemoryData("Before start")
276+
if err != nil {
277+
fmt.Printf("Failed to get memory data: %v\n", err)
273278
}
274279
}
275280
}
@@ -398,6 +403,16 @@ func InitializeScenario(s *godog.ScenarioContext) {
398403
}
399404
}
400405

406+
if tag.Name == "@performance" {
407+
err := getTimestamp("finish")
408+
if err != nil {
409+
fmt.Printf("Failed to get finish getTimestamp: %v\n", err)
410+
}
411+
if err := monitor.Stop(); err != nil {
412+
fmt.Printf("Failed to stop monitoring: %v\n", err)
413+
}
414+
fmt.Printf("Collection has stopped\n")
415+
}
401416
}
402417

403418
return ctx, nil
@@ -579,8 +594,8 @@ func InitializeScenario(s *godog.ScenarioContext) {
579594
EnsureApplicationIsAccessibleViaNodePort)
580595
s.Step(`^persistent volume of size "([^"]*)"GB exists$`,
581596
EnsureVMPartitionSizeCorrect)
582-
s.Step(`^get cpu data "([^"]*)"`,
583-
getCPUdata)
597+
s.Step(`^record timestamp "([^"]*)"`,
598+
getTimestamp)
584599
s.Step(`^get memory data "([^"]*)"`,
585600
getMemoryData)
586601

@@ -1320,20 +1335,6 @@ func deserializeListBlockDeviceCommandOutputToExtractPVSize(lsblkOutput string)
13201335
return diskSize - (lvmSize + 1), nil
13211336
}
13221337

1323-
func getCPUdata(content string) error {
1324-
cpuData, err := cpu.Percent(0, false)
1325-
if err != nil {
1326-
return fmt.Errorf("failed to get CPU data: %v", err)
1327-
}
1328-
if len(cpuData) == 0 {
1329-
return fmt.Errorf("no CPU data available")
1330-
}
1331-
data := fmt.Sprintf("%s: %.2f%%\n", content, cpuData)
1332-
wd, _ := os.Getwd()
1333-
file := filepath.Join(wd, "../test-results/cpu-consume.txt")
1334-
return util.WriteToFile(data, file)
1335-
}
1336-
13371338
func getMemoryData(content string) error {
13381339
v, err := mem.VirtualMemory()
13391340
if err != nil {
@@ -1351,3 +1352,14 @@ func getMemoryData(content string) error {
13511352
file := filepath.Join(wd, "../test-results/memory-consume.txt")
13521353
return util.WriteToFile(data, file)
13531354
}
1355+
1356+
func getTimestamp(content string) error {
1357+
data := fmt.Sprintf("[%s], %s\n",
1358+
time.Now().Format("15:04:05"), content)
1359+
wd, err := os.Getwd()
1360+
if err != nil {
1361+
fmt.Printf("failed to get working directory: %v\n", err)
1362+
}
1363+
file := filepath.Join(wd, "../test-results/time-stamp.txt")
1364+
return util.WriteToFile(data, file)
1365+
}

0 commit comments

Comments
 (0)