Files
Gleb Chesnokov 1f48a4f400 tests: Cover SCSI commands on local and iSCSI targets
Add shared sg3_utils scenarios for scst_local and iSCSI exports: inquiry
and VPD identity, capacity, LUN visibility, write protection and invalid
LBA handling. Require the expected SCSI status and raw sense for rejected
commands, then verify that valid reads still work.

Use temporary fileio backends with 512-byte sectors. Keep fixture
identifiers within vdisk's 20-character USN limit. Match each exported
device to its fixture by identity and geometry before submitting commands.
Carry binary responses over the existing supervised command transports
and retain fixture ownership through successful cleanup.

Add framework checks for response parsing, device selection and command
interruption. Document tool prerequisites and the scsi label for both
transports through the common Make targets.
2026-10-13 12:42:36 +03:00

69 lines
1.8 KiB
Go

// SPDX-License-Identifier: GPL-2.0-only
package dataio
import (
"context"
_ "embed"
"encoding/json"
"fmt"
"time"
"scst-component-tests/internal/admin"
)
type RunFunc func(context.Context, time.Duration, ...string) (admin.Result, error)
//go:embed command.py
var binaryCommand string
type Reply struct {
ExitCode int `json:"exit_code"`
Data []byte `json:"data"`
Stderr string `json:"stderr"`
}
func invoke(ctx context.Context, run RunFunc, timeout time.Duration, request any) (Reply, error) {
var response Reply
data, err := json.Marshal(request)
if err != nil {
return response, err
}
r, err := run(ctx, timeout, "python3", "-c", binaryCommand, string(data))
if err != nil {
return response, fmt.Errorf("data command execution: %w\n%s", err, r.String())
}
if r.ExitCode != 0 {
return response, fmt.Errorf("data command helper: %s", r.String())
}
var wire struct {
ExitCode *int `json:"exit_code"`
Data *[]byte `json:"data"`
Stderr *string `json:"stderr"`
}
if err := json.Unmarshal([]byte(r.Stdout), &wire); err != nil {
return response, fmt.Errorf("data command response: %w", err)
}
if wire.ExitCode == nil || wire.Data == nil || wire.Stderr == nil {
return response, fmt.Errorf("incomplete data command response")
}
response = Reply{*wire.ExitCode, *wire.Data, *wire.Stderr}
return response, nil
}
func command(ctx context.Context, run RunFunc, timeout time.Duration, input []byte, argv ...string) (Reply, error) {
return invoke(ctx, run, timeout, struct {
Args []string `json:"argv"`
Input []byte `json:"input,omitempty"`
}{argv, input})
}
func success(r Reply, err error) ([]byte, error) {
if err != nil {
return nil, err
}
if r.ExitCode != 0 {
return nil, fmt.Errorf("data command exit %d: %s", r.ExitCode, r.Stderr)
}
return r.Data, nil
}