Files
transcriber/internal/controller/http/transcribe_test.go

369 lines
10 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package http
import (
"bytes"
"database/sql"
"encoding/json"
"io"
"mime/multipart"
"net/http"
"net/http/httptest"
"os"
"path"
"path/filepath"
"runtime"
"testing"
"time"
"git.vakhrushev.me/av/transcriber/internal/adapter/ffmpeg"
"git.vakhrushev.me/av/transcriber/internal/adapter/s3"
"git.vakhrushev.me/av/transcriber/internal/adapter/sqlite"
"git.vakhrushev.me/av/transcriber/internal/entity"
"git.vakhrushev.me/av/transcriber/internal/service"
"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/pressly/goose/v3"
"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)
err = goose.SetDialect("sqlite3")
require.NoError(t, err)
_, b, _, _ := runtime.Caller(0)
migpath, err := filepath.Abs(path.Join(b, "../../../../migrations"))
require.NoError(t, err)
err = goose.Up(db, migpath)
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)
converter := ffmpeg.NewFfmpegConverter()
s3Service := &s3.TestS3service{}
trsService := service.NewTranscribeService(jobRepo, fileRepo, converter, s3Service)
handler := NewTranscribeHandler(jobRepo, trsService)
router := gin.New()
router.MaxMultipartMemory = 32 << 20 // 32 MiB
api := router.Group("/api")
{
api.POST("/audio", handler.CreateTranscribeJob)
api.GET("/status/: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/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/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/status/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/status/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"])
}