go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/milo/frontend/view_console_test.go (about) 1 // Copyright 2020 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package frontend 16 17 import ( 18 "encoding/json" 19 "html/template" 20 "net/http" 21 "net/http/httptest" 22 "testing" 23 24 . "github.com/smartystreets/goconvey/convey" 25 "go.chromium.org/luci/appengine/gaetesting" 26 "go.chromium.org/luci/milo/frontend/ui" 27 projectconfigpb "go.chromium.org/luci/milo/proto/projectconfig" 28 ) 29 30 func TestRenderOncallers(t *testing.T) { 31 t.Parallel() 32 ctx := gaetesting.TestingContext() 33 Convey("Oncall fetching works", t, func() { 34 serveMux := http.NewServeMux() 35 serverResponse := func(w http.ResponseWriter, r *http.Request) { 36 name := r.URL.Query()["name"][0] 37 if name == "bad" { 38 w.WriteHeader(http.StatusInternalServerError) 39 return 40 } 41 res := map[string]any{ 42 "emails": []string{"foo"}, 43 } 44 bytes, _ := json.Marshal(res) 45 w.Write(bytes) 46 } 47 serveMux.HandleFunc("/", serverResponse) 48 server := httptest.NewServer(serveMux) 49 defer server.Close() 50 51 Convey("Fetch failed", func() { 52 oncallConfig := projectconfigpb.Oncall{ 53 Url: server.URL + "?name=bad", 54 } 55 result, err := getOncallData(ctx, &oncallConfig) 56 So(err, ShouldBeNil) 57 So(result.Oncallers, ShouldEqual, template.HTML(`ERROR: Fetching oncall failed`)) 58 }) 59 Convey("Fetch succeeded", func() { 60 oncallConfig := projectconfigpb.Oncall{ 61 Name: "Good rotation", 62 Url: server.URL + "?name=good", 63 } 64 result, err := getOncallData(ctx, &oncallConfig) 65 So(err, ShouldBeNil) 66 So(result.Name, ShouldEqual, "Good rotation") 67 So(result.Oncallers, ShouldEqual, template.HTML(`foo`)) 68 }) 69 }) 70 71 Convey("Rendering oncallers works", t, func() { 72 Convey("Legacy trooper format", func() { 73 oncallConfig := projectconfigpb.Oncall{ 74 Name: "Legacy trooper", 75 Url: "http://fake-rota.appspot.com/legacy/trooper.json", 76 } 77 Convey("No-one oncall", func() { 78 response := ui.Oncall{ 79 Primary: "", 80 Secondaries: []string{}, 81 } 82 83 So(renderOncallers(&oncallConfig, &response), ShouldEqual, template.HTML(`<none>`)) 84 }) 85 Convey("No-one oncall with 'None' string", func() { 86 response := ui.Oncall{ 87 Primary: "None", 88 Secondaries: []string{}, 89 } 90 91 So(renderOncallers(&oncallConfig, &response), ShouldEqual, template.HTML(`None`)) 92 }) 93 Convey("Primary only", func() { 94 Convey("Googler", func() { 95 response := ui.Oncall{ 96 Primary: "foo@google.com", 97 Secondaries: []string{}, 98 } 99 100 So(renderOncallers(&oncallConfig, &response), ShouldEqual, template.HTML(`foo`)) 101 }) 102 Convey("Non-Googler", func() { 103 response := ui.Oncall{ 104 Primary: "foo@example.com", 105 Secondaries: []string{}, 106 } 107 108 So(renderOncallers(&oncallConfig, &response), ShouldEqual, template.HTML( 109 `foo<span style="display:none">ohnoyoudont</span>@example.com`)) 110 }) 111 }) 112 Convey("Primary and secondaries", func() { 113 response := ui.Oncall{ 114 Primary: "foo@google.com", 115 Secondaries: []string{"bar@google.com", "baz@example.com"}, 116 } 117 118 So(renderOncallers(&oncallConfig, &response), ShouldEqual, template.HTML( 119 `foo (primary), bar (secondary), baz<span style="display:none">ohnoyoudont</span>@example.com (secondary)`)) 120 }) 121 }) 122 Convey("Email-only format", func() { 123 oncallConfig := projectconfigpb.Oncall{ 124 Name: "Legacy trooper", 125 Url: "http://fake-rota.appspot.com/legacy/trooper.json", 126 } 127 128 Convey("No-one oncall", func() { 129 response := ui.Oncall{ 130 Emails: []string{}, 131 } 132 133 So(renderOncallers(&oncallConfig, &response), ShouldEqual, template.HTML(`<none>`)) 134 }) 135 136 Convey("Primary only", func() { 137 Convey("Googler", func() { 138 response := ui.Oncall{ 139 Emails: []string{"foo@google.com"}, 140 } 141 142 So(renderOncallers(&oncallConfig, &response), ShouldEqual, template.HTML(`foo`)) 143 }) 144 Convey("Non-Googler", func() { 145 response := ui.Oncall{ 146 Emails: []string{"foo@example.com"}, 147 } 148 149 So(renderOncallers(&oncallConfig, &response), ShouldEqual, template.HTML( 150 `foo<span style="display:none">ohnoyoudont</span>@example.com`)) 151 }) 152 }) 153 154 Convey("Primary and secondaries", func() { 155 Convey("Primary/secondary labeling disabled", func() { 156 response := ui.Oncall{ 157 Emails: []string{"foo@google.com", "bar@google.com", "baz@example.com"}, 158 } 159 160 So(renderOncallers(&oncallConfig, &response), ShouldEqual, template.HTML( 161 `foo, bar, baz<span style="display:none">ohnoyoudont</span>@example.com`)) 162 }) 163 Convey("Primary/secondary labeling enabled", func() { 164 oncallConfig := projectconfigpb.Oncall{ 165 Name: "Legacy trooper", 166 Url: "http://fake-rota.appspot.com/legacy/trooper.json", 167 ShowPrimarySecondaryLabels: true, 168 } 169 response := ui.Oncall{ 170 Emails: []string{"foo@google.com", "bar@google.com", "baz@example.com"}, 171 } 172 173 So(renderOncallers(&oncallConfig, &response), ShouldEqual, template.HTML( 174 `foo (primary), bar (secondary), baz<span style="display:none">ohnoyoudont</span>@example.com (secondary)`)) 175 }) 176 }) 177 }) 178 }) 179 }