guard_test.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. package agentserver
  2. import (
  3. "context"
  4. "errors"
  5. "testing"
  6. )
  7. type fakeStore struct {
  8. owners map[string]string // sessionId → userId(未删除)
  9. resources map[string]string // resourceId → sessionId
  10. err error
  11. }
  12. func (f *fakeStore) SessionOwner(_ context.Context, sid string) (string, bool, error) {
  13. if f.err != nil {
  14. return "", false, f.err
  15. }
  16. o, ok := f.owners[sid]
  17. return o, ok, nil
  18. }
  19. func (f *fakeStore) ResourceSession(_ context.Context, id string) (string, bool, error) {
  20. s, ok := f.resources[id]
  21. return s, ok, nil
  22. }
  23. func (f *fakeStore) RecentSessionIds(_ context.Context, uid string, _ int) ([]string, error) {
  24. var out []string
  25. for s, o := range f.owners {
  26. if o == uid {
  27. out = append(out, s)
  28. }
  29. }
  30. return out, nil
  31. }
  32. type fakeUpstream struct {
  33. runs map[string]string // runId → sessionId
  34. files map[string][]string
  35. itx map[string][]string
  36. }
  37. func (f *fakeUpstream) GetRun(_ context.Context, id string) (*RunDto, error) {
  38. s, ok := f.runs[id]
  39. if !ok {
  40. return nil, ErrNotFound
  41. }
  42. return &RunDto{Id: id, SessionId: s}, nil
  43. }
  44. func (f *fakeUpstream) ListFiles(_ context.Context, sid string) ([]FileDto, error) {
  45. var out []FileDto
  46. for _, id := range f.files[sid] {
  47. out = append(out, FileDto{Id: id, SessionId: sid})
  48. }
  49. return out, nil
  50. }
  51. func (f *fakeUpstream) PendingInteractions(_ context.Context, sid string) ([]InteractionRefDto, error) {
  52. var out []InteractionRefDto
  53. for _, id := range f.itx[sid] {
  54. out = append(out, InteractionRefDto{InteractionId: id})
  55. }
  56. return out, nil
  57. }
  58. type fakeSink struct{ got []Resource }
  59. func (f *fakeSink) Record(rs []Resource) { f.got = append(f.got, rs...) }
  60. func newTestGuard() (*Guard, *fakeSink) {
  61. sink := &fakeSink{}
  62. return &Guard{
  63. Store: &fakeStore{
  64. owners: map[string]string{"ses_a1": "alice", "ses_b1": "bob"},
  65. resources: map[string]string{"run_a": "ses_a1", "file_b": "ses_b1"},
  66. },
  67. Upstream: &fakeUpstream{
  68. runs: map[string]string{"run_a2": "ses_a1", "run_b2": "ses_b1"},
  69. files: map[string][]string{"ses_a1": {"file_a2"}, "ses_b1": {"file_b2"}},
  70. itx: map[string][]string{"ses_a1": {"itx_a2"}, "ses_b1": {"itx_b2"}},
  71. },
  72. Sink: sink,
  73. }, sink
  74. }
  75. func TestGuardCheck(t *testing.T) {
  76. g, sink := newTestGuard()
  77. ctx := context.Background()
  78. cases := []struct {
  79. name string
  80. route Route
  81. ok bool
  82. sid string
  83. }{
  84. {"元数据", Route{Owner: OwnerNone}, true, ""},
  85. {"本人会话", Route{Owner: OwnerSession, Id: "ses_a1"}, true, "ses_a1"},
  86. {"他人会话", Route{Owner: OwnerSession, Id: "ses_b1"}, false, ""},
  87. {"不存在的会话", Route{Owner: OwnerSession, Id: "ses_zz"}, false, ""},
  88. {"查询参数会话(他人)", Route{Owner: OwnerQuerySession, Id: "ses_b1"}, false, ""},
  89. {"索引中的本人 run", Route{Owner: OwnerRun, Id: "run_a"}, true, "ses_a1"},
  90. {"索引中的他人文件", Route{Owner: OwnerFile, Id: "file_b"}, false, ""},
  91. {"反查本人 run", Route{Owner: OwnerRun, Id: "run_a2"}, true, "ses_a1"},
  92. {"反查他人 run", Route{Owner: OwnerRun, Id: "run_b2"}, false, ""},
  93. {"反查不存在的 run", Route{Owner: OwnerRun, Id: "run_zz"}, false, ""},
  94. {"反查本人文件", Route{Owner: OwnerFile, Id: "file_a2"}, true, "ses_a1"},
  95. {"反查他人文件", Route{Owner: OwnerFile, Id: "file_b2"}, false, ""},
  96. {"反查本人交互", Route{Owner: OwnerInteraction, Id: "itx_a2"}, true, "ses_a1"},
  97. {"反查他人交互", Route{Owner: OwnerInteraction, Id: "itx_b2"}, false, ""},
  98. }
  99. for _, c := range cases {
  100. sid, ok, err := g.Check(ctx, "alice", c.route)
  101. if err != nil {
  102. t.Errorf("%s: err %v", c.name, err)
  103. continue
  104. }
  105. if ok != c.ok || sid != c.sid {
  106. t.Errorf("%s: got ok=%v sid=%q, want ok=%v sid=%q", c.name, ok, sid, c.ok, c.sid)
  107. }
  108. }
  109. // 反查成功的三项应补写索引
  110. want := map[string]string{"run_a2": "ses_a1", "file_a2": "ses_a1", "itx_a2": "ses_a1"}
  111. if len(sink.got) != len(want) {
  112. t.Fatalf("补写索引 %v", sink.got)
  113. }
  114. for _, r := range sink.got {
  115. if want[r.Id] != r.SessionId {
  116. t.Errorf("补写了不应写入的索引 %+v", r)
  117. }
  118. }
  119. }
  120. func TestGuardStoreError(t *testing.T) {
  121. g := &Guard{Store: &fakeStore{err: errors.New("mongo down")}}
  122. if _, ok, err := g.Check(context.Background(), "alice", Route{Owner: OwnerSession, Id: "ses_a1"}); err == nil || ok {
  123. t.Fatalf("存储出错时应返回错误且不放行,得到 ok=%v err=%v", ok, err)
  124. }
  125. }