Files
mattermost/api4/cloud_test.go
Pablo Andrés Vélez Vidal 059ea7eb44 MM-45174 - split validate business email logic (#20581)
* MM-45174 - split validate business email logic

* remove unnecessary interface method

* check for error just after the cloud call to prevent server panic

Co-authored-by: Pablo Velez Vidal <pablo.velez@mattermost.com>
Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
2022-07-13 12:05:35 +02:00

634 lines
19 KiB
Go

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package api4
import (
"errors"
"fmt"
"net/http"
"net/http/httptest"
"os"
"testing"
"time"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/mattermost/mattermost-server/v6/einterfaces/mocks"
"github.com/mattermost/mattermost-server/v6/model"
)
func Test_getCloudLimits(t *testing.T) {
t.Run("no license returns not implemented", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.App.Srv().RemoveLicense()
th.Client.Login(th.BasicUser.Email, th.BasicUser.Password)
limits, r, err := th.Client.GetProductLimits()
require.Error(t, err)
require.Nil(t, limits)
require.Equal(t, http.StatusNotImplemented, r.StatusCode, "Expected 501 Not Implemented")
})
t.Run("non cloud license returns not implemented", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.App.Srv().SetLicense(model.NewTestLicense())
th.Client.Login(th.BasicUser.Email, th.BasicUser.Password)
limits, r, err := th.Client.GetProductLimits()
require.Error(t, err)
require.Nil(t, limits)
require.Equal(t, http.StatusNotImplemented, r.StatusCode, "Expected 501 Not Implemented")
})
t.Run("error fetching limits returns internal server error", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
cloud := &mocks.CloudInterface{}
cloud.Mock.On("GetCloudLimits", mock.Anything).Return(nil, errors.New("Unable to get limits"))
cloudImpl := th.App.Srv().Cloud
defer func() {
th.App.Srv().Cloud = cloudImpl
}()
th.App.Srv().Cloud = cloud
th.Client.Login(th.BasicUser.Email, th.BasicUser.Password)
limits, r, err := th.Client.GetProductLimits()
require.Error(t, err)
require.Nil(t, limits)
require.Equal(t, http.StatusInternalServerError, r.StatusCode, "Expected 500 Internal Server Error")
})
t.Run("unauthenticated users can not access", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.Client.Logout()
limits, r, err := th.Client.GetProductLimits()
require.Error(t, err)
require.Nil(t, limits)
require.Equal(t, http.StatusUnauthorized, r.StatusCode, "Expected 401 Unauthorized")
})
t.Run("good request with cloud server", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
cloud := &mocks.CloudInterface{}
ten := 10
mockLimits := &model.ProductLimits{
Messages: &model.MessagesLimits{
History: &ten,
},
}
cloud.Mock.On("GetCloudLimits", mock.Anything).Return(mockLimits, nil)
cloudImpl := th.App.Srv().Cloud
defer func() {
th.App.Srv().Cloud = cloudImpl
}()
th.App.Srv().Cloud = cloud
th.Client.Login(th.BasicUser.Email, th.BasicUser.Password)
limits, r, err := th.Client.GetProductLimits()
require.NoError(t, err)
require.Equal(t, http.StatusOK, r.StatusCode, "Expected 200 OK")
require.Equal(t, mockLimits, limits)
require.Equal(t, *mockLimits.Messages.History, *limits.Messages.History)
})
}
func Test_GetSubscription(t *testing.T) {
subscription := &model.Subscription{
ID: "MySubscriptionID",
CustomerID: "MyCustomer",
ProductID: "SomeProductId",
AddOns: []string{},
StartAt: 1000000000,
EndAt: 2000000000,
CreateAt: 1000000000,
Seats: 10,
IsFreeTrial: "true",
DNS: "some.dns.server",
IsPaidTier: "false",
TrialEndAt: 2000000000,
LastInvoice: &model.Invoice{},
}
userFacingSubscription := &model.Subscription{
ID: "MySubscriptionID",
CustomerID: "",
ProductID: "SomeProductId",
AddOns: []string{},
StartAt: 0,
EndAt: 0,
CreateAt: 0,
Seats: 0,
IsFreeTrial: "true",
DNS: "",
IsPaidTier: "",
TrialEndAt: 2000000000,
LastInvoice: &model.Invoice{},
}
t.Run("NON Admin users receive the user facing subscription", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.Client.Login(th.BasicUser.Email, th.BasicUser.Password)
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
cloud := mocks.CloudInterface{}
cloud.Mock.On("GetSubscription", mock.Anything).Return(subscription, nil)
cloudImpl := th.App.Srv().Cloud
defer func() {
th.App.Srv().Cloud = cloudImpl
}()
th.App.Srv().Cloud = &cloud
subscriptionReturned, r, err := th.Client.GetSubscription()
require.NoError(t, err)
require.Equal(t, subscriptionReturned, userFacingSubscription)
require.Equal(t, http.StatusOK, r.StatusCode, "Status OK")
})
t.Run("Admin users receive the full subscription information", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.Client.Login(th.BasicUser.Email, th.BasicUser.Password)
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
cloud := mocks.CloudInterface{}
cloud.Mock.On("GetSubscription", mock.Anything).Return(subscription, nil)
cloudImpl := th.App.Srv().Cloud
defer func() {
th.App.Srv().Cloud = cloudImpl
}()
th.App.Srv().Cloud = &cloud
subscriptionReturned, r, err := th.SystemAdminClient.GetSubscription()
require.NoError(t, err)
require.Equal(t, subscriptionReturned, subscription)
require.Equal(t, http.StatusOK, r.StatusCode, "Status OK")
})
}
func Test_requestTrial(t *testing.T) {
subscription := &model.Subscription{
ID: "MySubscriptionID",
CustomerID: "MyCustomer",
ProductID: "SomeProductId",
AddOns: []string{},
StartAt: 1000000000,
EndAt: 2000000000,
CreateAt: 1000000000,
Seats: 10,
DNS: "some.dns.server",
IsPaidTier: "false",
}
newValidBusinessEmail := model.StartCloudTrialRequest{Email: ""}
t.Run("NON Admin users are UNABLE to request the trial", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.Client.Login(th.BasicUser.Email, th.BasicUser.Password)
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
cloud := mocks.CloudInterface{}
cloud.Mock.On("GetSubscription", mock.Anything).Return(subscription, nil)
cloud.Mock.On("RequestCloudTrial", mock.Anything, mock.Anything, "").Return(subscription, nil)
cloud.Mock.On("InvalidateCaches").Return(nil)
cloudImpl := th.App.Srv().Cloud
defer func() {
th.App.Srv().Cloud = cloudImpl
}()
th.App.Srv().Cloud = &cloud
subscriptionChanged, r, err := th.Client.RequestCloudTrial(&newValidBusinessEmail)
require.Error(t, err)
require.Nil(t, subscriptionChanged)
require.Equal(t, http.StatusForbidden, r.StatusCode, "403 Forbidden")
})
t.Run("ADMIN user are ABLE to request the trial", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.Client.Login(th.BasicUser.Email, th.BasicUser.Password)
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
cloud := mocks.CloudInterface{}
cloud.Mock.On("GetSubscription", mock.Anything).Return(subscription, nil)
cloud.Mock.On("RequestCloudTrial", mock.Anything, mock.Anything, "").Return(subscription, nil)
cloud.Mock.On("InvalidateCaches").Return(nil)
cloudImpl := th.App.Srv().Cloud
defer func() {
th.App.Srv().Cloud = cloudImpl
}()
th.App.Srv().Cloud = &cloud
subscriptionChanged, r, err := th.SystemAdminClient.RequestCloudTrial(&newValidBusinessEmail)
require.NoError(t, err)
require.Equal(t, subscriptionChanged, subscription)
require.Equal(t, http.StatusOK, r.StatusCode, "Status OK")
})
t.Run("ADMIN user are ABLE to request the trial with valid business email", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
// patch the customer with the additional contact updated with the valid business email
newValidBusinessEmail.Email = *model.NewString("valid.email@mattermost.com")
th.Client.Login(th.BasicUser.Email, th.BasicUser.Password)
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
cloud := mocks.CloudInterface{}
cloud.Mock.On("GetSubscription", mock.Anything).Return(subscription, nil)
cloud.Mock.On("RequestCloudTrial", mock.Anything, mock.Anything, "valid.email@mattermost.com").Return(subscription, nil)
cloud.Mock.On("InvalidateCaches").Return(nil)
cloudImpl := th.App.Srv().Cloud
defer func() {
th.App.Srv().Cloud = cloudImpl
}()
th.App.Srv().Cloud = &cloud
subscriptionChanged, r, err := th.SystemAdminClient.RequestCloudTrial(&newValidBusinessEmail)
require.NoError(t, err)
require.Equal(t, subscriptionChanged, subscription)
require.Equal(t, http.StatusOK, r.StatusCode, "Status OK")
})
}
func TestNotifyAdminToUpgrade(t *testing.T) {
t.Run("user can only notify admin once in cool off period", func(t *testing.T) {
th := Setup(t).InitBasic().InitLogin()
defer th.TearDown()
statusCode := th.Client.NotifyAdmin(&model.NotifyAdminToUpgradeRequest{
CurrentTeamId: th.BasicTeam.Id,
})
bot, appErr := th.App.GetSystemBot()
require.Nil(t, appErr)
// message sending is async, wait time for it
var channel *model.Channel
var err error
var timeout = 5 * time.Second
begin := time.Now()
for {
if time.Since(begin) > timeout {
break
}
channel, err = th.App.Srv().Store.Channel().GetByName("", model.GetDMNameFromIds(bot.UserId, th.SystemAdminUser.Id), false)
if err == nil && channel != nil {
break
}
time.Sleep(100 * time.Millisecond)
}
require.NoError(t, err, "Expected message to have been sent within %d seconds", timeout)
postList, err := th.App.Srv().Store.Post().GetPosts(model.GetPostsOptions{ChannelId: channel.Id, Page: 0, PerPage: 1}, false, map[string]bool{})
require.NoError(t, err)
require.Equal(t, len(postList.Order), 1)
post := postList.Posts[postList.Order[0]]
require.Equal(t, fmt.Sprintf("%sup_notification", model.PostCustomTypePrefix), post.Type)
require.Equal(t, bot.UserId, post.UserId)
require.Equal(t, fmt.Sprintf("A member of %s has notified you to upgrade this workspace.", th.BasicTeam.Name), post.Message)
require.Equal(t, http.StatusOK, statusCode)
// second time trying to call notify endpoint by same user is forbidden
statusCode = th.Client.NotifyAdmin(&model.NotifyAdminToUpgradeRequest{
CurrentTeamId: th.BasicTeam.Id,
})
require.Equal(t, http.StatusForbidden, statusCode)
})
t.Run("user can only notify admin after cool off period", func(t *testing.T) {
th := Setup(t).InitBasic().InitLogin()
defer th.TearDown()
os.Setenv("MM_CLOUD_NOTIFY_ADMIN_COOL_OFF_DAYS", "0.00003472222222") // set to 3 seconds
defer os.Unsetenv("MM_CLOUD_NOTIFY_ADMIN_COOL_OFF_DAYS")
statusCode := th.Client.NotifyAdmin(&model.NotifyAdminToUpgradeRequest{
CurrentTeamId: th.BasicTeam.Id,
})
bot, appErr := th.App.GetSystemBot()
require.Nil(t, appErr)
channel, err := th.App.Srv().Store.Channel().GetByName("", model.GetDMNameFromIds(bot.UserId, th.SystemAdminUser.Id), false)
require.NoError(t, err)
postList, err := th.App.Srv().Store.Post().GetPosts(model.GetPostsOptions{ChannelId: channel.Id, Page: 0, PerPage: 1}, false, map[string]bool{})
require.NoError(t, err)
require.Equal(t, len(postList.Order), 1)
post := postList.Posts[postList.Order[0]]
require.Equal(t, fmt.Sprintf("%sup_notification", model.PostCustomTypePrefix), post.Type)
require.Equal(t, bot.UserId, post.UserId)
require.Equal(t, fmt.Sprintf("A member of %s has notified you to upgrade this workspace.", th.BasicTeam.Name), post.Message)
require.Equal(t, http.StatusOK, statusCode)
time.Sleep(5 * time.Second)
// second time trying to call notify endpoint by same user is NOT forbidden because it is after cool off period set to 3 seconds
statusCode = th.Client.NotifyAdmin(&model.NotifyAdminToUpgradeRequest{
CurrentTeamId: th.BasicTeam.Id,
})
require.Equal(t, http.StatusOK, statusCode)
})
t.Run("can cloud/model.Notify", func(t *testing.T) {
os.Setenv("MM_CLOUD_NOTIFY_ADMIN_COOL_OFF_DAYS", "10") // set to 10 days
canNotify := model.CanNotify(model.GetMillis())
require.Equal(t, false, canNotify)
os.Setenv("MM_CLOUD_NOTIFY_ADMIN_COOL_OFF_DAYS", "0.00003472222222") // set to 3 seconds
canNotify = model.CanNotify(model.GetMillis())
time.Sleep(5 * time.Second)
require.Equal(t, false, canNotify)
os.Unsetenv("MM_CLOUD_NOTIFY_ADMIN_COOL_OFF_DAYS")
})
}
func Test_validateBusinessEmail(t *testing.T) {
t.Run("Initial request has invalid email", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.Client.Login(th.BasicUser.Email, th.BasicUser.Password)
validateBusinessEmail := model.ValidateBusinessEmailRequest{Email: ""}
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
cloud := mocks.CloudInterface{}
resp := httptest.NewRecorder()
cloud.Mock.On("ValidateBusinessEmail", mock.Anything).Return(resp, nil)
cloudImpl := th.App.Srv().Cloud
defer func() {
th.App.Srv().Cloud = cloudImpl
}()
th.App.Srv().Cloud = &cloud
_, err := th.Client.ValidateBusinessEmail(&validateBusinessEmail)
require.Error(t, err)
})
}
func Test_validateWorkspaceBusinessEmail(t *testing.T) {
t.Run("validate the Cloud Customer has used a valid email to create the workspace", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.Client.Login(th.BasicUser.Email, th.BasicUser.Password)
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
cloud := mocks.CloudInterface{}
cloudCustomerInfo := model.CloudCustomerInfo{
Email: "valid@mattermost.com",
}
cloudCustomer := &model.CloudCustomer{
CloudCustomerInfo: cloudCustomerInfo,
}
cloud.Mock.On("GetCloudCustomer", th.SystemAdminUser.Id).Return(cloudCustomer, nil)
cloud.Mock.On("ValidateBusinessEmail", th.SystemAdminUser.Id, cloudCustomerInfo.Email).Return(nil)
cloudImpl := th.App.Srv().Cloud
defer func() {
th.App.Srv().Cloud = cloudImpl
}()
th.App.Srv().Cloud = &cloud
_, err := th.SystemAdminClient.ValidateWorkspaceBusinessEmail()
require.NoError(t, err)
})
t.Run("validate the Cloud Customer has used a invalid email to create the workspace and must validate admin email", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.Client.Login(th.BasicUser.Email, th.BasicUser.Password)
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
cloud := mocks.CloudInterface{}
cloudCustomerInfo := model.CloudCustomerInfo{
Email: "invalid@gmail.com",
}
cloudCustomer := &model.CloudCustomer{
CloudCustomerInfo: cloudCustomerInfo,
}
cloud.Mock.On("GetCloudCustomer", th.SystemAdminUser.Id).Return(cloudCustomer, nil)
// first call to validate the cloud customer email
cloud.Mock.On("ValidateBusinessEmail", th.SystemAdminUser.Id, cloudCustomerInfo.Email).Return(errors.New("invalid email"))
// second call to validate the user admin email
cloud.Mock.On("ValidateBusinessEmail", th.SystemAdminUser.Id, th.SystemAdminUser.Email).Return(nil)
cloudImpl := th.App.Srv().Cloud
defer func() {
th.App.Srv().Cloud = cloudImpl
}()
th.App.Srv().Cloud = &cloud
_, err := th.SystemAdminClient.ValidateWorkspaceBusinessEmail()
require.NoError(t, err)
})
}
func TestGetCloudProducts(t *testing.T) {
cloudProducts := []*model.Product{
{
ID: "prod_test1",
Name: "name",
Description: "description",
PricePerSeat: 10,
SKU: "sku",
PriceID: "price_id",
Family: "family",
RecurringInterval: "recurring_interval",
BillingScheme: "billing_scheme",
},
{
ID: "prod_test2",
Name: "name2",
Description: "description2",
PricePerSeat: 100,
SKU: "sku2",
PriceID: "price_id2",
Family: "family2",
RecurringInterval: "recurring_interval2",
BillingScheme: "billing_scheme2",
},
{
ID: "prod_test3",
Name: "name3",
Description: "description3",
PricePerSeat: 1000,
SKU: "sku3",
PriceID: "price_id3",
Family: "family3",
RecurringInterval: "recurring_interval3",
BillingScheme: "billing_scheme3",
},
}
sanitizedProducts := []*model.Product{
{
ID: "prod_test1",
Name: "name",
PricePerSeat: 10,
SKU: "sku",
},
{
ID: "prod_test2",
Name: "name2",
PricePerSeat: 100,
SKU: "sku2",
},
{
ID: "prod_test3",
Name: "name3",
PricePerSeat: 1000,
SKU: "sku3",
},
}
t.Run("get products for admins", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.Client.Login(th.SystemAdminUser.Email, th.SystemAdminUser.Password)
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
cloud := mocks.CloudInterface{}
cloud.Mock.On("GetCloudProducts", mock.Anything, mock.Anything).Return(cloudProducts, nil)
cloudImpl := th.App.Srv().Cloud
defer func() {
th.App.Srv().Cloud = cloudImpl
}()
th.App.Srv().Cloud = &cloud
returnedProducts, r, err := th.Client.GetCloudProducts()
require.NoError(t, err)
require.Equal(t, http.StatusOK, r.StatusCode, "Status OK")
require.Equal(t, returnedProducts, cloudProducts)
})
t.Run("get products for non admins", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.Client.Login(th.BasicUser.Email, th.BasicUser.Password)
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
cloud := mocks.CloudInterface{}
cloud.Mock.On("GetCloudProducts", mock.Anything, mock.Anything).Return(cloudProducts, nil)
cloudImpl := th.App.Srv().Cloud
defer func() {
th.App.Srv().Cloud = cloudImpl
}()
th.App.Srv().Cloud = &cloud
returnedProducts, r, err := th.Client.GetCloudProducts()
require.NoError(t, err)
require.Equal(t, http.StatusOK, r.StatusCode, "Status OK")
require.Equal(t, returnedProducts, sanitizedProducts)
// make a more explicit check
require.Equal(t, returnedProducts[0].ID, "prod_test1")
require.Equal(t, returnedProducts[0].Name, "name")
require.Equal(t, returnedProducts[0].SKU, "sku")
require.Equal(t, returnedProducts[0].PricePerSeat, float64(10))
require.Equal(t, returnedProducts[0].Description, "")
require.Equal(t, returnedProducts[0].PriceID, "")
require.Equal(t, returnedProducts[0].Family, model.SubscriptionFamily(""))
require.Equal(t, returnedProducts[0].RecurringInterval, model.RecurringInterval(""))
require.Equal(t, returnedProducts[0].BillingScheme, model.BillingScheme(""))
require.Equal(t, returnedProducts[1].ID, "prod_test2")
require.Equal(t, returnedProducts[1].Name, "name2")
require.Equal(t, returnedProducts[1].SKU, "sku2")
require.Equal(t, returnedProducts[1].PricePerSeat, float64(100))
require.Equal(t, returnedProducts[1].Description, "")
require.Equal(t, returnedProducts[1].PriceID, "")
require.Equal(t, returnedProducts[1].Family, model.SubscriptionFamily(""))
require.Equal(t, returnedProducts[1].RecurringInterval, model.RecurringInterval(""))
require.Equal(t, returnedProducts[1].BillingScheme, model.BillingScheme(""))
require.Equal(t, returnedProducts[2].ID, "prod_test3")
require.Equal(t, returnedProducts[2].Name, "name3")
require.Equal(t, returnedProducts[2].SKU, "sku3")
require.Equal(t, returnedProducts[2].PricePerSeat, float64(1000))
require.Equal(t, returnedProducts[2].Description, "")
require.Equal(t, returnedProducts[2].PriceID, "")
require.Equal(t, returnedProducts[2].Family, model.SubscriptionFamily(""))
require.Equal(t, returnedProducts[2].RecurringInterval, model.RecurringInterval(""))
require.Equal(t, returnedProducts[2].BillingScheme, model.BillingScheme(""))
})
}