package repository import ( "sync" "testing" "time" "job-cheng-xing/model" ) func strPtr(s string) *string { return &s } func TestMemoryRepo_CreateAndFind(t *testing.T) { repo := NewMemoryRepo() order := &model.Order{ ID: "ord_001", Status: model.StatusPending, ServiceTime: time.Now(), Duration: 120, Address: "北京朝阳", CreatedAt: time.Now(), UpdatedAt: time.Now(), } err := repo.Create(order) if err != nil { t.Fatalf("Create failed: %v", err) } found, err := repo.FindByID("ord_001") if err != nil { t.Fatalf("FindByID failed: %v", err) } if found.ID != "ord_001" { t.Errorf("expected ord_001, got %s", found.ID) } } func TestMemoryRepo_FindByID_NotFound(t *testing.T) { repo := NewMemoryRepo() _, err := repo.FindByID("nonexistent") if err != model.ErrNotFound { t.Errorf("expected ErrNotFound, got %v", err) } } func TestMemoryRepo_Update_CAS_Success(t *testing.T) { repo := NewMemoryRepo() order := &model.Order{ ID: "ord_001", Status: model.StatusPending, ServiceTime: time.Now(), Duration: 120, Address: "北京朝阳", CreatedAt: time.Now(), UpdatedAt: time.Now(), } repo.Create(order) newOrder := &model.Order{ Status: model.StatusAccepted, ProviderID: strPtr("prov_001"), UpdatedAt: time.Now(), } err := repo.Update("ord_001", model.StatusPending, newOrder) if err != nil { t.Fatalf("Update failed: %v", err) } found, _ := repo.FindByID("ord_001") if found.Status != model.StatusAccepted { t.Errorf("expected accepted, got %s", found.Status) } if *found.ProviderID != "prov_001" { t.Errorf("expected prov_001, got %s", *found.ProviderID) } } func TestMemoryRepo_Update_CAS_Fail_WrongStatus(t *testing.T) { repo := NewMemoryRepo() order := &model.Order{ ID: "ord_001", Status: model.StatusPending, } repo.Create(order) newOrder := &model.Order{Status: model.StatusCanceled} err := repo.Update("ord_001", model.StatusAccepted, newOrder) if err != model.ErrStatusConflict { t.Errorf("expected ErrStatusConflict, got %v", err) } } func TestMemoryRepo_ConcurrentAccept(t *testing.T) { repo := NewMemoryRepo() order := &model.Order{ ID: "ord_001", Status: model.StatusPending, ServiceTime: time.Now(), Duration: 120, Address: "北京朝阳", CreatedAt: time.Now(), UpdatedAt: time.Now(), } repo.Create(order) const numGoroutines = 50 var wg sync.WaitGroup results := make(chan error, numGoroutines) for i := 0; i < numGoroutines; i++ { wg.Add(1) go func(idx int) { defer wg.Done() pid := "prov_" + string(rune('a'+idx%26)) + string(rune('0'+idx/26)) newOrder := &model.Order{ Status: model.StatusAccepted, ProviderID: &pid, UpdatedAt: time.Now(), } results <- repo.Update("ord_001", model.StatusPending, newOrder) }(i) } wg.Wait() close(results) successCount := 0 failCount := 0 for err := range results { if err == nil { successCount++ } else if err == model.ErrStatusConflict { failCount++ } else { t.Errorf("unexpected error: %v", err) } } if successCount != 1 { t.Errorf("expected exactly 1 success, got %d", successCount) } if failCount != numGoroutines-1 { t.Errorf("expected %d failures, got %d", numGoroutines-1, failCount) } found, _ := repo.FindByID("ord_001") if found.ProviderID == nil { t.Fatal("expected ProviderID to be set") } t.Logf("winner provider: %s", *found.ProviderID) }