go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/luci_notify/mailtmpl/bundle_test.go (about)

     1  // Copyright 2019 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 mailtmpl
    16  
    17  import (
    18  	"context"
    19  	"testing"
    20  
    21  	buildbucketpb "go.chromium.org/luci/buildbucket/proto"
    22  	"go.chromium.org/luci/gae/impl/memory"
    23  	"go.chromium.org/luci/gae/service/datastore"
    24  
    25  	"go.chromium.org/luci/luci_notify/api/config"
    26  	"go.chromium.org/luci/luci_notify/common"
    27  
    28  	. "github.com/smartystreets/goconvey/convey"
    29  	. "go.chromium.org/luci/common/testing/assertions"
    30  )
    31  
    32  func TestBundle(t *testing.T) {
    33  	t.Parallel()
    34  
    35  	Convey(`bundle`, t, func() {
    36  		c := memory.Use(context.Background())
    37  		c = common.SetAppIDForTest(c, "luci-config")
    38  
    39  		templates := []*Template{
    40  			{
    41  				Name:                "default",
    42  				SubjectTextTemplate: "Build {{.Build.Id}} completed",
    43  				BodyHTMLTemplate:    `Build {{.Build.Id}} completed with status {{.Build.Status}}`,
    44  			},
    45  			{
    46  				Name:                "markdown",
    47  				SubjectTextTemplate: "Build {{.Build.Id}}",
    48  				BodyHTMLTemplate:    `{{.Build.SummaryMarkdown | markdown}}`,
    49  			},
    50  			{
    51  				Name:                "using_other_files",
    52  				SubjectTextTemplate: "",
    53  				BodyHTMLTemplate: `
    54  Reusing templates from other files.
    55  {{template "inlineEntireFile" .}}
    56  {{template "steps" .}}`,
    57  			},
    58  			{
    59  				Name:                "inlineEntireFile",
    60  				SubjectTextTemplate: "this file is shared",
    61  				BodyHTMLTemplate:    `Build {{.Build.Id}}`,
    62  			},
    63  			{
    64  				Name:                "shared",
    65  				SubjectTextTemplate: "this file is shared",
    66  				BodyHTMLTemplate:    `{{define "steps"}}steps of build {{.Build.Id}} go here{{end}}`,
    67  			},
    68  			{
    69  				Name:                "bad",
    70  				SubjectTextTemplate: "bad template",
    71  				BodyHTMLTemplate:    `{{.FieldDoesNotExist}}`,
    72  			},
    73  		}
    74  		So(datastore.Put(c, templates), ShouldBeNil)
    75  		datastore.GetTestable(c).CatchupIndexes()
    76  
    77  		bundle := NewBundle(templates)
    78  		So(bundle.Err, ShouldBeNil)
    79  		So(bundle.bodies.Lookup("default"), ShouldNotBeNil)
    80  
    81  		Convey(`GenerateEmail`, func() {
    82  			input := &config.TemplateInput{
    83  				BuildbucketHostname: "buildbucket.example.com",
    84  				Build: &buildbucketpb.Build{
    85  					Id: 54,
    86  					Builder: &buildbucketpb.BuilderID{
    87  						Project: "chromium",
    88  						Bucket:  "ci",
    89  						Builder: "linux-rel",
    90  					},
    91  					Status:          buildbucketpb.Status_SUCCESS,
    92  					SummaryMarkdown: "*ninja* compiled `11` files",
    93  				},
    94  			}
    95  
    96  			Convey("simple template", func() {
    97  				subject, body := bundle.GenerateEmail("default", input)
    98  				// Assert on body first, since errors would be rendered in body.
    99  				So(body, ShouldEqual, "Build 54 completed with status SUCCESS")
   100  				So(subject, ShouldEqual, "Build 54 completed")
   101  			})
   102  
   103  			Convey("markdown", func() {
   104  				_, body := bundle.GenerateEmail("markdown", input)
   105  				So(body, ShouldEqual, "<p><em>ninja</em> compiled <code>11</code> files</p>\n")
   106  			})
   107  
   108  			Convey("template using other files", func() {
   109  				_, body := bundle.GenerateEmail("using_other_files", input)
   110  				So(body, ShouldEqual, `
   111  Reusing templates from other files.
   112  Build 54
   113  steps of build 54 go here`)
   114  			})
   115  
   116  			Convey("error", func() {
   117  				_, body := bundle.GenerateEmail("bad", input)
   118  				So(body, ShouldContainSubstring, "spartan")
   119  				So(body, ShouldContainSubstring, "buildbucket.example.com")
   120  			})
   121  		})
   122  
   123  		Convey(`generateDefaultStatusMessage`, func() {
   124  			input := &config.TemplateInput{
   125  				BuildbucketHostname: "buildbucket.example.com",
   126  				Build: &buildbucketpb.Build{
   127  					Id: 123,
   128  					Builder: &buildbucketpb.BuilderID{
   129  						Project: "chromium",
   130  						Bucket:  "ci",
   131  						Builder: "linux-rel",
   132  					},
   133  					Input: &buildbucketpb.Build_Input{
   134  						GitilesCommit: &buildbucketpb.GitilesCommit{
   135  							Id: "deadbeefdeadbeef",
   136  						},
   137  					},
   138  				},
   139  				MatchingFailedSteps: []*buildbucketpb.Step{
   140  					{Name: "test1"},
   141  					{Name: "test2"},
   142  				},
   143  			}
   144  
   145  			So(generateDefaultStatusMessage(input), ShouldEqual,
   146  				`"test1", "test2" on https://buildbucket.example.com/build/123 linux-rel from deadbeefdeadbeef`)
   147  		})
   148  
   149  		// Regression test for https://crbug.com/1084358.
   150  		Convey(`GenerateStatusMessage, nil commit`, func() {
   151  			input := &config.TemplateInput{
   152  				BuildbucketHostname: "buildbucket.example.com",
   153  				Build: &buildbucketpb.Build{
   154  					Id: 123,
   155  					Builder: &buildbucketpb.BuilderID{
   156  						Project: "chromium",
   157  						Bucket:  "ci",
   158  						Builder: "linux-rel",
   159  					},
   160  					Input: &buildbucketpb.Build_Input{GitilesCommit: nil},
   161  				},
   162  				MatchingFailedSteps: []*buildbucketpb.Step{
   163  					{Name: "test1"},
   164  					{Name: "test2"},
   165  				},
   166  			}
   167  
   168  			So(generateDefaultStatusMessage(input), ShouldEqual,
   169  				`"test1", "test2" on https://buildbucket.example.com/build/123 linux-rel`)
   170  		})
   171  	})
   172  }
   173  
   174  func TestSplitTemplateFile(t *testing.T) {
   175  	t.Parallel()
   176  	Convey(`SplitTemplateFile`, t, func() {
   177  		Convey(`valid template`, func() {
   178  			s, b, err := SplitTemplateFile(`subject
   179  
   180          body`)
   181  
   182  			So(err, ShouldBeNil)
   183  			So(s, ShouldEqual, "subject")
   184  			So(b, ShouldEqual, "body")
   185  		})
   186  
   187  		Convey(`empty`, func() {
   188  			_, _, err := SplitTemplateFile(``)
   189  			So(err, ShouldErrLike, "empty")
   190  		})
   191  
   192  		Convey(`single line`, func() {
   193  			s, b, err := SplitTemplateFile("one line")
   194  
   195  			So(err, ShouldBeNil)
   196  			So(s, ShouldEqual, "one line")
   197  			So(b, ShouldEqual, "")
   198  		})
   199  
   200  		Convey(`blank second line`, func() {
   201  			s, b, err := SplitTemplateFile(`subject
   202  `)
   203  
   204  			So(err, ShouldBeNil)
   205  			So(s, ShouldEqual, "subject")
   206  			So(b, ShouldEqual, "")
   207  		})
   208  
   209  		Convey(`non-blank second line`, func() {
   210  			_, _, err := SplitTemplateFile(`subject
   211          body`)
   212  
   213  			So(err, ShouldErrLike, "second line is not blank")
   214  		})
   215  
   216  		Convey(`no blank line`, func() {
   217  			_, _, err := SplitTemplateFile(`subject
   218          body
   219          second line
   220          `)
   221  			So(err, ShouldErrLike, "second line is not blank")
   222  		})
   223  	})
   224  }