Skip to content

Commit 3c07a32

Browse files
committed
feat: implement basic structures and testing
This commit provides the basic framework, interfaces and some tests as example for futher extention. Signed-off-by: Christopher Meis <christopher.meis@9elements.com>
1 parent 1e222a6 commit 3c07a32

28 files changed

+1837
-100
lines changed

Taskfile.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ tasks:
1212
matrix:
1313
OS: ['linux']
1414
ARCH: ['amd64', 'arm', 'arm64']
15-
cmd: GOOS="{{.ITEM.OS}}" GOARCH="{{.ITEM.ARCH}}" go build -ldflags="-s -w" -o "bin/bmc-test-go-{{.ITEM.OS}}-{{.ITEM.ARCH}}-{{.SEMVER}}"
15+
cmd: GOOS="{{.ITEM.OS}}" GOARCH="{{.ITEM.ARCH}}" go build -ldflags="-s -w" -o "bin/bmc-test-go-{{.ITEM.OS}}-{{.ITEM.ARCH}}-{{.SEMVER}}" ./cmds/openbmc-tests
1616

1717
lint:
1818
desc: Run linters

cmds/openbmc-tests/cmdline.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
)
6+
7+
var (
8+
runSingleCmd string = "single"
9+
runSuiteCmd string = "suite"
10+
runAllCmd string = "run-all"
11+
cfgCheckCmd string = "cfg-check"
12+
listTestsCmd string = "list-tests"
13+
listSuitesCmd string = "list-suites"
14+
runCfgCmd string = "run-from-cfg"
15+
)
16+
17+
type flags struct {
18+
cmd string
19+
configPath string
20+
execEnv string
21+
suite string
22+
testName string
23+
logType string
24+
logFile string
25+
}
26+
27+
func parseFlags(args []string) (*flags, error) {
28+
f := &flags{
29+
cmd: args[0],
30+
}
31+
32+
cfgCheckFS := flag.NewFlagSet(cfgCheckCmd, flag.ExitOnError)
33+
cfgCheckFS.StringVar(&f.configPath, "config", "contrib/example_config.yaml", "Path to device specific test case configuration file")
34+
35+
runSingleFS := flag.NewFlagSet(runSingleCmd, flag.ExitOnError)
36+
runSingleFS.StringVar(&f.testName, "testname", "", "Run a single test with 'testname'. Use the short name. No default")
37+
runSingleFS.StringVar(&f.execEnv, "exec-env", "remote", "Run the test locally or remotely '<local, remote>'. Default: remote")
38+
runSingleFS.StringVar(&f.configPath, "config", "contrib/example_config.yaml", "Path to device specific test case configuration file")
39+
runSingleFS.StringVar(&f.logType, "log", "default", "Logging options <default, structured>")
40+
runSingleFS.StringVar(&f.logFile, "logfile", "", "Path to log file. Only with structured logging option.")
41+
42+
runSuiteFS := flag.NewFlagSet(runSuiteCmd, flag.ExitOnError)
43+
runSuiteFS.StringVar(&f.execEnv, "exec-env", "remote", "Run the test locally or remotely '<local, remote>'. Default: remote")
44+
runSuiteFS.StringVar(&f.suite, "suite", "", "Specify the suite. <redfish, ipmi, ifaces>")
45+
runSuiteFS.StringVar(&f.configPath, "config", "contrib/example_config.yaml", "Path to device specific test case configuration file")
46+
runSuiteFS.StringVar(&f.logType, "log", "default", "Logging options <default, structured>")
47+
runSuiteFS.StringVar(&f.logFile, "logfile", "", "Path to log file. Only with structured logging option.")
48+
49+
runAllFS := flag.NewFlagSet(runAllCmd, flag.ExitOnError)
50+
runAllFS.StringVar(&f.execEnv, "exec-env", "remote", "Run the test locally or remotely '<local, remote>'.")
51+
runAllFS.StringVar(&f.configPath, "config", "contrib/example_config.yaml", "Path to device specific test case configuration file")
52+
runAllFS.StringVar(&f.logType, "log", "default", "Logging options <default, structured>")
53+
runAllFS.StringVar(&f.logFile, "logfile", "", "Path to log file. Only with structured logging option.")
54+
55+
listTestsFS := flag.NewFlagSet(listTestsCmd, flag.ExitOnError)
56+
listTestsFS.StringVar(&f.logType, "log", "default", "Logging options <default, structured>")
57+
listTestsFS.StringVar(&f.logFile, "logfile", "", "Path to log file. Only with structured logging option.")
58+
listTestsFS.StringVar(&f.suite, "suite", "", "Specify the suite. <redfish, ipmi, ifaces>")
59+
60+
runFromCfgFS := flag.NewFlagSet(runCfgCmd, flag.ExitOnError)
61+
runFromCfgFS.StringVar(&f.execEnv, "exec-env", "remote", "Run the test locally or remotely '<local, remote>'. Default: remote")
62+
runFromCfgFS.StringVar(&f.configPath, "config", "contrib/example_config.yaml", "Path to device specific test case configuration file")
63+
runFromCfgFS.StringVar(&f.logType, "log", "default", "Logging options <default, structured>")
64+
runFromCfgFS.StringVar(&f.logFile, "logfile", "", "Path to log file. Only with structured logging option.")
65+
66+
var err error
67+
switch args[0] {
68+
case cfgCheckCmd:
69+
err = cfgCheckFS.Parse(args[1:])
70+
case runSingleCmd:
71+
err = runSingleFS.Parse(args[1:])
72+
case runSuiteCmd:
73+
err = runSuiteFS.Parse(args[1:])
74+
case runAllCmd:
75+
err = runAllFS.Parse(args[1:])
76+
case listTestsCmd:
77+
err = listTestsFS.Parse(args[1:])
78+
case listSuitesCmd:
79+
case runCfgCmd:
80+
err = runFromCfgFS.Parse(args[1:])
81+
default:
82+
cfgCheckFS.Usage()
83+
runSingleFS.Usage()
84+
runSuiteFS.Usage()
85+
runAllFS.Usage()
86+
listTestsFS.Usage()
87+
}
88+
if err != nil {
89+
return nil, err
90+
}
91+
92+
return f, nil
93+
}

