github.com/dschalla/mattermost-server@v4.8.1-rc1+incompatible/api/post_test.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package api
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  	"net/http"
    10  	"net/http/httptest"
    11  	"net/url"
    12  	"reflect"
    13  	"strings"
    14  
    15  	"testing"
    16  	"time"
    17  
    18  	"github.com/mattermost/mattermost-server/app"
    19  	"github.com/mattermost/mattermost-server/model"
    20  	"github.com/mattermost/mattermost-server/store"
    21  	"github.com/mattermost/mattermost-server/utils"
    22  )
    23  
    24  func TestCreatePost(t *testing.T) {
    25  	th := Setup().InitBasic()
    26  	defer th.TearDown()
    27  
    28  	Client := th.BasicClient
    29  	team := th.BasicTeam
    30  	team2 := th.CreateTeam(th.BasicClient)
    31  	user3 := th.CreateUser(th.BasicClient)
    32  	th.LinkUserToTeam(user3, team2)
    33  	channel1 := th.BasicChannel
    34  	channel2 := th.CreateChannel(Client, team)
    35  
    36  	th.InitSystemAdmin()
    37  	AdminClient := th.SystemAdminClient
    38  	adminTeam := th.SystemAdminTeam
    39  	adminUser := th.CreateUser(th.SystemAdminClient)
    40  	th.LinkUserToTeam(adminUser, adminTeam)
    41  
    42  	post1 := &model.Post{ChannelId: channel1.Id, Message: "#hashtag a" + model.NewId() + "a", Props: model.StringInterface{model.PROPS_ADD_CHANNEL_MEMBER: "no good"}}
    43  	rpost1, err := Client.CreatePost(post1)
    44  	if err != nil {
    45  		t.Fatal(err)
    46  	}
    47  
    48  	if rpost1.Data.(*model.Post).Message != post1.Message {
    49  		t.Fatal("message didn't match")
    50  	}
    51  
    52  	if rpost1.Data.(*model.Post).Hashtags != "#hashtag" {
    53  		t.Fatal("hashtag didn't match")
    54  	}
    55  
    56  	if len(rpost1.Data.(*model.Post).FileIds) != 0 {
    57  		t.Fatal("shouldn't have files")
    58  	}
    59  
    60  	if rpost1.Data.(*model.Post).EditAt != 0 {
    61  		t.Fatal("Newly craeted post shouldn't have EditAt set")
    62  	}
    63  
    64  	if rpost1.Data.(*model.Post).Props[model.PROPS_ADD_CHANNEL_MEMBER] != nil {
    65  		t.Fatal("newly created post shouldn't have Props['add_channel_member'] set")
    66  	}
    67  
    68  	_, err = Client.CreatePost(&model.Post{ChannelId: channel1.Id, Message: "#hashtag a" + model.NewId() + "a", Type: model.POST_SYSTEM_GENERIC})
    69  	if err == nil {
    70  		t.Fatal("should have failed - bad post type")
    71  	}
    72  
    73  	post2 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: rpost1.Data.(*model.Post).Id}
    74  	rpost2, err := Client.CreatePost(post2)
    75  	if err != nil {
    76  		t.Fatal(err)
    77  	}
    78  
    79  	post3 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: rpost1.Data.(*model.Post).Id, ParentId: rpost2.Data.(*model.Post).Id}
    80  	_, err = Client.CreatePost(post3)
    81  	if err != nil {
    82  		t.Fatal(err)
    83  	}
    84  
    85  	post4 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: "junk"}
    86  	_, err = Client.CreatePost(post4)
    87  	if err.StatusCode != http.StatusBadRequest {
    88  		t.Fatal("Should have been invalid param")
    89  	}
    90  
    91  	post5 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: rpost1.Data.(*model.Post).Id, ParentId: "junk"}
    92  	_, err = Client.CreatePost(post5)
    93  	if err.StatusCode != http.StatusBadRequest {
    94  		t.Fatal("Should have been invalid param")
    95  	}
    96  
    97  	post1c2 := &model.Post{ChannelId: channel2.Id, Message: "zz" + model.NewId() + "a"}
    98  	rpost1c2, err := Client.CreatePost(post1c2)
    99  
   100  	post2c2 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: rpost1c2.Data.(*model.Post).Id}
   101  	_, err = Client.CreatePost(post2c2)
   102  	if err.StatusCode != http.StatusBadRequest {
   103  		t.Fatal("Should have been invalid param")
   104  	}
   105  
   106  	post6 := &model.Post{ChannelId: "junk", Message: "zz" + model.NewId() + "a"}
   107  	_, err = Client.CreatePost(post6)
   108  	if err.StatusCode != http.StatusForbidden {
   109  		t.Fatal("Should have been forbidden")
   110  	}
   111  
   112  	th.LoginBasic2()
   113  
   114  	post7 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
   115  	_, err = Client.CreatePost(post7)
   116  	if err.StatusCode != http.StatusForbidden {
   117  		t.Fatal("Should have been forbidden")
   118  	}
   119  
   120  	Client.Login(user3.Email, user3.Password)
   121  	Client.SetTeamId(team2.Id)
   122  	channel3 := th.CreateChannel(Client, team2)
   123  
   124  	post8 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
   125  	_, err = Client.CreatePost(post8)
   126  	if err.StatusCode != http.StatusForbidden {
   127  		t.Fatal("Should have been forbidden")
   128  	}
   129  
   130  	if _, err = Client.DoApiPost("/channels/"+channel3.Id+"/create", "garbage"); err == nil {
   131  		t.Fatal("should have been an error")
   132  	}
   133  
   134  	fileIds := make([]string, 4)
   135  	if data, err := readTestFile("test.png"); err != nil {
   136  		t.Fatal(err)
   137  	} else {
   138  		for i := 0; i < 3; i++ {
   139  			fileIds[i] = Client.MustGeneric(Client.UploadPostAttachment(data, channel3.Id, "test.png")).(*model.FileUploadResponse).FileInfos[0].Id
   140  		}
   141  	}
   142  
   143  	// Make sure duplicated file ids are removed
   144  	fileIds[3] = fileIds[0]
   145  
   146  	post9 := &model.Post{
   147  		ChannelId: channel3.Id,
   148  		Message:   "test",
   149  		FileIds:   fileIds,
   150  	}
   151  	if resp, err := Client.CreatePost(post9); err != nil {
   152  		t.Fatal(err)
   153  	} else if rpost9 := resp.Data.(*model.Post); len(rpost9.FileIds) != 3 {
   154  		t.Fatal("post should have 3 files")
   155  	} else {
   156  		infos := store.Must(th.App.Srv.Store.FileInfo().GetForPost(rpost9.Id, true, true)).([]*model.FileInfo)
   157  
   158  		if len(infos) != 3 {
   159  			t.Fatal("should've attached all 3 files to post")
   160  		}
   161  	}
   162  
   163  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.ExperimentalTownSquareIsReadOnly = true })
   164  	th.App.SetLicense(model.NewTestLicense())
   165  
   166  	defaultChannel := store.Must(th.App.Srv.Store.Channel().GetByName(team.Id, model.DEFAULT_CHANNEL, true)).(*model.Channel)
   167  	defaultPost := &model.Post{
   168  		ChannelId: defaultChannel.Id,
   169  		Message:   "Default Channel Post",
   170  	}
   171  	if _, err = Client.CreatePost(defaultPost); err == nil {
   172  		t.Fatal("should have failed -- ExperimentalTownSquareIsReadOnly is true and it's a read only channel")
   173  	}
   174  
   175  	adminDefaultChannel := store.Must(th.App.Srv.Store.Channel().GetByName(adminTeam.Id, model.DEFAULT_CHANNEL, true)).(*model.Channel)
   176  	adminDefaultPost := &model.Post{
   177  		ChannelId: adminDefaultChannel.Id,
   178  		Message:   "Admin Default Channel Post",
   179  	}
   180  	if _, err = AdminClient.CreatePost(adminDefaultPost); err != nil {
   181  		t.Fatal("should not have failed -- ExperimentalTownSquareIsReadOnly is true and admin can post to channel")
   182  	}
   183  }
   184  
   185  func TestCreatePostWithCreateAt(t *testing.T) {
   186  
   187  	// An ordinary user cannot use CreateAt
   188  
   189  	th := Setup().InitBasic()
   190  	defer th.TearDown()
   191  
   192  	Client := th.BasicClient
   193  	channel1 := th.BasicChannel
   194  
   195  	post := &model.Post{
   196  		ChannelId: channel1.Id,
   197  		Message:   "PLT-4349",
   198  		CreateAt:  1234,
   199  	}
   200  	if resp, err := Client.CreatePost(post); err != nil {
   201  		t.Fatal(err)
   202  	} else if rpost := resp.Data.(*model.Post); rpost.CreateAt == post.CreateAt {
   203  		t.Fatal("post should be created with default CreateAt timestamp for ordinary user")
   204  	}
   205  
   206  	// But a System Admin user can
   207  
   208  	th.InitSystemAdmin()
   209  	SysClient := th.SystemAdminClient
   210  
   211  	if resp, err := SysClient.CreatePost(post); err != nil {
   212  		t.Fatal(err)
   213  	} else if rpost := resp.Data.(*model.Post); rpost.CreateAt != post.CreateAt {
   214  		t.Fatal("post should be created with provided CreateAt timestamp for System Admin user")
   215  	}
   216  }
   217  
   218  func testCreatePostWithOutgoingHook(
   219  	t *testing.T,
   220  	hookContentType, expectedContentType, message, triggerWord string,
   221  	fileIds []string,
   222  	triggerWhen int,
   223  ) {
   224  	th := Setup().InitSystemAdmin()
   225  	defer th.TearDown()
   226  
   227  	Client := th.SystemAdminClient
   228  	team := th.SystemAdminTeam
   229  	user := th.SystemAdminUser
   230  	channel := th.CreateChannel(Client, team)
   231  
   232  	th.App.UpdateConfig(func(cfg *model.Config) {
   233  		cfg.ServiceSettings.EnableOutgoingWebhooks = true
   234  		*cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost 127.0.0.1"
   235  	})
   236  
   237  	var hook *model.OutgoingWebhook
   238  	var post *model.Post
   239  
   240  	// Create a test server that is the target of the outgoing webhook. It will
   241  	// validate the webhook body fields and write to the success channel on
   242  	// success/failure.
   243  	success := make(chan bool)
   244  	wait := make(chan bool, 1)
   245  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   246  		<-wait
   247  
   248  		requestContentType := r.Header.Get("Content-Type")
   249  		if requestContentType != expectedContentType {
   250  			t.Logf("Content-Type is %s, should be %s", requestContentType, expectedContentType)
   251  			success <- false
   252  			return
   253  		}
   254  
   255  		expectedPayload := &model.OutgoingWebhookPayload{
   256  			Token:       hook.Token,
   257  			TeamId:      hook.TeamId,
   258  			TeamDomain:  team.Name,
   259  			ChannelId:   post.ChannelId,
   260  			ChannelName: channel.Name,
   261  			Timestamp:   post.CreateAt,
   262  			UserId:      post.UserId,
   263  			UserName:    user.Username,
   264  			PostId:      post.Id,
   265  			Text:        post.Message,
   266  			TriggerWord: triggerWord,
   267  			FileIds:     strings.Join(post.FileIds, ","),
   268  		}
   269  
   270  		// depending on the Content-Type, we expect to find a JSON or form encoded payload
   271  		if requestContentType == "application/json" {
   272  			decoder := json.NewDecoder(r.Body)
   273  			o := &model.OutgoingWebhookPayload{}
   274  			decoder.Decode(&o)
   275  
   276  			if !reflect.DeepEqual(expectedPayload, o) {
   277  				t.Logf("JSON payload is %+v, should be %+v", o, expectedPayload)
   278  				success <- false
   279  				return
   280  			}
   281  		} else {
   282  			err := r.ParseForm()
   283  			if err != nil {
   284  				t.Logf("Error parsing form: %q", err)
   285  				success <- false
   286  				return
   287  			}
   288  
   289  			expectedFormValues, _ := url.ParseQuery(expectedPayload.ToFormValues())
   290  			if !reflect.DeepEqual(expectedFormValues, r.Form) {
   291  				t.Logf("Form values are %q, should be %q", r.Form, expectedFormValues)
   292  				success <- false
   293  				return
   294  			}
   295  		}
   296  
   297  		resp := &model.OutgoingWebhookResponse{}
   298  		resp.Text = model.NewString("some test text")
   299  		resp.Username = "testusername"
   300  		resp.IconURL = "http://www.mattermost.org/wp-content/uploads/2016/04/icon.png"
   301  		resp.Props = map[string]interface{}{"someprop": "somevalue"}
   302  		resp.Type = "custom_test"
   303  
   304  		w.Write([]byte(resp.ToJson()))
   305  
   306  		success <- true
   307  	}))
   308  	defer ts.Close()
   309  
   310  	// create an outgoing webhook, passing it the test server URL
   311  	var triggerWords []string
   312  	if triggerWord != "" {
   313  		triggerWords = []string{triggerWord}
   314  	}
   315  
   316  	hook = &model.OutgoingWebhook{
   317  		ChannelId:    channel.Id,
   318  		TeamId:       team.Id,
   319  		ContentType:  hookContentType,
   320  		TriggerWords: triggerWords,
   321  		TriggerWhen:  triggerWhen,
   322  		CallbackURLs: []string{ts.URL},
   323  	}
   324  
   325  	if result, err := Client.CreateOutgoingWebhook(hook); err != nil {
   326  		t.Fatal(err)
   327  	} else {
   328  		hook = result.Data.(*model.OutgoingWebhook)
   329  	}
   330  
   331  	// create a post to trigger the webhook
   332  	post = &model.Post{
   333  		ChannelId: channel.Id,
   334  		Message:   message,
   335  		FileIds:   fileIds,
   336  	}
   337  
   338  	if result, err := Client.CreatePost(post); err != nil {
   339  		t.Fatal(err)
   340  	} else {
   341  		post = result.Data.(*model.Post)
   342  	}
   343  
   344  	wait <- true
   345  
   346  	// We wait for the test server to write to the success channel and we make
   347  	// the test fail if that doesn't happen before the timeout.
   348  	select {
   349  	case ok := <-success:
   350  		if !ok {
   351  			t.Fatal("Test server did send an invalid webhook.")
   352  		}
   353  	case <-time.After(time.Second):
   354  		t.Fatal("Timeout, test server did not send the webhook.")
   355  	}
   356  }
   357  
   358  func TestCreatePostWithOutgoingHook_form_urlencoded(t *testing.T) {
   359  	testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH)
   360  	testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "triggerwordaaazzz lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH)
   361  	testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "", "", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH)
   362  	testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "", "", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH)
   363  }
   364  
   365  func TestCreatePostWithOutgoingHook_json(t *testing.T) {
   366  	testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerword lorem ipsum", "triggerword", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_EXACT_MATCH)
   367  	testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerwordaaazzz lorem ipsum", "triggerword", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_STARTS_WITH)
   368  	testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerword lorem ipsum", "", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH)
   369  	testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerwordaaazzz lorem ipsum", "", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH)
   370  }
   371  
   372  // hooks created before we added the ContentType field should be considered as
   373  // application/x-www-form-urlencoded
   374  func TestCreatePostWithOutgoingHook_no_content_type(t *testing.T) {
   375  	testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH)
   376  	testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerwordaaazzz lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH)
   377  	testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_EXACT_MATCH)
   378  	testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerwordaaazzz lorem ipsum", "", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_STARTS_WITH)
   379  }
   380  
   381  func TestUpdatePost(t *testing.T) {
   382  	th := Setup().InitBasic()
   383  	defer th.TearDown()
   384  
   385  	Client := th.BasicClient
   386  	channel1 := th.BasicChannel
   387  
   388  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowEditPost = model.ALLOW_EDIT_POST_ALWAYS })
   389  
   390  	post1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
   391  	rpost1, err := Client.CreatePost(post1)
   392  	if err != nil {
   393  		t.Fatal(err)
   394  	}
   395  
   396  	if rpost1.Data.(*model.Post).Message != post1.Message {
   397  		t.Fatal("full name didn't match")
   398  	}
   399  
   400  	post2 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: rpost1.Data.(*model.Post).Id}
   401  	rpost2, err := Client.CreatePost(post2)
   402  	if err != nil {
   403  		t.Fatal(err)
   404  	}
   405  
   406  	if rpost2.Data.(*model.Post).EditAt != 0 {
   407  		t.Fatal("Newly craeted post shouldn't have EditAt set")
   408  	}
   409  
   410  	msg2 := "zz" + model.NewId() + " update post 1"
   411  	rpost2.Data.(*model.Post).Message = msg2
   412  	rpost2.Data.(*model.Post).Props[model.PROPS_ADD_CHANNEL_MEMBER] = "no good"
   413  	if rupost2, err := Client.UpdatePost(rpost2.Data.(*model.Post)); err != nil {
   414  		t.Fatal(err)
   415  	} else {
   416  		if rupost2.Data.(*model.Post).Message != msg2 {
   417  			t.Fatal("failed to updates")
   418  		}
   419  		if rupost2.Data.(*model.Post).EditAt == 0 {
   420  			t.Fatal("EditAt not updated for post")
   421  		}
   422  		if rupost2.Data.(*model.Post).Props[model.PROPS_ADD_CHANNEL_MEMBER] != nil {
   423  			t.Fatal("failed to sanitize Props['add_channel_member'], should be nil")
   424  		}
   425  	}
   426  
   427  	msg1 := "#hashtag a" + model.NewId() + " update post 2"
   428  	rpost1.Data.(*model.Post).Message = msg1
   429  	if rupost1, err := Client.UpdatePost(rpost1.Data.(*model.Post)); err != nil {
   430  		t.Fatal(err)
   431  	} else {
   432  		if rupost1.Data.(*model.Post).Message != msg1 && rupost1.Data.(*model.Post).Hashtags != "#hashtag" {
   433  			t.Fatal("failed to updates")
   434  		}
   435  	}
   436  
   437  	up12 := &model.Post{Id: rpost1.Data.(*model.Post).Id, ChannelId: channel1.Id, Message: "zz" + model.NewId() + " updaet post 1 update 2"}
   438  	if rup12, err := Client.UpdatePost(up12); err != nil {
   439  		t.Fatal(err)
   440  	} else {
   441  		if rup12.Data.(*model.Post).Message != up12.Message {
   442  			t.Fatal("failed to updates")
   443  		}
   444  	}
   445  
   446  	rpost3, err := th.App.CreatePost(&model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", Type: model.POST_JOIN_LEAVE, UserId: th.BasicUser.Id}, channel1, false)
   447  	if err != nil {
   448  		t.Fatal(err)
   449  	}
   450  
   451  	up3 := &model.Post{Id: rpost3.Id, ChannelId: channel1.Id, Message: "zz" + model.NewId() + " update post 3"}
   452  	if _, err := Client.UpdatePost(up3); err == nil {
   453  		t.Fatal("shouldn't have been able to update system message")
   454  	}
   455  
   456  	// Test licensed policy controls for edit post
   457  	th.App.SetLicense(model.NewTestLicense())
   458  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowEditPost = model.ALLOW_EDIT_POST_NEVER })
   459  
   460  	post4 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: rpost1.Data.(*model.Post).Id}
   461  	rpost4, err := Client.CreatePost(post4)
   462  	if err != nil {
   463  		t.Fatal(err)
   464  	}
   465  
   466  	up4 := &model.Post{Id: rpost4.Data.(*model.Post).Id, ChannelId: channel1.Id, Message: "zz" + model.NewId() + " update post 4"}
   467  	if _, err := Client.UpdatePost(up4); err == nil {
   468  		t.Fatal("shouldn't have been able to update a message when not allowed")
   469  	}
   470  
   471  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.AllowEditPost = model.ALLOW_EDIT_POST_TIME_LIMIT })
   472  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.PostEditTimeLimit = 1 }) //seconds
   473  
   474  	post5 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: rpost1.Data.(*model.Post).Id}
   475  	rpost5, err := Client.CreatePost(post5)
   476  	if err != nil {
   477  		t.Fatal(err)
   478  	}
   479  
   480  	msg5 := "zz" + model.NewId() + " update post 5"
   481  	up5 := &model.Post{Id: rpost5.Data.(*model.Post).Id, ChannelId: channel1.Id, Message: msg5}
   482  	if rup5, err := Client.UpdatePost(up5); err != nil {
   483  		t.Fatal(err)
   484  	} else {
   485  		if rup5.Data.(*model.Post).Message != up5.Message {
   486  			t.Fatal("failed to updates")
   487  		}
   488  	}
   489  
   490  	time.Sleep(1000 * time.Millisecond)
   491  
   492  	up6 := &model.Post{Id: rpost5.Data.(*model.Post).Id, ChannelId: channel1.Id, Message: "zz" + model.NewId() + " update post 5"}
   493  	if _, err := Client.UpdatePost(up6); err == nil {
   494  		t.Fatal("shouldn't have been able to update a message after time limit")
   495  	}
   496  }
   497  
   498  func TestGetPosts(t *testing.T) {
   499  	th := Setup().InitBasic()
   500  	defer th.TearDown()
   501  
   502  	Client := th.BasicClient
   503  	channel1 := th.BasicChannel
   504  
   505  	time.Sleep(10 * time.Millisecond)
   506  	post1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
   507  	post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
   508  
   509  	time.Sleep(10 * time.Millisecond)
   510  	post1a1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: post1.Id}
   511  	post1a1 = Client.Must(Client.CreatePost(post1a1)).Data.(*model.Post)
   512  
   513  	time.Sleep(10 * time.Millisecond)
   514  	post2 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
   515  	post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
   516  
   517  	time.Sleep(10 * time.Millisecond)
   518  	post3 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
   519  	post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post)
   520  
   521  	time.Sleep(10 * time.Millisecond)
   522  	post3a1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: post3.Id}
   523  	post3a1 = Client.Must(Client.CreatePost(post3a1)).Data.(*model.Post)
   524  
   525  	r1 := Client.Must(Client.GetPosts(channel1.Id, 0, 2, "")).Data.(*model.PostList)
   526  
   527  	if r1.Order[0] != post3a1.Id {
   528  		t.Fatal("wrong order")
   529  	}
   530  
   531  	if r1.Order[1] != post3.Id {
   532  		t.Fatal("wrong order")
   533  	}
   534  
   535  	if len(r1.Posts) != 2 { // 3a1 and 3; 3a1's parent already there
   536  		t.Fatal("wrong size")
   537  	}
   538  
   539  	r2 := Client.Must(Client.GetPosts(channel1.Id, 2, 2, "")).Data.(*model.PostList)
   540  
   541  	if r2.Order[0] != post2.Id {
   542  		t.Fatal("wrong order")
   543  	}
   544  
   545  	if r2.Order[1] != post1a1.Id {
   546  		t.Fatal("wrong order")
   547  	}
   548  
   549  	if len(r2.Posts) != 3 { // 2 and 1a1; + 1a1's parent
   550  		t.Log(r2.Posts)
   551  		t.Fatal("wrong size")
   552  	}
   553  }
   554  
   555  func TestGetPostsSince(t *testing.T) {
   556  	th := Setup().InitBasic()
   557  	defer th.TearDown()
   558  
   559  	Client := th.BasicClient
   560  	channel1 := th.BasicChannel
   561  
   562  	time.Sleep(10 * time.Millisecond)
   563  	post0 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
   564  	post0 = Client.Must(Client.CreatePost(post0)).Data.(*model.Post)
   565  
   566  	time.Sleep(10 * time.Millisecond)
   567  	post1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
   568  	post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
   569  
   570  	time.Sleep(10 * time.Millisecond)
   571  	post1a1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: post1.Id}
   572  	post1a1 = Client.Must(Client.CreatePost(post1a1)).Data.(*model.Post)
   573  
   574  	time.Sleep(10 * time.Millisecond)
   575  	post2 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
   576  	post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
   577  
   578  	time.Sleep(10 * time.Millisecond)
   579  	post3 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
   580  	post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post)
   581  
   582  	time.Sleep(10 * time.Millisecond)
   583  	post3a1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: post3.Id}
   584  	post3a1 = Client.Must(Client.CreatePost(post3a1)).Data.(*model.Post)
   585  
   586  	r1 := Client.Must(Client.GetPostsSince(channel1.Id, post1.CreateAt)).Data.(*model.PostList)
   587  
   588  	if r1.Order[0] != post3a1.Id {
   589  		t.Fatal("wrong order")
   590  	}
   591  
   592  	if r1.Order[1] != post3.Id {
   593  		t.Fatal("wrong order")
   594  	}
   595  
   596  	if len(r1.Posts) != 5 {
   597  		t.Fatal("wrong size")
   598  	}
   599  
   600  	now := model.GetMillis()
   601  	r2 := Client.Must(Client.GetPostsSince(channel1.Id, now)).Data.(*model.PostList)
   602  
   603  	if len(r2.Posts) != 0 {
   604  		t.Fatal("should have been empty")
   605  	}
   606  
   607  	post2.Message = "new message"
   608  	Client.Must(Client.UpdatePost(post2))
   609  
   610  	r3 := Client.Must(Client.GetPostsSince(channel1.Id, now)).Data.(*model.PostList)
   611  
   612  	if len(r3.Order) != 2 { // 2 because deleted post is returned as well
   613  		t.Fatal("missing post update")
   614  	}
   615  }
   616  
   617  func TestGetPostsBeforeAfter(t *testing.T) {
   618  	th := Setup().InitBasic()
   619  	defer th.TearDown()
   620  
   621  	Client := th.BasicClient
   622  	channel1 := th.BasicChannel
   623  
   624  	time.Sleep(10 * time.Millisecond)
   625  	post0 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
   626  	post0 = Client.Must(Client.CreatePost(post0)).Data.(*model.Post)
   627  
   628  	time.Sleep(10 * time.Millisecond)
   629  	post1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
   630  	post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
   631  
   632  	time.Sleep(10 * time.Millisecond)
   633  	post1a1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: post1.Id}
   634  	post1a1 = Client.Must(Client.CreatePost(post1a1)).Data.(*model.Post)
   635  
   636  	time.Sleep(10 * time.Millisecond)
   637  	post2 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
   638  	post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
   639  
   640  	time.Sleep(10 * time.Millisecond)
   641  	post3 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
   642  	post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post)
   643  
   644  	time.Sleep(10 * time.Millisecond)
   645  	post3a1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: post3.Id}
   646  	post3a1 = Client.Must(Client.CreatePost(post3a1)).Data.(*model.Post)
   647  
   648  	r1 := Client.Must(Client.GetPostsBefore(channel1.Id, post1a1.Id, 0, 10, "")).Data.(*model.PostList)
   649  
   650  	if r1.Order[0] != post1.Id {
   651  		t.Fatal("wrong order")
   652  	}
   653  
   654  	if r1.Order[1] != post0.Id {
   655  		t.Fatal("wrong order")
   656  	}
   657  
   658  	// including created post from test helper and system 'joined' message
   659  	if len(r1.Posts) != 4 {
   660  		t.Fatal("wrong size")
   661  	}
   662  
   663  	r2 := Client.Must(Client.GetPostsAfter(channel1.Id, post3a1.Id, 0, 3, "")).Data.(*model.PostList)
   664  
   665  	if len(r2.Posts) != 0 {
   666  		t.Fatal("should have been empty")
   667  	}
   668  
   669  	post2.Message = "new message"
   670  	Client.Must(Client.UpdatePost(post2))
   671  
   672  	r3 := Client.Must(Client.GetPostsAfter(channel1.Id, post1a1.Id, 0, 2, "")).Data.(*model.PostList)
   673  
   674  	if r3.Order[0] != post3.Id {
   675  		t.Fatal("wrong order")
   676  	}
   677  
   678  	if r3.Order[1] != post2.Id {
   679  		t.Fatal("wrong order")
   680  	}
   681  
   682  	if len(r3.Order) != 2 {
   683  		t.Fatal("missing post update")
   684  	}
   685  }
   686  
   687  func TestSearchPosts(t *testing.T) {
   688  	th := Setup().InitBasic()
   689  	defer th.TearDown()
   690  
   691  	Client := th.BasicClient
   692  	channel1 := th.BasicChannel
   693  
   694  	post1 := &model.Post{ChannelId: channel1.Id, Message: "search for post1"}
   695  	post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
   696  
   697  	post2 := &model.Post{ChannelId: channel1.Id, Message: "search for post2"}
   698  	post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
   699  
   700  	post3 := &model.Post{ChannelId: channel1.Id, Message: "#hashtag search for post3"}
   701  	post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post)
   702  
   703  	post4 := &model.Post{ChannelId: channel1.Id, Message: "hashtag for post4"}
   704  	post4 = Client.Must(Client.CreatePost(post4)).Data.(*model.Post)
   705  
   706  	r1 := Client.Must(Client.SearchPosts("search", false)).Data.(*model.PostList)
   707  
   708  	if len(r1.Order) != 3 {
   709  		t.Fatal("wrong search")
   710  	}
   711  
   712  	r2 := Client.Must(Client.SearchPosts("post2", false)).Data.(*model.PostList)
   713  
   714  	if len(r2.Order) != 1 && r2.Order[0] == post2.Id {
   715  		t.Fatal("wrong search")
   716  	}
   717  
   718  	r3 := Client.Must(Client.SearchPosts("#hashtag", false)).Data.(*model.PostList)
   719  
   720  	if len(r3.Order) != 1 && r3.Order[0] == post3.Id {
   721  		t.Fatal("wrong search")
   722  	}
   723  
   724  	if r4 := Client.Must(Client.SearchPosts("*", false)).Data.(*model.PostList); len(r4.Order) != 0 {
   725  		t.Fatal("searching for just * shouldn't return any results")
   726  	}
   727  
   728  	r5 := Client.Must(Client.SearchPosts("post1 post2", true)).Data.(*model.PostList)
   729  
   730  	if len(r5.Order) != 2 {
   731  		t.Fatal("wrong search results")
   732  	}
   733  }
   734  
   735  func TestSearchHashtagPosts(t *testing.T) {
   736  	th := Setup().InitBasic()
   737  	defer th.TearDown()
   738  
   739  	Client := th.BasicClient
   740  	channel1 := th.BasicChannel
   741  
   742  	post1 := &model.Post{ChannelId: channel1.Id, Message: "#sgtitlereview with space"}
   743  	post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
   744  
   745  	post2 := &model.Post{ChannelId: channel1.Id, Message: "#sgtitlereview\n with return"}
   746  	post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
   747  
   748  	post3 := &model.Post{ChannelId: channel1.Id, Message: "no hashtag"}
   749  	post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post)
   750  
   751  	r1 := Client.Must(Client.SearchPosts("#sgtitlereview", false)).Data.(*model.PostList)
   752  
   753  	if len(r1.Order) != 2 {
   754  		t.Fatal("wrong search")
   755  	}
   756  }
   757  
   758  func TestSearchPostsInChannel(t *testing.T) {
   759  	th := Setup().InitBasic()
   760  	defer th.TearDown()
   761  
   762  	Client := th.BasicClient
   763  	channel1 := th.BasicChannel
   764  	team := th.BasicTeam
   765  
   766  	post1 := &model.Post{ChannelId: channel1.Id, Message: "sgtitlereview with space"}
   767  	post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
   768  
   769  	channel2 := &model.Channel{DisplayName: "TestGetPosts", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
   770  	channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
   771  
   772  	channel3 := &model.Channel{DisplayName: "TestGetPosts", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
   773  	channel3 = Client.Must(Client.CreateChannel(channel3)).Data.(*model.Channel)
   774  
   775  	post2 := &model.Post{ChannelId: channel2.Id, Message: "sgtitlereview\n with return"}
   776  	post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
   777  
   778  	post3 := &model.Post{ChannelId: channel2.Id, Message: "other message with no return"}
   779  	post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post)
   780  
   781  	post4 := &model.Post{ChannelId: channel3.Id, Message: "other message with no return"}
   782  	post4 = Client.Must(Client.CreatePost(post4)).Data.(*model.Post)
   783  
   784  	if result := Client.Must(Client.SearchPosts("channel:", false)).Data.(*model.PostList); len(result.Order) != 0 {
   785  		t.Fatalf("wrong number of posts returned %v", len(result.Order))
   786  	}
   787  
   788  	if result := Client.Must(Client.SearchPosts("in:", false)).Data.(*model.PostList); len(result.Order) != 0 {
   789  		t.Fatalf("wrong number of posts returned %v", len(result.Order))
   790  	}
   791  
   792  	if result := Client.Must(Client.SearchPosts("channel:"+channel1.Name, false)).Data.(*model.PostList); len(result.Order) != 2 {
   793  		t.Fatalf("wrong number of posts returned %v", len(result.Order))
   794  	}
   795  
   796  	if result := Client.Must(Client.SearchPosts("in: "+channel2.Name, false)).Data.(*model.PostList); len(result.Order) != 2 {
   797  		t.Fatalf("wrong number of posts returned %v", len(result.Order))
   798  	}
   799  
   800  	if result := Client.Must(Client.SearchPosts("channel: "+channel2.Name, false)).Data.(*model.PostList); len(result.Order) != 2 {
   801  		t.Fatalf("wrong number of posts returned %v", len(result.Order))
   802  	}
   803  
   804  	if result := Client.Must(Client.SearchPosts("ChAnNeL: "+channel2.Name, false)).Data.(*model.PostList); len(result.Order) != 2 {
   805  		t.Fatalf("wrong number of posts returned %v", len(result.Order))
   806  	}
   807  
   808  	if result := Client.Must(Client.SearchPosts("sgtitlereview", false)).Data.(*model.PostList); len(result.Order) != 2 {
   809  		t.Fatalf("wrong number of posts returned %v", len(result.Order))
   810  	}
   811  
   812  	if result := Client.Must(Client.SearchPosts("sgtitlereview channel:"+channel1.Name, false)).Data.(*model.PostList); len(result.Order) != 1 {
   813  		t.Fatalf("wrong number of posts returned %v", len(result.Order))
   814  	}
   815  
   816  	if result := Client.Must(Client.SearchPosts("sgtitlereview in: "+channel2.Name, false)).Data.(*model.PostList); len(result.Order) != 1 {
   817  		t.Fatalf("wrong number of posts returned %v", len(result.Order))
   818  	}
   819  
   820  	if result := Client.Must(Client.SearchPosts("sgtitlereview channel: "+channel2.Name, false)).Data.(*model.PostList); len(result.Order) != 1 {
   821  		t.Fatalf("wrong number of posts returned %v", len(result.Order))
   822  	}
   823  
   824  	if result := Client.Must(Client.SearchPosts("channel: "+channel2.Name+" channel: "+channel3.Name, false)).Data.(*model.PostList); len(result.Order) != 3 {
   825  		t.Fatalf("wrong number of posts returned :) %v :) %v", result.Posts, result.Order)
   826  	}
   827  }
   828  
   829  func TestSearchPostsFromUser(t *testing.T) {
   830  	th := Setup().InitBasic()
   831  	defer th.TearDown()
   832  
   833  	Client := th.BasicClient
   834  	channel1 := th.BasicChannel
   835  	team := th.BasicTeam
   836  	user1 := th.BasicUser
   837  	user2 := th.BasicUser2
   838  	channel2 := th.CreateChannel(Client, team)
   839  	Client.Must(Client.AddChannelMember(channel1.Id, th.BasicUser2.Id))
   840  	Client.Must(Client.AddChannelMember(channel2.Id, th.BasicUser2.Id))
   841  	user3 := th.CreateUser(Client)
   842  	th.LinkUserToTeam(user3, team)
   843  	Client.Must(Client.AddChannelMember(channel1.Id, user3.Id))
   844  	Client.Must(Client.AddChannelMember(channel2.Id, user3.Id))
   845  
   846  	post1 := &model.Post{ChannelId: channel1.Id, Message: "sgtitlereview with space"}
   847  	post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
   848  
   849  	th.LoginBasic2()
   850  
   851  	post2 := &model.Post{ChannelId: channel2.Id, Message: "sgtitlereview\n with return"}
   852  	post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
   853  
   854  	if result := Client.Must(Client.SearchPosts("from: "+user1.Username, false)).Data.(*model.PostList); len(result.Order) != 2 {
   855  		t.Fatalf("wrong number of posts returned %v", len(result.Order))
   856  	}
   857  
   858  	if result := Client.Must(Client.SearchPosts("from: "+user2.Username, false)).Data.(*model.PostList); len(result.Order) != 1 {
   859  		t.Fatalf("wrong number of posts returned %v", len(result.Order))
   860  	}
   861  
   862  	if result := Client.Must(Client.SearchPosts("from: "+user2.Username+" sgtitlereview", false)).Data.(*model.PostList); len(result.Order) != 1 {
   863  		t.Fatalf("wrong number of posts returned %v", len(result.Order))
   864  	}
   865  
   866  	post3 := &model.Post{ChannelId: channel1.Id, Message: "hullo"}
   867  	post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post)
   868  
   869  	if result := Client.Must(Client.SearchPosts("from: "+user2.Username+" in:"+channel1.Name, false)).Data.(*model.PostList); len(result.Order) != 1 {
   870  		t.Fatalf("wrong number of posts returned %v", len(result.Order))
   871  	}
   872  
   873  	Client.Login(user3.Email, user3.Password)
   874  
   875  	// wait for the join/leave messages to be created for user3 since they're done asynchronously
   876  	time.Sleep(100 * time.Millisecond)
   877  
   878  	if result := Client.Must(Client.SearchPosts("from: "+user2.Username, false)).Data.(*model.PostList); len(result.Order) != 2 {
   879  		t.Fatalf("wrong number of posts returned %v", len(result.Order))
   880  	}
   881  
   882  	if result := Client.Must(Client.SearchPosts("from: "+user2.Username+" from: "+user3.Username, false)).Data.(*model.PostList); len(result.Order) != 2 {
   883  		t.Fatalf("wrong number of posts returned %v", len(result.Order))
   884  	}
   885  
   886  	if result := Client.Must(Client.SearchPosts("from: "+user2.Username+" from: "+user3.Username+" in:"+channel2.Name, false)).Data.(*model.PostList); len(result.Order) != 1 {
   887  		t.Fatalf("wrong number of posts returned %v", len(result.Order))
   888  	}
   889  
   890  	post4 := &model.Post{ChannelId: channel2.Id, Message: "coconut"}
   891  	post4 = Client.Must(Client.CreatePost(post4)).Data.(*model.Post)
   892  
   893  	if result := Client.Must(Client.SearchPosts("from: "+user2.Username+" from: "+user3.Username+" in:"+channel2.Name+" coconut", false)).Data.(*model.PostList); len(result.Order) != 1 {
   894  		t.Fatalf("wrong number of posts returned %v", len(result.Order))
   895  	}
   896  }
   897  
   898  func TestGetPostsCache(t *testing.T) {
   899  	th := Setup().InitBasic()
   900  	defer th.TearDown()
   901  
   902  	Client := th.BasicClient
   903  	channel1 := th.BasicChannel
   904  
   905  	time.Sleep(10 * time.Millisecond)
   906  	post1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
   907  	post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
   908  
   909  	time.Sleep(10 * time.Millisecond)
   910  	post2 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
   911  	post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
   912  
   913  	time.Sleep(10 * time.Millisecond)
   914  	post3 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
   915  	post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post)
   916  
   917  	etag := Client.Must(Client.GetPosts(channel1.Id, 0, 2, "")).Etag
   918  
   919  	// test etag caching
   920  	if cache_result, err := Client.GetPosts(channel1.Id, 0, 2, etag); err != nil {
   921  		t.Fatal(err)
   922  	} else if cache_result.Data.(*model.PostList) != nil {
   923  		t.Log(cache_result.Data)
   924  		t.Fatal("cache should be empty")
   925  	}
   926  
   927  	etag = Client.Must(Client.GetPost(channel1.Id, post1.Id, "")).Etag
   928  
   929  	// test etag caching
   930  	if cache_result, err := Client.GetPost(channel1.Id, post1.Id, etag); err != nil {
   931  		t.Fatal(err)
   932  	} else if cache_result.Data.(*model.PostList) != nil {
   933  		t.Log(cache_result.Data)
   934  		t.Fatal("cache should be empty")
   935  	}
   936  
   937  }
   938  
   939  func TestDeletePosts(t *testing.T) {
   940  	th := Setup().InitBasic().InitSystemAdmin()
   941  	defer th.TearDown()
   942  
   943  	Client := th.BasicClient
   944  	channel1 := th.BasicChannel
   945  	team1 := th.BasicTeam
   946  
   947  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.RestrictPostDelete = model.PERMISSIONS_DELETE_POST_ALL })
   948  
   949  	time.Sleep(10 * time.Millisecond)
   950  	post1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
   951  	post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
   952  
   953  	time.Sleep(10 * time.Millisecond)
   954  	post1a1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: post1.Id}
   955  	post1a1 = Client.Must(Client.CreatePost(post1a1)).Data.(*model.Post)
   956  
   957  	time.Sleep(10 * time.Millisecond)
   958  	post1a2 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: post1.Id, ParentId: post1a1.Id}
   959  	post1a2 = Client.Must(Client.CreatePost(post1a2)).Data.(*model.Post)
   960  
   961  	time.Sleep(10 * time.Millisecond)
   962  	post2 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
   963  	post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
   964  
   965  	time.Sleep(10 * time.Millisecond)
   966  	post3 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
   967  	post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post)
   968  
   969  	time.Sleep(10 * time.Millisecond)
   970  	post3a1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: post3.Id}
   971  	post3a1 = Client.Must(Client.CreatePost(post3a1)).Data.(*model.Post)
   972  
   973  	time.Sleep(10 * time.Millisecond)
   974  	Client.Must(Client.DeletePost(channel1.Id, post3.Id))
   975  
   976  	r2 := Client.Must(Client.GetPosts(channel1.Id, 0, 10, "")).Data.(*model.PostList)
   977  
   978  	if post := r2.Posts[post3.Id]; post != nil {
   979  		t.Fatal("should have not returned deleted post")
   980  	}
   981  
   982  	time.Sleep(10 * time.Millisecond)
   983  	post4a := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
   984  	post4a = Client.Must(Client.CreatePost(post4a)).Data.(*model.Post)
   985  
   986  	time.Sleep(10 * time.Millisecond)
   987  	post4b := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
   988  	post4b = Client.Must(Client.CreatePost(post4b)).Data.(*model.Post)
   989  
   990  	SystemAdminClient := th.SystemAdminClient
   991  	th.LinkUserToTeam(th.SystemAdminUser, th.BasicTeam)
   992  	SystemAdminClient.Must(SystemAdminClient.JoinChannel(channel1.Id))
   993  
   994  	th.LoginBasic2()
   995  	Client.Must(Client.JoinChannel(channel1.Id))
   996  
   997  	if _, err := Client.DeletePost(channel1.Id, post4a.Id); err == nil {
   998  		t.Fatal(err)
   999  	}
  1000  
  1001  	// Test licensed policy controls for delete post
  1002  	th.App.SetLicense(model.NewTestLicense())
  1003  
  1004  	th.UpdateUserToTeamAdmin(th.BasicUser2, th.BasicTeam)
  1005  
  1006  	Client.Logout()
  1007  	th.LoginBasic2()
  1008  	Client.SetTeamId(team1.Id)
  1009  
  1010  	Client.Must(Client.DeletePost(channel1.Id, post4a.Id))
  1011  
  1012  	SystemAdminClient.Must(SystemAdminClient.DeletePost(channel1.Id, post4b.Id))
  1013  
  1014  	th.App.UpdateConfig(func(cfg *model.Config) {
  1015  		*cfg.ServiceSettings.RestrictPostDelete = model.PERMISSIONS_DELETE_POST_TEAM_ADMIN
  1016  	})
  1017  
  1018  	th.LoginBasic()
  1019  
  1020  	time.Sleep(10 * time.Millisecond)
  1021  	post5a := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
  1022  	post5a = Client.Must(Client.CreatePost(post5a)).Data.(*model.Post)
  1023  
  1024  	time.Sleep(10 * time.Millisecond)
  1025  	post5b := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
  1026  	post5b = Client.Must(Client.CreatePost(post5b)).Data.(*model.Post)
  1027  
  1028  	if _, err := Client.DeletePost(channel1.Id, post5a.Id); err == nil {
  1029  		t.Fatal(err)
  1030  	}
  1031  
  1032  	th.LoginBasic2()
  1033  
  1034  	Client.Must(Client.DeletePost(channel1.Id, post5a.Id))
  1035  
  1036  	SystemAdminClient.Must(SystemAdminClient.DeletePost(channel1.Id, post5b.Id))
  1037  
  1038  	th.App.UpdateConfig(func(cfg *model.Config) {
  1039  		*cfg.ServiceSettings.RestrictPostDelete = model.PERMISSIONS_DELETE_POST_SYSTEM_ADMIN
  1040  	})
  1041  
  1042  	th.LoginBasic()
  1043  
  1044  	time.Sleep(10 * time.Millisecond)
  1045  	post6a := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
  1046  	post6a = Client.Must(Client.CreatePost(post6a)).Data.(*model.Post)
  1047  
  1048  	if _, err := Client.DeletePost(channel1.Id, post6a.Id); err == nil {
  1049  		t.Fatal(err)
  1050  	}
  1051  
  1052  	th.LoginBasic2()
  1053  
  1054  	if _, err := Client.DeletePost(channel1.Id, post6a.Id); err == nil {
  1055  		t.Fatal(err)
  1056  	}
  1057  
  1058  	// Check that if unlicensed the policy restriction is not enforced.
  1059  	th.App.SetLicense(nil)
  1060  
  1061  	time.Sleep(10 * time.Millisecond)
  1062  	post7 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
  1063  	post7 = Client.Must(Client.CreatePost(post7)).Data.(*model.Post)
  1064  
  1065  	if _, err := Client.DeletePost(channel1.Id, post7.Id); err != nil {
  1066  		t.Fatal(err)
  1067  	}
  1068  
  1069  	SystemAdminClient.Must(SystemAdminClient.DeletePost(channel1.Id, post6a.Id))
  1070  
  1071  }
  1072  
  1073  func TestEmailMention(t *testing.T) {
  1074  	th := Setup().InitBasic()
  1075  	defer th.TearDown()
  1076  
  1077  	Client := th.BasicClient
  1078  	channel1 := th.BasicChannel
  1079  	Client.Must(Client.AddChannelMember(channel1.Id, th.BasicUser2.Id))
  1080  
  1081  	th.LoginBasic2()
  1082  	//Set the notification properties
  1083  	data := make(map[string]string)
  1084  	data["user_id"] = th.BasicUser2.Id
  1085  	data["email"] = "true"
  1086  	data["desktop"] = "all"
  1087  	data["desktop_sound"] = "false"
  1088  	data["comments"] = "any"
  1089  	Client.Must(Client.UpdateUserNotify(data))
  1090  
  1091  	store.Must(th.App.Srv.Store.Preference().Save(&model.Preferences{{
  1092  		UserId:   th.BasicUser2.Id,
  1093  		Category: model.PREFERENCE_CATEGORY_NOTIFICATIONS,
  1094  		Name:     model.PREFERENCE_NAME_EMAIL_INTERVAL,
  1095  		Value:    "0",
  1096  	}}))
  1097  
  1098  	//Delete all the messages before create a mention post
  1099  	utils.DeleteMailBox(th.BasicUser2.Email)
  1100  
  1101  	//Send a mention message from user1 to user2
  1102  	th.LoginBasic()
  1103  	time.Sleep(10 * time.Millisecond)
  1104  	post1 := &model.Post{ChannelId: channel1.Id, Message: "@" + th.BasicUser2.Username + " this is a test"}
  1105  	post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
  1106  
  1107  	var resultsMailbox utils.JSONMessageHeaderInbucket
  1108  	err := utils.RetryInbucket(5, func() error {
  1109  		var err error
  1110  		resultsMailbox, err = utils.GetMailBox(th.BasicUser2.Email)
  1111  		return err
  1112  	})
  1113  	if err != nil {
  1114  		t.Log(err)
  1115  		t.Log("No email was received, maybe due load on the server. Disabling this verification")
  1116  	}
  1117  	if err == nil && len(resultsMailbox) > 0 {
  1118  		if !strings.ContainsAny(resultsMailbox[len(resultsMailbox)-1].To[0], th.BasicUser2.Email) {
  1119  			t.Fatal("Wrong To recipient")
  1120  		} else {
  1121  			for i := 0; i < 30; i++ {
  1122  				for j := len(resultsMailbox) - 1; j >= 0; j-- {
  1123  					isUser := false
  1124  					for _, to := range resultsMailbox[j].To {
  1125  						if to == "<"+th.BasicUser2.Email+">" {
  1126  							isUser = true
  1127  						}
  1128  					}
  1129  					if !isUser {
  1130  						continue
  1131  					}
  1132  					if resultsEmail, err := utils.GetMessageFromMailbox(th.BasicUser2.Email, resultsMailbox[j].ID); err == nil {
  1133  						if strings.Contains(resultsEmail.Body.Text, post1.Message) {
  1134  							return
  1135  						} else if i == 4 {
  1136  							t.Log(resultsEmail.Body.Text)
  1137  							t.Fatal("Received wrong Message")
  1138  						}
  1139  					}
  1140  				}
  1141  				time.Sleep(100 * time.Millisecond)
  1142  			}
  1143  			t.Fatal("Didn't receive message")
  1144  		}
  1145  	}
  1146  }
  1147  
  1148  func TestFuzzyPosts(t *testing.T) {
  1149  	th := Setup().InitBasic()
  1150  	defer th.TearDown()
  1151  
  1152  	Client := th.BasicClient
  1153  	channel1 := th.BasicChannel
  1154  
  1155  	for i := 0; i < len(utils.FUZZY_STRINGS_POSTS); i++ {
  1156  		post := &model.Post{ChannelId: channel1.Id, Message: utils.FUZZY_STRINGS_POSTS[i]}
  1157  
  1158  		_, err := Client.CreatePost(post)
  1159  		if err != nil {
  1160  			t.Fatal(err)
  1161  		}
  1162  	}
  1163  }
  1164  
  1165  func TestGetFlaggedPosts(t *testing.T) {
  1166  	th := Setup().InitBasic()
  1167  	defer th.TearDown()
  1168  
  1169  	Client := th.BasicClient
  1170  	user1 := th.BasicUser
  1171  	post1 := th.BasicPost
  1172  
  1173  	preferences := &model.Preferences{
  1174  		{
  1175  			UserId:   user1.Id,
  1176  			Category: model.PREFERENCE_CATEGORY_FLAGGED_POST,
  1177  			Name:     post1.Id,
  1178  			Value:    "true",
  1179  		},
  1180  	}
  1181  	Client.Must(Client.SetPreferences(preferences))
  1182  
  1183  	r1 := Client.Must(Client.GetFlaggedPosts(0, 2)).Data.(*model.PostList)
  1184  
  1185  	if len(r1.Order) == 0 {
  1186  		t.Fatal("should have gotten a flagged post")
  1187  	}
  1188  
  1189  	if _, ok := r1.Posts[post1.Id]; !ok {
  1190  		t.Fatal("missing flagged post")
  1191  	}
  1192  
  1193  	Client.DeletePreferences(preferences)
  1194  
  1195  	r2 := Client.Must(Client.GetFlaggedPosts(0, 2)).Data.(*model.PostList)
  1196  
  1197  	if len(r2.Order) != 0 {
  1198  		t.Fatal("should not have gotten a flagged post")
  1199  	}
  1200  
  1201  	Client.SetTeamId(model.NewId())
  1202  	if _, err := Client.GetFlaggedPosts(0, 2); err == nil {
  1203  		t.Fatal("should have failed - bad team id")
  1204  	}
  1205  }
  1206  
  1207  func TestGetMessageForNotification(t *testing.T) {
  1208  	th := Setup().InitBasic()
  1209  	defer th.TearDown()
  1210  
  1211  	testPng := store.Must(th.App.Srv.Store.FileInfo().Save(&model.FileInfo{
  1212  		CreatorId: model.NewId(),
  1213  		Path:      "test1.png",
  1214  		Name:      "test1.png",
  1215  		MimeType:  "image/png",
  1216  	})).(*model.FileInfo)
  1217  
  1218  	testJpg1 := store.Must(th.App.Srv.Store.FileInfo().Save(&model.FileInfo{
  1219  		CreatorId: model.NewId(),
  1220  		Path:      "test2.jpg",
  1221  		Name:      "test2.jpg",
  1222  		MimeType:  "image/jpeg",
  1223  	})).(*model.FileInfo)
  1224  
  1225  	testFile := store.Must(th.App.Srv.Store.FileInfo().Save(&model.FileInfo{
  1226  		CreatorId: model.NewId(),
  1227  		Path:      "test1.go",
  1228  		Name:      "test1.go",
  1229  		MimeType:  "text/plain",
  1230  	})).(*model.FileInfo)
  1231  
  1232  	testJpg2 := store.Must(th.App.Srv.Store.FileInfo().Save(&model.FileInfo{
  1233  		CreatorId: model.NewId(),
  1234  		Path:      "test3.jpg",
  1235  		Name:      "test3.jpg",
  1236  		MimeType:  "image/jpeg",
  1237  	})).(*model.FileInfo)
  1238  
  1239  	translateFunc := utils.GetUserTranslations("en")
  1240  
  1241  	post := &model.Post{
  1242  		Id:      model.NewId(),
  1243  		Message: "test",
  1244  	}
  1245  
  1246  	if th.App.GetMessageForNotification(post, translateFunc) != "test" {
  1247  		t.Fatal("should've returned message text")
  1248  	}
  1249  
  1250  	post.FileIds = model.StringArray{testPng.Id}
  1251  	store.Must(th.App.Srv.Store.FileInfo().AttachToPost(testPng.Id, post.Id))
  1252  	if th.App.GetMessageForNotification(post, translateFunc) != "test" {
  1253  		t.Fatal("should've returned message text, even with attachments")
  1254  	}
  1255  
  1256  	post.Message = ""
  1257  	if message := th.App.GetMessageForNotification(post, translateFunc); message != "1 image sent: test1.png" {
  1258  		t.Fatal("should've returned number of images:", message)
  1259  	}
  1260  
  1261  	post.FileIds = model.StringArray{testPng.Id, testJpg1.Id}
  1262  	store.Must(th.App.Srv.Store.FileInfo().AttachToPost(testJpg1.Id, post.Id))
  1263  	th.App.Srv.Store.FileInfo().InvalidateFileInfosForPostCache(post.Id)
  1264  	if message := th.App.GetMessageForNotification(post, translateFunc); message != "2 images sent: test1.png, test2.jpg" && message != "2 images sent: test2.jpg, test1.png" {
  1265  		t.Fatal("should've returned number of images:", message)
  1266  	}
  1267  
  1268  	post.Id = model.NewId()
  1269  	post.FileIds = model.StringArray{testFile.Id}
  1270  	store.Must(th.App.Srv.Store.FileInfo().AttachToPost(testFile.Id, post.Id))
  1271  	if message := th.App.GetMessageForNotification(post, translateFunc); message != "1 file sent: test1.go" {
  1272  		t.Fatal("should've returned number of files:", message)
  1273  	}
  1274  
  1275  	store.Must(th.App.Srv.Store.FileInfo().AttachToPost(testJpg2.Id, post.Id))
  1276  	th.App.Srv.Store.FileInfo().InvalidateFileInfosForPostCache(post.Id)
  1277  	post.FileIds = model.StringArray{testFile.Id, testJpg2.Id}
  1278  	if message := th.App.GetMessageForNotification(post, translateFunc); message != "2 files sent: test1.go, test3.jpg" && message != "2 files sent: test3.jpg, test1.go" {
  1279  		t.Fatal("should've returned number of mixed files:", message)
  1280  	}
  1281  }
  1282  
  1283  func TestGetFileInfosForPost(t *testing.T) {
  1284  	th := Setup().InitBasic()
  1285  	defer th.TearDown()
  1286  
  1287  	Client := th.BasicClient
  1288  	channel1 := th.BasicChannel
  1289  
  1290  	fileIds := make([]string, 3)
  1291  	if data, err := readTestFile("test.png"); err != nil {
  1292  		t.Fatal(err)
  1293  	} else {
  1294  		for i := 0; i < 3; i++ {
  1295  			fileIds[i] = Client.MustGeneric(Client.UploadPostAttachment(data, channel1.Id, "test.png")).(*model.FileUploadResponse).FileInfos[0].Id
  1296  		}
  1297  	}
  1298  
  1299  	post1 := Client.Must(Client.CreatePost(&model.Post{
  1300  		ChannelId: channel1.Id,
  1301  		Message:   "test",
  1302  		FileIds:   fileIds,
  1303  	})).Data.(*model.Post)
  1304  
  1305  	var etag string
  1306  	if infos, err := Client.GetFileInfosForPost(channel1.Id, post1.Id, ""); err != nil {
  1307  		t.Fatal(err)
  1308  	} else if len(infos) != 3 {
  1309  		t.Fatal("should've received 3 files")
  1310  	} else if Client.Etag == "" {
  1311  		t.Fatal("should've received etag")
  1312  	} else {
  1313  		etag = Client.Etag
  1314  	}
  1315  
  1316  	if infos, err := Client.GetFileInfosForPost(channel1.Id, post1.Id, etag); err != nil {
  1317  		t.Fatal(err)
  1318  	} else if len(infos) != 0 {
  1319  		t.Fatal("should've returned nothing because of etag")
  1320  	}
  1321  }
  1322  
  1323  func TestGetPostById(t *testing.T) {
  1324  	th := Setup().InitBasic()
  1325  	defer th.TearDown()
  1326  
  1327  	Client := th.BasicClient
  1328  	channel1 := th.BasicChannel
  1329  
  1330  	time.Sleep(10 * time.Millisecond)
  1331  	post1 := &model.Post{ChannelId: channel1.Id, Message: "yommamma" + model.NewId() + "a"}
  1332  	post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
  1333  
  1334  	if post, respMetadata := Client.GetPostById(post1.Id, ""); respMetadata.Error != nil {
  1335  		t.Fatal(respMetadata.Error)
  1336  	} else {
  1337  		if len(post.Order) != 1 {
  1338  			t.Fatal("should be just one post")
  1339  		}
  1340  
  1341  		if post.Order[0] != post1.Id {
  1342  			t.Fatal("wrong order")
  1343  		}
  1344  
  1345  		if post.Posts[post.Order[0]].Message != post1.Message {
  1346  			t.Fatal("wrong message from post")
  1347  		}
  1348  	}
  1349  
  1350  	if _, respMetadata := Client.GetPostById("45345435345345", ""); respMetadata.Error == nil {
  1351  		t.Fatal(respMetadata.Error)
  1352  	}
  1353  }
  1354  
  1355  func TestGetPermalinkTmp(t *testing.T) {
  1356  	th := Setup().InitBasic().InitSystemAdmin()
  1357  	defer th.TearDown()
  1358  
  1359  	Client := th.BasicClient
  1360  	channel1 := th.BasicChannel
  1361  	team := th.BasicTeam
  1362  
  1363  	th.LoginBasic()
  1364  
  1365  	time.Sleep(10 * time.Millisecond)
  1366  	post1 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
  1367  	post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
  1368  
  1369  	time.Sleep(10 * time.Millisecond)
  1370  	post2 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a"}
  1371  	post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
  1372  
  1373  	etag := Client.Must(Client.GetPost(channel1.Id, post1.Id, "")).Etag
  1374  
  1375  	// test etag caching
  1376  	if cache_result, respMetadata := Client.GetPermalink(channel1.Id, post1.Id, etag); respMetadata.Error != nil {
  1377  		t.Fatal(respMetadata.Error)
  1378  	} else if cache_result != nil {
  1379  		t.Log(cache_result)
  1380  		t.Fatal("cache should be empty")
  1381  	}
  1382  
  1383  	if results, respMetadata := Client.GetPermalink(channel1.Id, post1.Id, ""); respMetadata.Error != nil {
  1384  		t.Fatal(respMetadata.Error)
  1385  	} else if results == nil {
  1386  		t.Fatal("should not be empty")
  1387  	}
  1388  
  1389  	// Test permalink to private channels.
  1390  	channel2 := &model.Channel{DisplayName: "TestGetPermalinkPriv", Name: "zz" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
  1391  	channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
  1392  	time.Sleep(10 * time.Millisecond)
  1393  	post3 := &model.Post{ChannelId: channel2.Id, Message: "zz" + model.NewId() + "a"}
  1394  	post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post)
  1395  
  1396  	if _, md := Client.GetPermalink(channel2.Id, post3.Id, ""); md.Error != nil {
  1397  		t.Fatal(md.Error)
  1398  	}
  1399  
  1400  	th.LoginBasic2()
  1401  
  1402  	if _, md := Client.GetPermalink(channel2.Id, post3.Id, ""); md.Error == nil {
  1403  		t.Fatal("Expected 403 error")
  1404  	}
  1405  
  1406  	// Test direct channels.
  1407  	th.LoginBasic()
  1408  	channel3 := Client.Must(Client.CreateDirectChannel(th.SystemAdminUser.Id)).Data.(*model.Channel)
  1409  	time.Sleep(10 * time.Millisecond)
  1410  	post4 := &model.Post{ChannelId: channel3.Id, Message: "zz" + model.NewId() + "a"}
  1411  	post4 = Client.Must(Client.CreatePost(post4)).Data.(*model.Post)
  1412  
  1413  	if _, md := Client.GetPermalink(channel3.Id, post4.Id, ""); md.Error != nil {
  1414  		t.Fatal(md.Error)
  1415  	}
  1416  
  1417  	th.LoginBasic2()
  1418  
  1419  	if _, md := Client.GetPermalink(channel3.Id, post4.Id, ""); md.Error == nil {
  1420  		t.Fatal("Expected 403 error")
  1421  	}
  1422  }
  1423  
  1424  func TestGetOpenGraphMetadata(t *testing.T) {
  1425  	th := Setup().InitBasic()
  1426  	defer th.TearDown()
  1427  
  1428  	Client := th.BasicClient
  1429  
  1430  	th.App.UpdateConfig(func(cfg *model.Config) {
  1431  		*cfg.ServiceSettings.EnableLinkPreviews = true
  1432  		*cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost 127.0.0.1"
  1433  	})
  1434  
  1435  	ogDataCacheMissCount := 0
  1436  
  1437  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1438  		ogDataCacheMissCount++
  1439  
  1440  		if r.URL.Path == "/og-data/" {
  1441  			fmt.Fprintln(w, `
  1442  				<html><head><meta property="og:type" content="article" />
  1443  		  		<meta property="og:title" content="Test Title" />
  1444  		  		<meta property="og:url" content="http://example.com/" />
  1445  				</head><body></body></html>
  1446  			`)
  1447  		} else if r.URL.Path == "/no-og-data/" {
  1448  			fmt.Fprintln(w, `<html><head></head><body></body></html>`)
  1449  		}
  1450  	}))
  1451  
  1452  	for _, data := range [](map[string]interface{}){
  1453  		{"path": "/og-data/", "title": "Test Title", "cacheMissCount": 1},
  1454  		{"path": "/no-og-data/", "title": "", "cacheMissCount": 2},
  1455  
  1456  		// Data should be cached for following
  1457  		{"path": "/og-data/", "title": "Test Title", "cacheMissCount": 2},
  1458  		{"path": "/no-og-data/", "title": "", "cacheMissCount": 2},
  1459  	} {
  1460  		res, err := Client.DoApiPost(
  1461  			"/get_opengraph_metadata",
  1462  			fmt.Sprintf("{\"url\":\"%s\"}", ts.URL+data["path"].(string)),
  1463  		)
  1464  		if err != nil {
  1465  			t.Fatal(err)
  1466  		}
  1467  
  1468  		ogData := model.StringInterfaceFromJson(res.Body)
  1469  		if strings.Compare(ogData["title"].(string), data["title"].(string)) != 0 {
  1470  			t.Fatal(fmt.Sprintf(
  1471  				"OG data title mismatch for path \"%s\". Expected title: \"%s\". Actual title: \"%s\"",
  1472  				data["path"].(string), data["title"].(string), ogData["title"].(string),
  1473  			))
  1474  		}
  1475  
  1476  		if ogDataCacheMissCount != data["cacheMissCount"].(int) {
  1477  			t.Fatal(fmt.Sprintf(
  1478  				"Cache miss count didn't match. Expected value %d. Actual value %d.",
  1479  				data["cacheMissCount"].(int), ogDataCacheMissCount,
  1480  			))
  1481  		}
  1482  	}
  1483  
  1484  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableLinkPreviews = false })
  1485  	if _, err := Client.DoApiPost("/get_opengraph_metadata", "{\"url\":\"/og-data/\"}"); err == nil || err.StatusCode != http.StatusNotImplemented {
  1486  		t.Fatal("should have failed with 501 - disabled link previews")
  1487  	}
  1488  }
  1489  
  1490  func TestPinPost(t *testing.T) {
  1491  	th := Setup().InitBasic()
  1492  	defer th.TearDown()
  1493  
  1494  	Client := th.BasicClient
  1495  
  1496  	post := th.BasicPost
  1497  	if rupost1, err := Client.PinPost(post.ChannelId, post.Id); err != nil {
  1498  		t.Fatal(err)
  1499  	} else {
  1500  		if !rupost1.Data.(*model.Post).IsPinned {
  1501  			t.Fatal("failed to pin post")
  1502  		}
  1503  	}
  1504  
  1505  	pinnedPost := th.PinnedPost
  1506  	if rupost2, err := Client.PinPost(pinnedPost.ChannelId, pinnedPost.Id); err != nil {
  1507  		t.Fatal(err)
  1508  	} else {
  1509  		if !rupost2.Data.(*model.Post).IsPinned {
  1510  			t.Fatal("pinning a post should be idempotent")
  1511  		}
  1512  	}
  1513  }
  1514  
  1515  func TestUnpinPost(t *testing.T) {
  1516  	th := Setup().InitBasic()
  1517  	defer th.TearDown()
  1518  
  1519  	Client := th.BasicClient
  1520  
  1521  	pinnedPost := th.PinnedPost
  1522  	if rupost1, err := Client.UnpinPost(pinnedPost.ChannelId, pinnedPost.Id); err != nil {
  1523  		t.Fatal(err)
  1524  	} else {
  1525  		if rupost1.Data.(*model.Post).IsPinned {
  1526  			t.Fatal("failed to unpin post")
  1527  		}
  1528  	}
  1529  
  1530  	post := th.BasicPost
  1531  	if rupost2, err := Client.UnpinPost(post.ChannelId, post.Id); err != nil {
  1532  		t.Fatal(err)
  1533  	} else {
  1534  		if rupost2.Data.(*model.Post).IsPinned {
  1535  			t.Fatal("unpinning a post should be idempotent")
  1536  		}
  1537  	}
  1538  }