go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/gae/impl/memory/mail_test.go (about) 1 // Copyright 2015 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 memory 16 17 import ( 18 "context" 19 net_mail "net/mail" 20 "testing" 21 22 "go.chromium.org/luci/gae/service/mail" 23 "go.chromium.org/luci/gae/service/user" 24 25 . "github.com/smartystreets/goconvey/convey" 26 . "go.chromium.org/luci/common/testing/assertions" 27 ) 28 29 func TestMail(t *testing.T) { 30 t.Parallel() 31 32 Convey("mail", t, func() { 33 c := Use(context.Background()) 34 35 Convey("good cases", func() { 36 Convey("start with an empty set of messages", func() { 37 So(mail.GetTestable(c).SentMessages(), ShouldBeEmpty) 38 }) 39 40 Convey("can send a message from the admin", func() { 41 So(mail.Send(c, &mail.Message{ 42 Sender: "admin@example.com", 43 To: []string{"Valued Customer <customer@example.com>"}, 44 Subject: "You are valued.", 45 Body: "We value you.", 46 }), ShouldBeNil) 47 48 Convey("and it shows up in sent messages", func() { 49 So(mail.GetTestable(c).SentMessages(), ShouldResemble, []*mail.TestMessage{ 50 {Message: mail.Message{ 51 Sender: "admin@example.com", 52 To: []string{"Valued Customer <customer@example.com>"}, 53 Subject: "You are valued.", 54 Body: "We value you.", 55 }}, 56 }) 57 58 Convey("which can be reset", func() { 59 mail.GetTestable(c).Reset() 60 So(mail.GetTestable(c).SentMessages(), ShouldBeEmpty) 61 }) 62 }) 63 }) 64 65 Convey("can send a message on behalf of a user", func() { 66 user.GetTestable(c).Login("dood@example.com", "", false) 67 So(mail.Send(c, &mail.Message{ 68 Sender: "Friendly Person <dood@example.com>", 69 To: []string{"Other Friendly Person <dudette@example.com>"}, 70 Subject: "Hi", 71 Body: "An app is sending a message for me. It's the future.", 72 }), ShouldBeNil) 73 }) 74 75 Convey("can send a message to the admins", func() { 76 So(mail.SendToAdmins(c, &mail.Message{ 77 Sender: "admin@example.com", 78 Subject: "Reminder", 79 Body: "I forgot", 80 }), ShouldBeNil) 81 82 So(mail.GetTestable(c).SentMessages(), ShouldResemble, []*mail.TestMessage{ 83 {Message: mail.Message{ 84 Sender: "admin@example.com", 85 To: []string{"admin@example.com"}, 86 Subject: "Reminder", 87 Body: "I forgot", 88 }}, 89 }) 90 }) 91 92 Convey("can set admin emails", func() { 93 mail.GetTestable(c).SetAdminEmails( 94 "Friendly <hello@example.com>", 95 "Epic <nerdsnipe@example.com>", 96 ) 97 98 So(mail.SendToAdmins(c, &mail.Message{ 99 Sender: "hello@example.com", 100 Subject: "Reminder", 101 Body: "I forgot", 102 }), ShouldBeNil) 103 104 So(mail.GetTestable(c).SentMessages(), ShouldResemble, []*mail.TestMessage{ 105 {Message: mail.Message{ 106 Sender: "hello@example.com", 107 To: []string{ 108 "Friendly <hello@example.com>", 109 "Epic <nerdsnipe@example.com>", 110 }, 111 Subject: "Reminder", 112 Body: "I forgot", 113 }}, 114 }) 115 }) 116 117 Convey("attachments get mimetypes assigned to them", func() { 118 So(mail.SendToAdmins(c, &mail.Message{ 119 Sender: "admin@example.com", 120 Subject: "Reminder", 121 Body: "I forgot", 122 Attachments: []mail.Attachment{ 123 {Name: "reminder.txt", Data: []byte("bananas")}, 124 {Name: "coolthing", Data: []byte("bananas")}, 125 }, 126 }), ShouldBeNil) 127 128 So(mail.GetTestable(c).SentMessages(), ShouldResemble, []*mail.TestMessage{ 129 { 130 Message: mail.Message{ 131 Sender: "admin@example.com", 132 To: []string{"admin@example.com"}, 133 Subject: "Reminder", 134 Body: "I forgot", 135 Attachments: []mail.Attachment{ 136 {Name: "reminder.txt", Data: []byte("bananas")}, 137 {Name: "coolthing", Data: []byte("bananas")}, 138 }, 139 }, 140 MIMETypes: []string{"text/plain", "application/octet-stream"}}, 141 }) 142 }) 143 144 Convey("can have headers", func() { 145 So(mail.SendToAdmins(c, &mail.Message{ 146 Sender: "admin@example.com", 147 Subject: "Reminder", 148 Body: "I forgot", 149 Headers: net_mail.Header{ 150 "in-reply-to": []string{"epicness"}, 151 "List-Id": []string{"spam"}, 152 }, 153 }), ShouldBeNil) 154 155 So(mail.GetTestable(c).SentMessages(), ShouldResemble, []*mail.TestMessage{ 156 {Message: mail.Message{ 157 Sender: "admin@example.com", 158 To: []string{"admin@example.com"}, 159 Subject: "Reminder", 160 Body: "I forgot", 161 Headers: net_mail.Header{ 162 "In-Reply-To": []string{"epicness"}, 163 "List-Id": []string{"spam"}, 164 }, 165 }}, 166 }) 167 168 }) 169 }) 170 171 Convey("errors", func() { 172 Convey("setting a non-email is a panic", func() { 173 So(func() { mail.GetTestable(c).SetAdminEmails("i am a banana") }, 174 ShouldPanicLike, `invalid email ("i am a banana")`) 175 }) 176 177 Convey("sending from a non-user, non-admin is an error", func() { 178 mail.GetTestable(c).SetAdminEmails("Friendly <hello@example.com>") 179 180 So(mail.Send(c, &mail.Message{ 181 Sender: "someone_else@example.com", 182 Subject: "Reminder", 183 Body: "I forgot", 184 }), ShouldErrLike, "invalid Sender: someone_else@example.com") 185 }) 186 187 Convey("sending from a bogus address is a problem", func() { 188 So(mail.Send(c, &mail.Message{ 189 Sender: "lalal", 190 }), ShouldErrLike, "unparsable Sender address: lalal") 191 }) 192 193 Convey("sending with no recipients is a problem", func() { 194 So(mail.Send(c, &mail.Message{ 195 Sender: "admin@example.com", 196 }), ShouldErrLike, "one of To, Cc or Bcc must be non-empty") 197 }) 198 199 Convey("bad addresses are a problem", func() { 200 So(mail.Send(c, &mail.Message{ 201 Sender: "admin@example.com", 202 To: []string{"wut"}, 203 }), ShouldErrLike, `invalid email ("wut")`) 204 205 So(mail.Send(c, &mail.Message{ 206 Sender: "admin@example.com", 207 Cc: []string{"wut"}, 208 }), ShouldErrLike, `invalid email ("wut")`) 209 210 So(mail.Send(c, &mail.Message{ 211 Sender: "admin@example.com", 212 Bcc: []string{"wut"}, 213 }), ShouldErrLike, `invalid email ("wut")`) 214 }) 215 216 Convey("no body is a problem", func() { 217 So(mail.Send(c, &mail.Message{ 218 Sender: "admin@example.com", 219 To: []string{"wut@example.com"}, 220 }), ShouldErrLike, `one of Body or HTMLBody must be non-empty`) 221 }) 222 223 Convey("bad attachments are a problem", func() { 224 So(mail.Send(c, &mail.Message{ 225 Sender: "admin@example.com", 226 To: []string{"wut@example.com"}, 227 Body: "nice thing", 228 Attachments: []mail.Attachment{ 229 {Name: "nice.exe", Data: []byte("boom")}, 230 }, 231 }), ShouldErrLike, `illegal attachment extension for "nice.exe"`) 232 }) 233 234 Convey("bad headers are a problem", func() { 235 So(mail.SendToAdmins(c, &mail.Message{ 236 Sender: "admin@example.com", 237 Subject: "Reminder", 238 Body: "I forgot", 239 Headers: net_mail.Header{"x-spam-cool": []string{"value"}}, 240 }), ShouldErrLike, `disallowed header: x-spam-cool`) 241 242 }) 243 244 }) 245 246 }) 247 }