internal/control/orglabel_test.go
125 lines · 4991 bytes
1package control
2
3import (
4 "strings"
5 "testing"
6
7 "gitbay.org/gitbay/internal/protocol"
8)
9
10func TestOrgLabelSetListRemove(t *testing.T) {
11 f := newOrgFixture(t)
12 // Two repos already hold bug; the org set folds them in.
13 f.st.SetLabel(f.core, "bug", "")
14 f.st.SetLabel(f.priv, "bug", "")
15 c, out := f.ctx(f.alice)
16 if code := runOrgLabelSet(c, []string{"acme", "bug", "--color", "ff0000"}); code != protocol.ExitOK ||
17 !strings.Contains(out.String(), `"folded":2`) {
18 t.Fatalf("set: exit %d %s", code, out.String())
19 }
20 out.Reset()
21 if code := runOrgLabelList(c, []string{"acme"}); code != protocol.ExitOK ||
22 !strings.Contains(out.String(), `"name":"bug"`) || !strings.Contains(out.String(), `"color":"#ff0000"`) {
23 t.Fatalf("list: exit %d %s", code, out.String())
24 }
25 out.Reset()
26 if code := runOrgLabelRemove(c, []string{"acme", "bug"}); code != protocol.ExitOK {
27 t.Fatalf("remove: exit %d %s", code, out.String())
28 }
29 out.Reset()
30 if code := runOrgLabelRemove(c, []string{"acme", "bug"}); code != protocol.ExitNotFound {
31 t.Fatalf("second remove: exit %d %s", code, out.String())
32 }
33}
34
35func TestOrgLabelWritesNeedOrgAdmin(t *testing.T) {
36 f := newOrgFixture(t)
37 c, out := f.ctx(f.bob)
38 if code := runOrgLabelSet(c, []string{"acme", "bug"}); code != protocol.ExitDenied {
39 t.Fatalf("member set: exit %d %s", code, out.String())
40 }
41 if code := runOrgLabelRemove(c, []string{"acme", "bug"}); code != protocol.ExitDenied {
42 t.Fatalf("member remove: exit %d %s", code, out.String())
43 }
44 c, out = f.ctx(f.alice)
45 if code := runOrgLabelSet(c, []string{"nope", "bug"}); code != protocol.ExitNotFound {
46 t.Fatalf("missing org: exit %d %s", code, out.String())
47 }
48 if code := runOrgLabelSet(c, []string{"acme", "bug", "--color", "zz"}); code != protocol.ExitUsage {
49 t.Fatalf("bad colour: exit %d %s", code, out.String())
50 }
51}
52
53func TestOrgLabelListVisibility(t *testing.T) {
54 f := newOrgFixture(t)
55 f.st.SetOrgLabel(f.org, "bug", "")
56 // Members read; an outsider reads because acme/core is public.
57 for _, uid := range []int64{f.bob, f.carol} {
58 c, out := f.ctx(uid)
59 if code := runOrgLabelList(c, []string{"acme"}); code != protocol.ExitOK {
60 t.Fatalf("user %d list: exit %d %s", uid, code, out.String())
61 }
62 }
63 // With every repo private, the outsider is refused, not told the org
64 // is missing.
65 f.st.SetRepoVisibility(f.core.ID, "private")
66 c, out := f.ctx(f.carol)
67 if code := runOrgLabelList(c, []string{"acme"}); code != protocol.ExitDenied ||
68 !strings.Contains(out.String(), "visible to its members") {
69 t.Fatalf("outsider list: exit %d %s", code, out.String())
70 }
71}
72
73func TestOrgMilestoneLifecycle(t *testing.T) {
74 f := newOrgFixture(t)
75 f.st.CreateMilestone(f.core, "v1", "", "")
76 c, out := f.ctx(f.alice)
77 if code := runOrgMilestoneCreate(c, []string{"acme", "v1", "--due", "2027-01-01"}); code != protocol.ExitOK ||
78 !strings.Contains(out.String(), `"folded":1`) {
79 t.Fatalf("create: exit %d %s", code, out.String())
80 }
81 out.Reset()
82 if code := runOrgMilestoneCreate(c, []string{"acme", "v1"}); code != protocol.ExitFailure {
83 t.Fatalf("duplicate create: exit %d %s", code, out.String())
84 }
85 out.Reset()
86 if code := runOrgMilestoneCreate(c, []string{"acme", "v2", "--due", "soon"}); code != protocol.ExitUsage {
87 t.Fatalf("bad due: exit %d %s", code, out.String())
88 }
89 out.Reset()
90 // An issue in each repo attaches by title; progress spans both.
91 f.st.CreateIssue(f.core.ID, f.alice, "c1", "", "md")
92 f.st.CreateIssue(f.priv.ID, f.alice, "p1", "", "md")
93 runIssueMilestone(c, []string{"acme/core", "1", "v1"})
94 runIssueMilestone(c, []string{"acme/priv", "1", "v1"})
95 out.Reset()
96 if code := runOrgMilestoneList(c, []string{"acme"}); code != protocol.ExitOK ||
97 !strings.Contains(out.String(), `"open":2`) || !strings.Contains(out.String(), `"due":"2027-01-01"`) {
98 t.Fatalf("list: exit %d %s", code, out.String())
99 }
100 out.Reset()
101 // carol reads only the public repo's count.
102 cc, cout := f.ctx(f.carol)
103 if code := runOrgMilestoneList(cc, []string{"acme"}); code != protocol.ExitOK || !strings.Contains(cout.String(), `"open":1`) {
104 t.Fatalf("outsider list: exit %d %s", code, cout.String())
105 }
106 if code := runOrgMilestoneClose(c, []string{"acme", "v1"}); code != protocol.ExitOK {
107 t.Fatalf("close: exit %d %s", code, out.String())
108 }
109 out.Reset()
110 if code := runOrgMilestoneList(c, []string{"acme"}); code != protocol.ExitOK || strings.Contains(out.String(), `"title":"v1"`) {
111 t.Fatalf("closed still listed as open: %s", out.String())
112 }
113 out.Reset()
114 if code := runOrgMilestoneReopen(c, []string{"acme", "v1"}); code != protocol.ExitOK {
115 t.Fatalf("reopen: exit %d %s", code, out.String())
116 }
117 out.Reset()
118 if code := runOrgMilestoneClose(c, []string{"acme", "nope"}); code != protocol.ExitNotFound {
119 t.Fatalf("close missing: exit %d %s", code, out.String())
120 }
121 bc, bout := f.ctx(f.bob)
122 if code := runOrgMilestoneClose(bc, []string{"acme", "v1"}); code != protocol.ExitDenied {
123 t.Fatalf("member close: exit %d %s", code, bout.String())
124 }
125}