0.1.3-prod

reduce timeouts
added tests and mock interface
This commit is contained in:
2025-08-22 03:38:57 +03:00
parent 6c95d944a1
commit 6c3950953e
3 changed files with 327 additions and 63 deletions

187
main_test.go Normal file
View File

@@ -0,0 +1,187 @@
package main
import (
"encoding/json"
"os"
"path/filepath"
"shtrih-kkt/pkg/shtrih"
"testing"
)
// loadCanonicalKKTData загружает эталонные данные ККТ из файла для тестов.
// Путь к файлу указывается относительно корня проекта.
func loadCanonicalKKTData(t *testing.T, path string) *shtrih.FiscalInfo {
data, err := os.ReadFile(path)
if err != nil {
t.Fatalf("Критическая ошибка: не удалось прочитать канонический файл данных '%s': %v", path, err)
}
var info shtrih.FiscalInfo
if err := json.Unmarshal(data, &info); err != nil {
t.Fatalf("Критическая ошибка: не удалось распарсить JSON из канонического файла '%s': %v", path, err)
}
return &info
}
// TestProcessDevices_NewFileFromDonor проверяет сценарий, когда для ККТ еще нет
// файла, но есть файл-донор с данными о рабочей станции.
func TestProcessDevices_NewFileFromDonor(t *testing.T) {
// --- Arrange (Подготовка) ---
// 1. Создаем временную директорию для теста, чтобы не засорять реальную папку `date`.
tempDir := t.TempDir()
originalOutputDir := outputDir
outputDir = tempDir
defer func() { outputDir = originalOutputDir }()
// 2. Загружаем канонические данные для мок-драйвера из файла.
// Этот файл должен быть создан заранее и помещен в pkg/shtrih/testdata/
mockKKTData := loadCanonicalKKTData(t, "pkg/shtrih/testdata/canonical_kkt_data.json")
// 3. Создаем файл-донор с уникальными данными о рабочей станции во временной папке.
donorData := map[string]interface{}{
"hostname": "DONOR-PC",
"teamviewer_id": "999888777",
"vc": "3.0-donor-test",
}
donorBytes, _ := json.Marshal(donorData)
donorFilePath := filepath.Join(tempDir, "donor.json")
if err := os.WriteFile(donorFilePath, donorBytes, 0644); err != nil {
t.Fatalf("Не удалось создать тестовый файл-донор: %v", err)
}
// 4. Создаем "фабрику", которая вернет мок-драйвер с нашими каноническими данными.
mockDriverFactory := func(config shtrih.Config) shtrih.Driver {
return shtrih.NewMockDriver(mockKKTData, nil, nil)
}
// 5. Готовим входные данные для processDevices.
testConfigs := []shtrih.Config{{ConnectionType: 6, IPAddress: "127.0.0.1"}}
// --- Act (Действие) ---
processDevices(testConfigs, mockDriverFactory)
// --- Assert (Проверка) ---
// 1. Проверяем, что был создан правильный JSON-файл.
expectedFileName := mockKKTData.SerialNumber + ".json"
resultFilePath := filepath.Join(tempDir, expectedFileName)
if _, err := os.Stat(resultFilePath); os.IsNotExist(err) {
t.Fatalf("Ожидалось, что будет создан файл '%s', но он не найден.", resultFilePath)
}
// 2. Читаем созданный файл и проверяем его содержимое.
resultBytes, err := os.ReadFile(resultFilePath)
if err != nil {
t.Fatalf("Не удалось прочитать результирующий файл '%s': %v", resultFilePath, err)
}
var resultMap map[string]interface{}
if err := json.Unmarshal(resultBytes, &resultMap); err != nil {
t.Fatalf("Не удалось распарсить JSON из результирующего файла: %v", err)
}
// 3. Проверяем, что данные из ККТ и донора корректно слились.
// Проверка поля от ККТ.
if resultMap["modelName"] != mockKKTData.ModelName {
t.Errorf("Поле 'modelName' неверно. Ожидалось '%s', получено '%v'", mockKKTData.ModelName, resultMap["modelName"])
}
// Проверка полей от донора.
if resultMap["hostname"] != donorData["hostname"] {
t.Errorf("Поле 'hostname' из донора не было добавлено. Ожидалось '%s', получено '%v'", donorData["hostname"], resultMap["hostname"])
}
if resultMap["vc"] != donorData["vc"] {
t.Errorf("Поле 'vc' из донора не было добавлено. Ожидалось '%s', получено '%v'", donorData["vc"], resultMap["vc"])
}
// Проверка автоматически сгенерированных полей времени.
if _, ok := resultMap["current_time"]; !ok {
t.Error("Отсутствует обязательное поле 'current_time'.")
}
if _, ok := resultMap["v_time"]; !ok {
t.Error("Отсутствует обязательное поле 'v_time'.")
}
}
// TestFindSourceWorkstationData_FileHandling проверяет непосредственно логику
// поиска и чтения донор-файла в смоделированной файловой структуре.
func TestFindSourceWorkstationData_FileHandling(t *testing.T) {
// --- Сценарий 1: В папке /date есть правильный донор-файл ---
t.Run("when valid donor file exists", func(t *testing.T) {
// Arrange: Готовим файловую систему
tempDir := t.TempDir()
originalOutputDir := outputDir
outputDir = tempDir // Указываем, что наша папка "date" находится во временной директории
defer func() { outputDir = originalOutputDir }()
// Создаем донор-файл с уникальными данными для проверки
donorData := map[string]interface{}{
"hostname": "REAL-DONOR-PC",
"vc": "v_from_real_file",
}
donorBytes, _ := json.Marshal(donorData)
if err := os.WriteFile(filepath.Join(tempDir, "donor_to_find.json"), donorBytes, 0644); err != nil {
t.Fatalf("Не удалось создать тестовый файл-донор: %v", err)
}
// Создаем "файл-ловушку" от другого ККТ, который должен быть проигнорирован
kktTrapData := map[string]interface{}{
"modelName": "SOME-OTHER-KKT",
"serialNumber": "TRAP000001",
"hostname": "FAKE-HOSTNAME",
}
trapBytes, _ := json.Marshal(kktTrapData)
if err := os.WriteFile(filepath.Join(tempDir, "000001.json"), trapBytes, 0644); err != nil {
t.Fatalf("Не удалось создать файл-ловушку: %v", err)
}
// Act: Вызываем тестируемую функцию
resultMap := findSourceWorkstationData()
// Assert: Проверяем результат
if resultMap == nil {
t.Fatal("findSourceWorkstationData() вернула nil, хотя ожидались данные из донора.")
}
if resultMap["hostname"] != "REAL-DONOR-PC" {
t.Errorf("Hostname из донора прочитан неверно. Ожидалось 'REAL-DONOR-PC', получено '%v'", resultMap["hostname"])
}
if resultMap["vc"] != "v_from_real_file" {
t.Errorf("Поле 'vc' из донора прочитано неверно. Ожидалось 'v_from_real_file', получено '%v'", resultMap["vc"])
}
})
// --- Сценарий 2: В папке /date нет подходящих файлов ---
t.Run("when no valid donor file exists", func(t *testing.T) {
// Arrange: Готовим файловую систему
tempDir := t.TempDir()
originalOutputDir := outputDir
outputDir = tempDir
defer func() { outputDir = originalOutputDir }()
// Создаем только "файл-ловушку", который не должен считаться донором
kktTrapData := map[string]interface{}{
"modelName": "SOME-OTHER-KKT",
"serialNumber": "TRAP000001",
"hostname": "FAKE-HOSTNAME",
}
trapBytes, _ := json.Marshal(kktTrapData)
if err := os.WriteFile(filepath.Join(tempDir, "000001.json"), trapBytes, 0644); err != nil {
t.Fatalf("Не удалось создать файл-ловушку: %v", err)
}
// Создаем текстовый файл, который тоже должен быть проигнорирован
if err := os.WriteFile(filepath.Join(tempDir, "readme.txt"), []byte("info"), 0644); err != nil {
t.Fatalf("Не удалось создать текстовый файл: %v", err)
}
// Act: Вызываем тестируемую функцию
resultMap := findSourceWorkstationData()
// Assert: Проверяем, что функция ничего не нашла
if resultMap != nil {
t.Fatal("findSourceWorkstationData() вернула данные, хотя в папке не было валидных доноров.")
}
})
}