test(H-271): remove race-suite lifecycle blockers (#45)
Co-authored-by: Rogee <rogee@ipao.vip>
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -26,12 +27,32 @@ func init() {
|
||||
|
||||
// ============ DB-Backed Test Helpers (Cov16) ============
|
||||
|
||||
// ponytail: coverage tests are sequential; use per-test DBs if they adopt t.Parallel.
|
||||
var (
|
||||
coverageTestDBMu sync.Mutex
|
||||
coverageTestDBs = make(map[string]*gorm.DB)
|
||||
)
|
||||
|
||||
func sharedCoverageTestDB(t *testing.T, name string, models ...interface{}) *gorm.DB {
|
||||
t.Helper()
|
||||
coverageTestDBMu.Lock()
|
||||
defer coverageTestDBMu.Unlock()
|
||||
|
||||
db := coverageTestDBs[name]
|
||||
if db == nil {
|
||||
var err error
|
||||
db, err = gorm.Open(sqlite.Open("file:"+name+"?mode=memory&cache=shared"), &gorm.Config{})
|
||||
require.NoError(t, err, "failed to open test database")
|
||||
require.NoError(t, db.AutoMigrate(models...), "failed to auto-migrate models")
|
||||
coverageTestDBs[name] = db
|
||||
}
|
||||
t.Cleanup(func() { testutil.TruncateAll(t, db) })
|
||||
return db
|
||||
}
|
||||
|
||||
// newTestDB_Cov16 creates an in-memory SQLite DB with a broad set of models auto-migrated.
|
||||
func newTestDB_Cov16(t *testing.T) *gorm.DB {
|
||||
t.Helper()
|
||||
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
|
||||
require.NoError(t, err, "failed to open test database")
|
||||
|
||||
models := []interface{}{
|
||||
&model.Account{},
|
||||
&model.User{},
|
||||
@@ -100,10 +121,7 @@ func newTestDB_Cov16(t *testing.T) *gorm.DB {
|
||||
&model.Audit{},
|
||||
}
|
||||
|
||||
err = db.AutoMigrate(models...)
|
||||
require.NoError(t, err, "failed to auto-migrate models")
|
||||
|
||||
return db
|
||||
return sharedCoverageTestDB(t, "coverage16", models...)
|
||||
}
|
||||
|
||||
// seedAccount_Cov16 creates and persists a test account.
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/gochat/gochat/internal/model"
|
||||
@@ -18,8 +17,6 @@ import (
|
||||
|
||||
func newTestDB_Cov18(t *testing.T) *gorm.DB {
|
||||
t.Helper()
|
||||
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
|
||||
require.NoError(t, err)
|
||||
models := []interface{}{
|
||||
&model.Account{}, &model.User{}, &model.AccountUser{}, &model.Inbox{},
|
||||
&model.Contact{}, &model.ContactInbox{}, &model.Conversation{}, &model.Message{},
|
||||
@@ -36,10 +33,7 @@ func newTestDB_Cov18(t *testing.T) *gorm.DB {
|
||||
&model.WorkingHour{}, &model.CaptainAssistant{}, &model.CaptainDocument{},
|
||||
&model.CaptainPreference{},
|
||||
}
|
||||
for _, m := range models {
|
||||
require.NoError(t, db.AutoMigrate(m))
|
||||
}
|
||||
return db
|
||||
return sharedCoverageTestDB(t, "coverage18", models...)
|
||||
}
|
||||
|
||||
func seedAccount_Cov18(t *testing.T, db *gorm.DB) uint {
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/gochat/gochat/internal/model"
|
||||
@@ -22,9 +21,6 @@ import (
|
||||
|
||||
func newTestDB_Cov19(t *testing.T) *gorm.DB {
|
||||
t.Helper()
|
||||
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
|
||||
require.NoError(t, err, "failed to open test database")
|
||||
|
||||
models := []interface{}{
|
||||
&model.Account{}, &model.User{}, &model.AccountUser{}, &model.Inbox{},
|
||||
&model.Contact{}, &model.ContactInbox{}, &model.Conversation{}, &model.Message{},
|
||||
@@ -42,8 +38,7 @@ func newTestDB_Cov19(t *testing.T) *gorm.DB {
|
||||
&model.ContactNote{}, &model.CaptainAssistant{}, &model.CaptainDocument{},
|
||||
&model.CaptainPreference{},
|
||||
}
|
||||
require.NoError(t, db.AutoMigrate(models...), "failed to auto-migrate models")
|
||||
return db
|
||||
return sharedCoverageTestDB(t, "coverage19", models...)
|
||||
}
|
||||
|
||||
func seedAccount_Cov19(t *testing.T, db *gorm.DB) *model.Account {
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/gochat/gochat/internal/model"
|
||||
@@ -24,9 +23,6 @@ import (
|
||||
|
||||
func newTestDB_Cov20(t *testing.T) *gorm.DB {
|
||||
t.Helper()
|
||||
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
|
||||
require.NoError(t, err, "failed to open test database")
|
||||
|
||||
models := []interface{}{
|
||||
&model.Account{}, &model.User{}, &model.AccountUser{}, &model.Inbox{},
|
||||
&model.Contact{}, &model.ContactInbox{}, &model.Conversation{}, &model.Message{},
|
||||
@@ -44,8 +40,7 @@ func newTestDB_Cov20(t *testing.T) *gorm.DB {
|
||||
&model.WorkingHour{}, &model.ContactNote{}, &model.CaptainAssistant{},
|
||||
&model.CaptainDocument{}, &model.CaptainPreference{}, &model.WidgetTest{},
|
||||
}
|
||||
require.NoError(t, db.AutoMigrate(models...), "failed to auto-migrate models")
|
||||
return db
|
||||
return sharedCoverageTestDB(t, "coverage20", models...)
|
||||
}
|
||||
|
||||
func seedAccount_Cov20(t *testing.T, db *gorm.DB) *model.Account {
|
||||
|
||||
@@ -1162,18 +1162,16 @@ func TestWatermillZapAdapter_With(t *testing.T) {
|
||||
// Returns the server side and the client side.
|
||||
func newTestWSConn(t *testing.T) (*websocket.Conn, *websocket.Conn) {
|
||||
t.Helper()
|
||||
// Create an in-process WebSocket server
|
||||
upgrader := websocket.Upgrader{
|
||||
CheckOrigin: func(r *http.Request) bool { return true },
|
||||
}
|
||||
serverConn := make(chan *websocket.Conn, 1)
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
conn, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// Block forever — the client side will close
|
||||
<-r.Context().Done()
|
||||
conn.Close()
|
||||
serverConn <- conn
|
||||
}))
|
||||
t.Cleanup(srv.Close)
|
||||
|
||||
@@ -1182,36 +1180,14 @@ func newTestWSConn(t *testing.T) (*websocket.Conn, *websocket.Conn) {
|
||||
clientConn, _, err := dialer.Dial(wsURL, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Accept the server-side connection by making a second request
|
||||
// Actually, httptest.NewServer with the upgrader already accepted it.
|
||||
// We need to get the server conn. Let's use a different approach:
|
||||
// Use net.Pipe-based websocket pair.
|
||||
clientConn.Close()
|
||||
srv.Close()
|
||||
|
||||
// Use websocket.NewPreparedMessages approach — or just use a pipe-based approach
|
||||
// Actually, simplest: use a real WS server that returns the server conn
|
||||
var serverConn *websocket.Conn
|
||||
srv2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
conn, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
serverConn = conn
|
||||
}))
|
||||
t.Cleanup(srv2.Close)
|
||||
|
||||
wsURL2 := "ws" + strings.TrimPrefix(srv2.URL, "http")
|
||||
clientConn2, _, err := dialer.Dial(wsURL2, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Wait briefly for serverConn to be set
|
||||
for i := 0; i < 100 && serverConn == nil; i++ {
|
||||
time.Sleep(time.Millisecond)
|
||||
select {
|
||||
case conn := <-serverConn:
|
||||
return conn, clientConn
|
||||
case <-time.After(2 * time.Second):
|
||||
clientConn.Close()
|
||||
t.Fatal("server connection was not established")
|
||||
return nil, nil
|
||||
}
|
||||
require.NotNil(t, serverConn, "server connection was not established")
|
||||
|
||||
return serverConn, clientConn2
|
||||
}
|
||||
|
||||
func TestHandlerHandleUnsubscribe_InvalidIdentifier(t *testing.T) {
|
||||
|
||||
@@ -2,11 +2,15 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gochat/gochat/internal/model"
|
||||
"github.com/gochat/gochat/internal/repository"
|
||||
"github.com/gochat/gochat/pkg/testutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gorm.io/driver/sqlite"
|
||||
@@ -14,33 +18,53 @@ import (
|
||||
"gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
// ponytail: coverage tests are sequential; use per-test DBs if they adopt t.Parallel.
|
||||
var (
|
||||
simpleServiceTestDBMu sync.Mutex
|
||||
simpleServiceDBs = make(map[string]*gorm.DB)
|
||||
)
|
||||
|
||||
func newSimpleServiceTestDB(t *testing.T, models ...interface{}) *gorm.DB {
|
||||
t.Helper()
|
||||
db, err := gorm.Open(sqlite.Open("file::memory:"), &gorm.Config{Logger: logger.Default.LogMode(logger.Silent)})
|
||||
require.NoError(t, err)
|
||||
allModels := append([]interface{}{
|
||||
&model.Account{}, &model.User{}, &model.AccountUser{},
|
||||
&model.Inbox{}, &model.Contact{}, &model.ContactInbox{},
|
||||
&model.Conversation{}, &model.Message{}, &model.Attachment{},
|
||||
&model.Notification{}, &model.NotificationPreference{},
|
||||
&model.Tag{}, &model.ConversationLabel{}, &model.ContactLabel{},
|
||||
&model.Team{}, &model.TeamMember{},
|
||||
&model.Banner{}, &model.Note{}, &model.ContactNote{},
|
||||
&model.InstallationConfig{},
|
||||
&model.InboxLimit{}, &model.InboxMember{},
|
||||
&model.AgentBot{}, &model.AgentBotInbox{},
|
||||
&model.DeliveryStatus{},
|
||||
&model.ReportingEvent{},
|
||||
&model.SlaEvent{}, &model.SlaPolicy{}, &model.AppliedSLA{},
|
||||
&model.WidgetTest{},
|
||||
&model.PushToken{},
|
||||
&model.NotificationSubscription{},
|
||||
&model.EmailChannelMigration{},
|
||||
&model.Article{},
|
||||
&model.Folder{},
|
||||
&model.CustomAttributeDefinition{},
|
||||
}, models...)
|
||||
require.NoError(t, db.AutoMigrate(allModels...))
|
||||
simpleServiceTestDBMu.Lock()
|
||||
defer simpleServiceTestDBMu.Unlock()
|
||||
|
||||
key := ""
|
||||
for _, model := range models {
|
||||
key += "|" + reflect.TypeOf(model).String()
|
||||
}
|
||||
db := simpleServiceDBs[key]
|
||||
if db == nil {
|
||||
baseModels := []interface{}{
|
||||
&model.Account{}, &model.User{}, &model.AccountUser{},
|
||||
&model.Inbox{}, &model.Contact{}, &model.ContactInbox{},
|
||||
&model.Conversation{}, &model.Message{}, &model.Attachment{},
|
||||
&model.Notification{}, &model.NotificationPreference{},
|
||||
&model.Tag{}, &model.ConversationLabel{}, &model.ContactLabel{},
|
||||
&model.Team{}, &model.TeamMember{},
|
||||
&model.Banner{}, &model.Note{}, &model.ContactNote{},
|
||||
&model.InstallationConfig{},
|
||||
&model.InboxLimit{}, &model.InboxMember{},
|
||||
&model.AgentBot{}, &model.AgentBotInbox{},
|
||||
&model.DeliveryStatus{},
|
||||
&model.ReportingEvent{},
|
||||
&model.SlaEvent{}, &model.SlaPolicy{}, &model.AppliedSLA{},
|
||||
&model.WidgetTest{},
|
||||
&model.PushToken{},
|
||||
&model.NotificationSubscription{},
|
||||
&model.EmailChannelMigration{},
|
||||
&model.Article{},
|
||||
&model.Folder{},
|
||||
&model.CustomAttributeDefinition{},
|
||||
}
|
||||
allModels := append(baseModels, models...)
|
||||
var err error
|
||||
db, err = gorm.Open(sqlite.Open(fmt.Sprintf("file:service-coverage-%d?mode=memory&cache=shared", len(simpleServiceDBs))), &gorm.Config{Logger: logger.Default.LogMode(logger.Silent)})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.AutoMigrate(allModels...))
|
||||
simpleServiceDBs[key] = db
|
||||
}
|
||||
t.Cleanup(func() { testutil.TruncateAll(t, db) })
|
||||
return db
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user