diff --git a/pkg/commands/runtime_libpod_test.go b/pkg/commands/runtime_libpod_test.go new file mode 100644 index 00000000..41f23a90 --- /dev/null +++ b/pkg/commands/runtime_libpod_test.go @@ -0,0 +1,258 @@ +//go:build linux && cgo + +package commands + +import ( + "testing" + "time" + + "github.com/containers/podman/v5/libpod/events" + "github.com/stretchr/testify/assert" +) + +func TestConvertLibpodEvent(t *testing.T) { + tests := []struct { + name string + input *events.Event + expected Event + }{ + { + name: "container start event", + input: &events.Event{ + Type: events.Container, + Status: events.Start, + ID: "abc123", + Name: "test-container", + Time: time.Unix(1234567890, 0), + Details: events.Details{ + Attributes: map[string]string{"image": "test:latest"}, + }, + }, + expected: Event{ + Type: "Container", + Action: "start", + Actor: EventActor{ + ID: "abc123", + Attributes: map[string]string{"image": "test:latest"}, + }, + Time: 1234567890, + }, + }, + { + name: "pod stop event", + input: &events.Event{ + Type: events.Pod, + Status: events.Stop, + ID: "pod456", + Name: "test-pod", + Time: time.Unix(1234567891, 0), + Details: events.Details{ + Attributes: nil, + }, + }, + expected: Event{ + Type: "Pod", + Action: "stop", + Actor: EventActor{ + ID: "pod456", + Attributes: nil, + }, + Time: 1234567891, + }, + }, + { + name: "image pull event", + input: &events.Event{ + Type: events.Image, + Status: events.Pull, + ID: "img789", + Name: "nginx:latest", + Time: time.Unix(1234567892, 0), + Details: events.Details{ + Attributes: map[string]string{}, + }, + }, + expected: Event{ + Type: "Image", + Action: "pull", + Actor: EventActor{ + ID: "img789", + Attributes: map[string]string{}, + }, + Time: 1234567892, + }, + }, + { + name: "volume create event", + input: &events.Event{ + Type: events.Volume, + Status: events.Create, + ID: "vol999", + Name: "test-volume", + Time: time.Unix(1234567893, 0), + }, + expected: Event{ + Type: "Volume", + Action: "create", + Actor: EventActor{ + ID: "vol999", + Attributes: nil, + }, + Time: 1234567893, + }, + }, + { + name: "network remove event", + input: &events.Event{ + Type: events.Network, + Status: events.Remove, + ID: "net111", + Name: "test-network", + Time: time.Unix(1234567894, 0), + }, + expected: Event{ + Type: "Network", + Action: "remove", + Actor: EventActor{ + ID: "net111", + Attributes: nil, + }, + Time: 1234567894, + }, + }, + { + name: "container die event with attributes", + input: &events.Event{ + Type: events.Container, + Status: events.Died, + ID: "ctr222", + Name: "dying-container", + Time: time.Unix(1234567895, 0), + Details: events.Details{ + Attributes: map[string]string{ + "exitCode": "1", + "image": "alpine:latest", + }, + }, + }, + expected: Event{ + Type: "Container", + Action: "died", + Actor: EventActor{ + ID: "ctr222", + Attributes: map[string]string{ + "exitCode": "1", + "image": "alpine:latest", + }, + }, + Time: 1234567895, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := convertLibpodEvent(tt.input) + assert.Equal(t, tt.expected.Type, result.Type, "Event type mismatch") + assert.Equal(t, tt.expected.Action, result.Action, "Event action mismatch") + assert.Equal(t, tt.expected.Actor.ID, result.Actor.ID, "Actor ID mismatch") + assert.Equal(t, tt.expected.Time, result.Time, "Event time mismatch") + assert.Equal(t, tt.expected.Actor.Attributes, result.Actor.Attributes, "Attributes mismatch") + }) + } +} + +func TestConvertLibpodEvent_AllEventTypes(t *testing.T) { + // Test that all major event types are correctly converted + eventTypes := []events.Type{ + events.Container, + events.Pod, + events.Image, + events.Volume, + events.Network, + events.System, + } + + for _, eventType := range eventTypes { + t.Run(string(eventType), func(t *testing.T) { + input := &events.Event{ + Type: eventType, + Status: events.Create, + ID: "test-id", + Time: time.Unix(1234567890, 0), + } + result := convertLibpodEvent(input) + assert.Equal(t, string(eventType), result.Type) + assert.Equal(t, "create", result.Action) + }) + } +} + +func TestConvertLibpodEvent_AllEventStatuses(t *testing.T) { + // Test that common event statuses are correctly converted + statuses := []events.Status{ + events.Start, + events.Stop, + events.Create, + events.Remove, + events.Pause, + events.Unpause, + events.Kill, + events.Died, + events.Pull, + events.Push, + events.Restart, + } + + for _, status := range statuses { + t.Run(string(status), func(t *testing.T) { + input := &events.Event{ + Type: events.Container, + Status: status, + ID: "test-id", + Time: time.Unix(1234567890, 0), + } + result := convertLibpodEvent(input) + assert.Equal(t, string(status), result.Action) + }) + } +} + +func TestConvertLibpodEvent_EmptyAttributes(t *testing.T) { + // Test that nil and empty attributes are handled correctly + testCases := []struct { + name string + attributes map[string]string + }{ + {"nil attributes", nil}, + {"empty attributes", map[string]string{}}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + input := &events.Event{ + Type: events.Container, + Status: events.Start, + ID: "test-id", + Time: time.Unix(1234567890, 0), + Details: events.Details{ + Attributes: tc.attributes, + }, + } + result := convertLibpodEvent(input) + assert.Equal(t, tc.attributes, result.Actor.Attributes) + }) + } +} + +func TestLibpodRuntimeEvents_ContextCancellation(t *testing.T) { + // This test verifies that Events() respects context cancellation + // Mock implementation would be needed for full testing + t.Skip("Requires mock libpod runtime for full integration test") +} + +func TestLibpodRuntimeEvents_ErrorHandling(t *testing.T) { + // This test verifies error handling in event streaming + // Mock implementation would be needed for full testing + t.Skip("Requires mock libpod runtime for full integration test") +}