github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/model/link_metadata_test.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package model 5 6 import ( 7 "encoding/json" 8 "fmt" 9 "strings" 10 "testing" 11 "unicode/utf8" 12 13 "github.com/dyatlov/go-opengraph/opengraph" 14 "github.com/stretchr/testify/assert" 15 "github.com/stretchr/testify/require" 16 ) 17 18 const BigText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus maximus faucibus ex, vitae placerat neque feugiat ac. Nam tempus libero quis pellentesque feugiat. Cras tristique diam vel condimentum viverra. Proin molestie posuere leo. Nam pulvinar, ex quis tristique cursus, turpis ante commodo elit, a dapibus est ipsum id eros. Mauris tortor dolor, posuere ac velit vitae, faucibus viverra fusce." 19 20 func sampleImage(imageName string) *opengraph.Image { 21 return &opengraph.Image{ 22 URL: fmt.Sprintf("http://example.com/%s", imageName), 23 SecureURL: fmt.Sprintf("https://example.com/%s", imageName), 24 Type: "png", 25 Width: 32, 26 Height: 32, 27 } 28 } 29 30 func TestLinkMetadataIsValid(t *testing.T) { 31 for _, test := range []struct { 32 Name string 33 Metadata *LinkMetadata 34 Expected bool 35 }{ 36 { 37 Name: "should be valid image metadata", 38 Metadata: &LinkMetadata{ 39 URL: "http://example.com", 40 Timestamp: 1546300800000, 41 Type: LINK_METADATA_TYPE_IMAGE, 42 Data: &PostImage{}, 43 }, 44 Expected: true, 45 }, 46 { 47 Name: "should be valid opengraph metadata", 48 Metadata: &LinkMetadata{ 49 URL: "http://example.com", 50 Timestamp: 1546300800000, 51 Type: LINK_METADATA_TYPE_OPENGRAPH, 52 Data: &opengraph.OpenGraph{}, 53 }, 54 Expected: true, 55 }, 56 { 57 Name: "should be valid with no metadata", 58 Metadata: &LinkMetadata{ 59 URL: "http://example.com", 60 Timestamp: 1546300800000, 61 Type: LINK_METADATA_TYPE_NONE, 62 Data: nil, 63 }, 64 Expected: true, 65 }, 66 { 67 Name: "should be invalid because of empty URL", 68 Metadata: &LinkMetadata{ 69 Timestamp: 1546300800000, 70 Type: LINK_METADATA_TYPE_IMAGE, 71 Data: &PostImage{}, 72 }, 73 Expected: false, 74 }, 75 { 76 Name: "should be invalid because of empty timestamp", 77 Metadata: &LinkMetadata{ 78 URL: "http://example.com", 79 Type: LINK_METADATA_TYPE_IMAGE, 80 Data: &PostImage{}, 81 }, 82 Expected: false, 83 }, 84 { 85 Name: "should be invalid because of unrounded timestamp", 86 Metadata: &LinkMetadata{ 87 URL: "http://example.com", 88 Timestamp: 1546300800001, 89 Type: LINK_METADATA_TYPE_IMAGE, 90 Data: &PostImage{}, 91 }, 92 Expected: false, 93 }, 94 { 95 Name: "should be invalid because of invalid type", 96 Metadata: &LinkMetadata{ 97 URL: "http://example.com", 98 Timestamp: 1546300800000, 99 Type: "garbage", 100 Data: &PostImage{}, 101 }, 102 Expected: false, 103 }, 104 { 105 Name: "should be invalid because of empty data", 106 Metadata: &LinkMetadata{ 107 URL: "http://example.com", 108 Timestamp: 1546300800000, 109 Type: LINK_METADATA_TYPE_IMAGE, 110 }, 111 Expected: false, 112 }, 113 { 114 Name: "should be invalid because of mismatched data and type, image type and opengraph data", 115 Metadata: &LinkMetadata{ 116 URL: "http://example.com", 117 Timestamp: 1546300800000, 118 Type: LINK_METADATA_TYPE_IMAGE, 119 Data: &opengraph.OpenGraph{}, 120 }, 121 Expected: false, 122 }, 123 { 124 Name: "should be invalid because of mismatched data and type, opengraph type and image data", 125 Metadata: &LinkMetadata{ 126 URL: "http://example.com", 127 Timestamp: 1546300800000, 128 Type: LINK_METADATA_TYPE_OPENGRAPH, 129 Data: &PostImage{}, 130 }, 131 Expected: false, 132 }, 133 { 134 Name: "should be invalid because of mismatched data and type, image type and random data", 135 Metadata: &LinkMetadata{ 136 URL: "http://example.com", 137 Timestamp: 1546300800000, 138 Type: LINK_METADATA_TYPE_OPENGRAPH, 139 Data: &Channel{}, 140 }, 141 Expected: false, 142 }, 143 } { 144 t.Run(test.Name, func(t *testing.T) { 145 err := test.Metadata.IsValid() 146 147 if test.Expected { 148 assert.Nil(t, err) 149 } else { 150 assert.NotNil(t, err) 151 } 152 }) 153 } 154 } 155 156 func TestLinkMetadataDeserializeDataToConcreteType(t *testing.T) { 157 t.Run("should convert []byte to PostImage", func(t *testing.T) { 158 image := &PostImage{ 159 Height: 400, 160 Width: 500, 161 } 162 163 metadata := &LinkMetadata{ 164 Type: LINK_METADATA_TYPE_IMAGE, 165 Data: []byte(image.ToJson()), 166 } 167 168 require.IsType(t, []byte{}, metadata.Data) 169 170 err := metadata.DeserializeDataToConcreteType() 171 172 assert.Nil(t, err) 173 assert.IsType(t, &PostImage{}, metadata.Data) 174 assert.Equal(t, *image, *metadata.Data.(*PostImage)) 175 }) 176 177 t.Run("should convert string to OpenGraph", func(t *testing.T) { 178 og := &opengraph.OpenGraph{ 179 URL: "http://example.com", 180 Description: "Hello, world!", 181 Images: []*opengraph.Image{ 182 { 183 URL: "http://example.com/image.png", 184 }, 185 }, 186 } 187 188 b, err := json.Marshal(og) 189 190 require.Nil(t, err) 191 192 metadata := &LinkMetadata{ 193 Type: LINK_METADATA_TYPE_OPENGRAPH, 194 Data: b, 195 } 196 197 require.IsType(t, []byte{}, metadata.Data) 198 199 err = metadata.DeserializeDataToConcreteType() 200 201 assert.Nil(t, err) 202 assert.IsType(t, &opengraph.OpenGraph{}, metadata.Data) 203 assert.Equal(t, *og, *metadata.Data.(*opengraph.OpenGraph)) 204 }) 205 206 t.Run("should ignore data of the correct type", func(t *testing.T) { 207 metadata := &LinkMetadata{ 208 Type: LINK_METADATA_TYPE_OPENGRAPH, 209 Data: 1234, 210 } 211 212 err := metadata.DeserializeDataToConcreteType() 213 214 assert.Nil(t, err) 215 }) 216 217 t.Run("should ignore an invalid type", func(t *testing.T) { 218 metadata := &LinkMetadata{ 219 Type: "garbage", 220 Data: "garbage", 221 } 222 223 err := metadata.DeserializeDataToConcreteType() 224 225 assert.Nil(t, err) 226 }) 227 228 t.Run("should return error for invalid data", func(t *testing.T) { 229 metadata := &LinkMetadata{ 230 Type: LINK_METADATA_TYPE_IMAGE, 231 Data: "garbage", 232 } 233 234 err := metadata.DeserializeDataToConcreteType() 235 236 assert.NotNil(t, err) 237 }) 238 } 239 240 func TestFloorToNearestHour(t *testing.T) { 241 assert.True(t, isRoundedToNearestHour(FloorToNearestHour(1546346096000))) 242 } 243 244 func TestTruncateText(t *testing.T) { 245 t.Run("Shouldn't affect strings smaller than 300 characters", func(t *testing.T) { 246 assert.Equal(t, utf8.RuneCountInString(truncateText("abc")), 3, "should be 3") 247 }) 248 t.Run("Shouldn't affect empty strings", func(t *testing.T) { 249 assert.Equal(t, utf8.RuneCountInString(truncateText("")), 0, "should be empty") 250 }) 251 t.Run("Truncates string to 300 + 5", func(t *testing.T) { 252 assert.Equal(t, utf8.RuneCountInString(truncateText(BigText)), 305, "should be 300 chars + 5") 253 }) 254 t.Run("Truncated text ends in elipsis", func(t *testing.T) { 255 assert.True(t, strings.HasSuffix(truncateText(BigText), "[...]")) 256 }) 257 } 258 259 func TestFirstNImages(t *testing.T) { 260 t.Run("when empty, return an empty one", func(t *testing.T) { 261 empty := make([]*opengraph.Image, 0) 262 assert.Exactly(t, firstNImages(empty, 1), empty, "Should be the same element") 263 }) 264 t.Run("when it contains one element, return the same array", func(t *testing.T) { 265 one := []*opengraph.Image{sampleImage("image.png")} 266 assert.Exactly(t, firstNImages(one, 1), one, "Should be the same element") 267 }) 268 t.Run("when it contains more than one element and asking for only one, return the first one", func(t *testing.T) { 269 two := []*opengraph.Image{sampleImage("image.png"), sampleImage("notme.png")} 270 assert.True(t, strings.HasSuffix(firstNImages(two, 1)[0].URL, "image.png"), "Should be the image element") 271 }) 272 t.Run("when it contains less than asked, return the original", func(t *testing.T) { 273 two := []*opengraph.Image{sampleImage("image.png"), sampleImage("notme.png")} 274 assert.Equal(t, two, firstNImages(two, 10), "should be the same pointer") 275 }) 276 277 t.Run("asking for negative images", func(t *testing.T) { 278 six := []*opengraph.Image{ 279 sampleImage("image.png"), 280 sampleImage("another.png"), 281 sampleImage("yetanother.jpg"), 282 sampleImage("metoo.gif"), 283 sampleImage("fifth.ico"), 284 sampleImage("notme.tiff"), 285 } 286 assert.Len(t, firstNImages(six, -10), MAX_IMAGES, "On negative, go for defaults") 287 }) 288 289 } 290 291 func TestTruncateOpenGraph(t *testing.T) { 292 og := opengraph.OpenGraph{ 293 Type: "something", 294 URL: "http://myawesomesite.com", 295 Title: BigText, 296 Description: BigText, 297 Determiner: BigText, 298 SiteName: BigText, 299 Locale: "[EN-en]", 300 LocalesAlternate: []string{"[EN-ca]", "[ES-es]"}, 301 Images: []*opengraph.Image{ 302 sampleImage("image.png"), 303 sampleImage("another.png"), 304 sampleImage("yetanother.jpg"), 305 sampleImage("metoo.gif"), 306 sampleImage("fifth.ico"), 307 sampleImage("notme.tiff")}, 308 Audios: []*opengraph.Audio{{}}, 309 Videos: []*opengraph.Video{{}}, 310 Article: &opengraph.Article{}, 311 Book: &opengraph.Book{}, 312 Profile: &opengraph.Profile{}, 313 } 314 result := TruncateOpenGraph(&og) 315 assert.Nil(t, result.Article, "No article stored") 316 assert.Nil(t, result.Book, "No book stored") 317 assert.Nil(t, result.Profile, "No profile stored") 318 assert.Len(t, result.Images, 5, "Only the first 5 images") 319 assert.Empty(t, result.Audios, "No audios stored") 320 assert.Empty(t, result.Videos, "No videos stored") 321 assert.Empty(t, result.LocalesAlternate, "No alternate locales stored") 322 assert.Equal(t, result.Determiner, "", "No determiner stored") 323 assert.Equal(t, utf8.RuneCountInString(result.Title), 305, "Title text is truncated") 324 assert.Equal(t, utf8.RuneCountInString(result.Description), 305, "Description text is truncated") 325 assert.Equal(t, utf8.RuneCountInString(result.SiteName), 305, "SiteName text is truncated") 326 }