github.com/GoogleCloudPlatform/testgrid@v0.0.174/pkg/api/v1/config_test.go (about) 1 /* 2 Copyright 2022 The TestGrid Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package v1 18 19 import ( 20 "context" 21 "testing" 22 23 apipb "github.com/GoogleCloudPlatform/testgrid/pb/api/v1" 24 configpb "github.com/GoogleCloudPlatform/testgrid/pb/config" 25 "github.com/GoogleCloudPlatform/testgrid/util/gcs" 26 "github.com/google/go-cmp/cmp" 27 "google.golang.org/protobuf/testing/protocmp" 28 ) 29 30 func getPathOrDie(t *testing.T, s string) *gcs.Path { 31 t.Helper() 32 path, err := gcs.NewPath(s) 33 if err != nil { 34 t.Fatalf("Couldn't make path %s: %v", s, err) 35 } 36 return path 37 } 38 39 func Test_GetDashboardGroup(t *testing.T) { 40 tests := []struct { 41 name string 42 config map[string]*configpb.Configuration 43 req *apipb.GetDashboardGroupRequest 44 expected *apipb.GetDashboardGroupResponse 45 expectError bool 46 }{ 47 { 48 name: "Returns an error when there's no resource", 49 config: map[string]*configpb.Configuration{ 50 "gs://default/config": {}, 51 }, 52 req: &apipb.GetDashboardGroupRequest{ 53 DashboardGroup: "", 54 }, 55 expectError: true, 56 }, 57 { 58 name: "Returns empty response from an empty Dashboard Group", 59 config: map[string]*configpb.Configuration{ 60 "gs://default/config": { 61 DashboardGroups: []*configpb.DashboardGroup{ 62 { 63 Name: "Group1", 64 }, 65 }, 66 }, 67 }, 68 req: &apipb.GetDashboardGroupRequest{ 69 DashboardGroup: "group1", 70 }, 71 expected: &apipb.GetDashboardGroupResponse{}, 72 }, 73 { 74 name: "Returns dashboards from group", 75 config: map[string]*configpb.Configuration{ 76 "gs://default/config": { 77 DashboardGroups: []*configpb.DashboardGroup{ 78 { 79 Name: "stooges", 80 DashboardNames: []string{"Larry", "Curly", "Moe"}, 81 }, 82 }, 83 }, 84 }, 85 req: &apipb.GetDashboardGroupRequest{ 86 DashboardGroup: "stooges", 87 }, 88 expected: &apipb.GetDashboardGroupResponse{ 89 Dashboards: []*apipb.Resource{ 90 {Name: "Curly", Link: "/dashboards/curly"}, 91 {Name: "Larry", Link: "/dashboards/larry"}, 92 {Name: "Moe", Link: "/dashboards/moe"}, 93 }, 94 }, 95 }, 96 { 97 name: "Reads specified configs", 98 config: map[string]*configpb.Configuration{ 99 "gs://default/config": { 100 DashboardGroups: []*configpb.DashboardGroup{ 101 { 102 Name: "wrong-group", 103 DashboardNames: []string{"no"}, 104 }, 105 }, 106 }, 107 "gs://example/config": { 108 DashboardGroups: []*configpb.DashboardGroup{ 109 { 110 Name: "right-group", 111 DashboardNames: []string{"yes"}, 112 }, 113 }, 114 }, 115 }, 116 req: &apipb.GetDashboardGroupRequest{ 117 DashboardGroup: "right-group", 118 Scope: "gs://example", 119 }, 120 expected: &apipb.GetDashboardGroupResponse{ 121 Dashboards: []*apipb.Resource{ 122 {Name: "yes", Link: "/dashboards/yes?scope=gs://example"}, 123 }, 124 }, 125 }, 126 { 127 name: "Specified configs never reads default config", 128 config: map[string]*configpb.Configuration{ 129 "gs://default/config": { 130 DashboardGroups: []*configpb.DashboardGroup{ 131 { 132 Name: "wrong-group", 133 DashboardNames: []string{"no"}, 134 }, 135 }, 136 }, 137 "gs://example/config": { 138 DashboardGroups: []*configpb.DashboardGroup{ 139 { 140 Name: "right-group", 141 DashboardNames: []string{"yes"}, 142 }, 143 }, 144 }, 145 }, 146 req: &apipb.GetDashboardGroupRequest{ 147 DashboardGroup: "wrong-group", 148 Scope: "gs://example", 149 }, 150 expectError: true, 151 }, 152 { 153 name: "Server error with unreadable config", 154 req: &apipb.GetDashboardGroupRequest{ 155 DashboardGroup: "group", 156 Scope: "garbage", 157 }, 158 expectError: true, 159 }, 160 } 161 for _, tc := range tests { 162 t.Run(tc.name, func(t *testing.T) { 163 server := setupTestServer(t, tc.config, nil, nil) 164 actual, err := server.GetDashboardGroup(context.Background(), tc.req) 165 if !tc.expectError && err != nil { 166 t.Errorf("Unexpected error: %v", err) 167 } 168 if tc.expectError && err == nil { 169 t.Errorf("Expected error, but got none") 170 } 171 if diff := cmp.Diff(actual, tc.expected, protocmp.Transform()); diff != "" { 172 t.Errorf("(-got, +want): %s", diff) 173 } 174 }) 175 } 176 } 177 178 func Test_GetDashboard(t *testing.T) { 179 tests := []struct { 180 name string 181 config map[string]*configpb.Configuration 182 req *apipb.GetDashboardRequest 183 expected *apipb.GetDashboardResponse 184 expectError bool 185 }{ 186 { 187 name: "Returns an error when there's no resource", 188 config: map[string]*configpb.Configuration{ 189 "gs://default/config": {}, 190 }, 191 req: &apipb.GetDashboardRequest{ 192 Dashboard: "", 193 }, 194 expectError: true, 195 }, 196 { 197 name: "Returns empty JSON from an empty Dashboard", 198 config: map[string]*configpb.Configuration{ 199 "gs://default/config": { 200 Dashboards: []*configpb.Dashboard{ 201 { 202 Name: "Dashboard1", 203 }, 204 }, 205 }, 206 }, 207 req: &apipb.GetDashboardRequest{ 208 Dashboard: "Dashboard1", 209 }, 210 expected: &apipb.GetDashboardResponse{}, 211 }, 212 { 213 name: "Returns dashboard info from dashboard", 214 config: map[string]*configpb.Configuration{ 215 "gs://default/config": { 216 Dashboards: []*configpb.Dashboard{ 217 { 218 Name: "Dashboard1", 219 DefaultTab: "defaultTab", 220 HighlightToday: true, 221 DownplayFailingTabs: true, 222 Notifications: []*configpb.Notification{ 223 { 224 Summary: "Notification summary", 225 ContextLink: "Notification context link", 226 }, 227 }, 228 }, 229 }, 230 }, 231 }, 232 req: &apipb.GetDashboardRequest{ 233 Dashboard: "Dashboard-1", 234 }, 235 expected: &apipb.GetDashboardResponse{ 236 Notifications: []*configpb.Notification{ 237 {Summary: "Notification summary", ContextLink: "Notification context link"}, 238 }, 239 DefaultTab: "defaultTab", 240 HighlightToday: true, 241 SuppressFailingTabs: true, 242 }, 243 }, 244 { 245 name: "Reads specified configs", 246 config: map[string]*configpb.Configuration{ 247 "gs://default/config": { 248 Dashboards: []*configpb.Dashboard{ 249 { 250 Name: "wrong-dashboard", 251 DefaultTab: "wrong-dashboard defaultTab", 252 }, 253 }, 254 }, 255 "gs://example/config": { 256 Dashboards: []*configpb.Dashboard{ 257 { 258 Name: "correct-dashboard", 259 DefaultTab: "correct-dashboard defaultTab", 260 HighlightToday: true, 261 }, 262 }, 263 }, 264 }, 265 req: &apipb.GetDashboardRequest{ 266 Dashboard: "correct-dashboard", 267 Scope: "gs://example", 268 }, 269 expected: &apipb.GetDashboardResponse{ 270 HighlightToday: true, 271 DefaultTab: "correct-dashboard defaultTab", 272 }, 273 }, 274 { 275 name: "Specified configs never reads default config", 276 config: map[string]*configpb.Configuration{ 277 "gs://default/config": { 278 Dashboards: []*configpb.Dashboard{ 279 { 280 Name: "wrong-dashboard", 281 DefaultTab: "wrong-dashboard defaultTab", 282 }, 283 }, 284 }, 285 "gs://example/config": { 286 Dashboards: []*configpb.Dashboard{ 287 { 288 Name: "correct-dashboard", 289 DefaultTab: "correct-dashboard defaultTab", 290 }, 291 }, 292 }, 293 }, 294 req: &apipb.GetDashboardRequest{ 295 Dashboard: "wrong-dashboard", 296 Scope: "gs://example", 297 }, 298 expectError: true, 299 }, 300 { 301 name: "Server error with unreadable config", 302 req: &apipb.GetDashboardRequest{ 303 Dashboard: "who", 304 }, 305 expectError: true, 306 }, 307 } 308 309 for _, tc := range tests { 310 t.Run(tc.name, func(t *testing.T) { 311 server := setupTestServer(t, tc.config, nil, nil) 312 actual, err := server.GetDashboard(context.Background(), tc.req) 313 if !tc.expectError && err != nil { 314 t.Errorf("Unexpected error: %v", err) 315 } 316 if tc.expectError && err == nil { 317 t.Errorf("Expected error, but got none") 318 } 319 if diff := cmp.Diff(actual, tc.expected, protocmp.Transform()); diff != "" { 320 t.Errorf("(-got, +want): %s", diff) 321 } 322 }) 323 } 324 } 325 326 func Test_ListDashboardTabs(t *testing.T) { 327 tests := []struct { 328 name string 329 config map[string]*configpb.Configuration 330 req *apipb.ListDashboardTabsRequest 331 expected *apipb.ListDashboardTabsResponse 332 expectError bool 333 }{ 334 { 335 name: "Returns an error when there's no resource", 336 config: map[string]*configpb.Configuration{ 337 "gs://default/config": {}, 338 }, 339 req: &apipb.ListDashboardTabsRequest{ 340 Dashboard: "", 341 }, 342 expectError: true, 343 }, 344 { 345 name: "Returns empty JSON from an empty Dashboard", 346 config: map[string]*configpb.Configuration{ 347 "gs://default/config": { 348 Dashboards: []*configpb.Dashboard{ 349 { 350 Name: "Dashboard1", 351 DashboardTab: []*configpb.DashboardTab{}, 352 }, 353 }, 354 }, 355 }, 356 req: &apipb.ListDashboardTabsRequest{ 357 Dashboard: "Dashboard1", 358 }, 359 expected: &apipb.ListDashboardTabsResponse{}, 360 }, 361 { 362 name: "Returns tabs list from a Dashboard", 363 config: map[string]*configpb.Configuration{ 364 "gs://default/config": { 365 Dashboards: []*configpb.Dashboard{ 366 { 367 Name: "Dashboard1", 368 DashboardTab: []*configpb.DashboardTab{ 369 { 370 Name: "tab 1", 371 }, 372 { 373 Name: "tab 2", 374 }, 375 }, 376 }, 377 }, 378 }, 379 }, 380 req: &apipb.ListDashboardTabsRequest{ 381 Dashboard: "Dashboard1", 382 }, 383 expected: &apipb.ListDashboardTabsResponse{ 384 DashboardTabs: []*apipb.Resource{ 385 {Name: "tab 1", Link: "/dashboards/dashboard1/tabs/tab1"}, 386 {Name: "tab 2", Link: "/dashboards/dashboard1/tabs/tab2"}, 387 }, 388 }, 389 }, 390 { 391 name: "Reads specified configs", 392 config: map[string]*configpb.Configuration{ 393 "gs://default/config": { 394 Dashboards: []*configpb.Dashboard{ 395 { 396 Name: "wrong-dashboard", 397 DashboardTab: []*configpb.DashboardTab{ 398 { 399 Name: "wrong-dashboard tab 1", 400 }, 401 }, 402 }, 403 }, 404 }, 405 "gs://example/config": { 406 Dashboards: []*configpb.Dashboard{ 407 { 408 Name: "correct-dashboard", 409 DashboardTab: []*configpb.DashboardTab{ 410 { 411 Name: "correct-dashboard tab 1", 412 }, 413 }, 414 }, 415 }, 416 }, 417 }, 418 req: &apipb.ListDashboardTabsRequest{ 419 Dashboard: "correct-dashboard", 420 Scope: "gs://example", 421 }, 422 expected: &apipb.ListDashboardTabsResponse{ 423 DashboardTabs: []*apipb.Resource{ 424 {Name: "correct-dashboard tab 1", Link: "/dashboards/correctdashboard/tabs/correctdashboardtab1?scope=gs://example"}, 425 }, 426 }, 427 }, 428 { 429 name: "Specified configs never reads default config", 430 config: map[string]*configpb.Configuration{ 431 "gs://default/config": { 432 Dashboards: []*configpb.Dashboard{ 433 { 434 Name: "wrong-dashboard", 435 DashboardTab: []*configpb.DashboardTab{ 436 { 437 Name: "wrong-dashboard tab 1", 438 }, 439 }, 440 }, 441 }, 442 }, 443 "gs://example/config": { 444 Dashboards: []*configpb.Dashboard{ 445 { 446 Name: "correct-dashboard", 447 DashboardTab: []*configpb.DashboardTab{ 448 { 449 Name: "correct-dashboard tab 1", 450 }, 451 }, 452 }, 453 }, 454 }, 455 }, 456 req: &apipb.ListDashboardTabsRequest{ 457 Dashboard: "wrong-dashboard", 458 Scope: "gs://example", 459 }, 460 expectError: true, 461 }, 462 { 463 name: "Server error with unreadable config", 464 req: &apipb.ListDashboardTabsRequest{ 465 Dashboard: "dashboard1", 466 Scope: "gibberish", 467 }, 468 expectError: true, 469 }, 470 } 471 472 for _, tc := range tests { 473 t.Run(tc.name, func(t *testing.T) { 474 server := setupTestServer(t, tc.config, nil, nil) 475 actual, err := server.ListDashboardTabs(context.Background(), tc.req) 476 if !tc.expectError && err != nil { 477 t.Errorf("Unexpected error: %v", err) 478 } 479 if tc.expectError && err == nil { 480 t.Errorf("Expected error, but got none") 481 } 482 if diff := cmp.Diff(actual, tc.expected, protocmp.Transform()); diff != "" { 483 t.Errorf("(-got, +want): %s", diff) 484 } 485 }) 486 } 487 } 488 489 // These methods are currently covered in HTTP tests only: 490 // ListDashboardGroup 491 // ListDashboard