386 lines
13 KiB
Go
386 lines
13 KiB
Go
package importer
|
|
|
|
import (
|
|
"bamort/database"
|
|
"bamort/models"
|
|
"bytes"
|
|
"encoding/json"
|
|
"io"
|
|
"mime/multipart"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func NoT_estImportCsv2Spell(t *testing.T) {
|
|
// Clear source cache to ensure clean test state
|
|
ClearSourceCache()
|
|
|
|
// Setup test database
|
|
database.SetupTestDB(true, false) // Use in-memory SQLite, no test data loading
|
|
defer database.ResetTestDB()
|
|
models.MigrateStructure()
|
|
/*
|
|
// Create test source data
|
|
testSources := []models.Source{
|
|
{Code: "ARK", Name: "Arkanum", GameSystemId: 1},
|
|
{Code: "MYS", Name: "Mysterium", GameSystemId: 1},
|
|
{Code: "KOD", Name: "Kodex", GameSystemId: 1},
|
|
}
|
|
for _, source := range testSources {
|
|
source.Create()
|
|
}
|
|
*/
|
|
t.Run("Import Zauber-Arkanum.csv", func(t *testing.T) {
|
|
// Test if file exists
|
|
csvPath := "/data/dev/bamort/backend/doc/Zauber-Arkanum.csv"
|
|
if _, err := os.Stat(csvPath); os.IsNotExist(err) {
|
|
t.Skipf("CSV file %s not found, skipping test", csvPath)
|
|
return
|
|
}
|
|
|
|
// Test import
|
|
err := ImportCsv2Spell(csvPath)
|
|
assert.NoError(t, err, "Import should succeed")
|
|
|
|
// Verify some spells were imported
|
|
var count int64
|
|
database.DB.Model(&models.Spell{}).Count(&count)
|
|
assert.Greater(t, count, int64(0), "Should have imported some spells")
|
|
|
|
// Test specific spell with more detailed debugging
|
|
var spell models.Spell
|
|
err = spell.First("Angst")
|
|
if err != nil {
|
|
// Let's check what spells actually exist
|
|
var allSpells []models.Spell
|
|
database.DB.Limit(10).Find(&allSpells)
|
|
t.Logf("Found %d spells in database, first 10:", count)
|
|
for i, s := range allSpells {
|
|
t.Logf("Spell %d: %s (Category: %s, Level: %d)", i+1, s.Name, s.Category, s.Stufe)
|
|
}
|
|
}
|
|
assert.NoError(t, err, "Should find 'Angst' spell")
|
|
assert.Equal(t, "Beherrschen", spell.Category, "Spell category should match")
|
|
assert.Equal(t, 2, spell.Stufe, "Spell level should be 2")
|
|
|
|
// Test that source_id was set correctly (ARK should have been looked up)
|
|
if spell.SourceID != 0 {
|
|
var source models.Source
|
|
err = database.DB.First(&source, spell.SourceID).Error
|
|
assert.NoError(t, err, "Should find source by ID")
|
|
assert.Equal(t, "ARK", source.Code, "Source code should be ARK")
|
|
}
|
|
})
|
|
|
|
t.Run("Import Zauber-Mysterium.csv", func(t *testing.T) {
|
|
// Test if file exists
|
|
csvPath := "/data/dev/bamort/backend/doc/Zauber-Mysterium.csv"
|
|
if _, err := os.Stat(csvPath); os.IsNotExist(err) {
|
|
t.Skipf("CSV file %s not found, skipping test", csvPath)
|
|
return
|
|
}
|
|
|
|
// Get current spell count
|
|
var countBefore int64
|
|
database.DB.Model(&models.Spell{}).Count(&countBefore)
|
|
|
|
// Test import
|
|
err := ImportCsv2Spell(csvPath)
|
|
assert.NoError(t, err, "Import should succeed")
|
|
|
|
// Verify more spells were imported
|
|
var countAfter int64
|
|
database.DB.Model(&models.Spell{}).Count(&countAfter)
|
|
assert.Greater(t, countAfter, countBefore, "Should have imported additional spells")
|
|
})
|
|
|
|
t.Run("Test update existing spell", func(t *testing.T) {
|
|
// Create a test spell first
|
|
testSpell := models.Spell{
|
|
GameSystem: "midgard",
|
|
Name: "Test Zauber",
|
|
Beschreibung: "Original description",
|
|
Stufe: 1,
|
|
}
|
|
err := testSpell.Create()
|
|
assert.NoError(t, err, "Should create test spell")
|
|
|
|
// Create temporary CSV with updated data
|
|
csvContent := `name,Beschreibung,stufe
|
|
Test Zauber,Updated description,2`
|
|
|
|
tmpFile, err := os.CreateTemp("", "test_spell_*.csv")
|
|
assert.NoError(t, err, "Should create temp file")
|
|
defer os.Remove(tmpFile.Name())
|
|
|
|
_, err = tmpFile.WriteString(csvContent)
|
|
assert.NoError(t, err, "Should write to temp file")
|
|
tmpFile.Close()
|
|
|
|
// Import the updated data
|
|
err = ImportCsv2Spell(tmpFile.Name())
|
|
assert.NoError(t, err, "Import should succeed")
|
|
|
|
// Verify the spell was updated
|
|
var updatedSpell models.Spell
|
|
err = updatedSpell.First("Test Zauber")
|
|
assert.NoError(t, err, "Should find updated spell")
|
|
assert.Equal(t, "Updated description", updatedSpell.Beschreibung, "Description should be updated")
|
|
assert.Equal(t, 2, updatedSpell.Stufe, "Level should be updated")
|
|
})
|
|
|
|
t.Run("Test source lookup function", func(t *testing.T) {
|
|
// Clear cache to ensure fresh lookups
|
|
ClearSourceCache()
|
|
|
|
// Test successful lookup of existing source
|
|
sourceID, err := lookupSourceID("ARK")
|
|
assert.NoError(t, err, "Should find ARK source")
|
|
assert.Greater(t, sourceID, uint(0), "Source ID should be greater than 0")
|
|
|
|
// Test auto-creation of non-existent source
|
|
newSourceID, err := lookupSourceID("NEWCODE")
|
|
assert.NoError(t, err, "Should auto-create NEWCODE source")
|
|
assert.Greater(t, newSourceID, uint(0), "New source ID should be greater than 0")
|
|
|
|
// Verify the source was actually created in the database
|
|
var newSource models.Source
|
|
err = database.DB.First(&newSource, newSourceID).Error
|
|
assert.NoError(t, err, "Should find newly created source")
|
|
assert.Equal(t, "NEWCODE", newSource.Code, "Source code should match")
|
|
assert.Equal(t, "NEWCODE", newSource.Name, "Source name should default to code")
|
|
assert.Equal(t, "midgard", newSource.GameSystem, "Game system should be midgard")
|
|
assert.True(t, newSource.IsActive, "New source should be active")
|
|
|
|
// Test that the second lookup uses cache (should return same ID)
|
|
cachedSourceID, err := lookupSourceID("NEWCODE")
|
|
assert.NoError(t, err, "Should find cached source")
|
|
assert.Equal(t, newSourceID, cachedSourceID, "Cached lookup should return same ID")
|
|
|
|
// Test empty source code
|
|
_, err = lookupSourceID("")
|
|
assert.Error(t, err, "Should return error for empty source code")
|
|
})
|
|
|
|
t.Run("Test auto-creation of sources during CSV import", func(t *testing.T) {
|
|
// Clear cache and check initial source count
|
|
ClearSourceCache()
|
|
var initialSourceCount int64
|
|
database.DB.Model(&models.Source{}).Count(&initialSourceCount)
|
|
|
|
// Create temporary CSV with a new source code
|
|
csvContent := `name,quelle,stufe,category
|
|
Test Spell,TESTSRC,1,Beherrschen`
|
|
|
|
tmpFile, err := os.CreateTemp("", "test_auto_source_*.csv")
|
|
assert.NoError(t, err, "Should create temp file")
|
|
defer os.Remove(tmpFile.Name())
|
|
|
|
_, err = tmpFile.WriteString(csvContent)
|
|
assert.NoError(t, err, "Should write to temp file")
|
|
tmpFile.Close()
|
|
|
|
// Import the CSV
|
|
err = ImportCsv2Spell(tmpFile.Name())
|
|
assert.NoError(t, err, "Import should succeed")
|
|
|
|
// Verify new source was created
|
|
var finalSourceCount int64
|
|
database.DB.Model(&models.Source{}).Count(&finalSourceCount)
|
|
assert.Greater(t, finalSourceCount, initialSourceCount, "Should have created new source")
|
|
|
|
// Verify the spell was imported with correct source
|
|
var importedSpell models.Spell
|
|
err = importedSpell.First("Test Spell")
|
|
assert.NoError(t, err, "Should find imported spell")
|
|
assert.Equal(t, "TESTSRC", importedSpell.Quelle, "Spell quelle should match")
|
|
assert.Greater(t, importedSpell.SourceID, uint(0), "Spell should have source ID")
|
|
|
|
// Verify the source details
|
|
var createdSource models.Source
|
|
err = database.DB.First(&createdSource, importedSpell.SourceID).Error
|
|
assert.NoError(t, err, "Should find created source")
|
|
assert.Equal(t, "TESTSRC", createdSource.Code, "Source code should match")
|
|
})
|
|
}
|
|
|
|
func NoT_estImportSpellCSVHandler(t *testing.T) {
|
|
// Setup test database
|
|
database.SetupTestDB(true, false)
|
|
defer database.ResetTestDB()
|
|
models.MigrateStructure()
|
|
|
|
// Create test source
|
|
testSource := models.Source{Code: "ARK", Name: "Arkanum", GameSystemId: 1}
|
|
testSource.Create()
|
|
|
|
// Setup Gin in test mode
|
|
gin.SetMode(gin.TestMode)
|
|
|
|
t.Run("Successful CSV import via HTTP", func(t *testing.T) {
|
|
// Create temporary test CSV file
|
|
csvContent := `name,quelle,stufe,category
|
|
Test Spell HTTP,ARK,3,Beherrschen`
|
|
|
|
tmpFile, err := os.CreateTemp("", "test_http_*.csv")
|
|
assert.NoError(t, err, "Should create temp file")
|
|
defer os.Remove(tmpFile.Name())
|
|
|
|
_, err = tmpFile.WriteString(csvContent)
|
|
assert.NoError(t, err, "Should write to temp file")
|
|
tmpFile.Close()
|
|
|
|
// Create test request
|
|
router := gin.New()
|
|
router.POST("/test", ImportSpellCSVHandler)
|
|
|
|
req, err := http.NewRequest("POST", "/test?file="+tmpFile.Name(), nil)
|
|
assert.NoError(t, err, "Should create request")
|
|
|
|
w := httptest.NewRecorder()
|
|
router.ServeHTTP(w, req)
|
|
|
|
// Assert response
|
|
assert.Equal(t, http.StatusOK, w.Code, "Should return 200 OK")
|
|
|
|
var response map[string]interface{}
|
|
err = json.Unmarshal(w.Body.Bytes(), &response)
|
|
assert.NoError(t, err, "Should parse JSON response")
|
|
assert.True(t, response["success"].(bool), "Should indicate success")
|
|
assert.Contains(t, response, "total_spells", "Should contain spell count")
|
|
|
|
// Verify spell was imported
|
|
var spell models.Spell
|
|
err = spell.First("Test Spell HTTP")
|
|
assert.NoError(t, err, "Should find imported spell")
|
|
assert.Equal(t, 3, spell.Stufe, "Spell level should be 3")
|
|
})
|
|
|
|
t.Run("Missing file parameter", func(t *testing.T) {
|
|
router := gin.New()
|
|
router.POST("/test", ImportSpellCSVHandler)
|
|
|
|
req, err := http.NewRequest("POST", "/test", nil)
|
|
assert.NoError(t, err, "Should create request")
|
|
|
|
w := httptest.NewRecorder()
|
|
router.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusBadRequest, w.Code, "Should return 400 Bad Request")
|
|
|
|
var response map[string]interface{}
|
|
err = json.Unmarshal(w.Body.Bytes(), &response)
|
|
assert.NoError(t, err, "Should parse JSON response")
|
|
assert.Equal(t, "Missing file parameter", response["error"], "Should return correct error")
|
|
})
|
|
|
|
t.Run("File not found", func(t *testing.T) {
|
|
router := gin.New()
|
|
router.POST("/test", ImportSpellCSVHandler)
|
|
|
|
req, err := http.NewRequest("POST", "/test?file=/nonexistent/file.csv", nil)
|
|
assert.NoError(t, err, "Should create request")
|
|
|
|
w := httptest.NewRecorder()
|
|
router.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusBadRequest, w.Code, "Should return 400 Bad Request")
|
|
|
|
var response map[string]interface{}
|
|
err = json.Unmarshal(w.Body.Bytes(), &response)
|
|
assert.NoError(t, err, "Should parse JSON response")
|
|
assert.Equal(t, "File not found", response["error"], "Should return correct error")
|
|
})
|
|
|
|
t.Run("Invalid file type", func(t *testing.T) {
|
|
// Create temporary non-CSV file
|
|
tmpFile, err := os.CreateTemp("", "test_*.txt")
|
|
assert.NoError(t, err, "Should create temp file")
|
|
defer os.Remove(tmpFile.Name())
|
|
tmpFile.Close()
|
|
|
|
router := gin.New()
|
|
router.POST("/test", ImportSpellCSVHandler)
|
|
|
|
req, err := http.NewRequest("POST", "/test?file="+tmpFile.Name(), nil)
|
|
assert.NoError(t, err, "Should create request")
|
|
|
|
w := httptest.NewRecorder()
|
|
router.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusBadRequest, w.Code, "Should return 400 Bad Request")
|
|
|
|
var response map[string]interface{}
|
|
err = json.Unmarshal(w.Body.Bytes(), &response)
|
|
assert.NoError(t, err, "Should parse JSON response")
|
|
assert.Equal(t, "Invalid file type", response["error"], "Should return correct error")
|
|
})
|
|
|
|
t.Run("File upload with multipart form", func(t *testing.T) {
|
|
// Setup test database
|
|
database.SetupTestDB(true, false)
|
|
models.MigrateStructure()
|
|
|
|
// Create test CSV content
|
|
csvContent := `name,beschreibung,quelle,stufe,ap
|
|
Test Spell Upload,Test description,ARK,1,2`
|
|
|
|
// Create temporary file
|
|
tmpFile, err := os.CreateTemp("", "test_spell_upload_*.csv")
|
|
assert.NoError(t, err, "Should create temp file")
|
|
defer os.Remove(tmpFile.Name())
|
|
|
|
_, err = tmpFile.WriteString(csvContent)
|
|
assert.NoError(t, err, "Should write CSV content")
|
|
tmpFile.Close()
|
|
|
|
// Create multipart form data
|
|
body := &bytes.Buffer{}
|
|
writer := multipart.NewWriter(body)
|
|
|
|
// Add file field
|
|
file, err := os.Open(tmpFile.Name())
|
|
assert.NoError(t, err, "Should open temp file")
|
|
defer file.Close()
|
|
|
|
part, err := writer.CreateFormFile("file", "test_spells.csv")
|
|
assert.NoError(t, err, "Should create form file")
|
|
|
|
_, err = io.Copy(part, file)
|
|
assert.NoError(t, err, "Should copy file content")
|
|
|
|
err = writer.Close()
|
|
assert.NoError(t, err, "Should close writer")
|
|
|
|
// Create request
|
|
router := gin.New()
|
|
router.POST("/test", ImportSpellCSVHandler)
|
|
|
|
req, err := http.NewRequest("POST", "/test", body)
|
|
assert.NoError(t, err, "Should create request")
|
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
|
|
|
w := httptest.NewRecorder()
|
|
router.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code, "Should return 200 OK")
|
|
|
|
var response map[string]interface{}
|
|
err = json.Unmarshal(w.Body.Bytes(), &response)
|
|
assert.NoError(t, err, "Should parse JSON response")
|
|
assert.True(t, response["success"].(bool), "Should be successful")
|
|
assert.Contains(t, response["message"], "imported successfully", "Should contain success message")
|
|
|
|
// Verify spell was imported
|
|
var spell models.Spell
|
|
err = database.DB.Where("name = ?", "Test Spell Upload").First(&spell).Error
|
|
assert.NoError(t, err, "Should find imported spell")
|
|
assert.Equal(t, "Test description", spell.Beschreibung, "Should have correct description")
|
|
})
|
|
}
|