cmds/openbmc-tests/main.go

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
3+
// Package main implements the core logic
4+
package main
5+
6+
import (
7+
"fmt"
8+
"log"
9+
"os"
10+
11+
"github.com/9elements/bmc-test-go/pkg/bmc"
12+
"github.com/9elements/bmc-test-go/pkg/configuration"
13+
"github.com/9elements/bmc-test-go/pkg/framework"
14+
"github.com/9elements/bmc-test-go/pkg/tests"
15+
"github.com/9elements/bmc-test-go/pkg/tests/ipmi"
16+
)
17+
18+
func runAll(bmc *bmc.BMC, cfg *configuration.Config) error {
19+
ipmiPre := &ipmi.IPMISDRPrecondition{}
20+
if err := ipmiPre.Run(bmc); err != nil {
21+
return err
22+
}
23+
24+
tests := tests.AllTests()
25+
if len(tests) < 1 {
26+
return fmt.Errorf("no tests to execute")
27+
}
28+
29+
for _, test := range tests {
30+
if !framework.RunTest(test, bmc, cfg, ipmiPre) {
31+
continue
32+
}
33+
}
34+
return nil
35+
}
36+
37+
func runSingle(testname string, bmc *bmc.BMC, cfg *configuration.Config) error {
38+
ipmiPre := &ipmi.IPMISDRPrecondition{}
39+
if err := ipmiPre.Run(bmc); err != nil {
40+
return err
41+
}
42+
43+
tests := tests.AllTests()
44+
if len(tests) < 1 {
45+
return fmt.Errorf("no tests to execute")
46+
}
47+
48+
for _, test := range tests {
49+
if test.ShortName() == testname {
50+
if !framework.RunTest(test, bmc, cfg, ipmiPre) {
51+
return fmt.Errorf("%s", test.ErrorText())
52+
}
53+
}
54+
}
55+
56+
return nil
57+
}
58+
59+
func runSuite(suite string, bmc *bmc.BMC, cfg *configuration.Config) error {
60+
ipmiPre := &ipmi.IPMISDRPrecondition{}
61+
if err := ipmiPre.Run(bmc); err != nil {
62+
return err
63+
}
64+
65+
tests := tests.GetSuite(suite)
66+
if len(tests) < 1 {
67+
return fmt.Errorf("no tests to execute")
68+
}
69+
70+
for _, test := range tests {
71+
if !framework.RunTest(test, bmc, cfg, ipmiPre) {
72+
return fmt.Errorf("%s", test.ErrorText())
73+
}
74+
}
75+
return nil
76+
}
77+
78+
func listTests(suite string) error {
79+
var t []framework.Test
80+
if suite != "" {
81+
t = tests.GetSuite(suite)
82+
} else {
83+
t = tests.AllTests()
84+
}
85+
86+
logger := log.New(os.Stdout, "", log.Lmsgprefix)
87+
88+
logger.Printf("List tests %s", suite)
89+
logger.Printf("-------------------------------------------------------")
90+
logger.Printf("-------------------------------------------------------")
91+
logger.Printf("%-30s | %s\n", "Long name", "Short name")
92+
logger.Printf("-------------------------------------------------------")
93+
for _, test := range t {
94+
logger.Printf("%-30s | %s\n", test.Name(), test.ShortName())
95+
logger.Printf("-------------------------------------------------------")
96+
}
97+
98+
return nil
99+
}
100+
101+
func runFromCfg(bmc *bmc.BMC, cfg *configuration.Config) error {
102+
ipmiPre := &ipmi.IPMISDRPrecondition{}
103+
if err := ipmiPre.Run(bmc); err != nil {
104+
return err
105+
}
106+
107+
alltests := tests.AllTests()
108+
109+
for _, testName := range cfg.Tests {
110+
for _, test := range alltests {
111+
if testName == test.ShortName() {
112+
framework.RunTest(test, bmc, cfg, ipmiPre)
113+
}
114+
}
115+
}
116+
return nil
117+
}
118+
119+
func listSuites() error {
120+
logger := log.New(os.Stdout, "", log.Lmsgprefix)
121+
122+
logger.Printf("List Suites")
123+
logger.Printf("-------------------------------------------------------")
124+
logger.Printf("-------------------------------------------------------")
125+
logger.Println("ipmi")
126+
logger.Println("ipmi-mct")
127+
logger.Println("ipmi-twitter")
128+
logger.Println("redfish")
129+
logger.Println("pci")
130+
logger.Println("iface")
131+
return nil
132+
}
133+
134+
func run() error {
135+
if len(os.Args) < 2 {
136+
return fmt.Errorf("invalid argument count")
137+
}
138+
flags, err := parseFlags(os.Args[1:])
139+
if err != nil {
140+
return err
141+
}
142+
143+
cfg, err := configuration.LoadConfig(flags.configPath)
144+
if err != nil {
145+
return err
146+
}
147+
148+
if err := framework.SetupReporting(flags.logType, flags.logFile); err != nil {
149+
return err
150+
}
151+
152+
switch flags.cmd {
153+
case runSingleCmd:
154+
bmc, err := bmc.NewBMC(flags.execEnv, cfg)
155+
if err != nil {
156+
return err
157+
}
158+
defer func() {
159+
if err := bmc.Close(); err != nil {
160+
log.Print(err)
161+
}
162+
}()
163+
return runSingle(flags.testName, bmc, cfg)
164+
case runSuiteCmd:
165+
bmc, err := bmc.NewBMC(flags.execEnv, cfg)
166+
if err != nil {
167+
return err
168+
}
169+
defer func() {
170+
if err := bmc.Close(); err != nil {
171+
log.Print(err)
172+
}
173+
}()
174+
return runSuite(flags.suite, bmc, cfg)
175+
case runAllCmd:
176+
bmc, err := bmc.NewBMC(flags.execEnv, cfg)
177+
if err != nil {
178+
return err
179+
}
180+
defer func() {
181+
if err := bmc.Close(); err != nil {
182+
log.Print(err)
183+
}
184+
}()
185+
return runAll(bmc, cfg)
186+
case runCfgCmd:
187+
bmc, err := bmc.NewBMC(flags.execEnv, cfg)
188+
if err != nil {
189+
return err
190+
}
191+
defer func() {
192+
if err := bmc.Close(); err != nil {
193+
log.Print(err)
194+
}
195+
}()
196+
return runFromCfg(bmc, cfg)
197+
case cfgCheckCmd:
198+
return configuration.Validate(cfg)
199+
case listTestsCmd:
200+
return listTests(flags.suite)
201+
case listSuitesCmd:
202+
return listSuites()
203+
default:
204+
return fmt.Errorf("unknown command: %s", flags.cmd)
205+
}
206+
}
207+
208+
func main() {
209+
if err := run(); err != nil {
210+
log.Print(err)
211+
os.Exit(1)
212+
}
213+
}

