github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/services/cache/lru_test.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package cache
     5  
     6  import (
     7  	"fmt"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/mattermost/mattermost-server/v5/model"
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  )
    15  
    16  func TestLRU(t *testing.T) {
    17  	l := NewLRU(&LRUOptions{
    18  		Size:                   128,
    19  		DefaultExpiry:          0,
    20  		InvalidateClusterEvent: "",
    21  	})
    22  
    23  	for i := 0; i < 256; i++ {
    24  		err := l.Set(fmt.Sprintf("%d", i), i)
    25  		require.Nil(t, err)
    26  	}
    27  	size, err := l.Len()
    28  	require.Nil(t, err)
    29  	require.Equalf(t, size, 128, "bad len: %v", size)
    30  
    31  	keys, err := l.Keys()
    32  	require.Nil(t, err)
    33  	for i, k := range keys {
    34  		var v int
    35  		err = l.Get(k, &v)
    36  		require.Nil(t, err, "bad key: %v", k)
    37  		require.Equalf(t, fmt.Sprintf("%d", v), k, "bad key: %v", k)
    38  		require.Equalf(t, i+128, v, "bad value: %v", k)
    39  	}
    40  	for i := 0; i < 128; i++ {
    41  		var v int
    42  		err = l.Get(fmt.Sprintf("%d", i), &v)
    43  		require.Equal(t, ErrKeyNotFound, err, "should be evicted %v: %v", i, err)
    44  	}
    45  	for i := 128; i < 256; i++ {
    46  		var v int
    47  		err = l.Get(fmt.Sprintf("%d", i), &v)
    48  		require.Nil(t, err, "should not be evicted %v: %v", i, err)
    49  	}
    50  	for i := 128; i < 192; i++ {
    51  		l.Remove(fmt.Sprintf("%d", i))
    52  		var v int
    53  		err = l.Get(fmt.Sprintf("%d", i), &v)
    54  		require.Equal(t, ErrKeyNotFound, err, "should be deleted %v: %v", i, err)
    55  	}
    56  
    57  	var v int
    58  	err = l.Get("192", &v) // expect 192 to be last key in l.Keys()
    59  	require.Nil(t, err, "should exist")
    60  	require.Equalf(t, 192, v, "bad value: %v", v)
    61  
    62  	keys, err = l.Keys()
    63  	require.Nil(t, err)
    64  	for i, k := range keys {
    65  		require.Falsef(t, i < 63 && k != fmt.Sprintf("%d", i+193), "out of order key: %v", k)
    66  		require.Falsef(t, i == 63 && k != "192", "out of order key: %v", k)
    67  	}
    68  
    69  	l.Purge()
    70  	size, err = l.Len()
    71  	require.Nil(t, err)
    72  	require.Equalf(t, size, 0, "bad len: %v", size)
    73  	err = l.Get("200", &v)
    74  	require.Equal(t, err, ErrKeyNotFound, "should contain nothing")
    75  
    76  	err = l.Set("201", 301)
    77  	require.Nil(t, err)
    78  	err = l.Get("201", &v)
    79  	require.Nil(t, err)
    80  	require.Equal(t, 301, v)
    81  
    82  }
    83  
    84  func TestLRUExpire(t *testing.T) {
    85  	l := NewLRU(&LRUOptions{
    86  		Size:                   128,
    87  		DefaultExpiry:          1 * time.Second,
    88  		InvalidateClusterEvent: "",
    89  	})
    90  
    91  	l.SetWithDefaultExpiry("1", 1)
    92  	l.SetWithExpiry("3", 3, 0*time.Second)
    93  
    94  	time.Sleep(time.Second * 2)
    95  
    96  	var r1 int
    97  	err := l.Get("1", &r1)
    98  	require.Equal(t, err, ErrKeyNotFound, "should not exist")
    99  
   100  	var r2 int
   101  	err2 := l.Get("3", &r2)
   102  	require.Nil(t, err2, "should exist")
   103  	require.Equal(t, 3, r2)
   104  }
   105  
   106  func TestLRUMarshalUnMarshal(t *testing.T) {
   107  	l := NewLRU(&LRUOptions{
   108  		Size:                   1,
   109  		DefaultExpiry:          0,
   110  		InvalidateClusterEvent: "",
   111  	})
   112  
   113  	value1 := map[string]interface{}{
   114  		"key1": 1,
   115  		"key2": "value2",
   116  	}
   117  	err := l.Set("test", value1)
   118  
   119  	require.Nil(t, err)
   120  
   121  	var value2 map[string]interface{}
   122  	err = l.Get("test", &value2)
   123  	require.Nil(t, err)
   124  
   125  	v1, ok := value2["key1"].(int64)
   126  	require.True(t, ok, "unable to cast value")
   127  	assert.Equal(t, int64(1), v1)
   128  
   129  	v2, ok := value2["key2"].(string)
   130  	require.True(t, ok, "unable to cast value")
   131  	assert.Equal(t, "value2", v2)
   132  
   133  	post := model.Post{
   134  		Id:            "id",
   135  		CreateAt:      11111,
   136  		UpdateAt:      11111,
   137  		DeleteAt:      11111,
   138  		EditAt:        111111,
   139  		IsPinned:      true,
   140  		UserId:        "UserId",
   141  		ChannelId:     "ChannelId",
   142  		RootId:        "RootId",
   143  		ParentId:      "ParentId",
   144  		OriginalId:    "OriginalId",
   145  		Message:       "OriginalId",
   146  		MessageSource: "MessageSource",
   147  		Type:          "Type",
   148  		Props: map[string]interface{}{
   149  			"key": "val",
   150  		},
   151  		Hashtags:      "Hashtags",
   152  		Filenames:     []string{"item1", "item2"},
   153  		FileIds:       []string{"item1", "item2"},
   154  		PendingPostId: "PendingPostId",
   155  		HasReactions:  true,
   156  		ReplyCount:    11111,
   157  		Metadata: &model.PostMetadata{
   158  			Embeds: []*model.PostEmbed{
   159  				{
   160  					Type: "Type",
   161  					URL:  "URL",
   162  					Data: "some data",
   163  				},
   164  				{
   165  					Type: "Type 2",
   166  					URL:  "URL 2",
   167  					Data: "some data 2",
   168  				},
   169  			},
   170  			Emojis: []*model.Emoji{
   171  				{
   172  					Id:   "id",
   173  					Name: "name",
   174  				},
   175  			},
   176  			Files: nil,
   177  			Images: map[string]*model.PostImage{
   178  				"key": {
   179  					Width:      1,
   180  					Height:     1,
   181  					Format:     "format",
   182  					FrameCount: 1,
   183  				},
   184  				"key2": {
   185  					Width:      999,
   186  					Height:     888,
   187  					Format:     "format 2",
   188  					FrameCount: 1000,
   189  				},
   190  			},
   191  			Reactions: []*model.Reaction{
   192  				{
   193  					UserId:    "user_id",
   194  					PostId:    "post_id",
   195  					EmojiName: "emoji_name",
   196  					CreateAt:  111,
   197  				},
   198  			},
   199  		},
   200  	}
   201  	err = l.Set("post", post.Clone())
   202  	require.Nil(t, err)
   203  
   204  	var p model.Post
   205  	err = l.Get("post", &p)
   206  	require.Nil(t, err)
   207  	require.Equal(t, post.Clone(), p.Clone())
   208  }
   209  
   210  func BenchmarkLRU(b *testing.B) {
   211  
   212  	value1 := "simplestring"
   213  
   214  	b.Run("simple=new", func(b *testing.B) {
   215  		for i := 0; i < b.N; i++ {
   216  			l2 := NewLRU(&LRUOptions{
   217  				Size:                   1,
   218  				DefaultExpiry:          0,
   219  				InvalidateClusterEvent: "",
   220  			})
   221  			err := l2.Set("test", value1)
   222  			require.Nil(b, err)
   223  
   224  			var val string
   225  			err = l2.Get("test", &val)
   226  			require.Nil(b, err)
   227  		}
   228  	})
   229  
   230  	type obj struct {
   231  		Field1 int
   232  		Field2 string
   233  		Field3 struct {
   234  			Field4 int
   235  			Field5 string
   236  		}
   237  		Field6 map[string]string
   238  	}
   239  
   240  	value2 := obj{
   241  		1,
   242  		"field2",
   243  		struct {
   244  			Field4 int
   245  			Field5 string
   246  		}{
   247  			6,
   248  			"field5 is a looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong string",
   249  		},
   250  		map[string]string{
   251  			"key0": "value0",
   252  			"key1": "value value1",
   253  			"key2": "value value value2",
   254  			"key3": "value value value value3",
   255  			"key4": "value value value value value4",
   256  			"key5": "value value value value value value5",
   257  			"key6": "value value value value value value value6",
   258  			"key7": "value value value value value value value value7",
   259  			"key8": "value value value value value value value value value8",
   260  			"key9": "value value value value value value value value value value9",
   261  		},
   262  	}
   263  
   264  	b.Run("complex=new", func(b *testing.B) {
   265  		for i := 0; i < b.N; i++ {
   266  			l2 := NewLRU(&LRUOptions{
   267  				Size:                   1,
   268  				DefaultExpiry:          0,
   269  				InvalidateClusterEvent: "",
   270  			})
   271  			err := l2.Set("test", value2)
   272  			require.Nil(b, err)
   273  
   274  			var val obj
   275  			err = l2.Get("test", &val)
   276  			require.Nil(b, err)
   277  		}
   278  	})
   279  
   280  	user := &model.User{
   281  		Id:             "id",
   282  		CreateAt:       11111,
   283  		UpdateAt:       11111,
   284  		DeleteAt:       11111,
   285  		Username:       "username",
   286  		Password:       "password",
   287  		AuthService:    "AuthService",
   288  		AuthData:       nil,
   289  		Email:          "Email",
   290  		EmailVerified:  true,
   291  		Nickname:       "Nickname",
   292  		FirstName:      "FirstName",
   293  		LastName:       "LastName",
   294  		Position:       "Position",
   295  		Roles:          "Roles",
   296  		AllowMarketing: true,
   297  		Props: map[string]string{
   298  			"key0": "value0",
   299  			"key1": "value value1",
   300  			"key2": "value value value2",
   301  			"key3": "value value value value3",
   302  			"key4": "value value value value value4",
   303  			"key5": "value value value value value value5",
   304  			"key6": "value value value value value value value6",
   305  			"key7": "value value value value value value value value7",
   306  			"key8": "value value value value value value value value value8",
   307  			"key9": "value value value value value value value value value value9",
   308  		},
   309  		NotifyProps: map[string]string{
   310  			"key0": "value0",
   311  			"key1": "value value1",
   312  			"key2": "value value value2",
   313  			"key3": "value value value value3",
   314  			"key4": "value value value value value4",
   315  			"key5": "value value value value value value5",
   316  			"key6": "value value value value value value value6",
   317  			"key7": "value value value value value value value value7",
   318  			"key8": "value value value value value value value value value8",
   319  			"key9": "value value value value value value value value value value9",
   320  		},
   321  		LastPasswordUpdate: 111111,
   322  		LastPictureUpdate:  111111,
   323  		FailedAttempts:     111111,
   324  		Locale:             "Locale",
   325  		Timezone: map[string]string{
   326  			"key0": "value0",
   327  			"key1": "value value1",
   328  			"key2": "value value value2",
   329  			"key3": "value value value value3",
   330  			"key4": "value value value value value4",
   331  			"key5": "value value value value value value5",
   332  			"key6": "value value value value value value value6",
   333  			"key7": "value value value value value value value value7",
   334  			"key8": "value value value value value value value value value8",
   335  			"key9": "value value value value value value value value value value9",
   336  		},
   337  		MfaActive:              true,
   338  		MfaSecret:              "MfaSecret",
   339  		LastActivityAt:         111111,
   340  		IsBot:                  true,
   341  		BotDescription:         "field5 is a looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong string",
   342  		BotLastIconUpdate:      111111,
   343  		TermsOfServiceId:       "TermsOfServiceId",
   344  		TermsOfServiceCreateAt: 111111,
   345  	}
   346  
   347  	b.Run("User=new", func(b *testing.B) {
   348  		for i := 0; i < b.N; i++ {
   349  			l2 := NewLRU(&LRUOptions{
   350  				Size:                   1,
   351  				DefaultExpiry:          0,
   352  				InvalidateClusterEvent: "",
   353  			})
   354  			err := l2.Set("test", user)
   355  			require.Nil(b, err)
   356  
   357  			var val model.User
   358  			err = l2.Get("test", &val)
   359  			require.Nil(b, err)
   360  		}
   361  	})
   362  
   363  	post := &model.Post{
   364  		Id:            "id",
   365  		CreateAt:      11111,
   366  		UpdateAt:      11111,
   367  		DeleteAt:      11111,
   368  		EditAt:        111111,
   369  		IsPinned:      true,
   370  		UserId:        "UserId",
   371  		ChannelId:     "ChannelId",
   372  		RootId:        "RootId",
   373  		ParentId:      "ParentId",
   374  		OriginalId:    "OriginalId",
   375  		Message:       "OriginalId",
   376  		MessageSource: "MessageSource",
   377  		Type:          "Type",
   378  		Props: map[string]interface{}{
   379  			"key": "val",
   380  		},
   381  		Hashtags:      "Hashtags",
   382  		Filenames:     []string{"item1", "item2"},
   383  		FileIds:       []string{"item1", "item2"},
   384  		PendingPostId: "PendingPostId",
   385  		HasReactions:  true,
   386  
   387  		// Transient data populated before sending a post to the client
   388  		ReplyCount: 11111,
   389  		Metadata: &model.PostMetadata{
   390  			Embeds: []*model.PostEmbed{
   391  				{
   392  					Type: "Type",
   393  					URL:  "URL",
   394  					Data: "some data",
   395  				},
   396  				{
   397  					Type: "Type 2",
   398  					URL:  "URL 2",
   399  					Data: "some data 2",
   400  				},
   401  			},
   402  			Emojis: []*model.Emoji{
   403  				{
   404  					Id:   "id",
   405  					Name: "name",
   406  				},
   407  			},
   408  			Files: nil,
   409  			Images: map[string]*model.PostImage{
   410  				"key": {
   411  					Width:      1,
   412  					Height:     1,
   413  					Format:     "format",
   414  					FrameCount: 1,
   415  				},
   416  				"key2": {
   417  					Width:      999,
   418  					Height:     888,
   419  					Format:     "format 2",
   420  					FrameCount: 1000,
   421  				},
   422  			},
   423  			Reactions: []*model.Reaction{},
   424  		},
   425  	}
   426  
   427  	b.Run("Post=new", func(b *testing.B) {
   428  		for i := 0; i < b.N; i++ {
   429  			l2 := NewLRU(&LRUOptions{
   430  				Size:                   1,
   431  				DefaultExpiry:          0,
   432  				InvalidateClusterEvent: "",
   433  			})
   434  			err := l2.Set("test", post)
   435  			require.Nil(b, err)
   436  
   437  			var val model.Post
   438  			err = l2.Get("test", &val)
   439  			require.Nil(b, err)
   440  		}
   441  	})
   442  
   443  	status := model.Status{
   444  		UserId:         "UserId",
   445  		Status:         "Status",
   446  		Manual:         true,
   447  		LastActivityAt: 111111,
   448  		ActiveChannel:  "ActiveChannel",
   449  	}
   450  
   451  	b.Run("Status=new", func(b *testing.B) {
   452  		for i := 0; i < b.N; i++ {
   453  			l2 := NewLRU(&LRUOptions{
   454  				Size:                   1,
   455  				DefaultExpiry:          0,
   456  				InvalidateClusterEvent: "",
   457  			})
   458  			err := l2.Set("test", status)
   459  			require.Nil(b, err)
   460  
   461  			var val model.Status
   462  			err = l2.Get("test", &val)
   463  			require.Nil(b, err)
   464  		}
   465  	})
   466  }