You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

385 lines
7.1 KiB

package testrunner
import (
"testing"
"time"
)
func TestParse_ValidScenario(t *testing.T) {
yaml := `
name: test-scenario
timeout: 5m
env:
repo_dir: "/tmp/repo"
topology:
nodes:
node1:
host: "192.168.1.1"
user: testdev
key: "/tmp/key"
targets:
primary:
node: node1
vol_size: 100M
iscsi_port: 3260
admin_port: 8080
iqn_suffix: test-primary
replica:
node: node1
vol_size: 100M
iscsi_port: 3261
admin_port: 8081
replica_data_port: 9011
replica_ctrl_port: 9012
rebuild_port: 9013
iqn_suffix: test-replica
phases:
- name: setup
actions:
- action: build_deploy
- action: start_target
target: primary
create: "true"
- name: cleanup
always: true
actions:
- action: stop_all_targets
ignore_error: true
`
s, err := Parse([]byte(yaml))
if err != nil {
t.Fatalf("Parse failed: %v", err)
}
if s.Name != "test-scenario" {
t.Errorf("name = %q, want %q", s.Name, "test-scenario")
}
if s.Timeout.Duration != 5*time.Minute {
t.Errorf("timeout = %v, want 5m", s.Timeout.Duration)
}
if len(s.Topology.Nodes) != 1 {
t.Errorf("nodes = %d, want 1", len(s.Topology.Nodes))
}
if len(s.Targets) != 2 {
t.Errorf("targets = %d, want 2", len(s.Targets))
}
if len(s.Phases) != 2 {
t.Errorf("phases = %d, want 2", len(s.Phases))
}
// Check target IQN generation.
if iqn := s.Targets["primary"].IQN(); iqn != "iqn.2024.com.seaweedfs:test-primary" {
t.Errorf("primary IQN = %q", iqn)
}
// Check always flag.
if !s.Phases[1].Always {
t.Error("cleanup phase should have always=true")
}
}
func TestParse_MissingName(t *testing.T) {
yaml := `
phases:
- name: test
actions:
- action: exec
cmd: "echo hi"
`
_, err := Parse([]byte(yaml))
if err == nil {
t.Fatal("expected error for missing name")
}
}
func TestParse_InvalidNodeRef(t *testing.T) {
yaml := `
name: bad-ref
topology:
nodes:
node1:
host: "1.2.3.4"
user: test
key: "/tmp/key"
targets:
tgt:
node: nonexistent
iscsi_port: 3260
iqn_suffix: test
phases:
- name: test
actions:
- action: exec
cmd: "echo"
`
_, err := Parse([]byte(yaml))
if err == nil {
t.Fatal("expected error for invalid node ref")
}
}
func TestParse_PortConflict(t *testing.T) {
yaml := `
name: port-conflict
topology:
nodes:
node1:
host: "1.2.3.4"
user: test
key: "/tmp/key"
targets:
tgt1:
node: node1
iscsi_port: 3260
iqn_suffix: t1
tgt2:
node: node1
iscsi_port: 3260
iqn_suffix: t2
phases:
- name: test
actions:
- action: exec
cmd: "echo"
`
_, err := Parse([]byte(yaml))
if err == nil {
t.Fatal("expected error for port conflict")
}
}
func TestParse_InvalidTargetRef(t *testing.T) {
yaml := `
name: bad-target-ref
topology:
nodes:
node1:
host: "1.2.3.4"
user: test
key: "/tmp/key"
targets:
primary:
node: node1
iscsi_port: 3260
iqn_suffix: test
phases:
- name: test
actions:
- action: start_target
target: nonexistent
`
_, err := Parse([]byte(yaml))
if err == nil {
t.Fatal("expected error for invalid target ref in action")
}
}
func TestParse_MissingIQNSuffix(t *testing.T) {
yaml := `
name: missing-iqn
topology:
nodes:
node1:
host: "1.2.3.4"
user: test
key: "/tmp/key"
targets:
tgt:
node: node1
iscsi_port: 3260
phases:
- name: test
actions:
- action: exec
cmd: "echo"
`
_, err := Parse([]byte(yaml))
if err == nil {
t.Fatal("expected error for missing iqn_suffix")
}
}
func TestParse_NoPhases(t *testing.T) {
yaml := `
name: no-phases
`
_, err := Parse([]byte(yaml))
if err == nil {
t.Fatal("expected error for no phases")
}
}
func TestParse_AgentTopology_Valid(t *testing.T) {
yaml := `
name: agent-topo
topology:
agents:
tp01: "192.168.1.188:9100"
m01: "192.168.1.181:9100"
nodes:
tp01_node:
host: "192.168.1.188"
agent: tp01
m01_node:
host: "192.168.1.181"
agent: m01
targets:
primary:
node: tp01_node
iscsi_port: 3260
iqn_suffix: primary
phases:
- name: test
actions:
- action: exec
node: tp01_node
cmd: "echo"
`
s, err := Parse([]byte(yaml))
if err != nil {
t.Fatalf("Parse failed: %v", err)
}
if len(s.Topology.Agents) != 2 {
t.Errorf("agents = %d, want 2", len(s.Topology.Agents))
}
if s.Topology.Nodes["tp01_node"].Agent != "tp01" {
t.Error("tp01_node should have agent=tp01")
}
}
func TestParse_AgentTopology_InvalidAgentRef(t *testing.T) {
yaml := `
name: bad-agent-ref
topology:
agents:
tp01: "192.168.1.188:9100"
nodes:
node1:
host: "192.168.1.181"
agent: nonexistent
phases:
- name: test
actions:
- action: exec
cmd: "echo"
`
_, err := Parse([]byte(yaml))
if err == nil {
t.Fatal("expected error for invalid agent reference")
}
}
func TestParse_ParallelPhase_SaveAsConflict(t *testing.T) {
yaml := `
name: save-as-conflict
topology:
nodes:
node1:
host: "1.2.3.4"
user: test
key: "/tmp/key"
phases:
- name: parallel_phase
parallel: true
actions:
- action: exec
node: node1
save_as: my_var
cmd: "echo a"
- action: exec
node: node1
save_as: my_var
cmd: "echo b"
`
_, err := Parse([]byte(yaml))
if err == nil {
t.Fatal("expected error for save_as conflict in parallel phase")
}
}
func TestParse_SequentialPhase_SaveAsDuplicate_Allowed(t *testing.T) {
yaml := `
name: save-as-sequential
topology:
nodes:
node1:
host: "1.2.3.4"
user: test
key: "/tmp/key"
phases:
- name: seq_phase
actions:
- action: exec
node: node1
save_as: device
cmd: "echo a"
- action: exec
node: node1
save_as: device
cmd: "echo b"
`
_, err := Parse([]byte(yaml))
if err != nil {
t.Fatalf("sequential save_as duplicate should be allowed, got: %v", err)
}
}
func TestParse_ActionRetryAndTimeout(t *testing.T) {
yaml := `
name: retry-test
topology:
nodes:
n1:
host: "1.2.3.4"
user: test
key: "/tmp/key"
phases:
- name: test
actions:
- action: start_target
node: n1
retry: 2
timeout: 30s
cmd: "echo"
`
s, err := Parse([]byte(yaml))
if err != nil {
t.Fatalf("Parse failed: %v", err)
}
act := s.Phases[0].Actions[0]
if act.Retry != 2 {
t.Errorf("retry = %d, want 2", act.Retry)
}
if act.Timeout != "30s" {
t.Errorf("timeout = %q, want 30s", act.Timeout)
}
}
func TestExtractVarsFromString(t *testing.T) {
tests := []struct {
input string
want []string
}{
{"{{ device }}", []string{"device"}},
{"{{written_md5}}", []string{"written_md5"}},
{"prefix {{ a }} middle {{ b }} suffix", []string{"a", "b"}},
{"no vars here", nil},
{"{{ }}", nil},
}
for _, tt := range tests {
got := extractVarsFromString(tt.input)
if len(got) != len(tt.want) {
t.Errorf("extractVarsFromString(%q) = %v, want %v", tt.input, got, tt.want)
continue
}
for i := range got {
if got[i] != tt.want[i] {
t.Errorf("extractVarsFromString(%q)[%d] = %q, want %q", tt.input, i, got[i], tt.want[i])
}
}
}
}