| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 |
- package service
- import (
- "encoding/json"
- "testing"
- "github.com/mhsanaei/3x-ui/v3/internal/database/model"
- )
- // TestExportImportPreservesDisabledEnable covers #6478: ExportAll keeps the
- // real enable flag; ImportClients must not force enable=true.
- func TestExportImportPreservesDisabledEnable(t *testing.T) {
- setupBulkDB(t)
- svc := &ClientService{}
- inboundSvc := &InboundService{}
- ib := mkInbound(t, 26001, model.VLESS, `{"clients":[]}`)
- const email = "portable@disabled"
- const subID = "sub-portable-disabled"
- if _, err := svc.Create(inboundSvc, &ClientCreatePayload{
- Client: model.Client{
- Email: email, SubID: subID, Enable: true,
- ID: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
- },
- InboundIds: []int{ib.Id},
- }); err != nil {
- t.Fatalf("Create: %v", err)
- }
- rec := lookupClientRecord(t, email)
- updated := rec.ToClient()
- updated.Enable = false
- if _, err := svc.Update(inboundSvc, rec.Id, *updated, 0); err != nil {
- t.Fatalf("Update disable: %v", err)
- }
- assertEnableEverywhere(t, svc, inboundSvc, ib.Id, email, false)
- exported, err := svc.ExportAll()
- if err != nil {
- t.Fatalf("ExportAll: %v", err)
- }
- if len(exported) != 1 {
- t.Fatalf("ExportAll len=%d, want 1", len(exported))
- }
- if exported[0].Client.Enable {
- t.Fatal("ExportAll should carry enable=false for a disabled client")
- }
- raw, err := json.Marshal(exported)
- if err != nil {
- t.Fatalf("marshal export: %v", err)
- }
- var roundTrip []ClientCreatePayload
- if err := json.Unmarshal(raw, &roundTrip); err != nil {
- t.Fatalf("unmarshal export: %v", err)
- }
- if roundTrip[0].Client.Enable {
- t.Fatal("JSON round-trip lost enable=false")
- }
- if _, err := svc.Delete(inboundSvc, rec.Id, false); err != nil {
- t.Fatalf("Delete: %v", err)
- }
- res, _, err := svc.ImportClients(inboundSvc, roundTrip)
- if err != nil {
- t.Fatalf("ImportClients: %v", err)
- }
- if res.Created != 1 || len(res.Skipped) != 0 {
- t.Fatalf("ImportClients result=%+v", res)
- }
- assertEnableEverywhere(t, svc, inboundSvc, ib.Id, email, false)
- }
- func TestImportClientsPreservesOrphanDisabledEnable(t *testing.T) {
- setupBulkDB(t)
- svc := &ClientService{}
- items := []ClientCreatePayload{{
- Client: model.Client{
- Email: "orphan@disabled", SubID: "sub-orphan-disabled", Enable: false,
- ID: "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
- },
- InboundIds: nil,
- }}
- res, _, err := svc.ImportClients(&InboundService{}, items)
- if err != nil {
- t.Fatalf("ImportClients orphan: %v", err)
- }
- if res.Created != 1 {
- t.Fatalf("created=%d, want 1; skipped=%v", res.Created, res.Skipped)
- }
- if got := recordEnableOf(t, svc, "orphan@disabled"); got {
- t.Fatal("orphan import forced enable=true; want false")
- }
- }
- func TestBulkCreatePreservesExplicitDisable(t *testing.T) {
- setupBulkDB(t)
- svc := &ClientService{}
- inboundSvc := &InboundService{}
- ib := mkInbound(t, 26002, model.VLESS, `{"clients":[]}`)
- const email = "bulk@disabled"
- res, _, err := svc.BulkCreate(inboundSvc, []ClientCreatePayload{{
- Client: model.Client{
- Email: email, SubID: "sub-bulk-disabled", Enable: false,
- ID: "cccccccc-cccc-cccc-cccc-cccccccccccc",
- },
- InboundIds: []int{ib.Id},
- }})
- if err != nil {
- t.Fatalf("BulkCreate: %v", err)
- }
- if res.Created != 1 {
- t.Fatalf("BulkCreate result=%+v", res)
- }
- assertEnableEverywhere(t, svc, inboundSvc, ib.Id, email, false)
- }
- func TestClientCreatePayload_OmitEnableDefaultsTrue(t *testing.T) {
- raw := []byte(`{"client":{"email":"omit@x","id":"dddddddd-dddd-dddd-dddd-dddddddddddd","subId":"sub-omit"},"inboundIds":[1]}`)
- var p ClientCreatePayload
- if err := json.Unmarshal(raw, &p); err != nil {
- t.Fatalf("unmarshal: %v", err)
- }
- if !p.Client.Enable {
- t.Fatal("omitted enable must default to true")
- }
- rawFalse := []byte(`{"client":{"email":"off@x","id":"eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee","subId":"sub-off","enable":false},"inboundIds":[1]}`)
- var pFalse ClientCreatePayload
- if err := json.Unmarshal(rawFalse, &pFalse); err != nil {
- t.Fatalf("unmarshal false: %v", err)
- }
- if pFalse.Client.Enable {
- t.Fatal("explicit enable:false must stay false")
- }
- }
- func TestBulkCreate_DisabledOnNodeSkipsAddClient(t *testing.T) {
- setupBulkDB(t)
- nodeID, fake := setupNodeRuntime(t)
- ib := nodeInbound(t, nodeID, 26003, nil)
- svc := &ClientService{}
- inboundSvc := &InboundService{}
- const email = "node@disabled"
- res, _, err := svc.BulkCreate(inboundSvc, []ClientCreatePayload{{
- Client: model.Client{
- Email: email, SubID: "sub-node-disabled", Enable: false,
- ID: "ffffffff-ffff-ffff-ffff-ffffffffffff",
- },
- InboundIds: []int{ib.Id},
- }})
- if err != nil {
- t.Fatalf("BulkCreate: %v", err)
- }
- if res.Created != 1 {
- t.Fatalf("BulkCreate result=%+v", res)
- }
- if got := fake.addClient.Load(); got != 0 {
- t.Fatalf("AddClient RPCs = %d, want 0 for enable=false", got)
- }
- assertEnableEverywhere(t, svc, inboundSvc, ib.Id, email, false)
- if _, _, dirty, _, err := (&NodeService{}).NodeSyncState(nodeID); err != nil {
- t.Fatalf("NodeSyncState: %v", err)
- } else if !dirty {
- t.Fatal("disabled node create must leave node dirty for reconcile")
- }
- }
|