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