Skip to content

Commit 7f2c155

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 7f2c155

37 files changed

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

cmds/openbmc-tests/main.go

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

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

0 commit comments

Comments
 (0)