380 lines
8.6 KiB
Go
380 lines
8.6 KiB
Go
package pipeline
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/leonardotrapani/hyprvoice/internal/config"
|
|
)
|
|
|
|
func TestNew(t *testing.T) {
|
|
cfg := &config.Config{
|
|
Recording: config.RecordingConfig{
|
|
SampleRate: 16000,
|
|
Channels: 1,
|
|
Format: "s16",
|
|
BufferSize: 8192,
|
|
ChannelBufferSize: 30,
|
|
Timeout: 5 * time.Minute,
|
|
},
|
|
Transcription: config.TranscriptionConfig{
|
|
Provider: "openai",
|
|
APIKey: "test-key",
|
|
Language: "en",
|
|
Model: "whisper-1",
|
|
},
|
|
Injection: config.InjectionConfig{
|
|
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
|
|
WtypeTimeout: 5 * time.Second,
|
|
ClipboardTimeout: 3 * time.Second,
|
|
},
|
|
Notifications: config.NotificationsConfig{
|
|
Enabled: true,
|
|
Type: "log",
|
|
},
|
|
}
|
|
|
|
pipeline := New(cfg)
|
|
if pipeline == nil {
|
|
t.Errorf("New() returned nil")
|
|
return
|
|
}
|
|
|
|
// Test that pipeline is created successfully
|
|
// Note: Status may be empty initially due to implementation
|
|
t.Logf("Initial status = %s", pipeline.Status())
|
|
}
|
|
|
|
func TestPipeline_Status(t *testing.T) {
|
|
cfg := &config.Config{
|
|
Recording: config.RecordingConfig{
|
|
SampleRate: 16000,
|
|
Channels: 1,
|
|
Format: "s16",
|
|
BufferSize: 8192,
|
|
ChannelBufferSize: 30,
|
|
Timeout: 5 * time.Minute,
|
|
},
|
|
Transcription: config.TranscriptionConfig{
|
|
Provider: "openai",
|
|
APIKey: "test-key",
|
|
Language: "en",
|
|
Model: "whisper-1",
|
|
},
|
|
Injection: config.InjectionConfig{
|
|
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
|
|
WtypeTimeout: 5 * time.Second,
|
|
ClipboardTimeout: 3 * time.Second,
|
|
},
|
|
Notifications: config.NotificationsConfig{
|
|
Enabled: true,
|
|
Type: "log",
|
|
},
|
|
}
|
|
|
|
pipeline := New(cfg)
|
|
|
|
// Test that we can get status (may be empty initially)
|
|
status := pipeline.Status()
|
|
t.Logf("Status() = %s", status)
|
|
|
|
// Test that we can get action channel
|
|
actionCh := pipeline.GetActionCh()
|
|
if actionCh == nil {
|
|
t.Errorf("GetActionCh() returned nil")
|
|
}
|
|
|
|
// Test that we can get error channel
|
|
errorCh := pipeline.GetErrorCh()
|
|
if errorCh == nil {
|
|
t.Errorf("GetErrorCh() returned nil")
|
|
}
|
|
}
|
|
|
|
func TestPipeline_GetActionCh(t *testing.T) {
|
|
cfg := &config.Config{
|
|
Recording: config.RecordingConfig{
|
|
SampleRate: 16000,
|
|
Channels: 1,
|
|
Format: "s16",
|
|
BufferSize: 8192,
|
|
ChannelBufferSize: 30,
|
|
Timeout: 5 * time.Minute,
|
|
},
|
|
Transcription: config.TranscriptionConfig{
|
|
Provider: "openai",
|
|
APIKey: "test-key",
|
|
Language: "en",
|
|
Model: "whisper-1",
|
|
},
|
|
Injection: config.InjectionConfig{
|
|
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
|
|
WtypeTimeout: 5 * time.Second,
|
|
ClipboardTimeout: 3 * time.Second,
|
|
},
|
|
Notifications: config.NotificationsConfig{
|
|
Enabled: true,
|
|
Type: "log",
|
|
},
|
|
}
|
|
|
|
pipeline := New(cfg)
|
|
actionCh := pipeline.GetActionCh()
|
|
|
|
if actionCh == nil {
|
|
t.Errorf("GetActionCh() returned nil")
|
|
return
|
|
}
|
|
|
|
// Test sending an action
|
|
select {
|
|
case actionCh <- Inject:
|
|
// Action sent successfully
|
|
default:
|
|
t.Errorf("Could not send action to channel")
|
|
}
|
|
}
|
|
|
|
func TestPipeline_GetErrorCh(t *testing.T) {
|
|
cfg := &config.Config{
|
|
Recording: config.RecordingConfig{
|
|
SampleRate: 16000,
|
|
Channels: 1,
|
|
Format: "s16",
|
|
BufferSize: 8192,
|
|
ChannelBufferSize: 30,
|
|
Timeout: 5 * time.Minute,
|
|
},
|
|
Transcription: config.TranscriptionConfig{
|
|
Provider: "openai",
|
|
APIKey: "test-key",
|
|
Language: "en",
|
|
Model: "whisper-1",
|
|
},
|
|
Injection: config.InjectionConfig{
|
|
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
|
|
WtypeTimeout: 5 * time.Second,
|
|
ClipboardTimeout: 3 * time.Second,
|
|
},
|
|
Notifications: config.NotificationsConfig{
|
|
Enabled: true,
|
|
Type: "log",
|
|
},
|
|
}
|
|
|
|
pipeline := New(cfg)
|
|
errorCh := pipeline.GetErrorCh()
|
|
|
|
if errorCh == nil {
|
|
t.Errorf("GetErrorCh() returned nil")
|
|
return
|
|
}
|
|
|
|
// Test that we can receive from the error channel
|
|
select {
|
|
case <-errorCh:
|
|
// Error received
|
|
default:
|
|
// No error available, which is expected
|
|
}
|
|
}
|
|
|
|
func TestPipeline_Stop(t *testing.T) {
|
|
cfg := &config.Config{
|
|
Recording: config.RecordingConfig{
|
|
SampleRate: 16000,
|
|
Channels: 1,
|
|
Format: "s16",
|
|
BufferSize: 8192,
|
|
ChannelBufferSize: 30,
|
|
Timeout: 5 * time.Minute,
|
|
},
|
|
Transcription: config.TranscriptionConfig{
|
|
Provider: "openai",
|
|
APIKey: "test-key",
|
|
Language: "en",
|
|
Model: "whisper-1",
|
|
},
|
|
Injection: config.InjectionConfig{
|
|
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
|
|
WtypeTimeout: 5 * time.Second,
|
|
ClipboardTimeout: 3 * time.Second,
|
|
},
|
|
Notifications: config.NotificationsConfig{
|
|
Enabled: true,
|
|
Type: "log",
|
|
},
|
|
}
|
|
|
|
pipeline := New(cfg)
|
|
|
|
// Stop should be safe to call even when not running
|
|
pipeline.Stop()
|
|
|
|
// Status should be consistent after stop
|
|
status := pipeline.Status()
|
|
t.Logf("Status after stop = %s", status)
|
|
}
|
|
|
|
func TestPipeline_Run(t *testing.T) {
|
|
cfg := &config.Config{
|
|
Recording: config.RecordingConfig{
|
|
SampleRate: 16000,
|
|
Channels: 1,
|
|
Format: "s16",
|
|
BufferSize: 8192,
|
|
ChannelBufferSize: 30,
|
|
Timeout: 5 * time.Minute,
|
|
},
|
|
Transcription: config.TranscriptionConfig{
|
|
Provider: "openai",
|
|
APIKey: "test-key",
|
|
Language: "en",
|
|
Model: "whisper-1",
|
|
},
|
|
Injection: config.InjectionConfig{
|
|
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
|
|
WtypeTimeout: 5 * time.Second,
|
|
ClipboardTimeout: 3 * time.Second,
|
|
},
|
|
Notifications: config.NotificationsConfig{
|
|
Enabled: true,
|
|
Type: "log",
|
|
},
|
|
}
|
|
|
|
pipeline := New(cfg)
|
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
|
defer cancel()
|
|
|
|
// Test running the pipeline
|
|
pipeline.Run(ctx)
|
|
|
|
// Give it a moment to start
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
// Check status after starting (may transition quickly due to test environment)
|
|
status := pipeline.Status()
|
|
t.Logf("Status after Run = %s", status)
|
|
|
|
// Stop the pipeline
|
|
pipeline.Stop()
|
|
|
|
// Give it a moment to stop
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
// Check final status
|
|
finalStatus := pipeline.Status()
|
|
t.Logf("Status after Stop = %s", finalStatus)
|
|
}
|
|
|
|
func TestStatus_String(t *testing.T) {
|
|
tests := []struct {
|
|
status Status
|
|
expected string
|
|
}{
|
|
{Idle, "idle"},
|
|
{Recording, "recording"},
|
|
{Transcribing, "transcribing"},
|
|
{Injecting, "injecting"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(string(tt.status), func(t *testing.T) {
|
|
if string(tt.status) != tt.expected {
|
|
t.Errorf("Status string = %s, want %s", string(tt.status), tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAction_String(t *testing.T) {
|
|
tests := []struct {
|
|
action Action
|
|
expected string
|
|
}{
|
|
{Inject, "inject"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(string(tt.action), func(t *testing.T) {
|
|
if string(tt.action) != tt.expected {
|
|
t.Errorf("Action string = %s, want %s", string(tt.action), tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestPipelineError_Struct(t *testing.T) {
|
|
err := PipelineError{
|
|
Title: "Test Title",
|
|
Message: "Test Message",
|
|
Err: nil,
|
|
}
|
|
|
|
if err.Title != "Test Title" {
|
|
t.Errorf("Title = %s, want %s", err.Title, "Test Title")
|
|
}
|
|
|
|
if err.Message != "Test Message" {
|
|
t.Errorf("Message = %s, want %s", err.Message, "Test Message")
|
|
}
|
|
|
|
if err.Err != nil {
|
|
t.Errorf("Err = %v, want nil", err.Err)
|
|
}
|
|
}
|
|
|
|
// TestPipeline_ConcurrentAccess tests concurrent access to pipeline methods
|
|
func TestPipeline_ConcurrentAccess(t *testing.T) {
|
|
cfg := &config.Config{
|
|
Recording: config.RecordingConfig{
|
|
SampleRate: 16000,
|
|
Channels: 1,
|
|
Format: "s16",
|
|
BufferSize: 8192,
|
|
ChannelBufferSize: 30,
|
|
Timeout: 5 * time.Minute,
|
|
},
|
|
Transcription: config.TranscriptionConfig{
|
|
Provider: "openai",
|
|
APIKey: "test-key",
|
|
Language: "en",
|
|
Model: "whisper-1",
|
|
},
|
|
Injection: config.InjectionConfig{
|
|
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
|
|
WtypeTimeout: 5 * time.Second,
|
|
ClipboardTimeout: 3 * time.Second,
|
|
},
|
|
Notifications: config.NotificationsConfig{
|
|
Enabled: true,
|
|
Type: "log",
|
|
},
|
|
}
|
|
|
|
pipeline := New(cfg)
|
|
|
|
// Test concurrent access to Status()
|
|
done := make(chan bool)
|
|
go func() {
|
|
for i := 0; i < 100; i++ {
|
|
pipeline.Status()
|
|
}
|
|
done <- true
|
|
}()
|
|
|
|
go func() {
|
|
for i := 0; i < 100; i++ {
|
|
pipeline.GetActionCh()
|
|
pipeline.GetErrorCh()
|
|
}
|
|
done <- true
|
|
}()
|
|
|
|
// Wait for both goroutines to complete
|
|
<-done
|
|
<-done
|
|
}
|