Transcribe: add func test

This commit is contained in:
2025-08-10 10:48:24 +03:00
parent d353f206fc
commit 87d8b05efb
4 changed files with 384 additions and 1 deletions

View File

@@ -0,0 +1,374 @@
package http
import (
"bytes"
"database/sql"
"encoding/json"
"io"
"mime/multipart"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
"time"
"git.vakhrushev.me/av/transcriber/internal/entity"
"git.vakhrushev.me/av/transcriber/internal/repo/sqlite"
"github.com/doug-martin/goqu/v9"
_ "github.com/doug-martin/goqu/v9/dialect/sqlite3"
"github.com/gin-gonic/gin"
_ "github.com/mattn/go-sqlite3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func setupTestDB(t *testing.T) (*sql.DB, *goqu.Database) {
// Создаем временную базу данных в памяти
db, err := sql.Open("sqlite3", ":memory:")
require.NoError(t, err)
gq := goqu.New("sqlite3", db)
// Создаем таблицы
createFilesTable := `
CREATE TABLE files (
id TEXT PRIMARY KEY,
storage TEXT NOT NULL,
size INTEGER NOT NULL,
created_at DATETIME NOT NULL
);`
createJobsTable := `
CREATE TABLE transcribe_jobs (
id TEXT PRIMARY KEY,
state TEXT NOT NULL,
file_id TEXT,
is_error BOOLEAN NOT NULL DEFAULT 0,
error_text TEXT,
worker TEXT,
acquired_at DATETIME,
created_at DATETIME NOT NULL,
FOREIGN KEY (file_id) REFERENCES files(id)
);`
_, err = db.Exec(createFilesTable)
require.NoError(t, err)
_, err = db.Exec(createJobsTable)
require.NoError(t, err)
return db, gq
}
func setupTestRouter(t *testing.T) (*gin.Engine, *TranscribeHandler) {
gin.SetMode(gin.TestMode)
db, gq := setupTestDB(t)
fileRepo := sqlite.NewFileRepository(db, gq)
jobRepo := sqlite.NewTranscriptJobRepository(db, gq)
handler := NewTranscribeHandler(jobRepo, fileRepo)
router := gin.New()
router.MaxMultipartMemory = 32 << 20 // 32 MiB
api := router.Group("/api")
{
api.POST("/transcribe/audio", handler.CreateTranscribeJob)
api.GET("/transcribe/:id", handler.GetTranscribeJobStatus)
}
return router, handler
}
func createMultipartRequest(t *testing.T, audioFilePath string) (*http.Request, string) {
// Открываем тестовый аудио файл
file, err := os.Open(audioFilePath)
require.NoError(t, err)
defer file.Close()
// Создаем буфер для multipart формы
var buf bytes.Buffer
writer := multipart.NewWriter(&buf)
// Создаем поле для файла
part, err := writer.CreateFormFile("audio", filepath.Base(audioFilePath))
require.NoError(t, err)
// Копируем содержимое файла
_, err = io.Copy(part, file)
require.NoError(t, err)
// Закрываем writer
err = writer.Close()
require.NoError(t, err)
// Создаем HTTP запрос
req, err := http.NewRequest("POST", "/api/transcribe/audio", &buf)
require.NoError(t, err)
req.Header.Set("Content-Type", writer.FormDataContentType())
return req, writer.FormDataContentType()
}
func TestCreateTranscribeJob_Success(t *testing.T) {
// Создаем временную директорию для файлов
tempDir := t.TempDir()
// Создаем структуру директорий для тестов
testDataDir := filepath.Join(tempDir, "data", "files")
err := os.MkdirAll(testDataDir, 0755)
require.NoError(t, err)
// Временно меняем рабочую директорию для сохранения файлов
originalWd, err := os.Getwd()
require.NoError(t, err)
defer os.Chdir(originalWd)
err = os.Chdir(tempDir)
require.NoError(t, err)
router, _ := setupTestRouter(t)
// Копируем тестовый файл во временную директорию
srcFile := filepath.Join(originalWd, "testdata", "sample.m4a")
dstFile := "sample.m4a"
src, err := os.Open(srcFile)
require.NoError(t, err)
defer src.Close()
dst, err := os.Create(dstFile)
require.NoError(t, err)
defer dst.Close()
_, err = io.Copy(dst, src)
require.NoError(t, err)
defer os.Remove(dstFile)
// Создаем запрос с тестовым аудио файлом
req, _ := createMultipartRequest(t, dstFile)
// Выполняем запрос
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
// Проверяем результат
assert.Equal(t, http.StatusCreated, w.Code)
var response CreateTranscribeJobResponse
err = json.Unmarshal(w.Body.Bytes(), &response)
require.NoError(t, err)
// Проверяем, что возвращается корректный ответ
assert.NotEmpty(t, response.JobID)
assert.Equal(t, entity.StateCreated, response.State)
// Проверяем, что файл был сохранен
files, err := filepath.Glob(filepath.Join("data", "files", "*"))
require.NoError(t, err)
assert.Len(t, files, 1)
// Проверяем размер сохраненного файла
fileInfo, err := os.Stat(files[0])
require.NoError(t, err)
assert.Greater(t, fileInfo.Size(), int64(0))
}
func TestCreateTranscribeJob_NoFile(t *testing.T) {
router, _ := setupTestRouter(t)
// Создаем запрос без файла
req, err := http.NewRequest("POST", "/api/transcribe/audio", nil)
require.NoError(t, err)
// Выполняем запрос
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
// Проверяем результат
assert.Equal(t, http.StatusBadRequest, w.Code)
var response map[string]string
err = json.Unmarshal(w.Body.Bytes(), &response)
require.NoError(t, err)
assert.Equal(t, "No audio file provided", response["error"])
}
func TestCreateTranscribeJob_EmptyFile(t *testing.T) {
// Создаем временную директорию для файлов
tempDir := t.TempDir()
// Создаем структуру директорий для тестов
testDataDir := filepath.Join(tempDir, "data", "files")
err := os.MkdirAll(testDataDir, 0755)
require.NoError(t, err)
// Временно меняем рабочую директорию для сохранения файлов
originalWd, err := os.Getwd()
require.NoError(t, err)
defer os.Chdir(originalWd)
err = os.Chdir(tempDir)
require.NoError(t, err)
router, _ := setupTestRouter(t)
// Создаем пустой временный файл в текущей директории теста
emptyFile := "empty.m4a"
f, err := os.Create(emptyFile)
require.NoError(t, err)
f.Close()
defer os.Remove(emptyFile)
// Создаем запрос с пустым файлом
req, _ := createMultipartRequest(t, emptyFile)
// Выполняем запрос
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
// Проверяем результат - даже пустой файл должен быть принят
assert.Equal(t, http.StatusCreated, w.Code)
var response CreateTranscribeJobResponse
err = json.Unmarshal(w.Body.Bytes(), &response)
require.NoError(t, err)
assert.NotEmpty(t, response.JobID)
assert.Equal(t, entity.StateCreated, response.State)
}
func TestCreateTranscribeJob_DifferentFileExtensions(t *testing.T) {
testCases := []struct {
name string
filename string
expectExt string
}{
{
name: "m4a file",
filename: "test.m4a",
expectExt: ".m4a",
},
{
name: "mp3 file",
filename: "test.mp3",
expectExt: ".mp3",
},
{
name: "wav file",
filename: "test.wav",
expectExt: ".wav",
},
{
name: "file without extension",
filename: "test",
expectExt: ".audio",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// Создаем временную директорию для файлов
tempDir := t.TempDir()
// Создаем структуру директорий для тестов
testDataDir := filepath.Join(tempDir, "data", "files")
err := os.MkdirAll(testDataDir, 0755)
require.NoError(t, err)
// Временно меняем рабочую директорию для сохранения файлов
originalWd, err := os.Getwd()
require.NoError(t, err)
defer os.Chdir(originalWd)
err = os.Chdir(tempDir)
require.NoError(t, err)
router, _ := setupTestRouter(t)
// Создаем временный файл с нужным именем в текущей директории теста
testFile := tc.filename
f, err := os.Create(testFile)
require.NoError(t, err)
f.WriteString("test audio content")
f.Close()
defer os.Remove(testFile)
// Создаем запрос
req, _ := createMultipartRequest(t, testFile)
// Выполняем запрос
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
// Проверяем результат
assert.Equal(t, http.StatusCreated, w.Code)
// Проверяем, что файл сохранен с правильным расширением
files, err := filepath.Glob(filepath.Join("data", "files", "*"+tc.expectExt))
require.NoError(t, err)
assert.Len(t, files, 1)
})
}
}
func TestGetTranscribeJobStatus_Success(t *testing.T) {
router, handler := setupTestRouter(t)
// Создаем тестовую запись в базе данных
job := &entity.TranscribeJob{
Id: "test-job-id",
State: entity.StateCreated,
FileID: nil,
IsError: false,
CreatedAt: time.Now(),
}
err := handler.jobRepo.Create(job)
require.NoError(t, err)
// Создаем запрос
req, err := http.NewRequest("GET", "/api/transcribe/test-job-id", nil)
require.NoError(t, err)
// Выполняем запрос
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
// Проверяем результат
assert.Equal(t, http.StatusOK, w.Code)
var response GetTranscribeJobResponse
err = json.Unmarshal(w.Body.Bytes(), &response)
require.NoError(t, err)
assert.Equal(t, "test-job-id", response.JobID)
assert.Equal(t, entity.StateCreated, response.State)
assert.NotZero(t, response.CreatedAt)
}
func TestGetTranscribeJobStatus_NotFound(t *testing.T) {
router, _ := setupTestRouter(t)
// Создаем запрос с несуществующим ID
req, err := http.NewRequest("GET", "/api/transcribe/non-existent-id", nil)
require.NoError(t, err)
// Выполняем запрос
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
// Проверяем результат
assert.Equal(t, http.StatusNotFound, w.Code)
var response map[string]string
err = json.Unmarshal(w.Body.Bytes(), &response)
require.NoError(t, err)
assert.Equal(t, "Job not found", response["error"])
}