package server import ( "context" "encoding/json" "fmt" "io/fs" "log" "net/http" "os" "testing" "time" "git.javil.eu/jacob1123/budgeteer/bcrypt" "git.javil.eu/jacob1123/budgeteer/config" "git.javil.eu/jacob1123/budgeteer/jwt" "git.javil.eu/jacob1123/budgeteer/postgres" "git.javil.eu/jacob1123/budgeteer/web" ) func TestMain(t *testing.T) { t.Parallel() cfg := config.Config{ DatabaseConnection: "postgres://budgeteer:budgeteer@db:5432/budgeteer_test", SessionSecret: "random string for JWT authorization", } queries, err := postgres.Connect("pgtx", cfg.DatabaseConnection) if err != nil { log.Fatalf("Failed connecting to DB: %v", err) } static, err := fs.Sub(web.Static, "dist") if err != nil { panic("couldn't open static files") } tokenVerifier, err := jwt.NewTokenVerifier(cfg.SessionSecret) if err != nil { panic(fmt.Errorf("couldn't create token verifier: %w", err)) } handler := &Handler{ Service: queries, TokenVerifier: tokenVerifier, CredentialsVerifier: &bcrypt.Verifier{}, StaticFS: http.FS(static), } ctx := context.Background() createUserParams := postgres.CreateUserParams{ Email: "test@example.com", Name: "test@example.com", Password: "this is my dumb password", } user, err := handler.Service.CreateUser(ctx, createUserParams) if err != nil { fmt.Println(err) t.Fail() return } budget, err := handler.Service.NewBudget(ctx, "My nice Budget", user.ID) if err != nil { fmt.Println(err) t.Fail() return } handler.DoYNABImport(ctx, t, budget) // check available balance for more dates handler.CheckAvailableBalance(ctx, t, budget) // check categories // check accounts } type CategoryTestData struct { Available float64 Activity float64 Assigned float64 } func (h Handler) CheckAvailableBalance(ctx context.Context, t *testing.T, budget *postgres.Budget) { t.Helper() loc := time.Now().Location() first := time.Date(2021, 12, 1, 0, 0, 0, 0, loc) firstOfNextMonth := time.Date(2022, 1, 1, 0, 0, 0, 0, loc) data, err := h.prepareBudgeting(ctx, *budget, firstOfNextMonth, first) if err != nil { t.Errorf("prepare budgeting: %s", err) return } // 2022-01 assert_equal(t, -115170.56, data.AvailableBalance.GetFloat64(), "available balance") assertEqual(t, -110181.600, data.AvailableBalance.GetFloat64(), "available balance") categoryTestDataFile, err := os.Open("../testdata/production-export/results/categories-2021-12.json") if err != nil { t.Errorf("could not load category test data: %s", err) return } var categoryTestData map[string]CategoryTestData dec := json.NewDecoder(categoryTestDataFile) err = dec.Decode(&categoryTestData) if err != nil { t.Errorf("could not decode category test data: %s", err) return } for categoryName, categoryTestData := range categoryTestData { found := false for _, category := range data.Categories { name := category.Group + " : " + category.Name if name == categoryName { assertEqual(t, categoryTestData.Available, category.Available.GetFloat64(), "available for "+categoryName) assertEqual(t, categoryTestData.Activity, category.Activity.GetFloat64(), "activity for "+categoryName) assertEqual(t, categoryTestData.Assigned, category.Assigned.GetFloat64(), "assigned for "+categoryName) found = true } } if !found { t.Errorf("category " + categoryName + " was not found in result") } } } func assertEqual(t *testing.T, expected, actual float64, message string) { t.Helper() if expected == actual { return } t.Errorf("%s: expected %f, got %f", message, expected, actual) } func (h Handler) DoYNABImport(ctx context.Context, t *testing.T, budget *postgres.Budget) { t.Helper() budgetID := budget.ID ynab, err := postgres.NewYNABImport(ctx, h.Service.Queries, budgetID) if err != nil { fmt.Println(err) t.Fail() return } transactions, err := os.Open("../testdata/production-export/Register.tsv") if err != nil { fmt.Println(err) t.Fail() return } assignments, err := os.Open("../testdata/production-export/Budget.tsv") if err != nil { fmt.Println(err) t.Fail() return } err = ynab.ImportTransactions(ctx, transactions) if err != nil { fmt.Println(err) t.Fail() return } err = ynab.ImportAssignments(ctx, assignments) if err != nil { fmt.Println(err) t.Fail() return } }