package identityprovider import ( "context" "io" "net/http" "strings" "testing" ) func TestReadDirectoryTraversesDepartmentsAndPages(t *testing.T) { previous := upstreamClient t.Cleanup(func() { upstreamClient = previous }) calls := map[string]int{} upstreamClient = &http.Client{Transport: transportFunc(func(req *http.Request) (*http.Response, error) { if req.Header.Get("Authorization") != "Bearer test-token" { t.Fatal("missing application token") } path := req.URL.Path calls[path]++ body := `{"code":0,"data":{"items":[]}}` switch path { case "/open-apis/contact/v3/scopes": body = `{"code":0,"data":{"department_ids":["0"],"user_ids":[]}}` case "/open-apis/contact/v3/departments/0/children": body = `{"code":0,"data":{"items":[{"open_department_id":"od_child","name":"研发","parent_department_id":"0"}]}}` case "/open-apis/contact/v3/users": if req.URL.Query().Get("department_id") == "0" && req.URL.Query().Get("page_token") == "" { body = `{"code":0,"data":{"items":[{"open_id":"ou_1","name":"甲","department_ids":["0"]}],"has_more":true,"page_token":"next"}}` } else if req.URL.Query().Get("department_id") == "0" && req.URL.Query().Get("page_token") == "next" { body = `{"code":0,"data":{"items":[{"open_id":"ou_2","name":"乙"}]}}` } else if req.URL.Query().Get("department_id") == "od_child" { body = `{"code":0,"data":{"items":[{"open_id":"ou_1","name":"甲","department_ids":["od_child"]}]}}` } else { t.Fatalf("unexpected page: %s", req.URL) } case "/open-apis/contact/v3/departments/od_child/children": default: t.Fatalf("unexpected endpoint: %s", req.URL) } return &http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(body)), Header: make(http.Header)}, nil })} snapshot, err := readDirectory(context.Background(), "test-token") if err != nil || len(snapshot.departments) != 2 || len(snapshot.members) != 2 || calls["/open-apis/contact/v3/users"] != 3 || snapshot.members["ou_1"].Departments != `["0","od_child"]` { t.Fatalf("unexpected snapshot: %v, %#v, %#v", err, snapshot, calls) } } func TestReadDirectoryFailsClosedOnIncompletePage(t *testing.T) { previous := upstreamClient t.Cleanup(func() { upstreamClient = previous }) upstreamClient = &http.Client{Transport: transportFunc(func(req *http.Request) (*http.Response, error) { body := `{"code":0,"data":{"department_ids":["0"]}}` if req.URL.Path != "/open-apis/contact/v3/scopes" { body = `{"code":0,"data":{"items":[],"has_more":true}}` } return &http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(body)), Header: make(http.Header)}, nil })} if _, err := readDirectory(context.Background(), "token"); err == nil || !strings.Contains(err.Error(), "分页游标") { t.Fatalf("accepted partial directory: %v", err) } }