contrib/example_config.yaml

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,43 @@
11
---
22
version: 0
33
name: ExampleServer
4-
requirements:
5-
redfish:
6-
general:
7-
cpuvendor: "TestVendor"
8-
cpumodel: TestModel
9-
psucount: 0
10-
voltage:
11-
- TestString 1
12-
- TestString 2
13-
temperatures:
14-
- Test Temp 1
15-
- Test Temp 2
16-
fans:
17-
- Test Fans 1
18-
- Test Fans 2
19-
dimms:
4+
bm_config:
5+
bmc_host: bmcIP
6+
bmc_user: root
7+
bmc_password: 0penBmc
8+
ssh_port: "22"
9+
numHosts: 1
10+
hosts:
11+
- host1:
12+
ip: hostIP1
13+
user: hostUser1
14+
password: hostPassword1
15+
- host2:
16+
ip: hostIP2
17+
user: hostUser2
18+
password: hostPassword2
19+
testdata:
20+
system:
21+
guid: guid-string
22+
cpu:
23+
cpuvendor: ""
24+
cpumodel: ""
25+
voltage:
26+
- TestString 1
27+
- TestString 2
28+
temperatures:
29+
- Test Temp 1
30+
- Test Temp 2
31+
fans:
32+
- Test Fans 1
33+
- Test Fans 2
34+
dimms:
2035
count: 0
2136
partNo: 0123
2237
vendor: TestDimmmVendor
2338
capacity: 1336
2439
fru:
25-
fruExpected:
26-
vendor: TestFruVendor
27-
name: TestFruName
28-
serial: TestSerial001
40+
- productManufacturer: TestVal
41+
productName: 'testName'
42+
productSerial: 'testSerial'
43+
boardManufacturer: testManufacturer

go.mod

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
module github.com/9elements/bmc-test-go
22

3-
go 1.23
3+
go 1.25.0
44

5-
require gopkg.in/yaml.v3 v3.0.1
5+
require (
6+
github.com/sirupsen/logrus v1.9.4
7+
github.com/stmcginnis/gofish v0.20.0
8+
golang.org/x/crypto v0.47.0
9+
gopkg.in/yaml.v3 v3.0.1
10+
)
11+
12+
require golang.org/x/sys v0.40.0 // indirect

0 commit comments

Comments
 (0)