6b65b7e7d0
This change removes the obsolete project member paging code. Previously, we implemented functionality for including project invitations in pages of project members. However, the satellite frontend still expected API responses to use the old paging style, so the related code could not be removed right away. Now that the frontend has been updated, this code is no longer necessary. References #5855 Change-Id: I12fdaaeb869977c4d87a0d50b9a7b11c68552c82
512 lines
16 KiB
Go
512 lines
16 KiB
Go
// Copyright (C) 2019 Storj Labs, Inc.
|
|
// See LICENSE for copying information.
|
|
|
|
package consoleql_test
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/graphql-go/graphql"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"go.uber.org/zap/zaptest"
|
|
|
|
"storj.io/common/testcontext"
|
|
"storj.io/common/uuid"
|
|
"storj.io/storj/private/post"
|
|
"storj.io/storj/private/testplanet"
|
|
"storj.io/storj/private/testredis"
|
|
"storj.io/storj/satellite/accounting"
|
|
"storj.io/storj/satellite/accounting/live"
|
|
"storj.io/storj/satellite/analytics"
|
|
"storj.io/storj/satellite/console"
|
|
"storj.io/storj/satellite/console/consoleauth"
|
|
"storj.io/storj/satellite/console/consoleweb/consoleql"
|
|
"storj.io/storj/satellite/console/restkeys"
|
|
"storj.io/storj/satellite/mailservice"
|
|
"storj.io/storj/satellite/payments"
|
|
"storj.io/storj/satellite/payments/paymentsconfig"
|
|
"storj.io/storj/satellite/payments/stripe"
|
|
)
|
|
|
|
// discardSender discard sending of an actual email.
|
|
type discardSender struct{}
|
|
|
|
// SendEmail immediately returns with nil error.
|
|
func (*discardSender) SendEmail(ctx context.Context, msg *post.Message) error {
|
|
return nil
|
|
}
|
|
|
|
// FromAddress returns empty post.Address.
|
|
func (*discardSender) FromAddress() post.Address {
|
|
return post.Address{}
|
|
}
|
|
|
|
func TestGraphqlMutation(t *testing.T) {
|
|
testplanet.Run(t, testplanet.Config{SatelliteCount: 1}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
|
sat := planet.Satellites[0]
|
|
db := sat.DB
|
|
log := zaptest.NewLogger(t)
|
|
|
|
analyticsService := analytics.NewService(log, analytics.Config{}, "test-satellite")
|
|
|
|
redis, err := testredis.Mini(ctx)
|
|
require.NoError(t, err)
|
|
defer ctx.Check(redis.Close)
|
|
|
|
cache, err := live.OpenCache(ctx, log.Named("cache"), live.Config{StorageBackend: "redis://" + redis.Addr() + "?db=0"})
|
|
require.NoError(t, err)
|
|
|
|
projectLimitCache := accounting.NewProjectLimitCache(db.ProjectAccounting(), 0, 0, 0, accounting.ProjectLimitConfig{CacheCapacity: 100})
|
|
|
|
projectUsage := accounting.NewService(db.ProjectAccounting(), cache, projectLimitCache, *sat.Metabase.DB, 5*time.Minute, -10*time.Second)
|
|
|
|
// TODO maybe switch this test to testplanet to avoid defining config and Stripe service
|
|
pc := paymentsconfig.Config{
|
|
UsagePrice: paymentsconfig.ProjectUsagePrice{
|
|
StorageTB: "10",
|
|
EgressTB: "45",
|
|
Segment: "0.0000022",
|
|
},
|
|
}
|
|
|
|
prices, err := pc.UsagePrice.ToModel()
|
|
require.NoError(t, err)
|
|
|
|
priceOverrides, err := pc.UsagePriceOverrides.ToModels()
|
|
require.NoError(t, err)
|
|
|
|
paymentsService, err := stripe.NewService(
|
|
log.Named("payments.stripe:service"),
|
|
stripe.NewStripeMock(
|
|
db.StripeCoinPayments().Customers(),
|
|
db.Console().Users(),
|
|
),
|
|
pc.StripeCoinPayments,
|
|
db.StripeCoinPayments(),
|
|
db.Wallets(),
|
|
db.Billing(),
|
|
db.Console().Projects(),
|
|
db.Console().Users(),
|
|
db.ProjectAccounting(),
|
|
prices,
|
|
priceOverrides,
|
|
pc.PackagePlans.Packages,
|
|
pc.BonusRate,
|
|
nil,
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
service, err := console.NewService(
|
|
log.Named("console"),
|
|
db.Console(),
|
|
restkeys.NewService(db.OIDC().OAuthTokens(), planet.Satellites[0].Config.RESTKeys),
|
|
db.ProjectAccounting(),
|
|
projectUsage,
|
|
sat.API.Buckets.Service,
|
|
paymentsService.Accounts(),
|
|
// TODO: do we need a payment deposit wallet here?
|
|
nil,
|
|
db.Billing(),
|
|
analyticsService,
|
|
consoleauth.NewService(consoleauth.Config{
|
|
TokenExpirationTime: 24 * time.Hour,
|
|
}, &consoleauth.Hmac{Secret: []byte("my-suppa-secret-key")}),
|
|
nil,
|
|
"",
|
|
"",
|
|
console.Config{
|
|
PasswordCost: console.TestPasswordCost,
|
|
DefaultProjectLimit: 5,
|
|
Session: console.SessionConfig{
|
|
Duration: time.Hour,
|
|
},
|
|
},
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
mailService, err := mailservice.New(log, &discardSender{}, "testdata")
|
|
require.NoError(t, err)
|
|
defer ctx.Check(mailService.Close)
|
|
|
|
rootObject := make(map[string]interface{})
|
|
rootObject["origin"] = "http://doesntmatter.com/"
|
|
rootObject[consoleql.ActivationPath] = "?activationToken="
|
|
rootObject[consoleql.SignInPath] = "login"
|
|
rootObject[consoleql.LetUsKnowURL] = "letUsKnowURL"
|
|
rootObject[consoleql.ContactInfoURL] = "contactInfoURL"
|
|
rootObject[consoleql.TermsAndConditionsURL] = "termsAndConditionsURL"
|
|
rootObject[consoleql.SatelliteRegion] = "EU1"
|
|
|
|
schema, err := consoleql.CreateSchema(log, service, mailService)
|
|
require.NoError(t, err)
|
|
|
|
createUser := console.CreateUser{
|
|
FullName: "John Roll",
|
|
ShortName: "Roll",
|
|
Email: "test@mail.test",
|
|
UserAgent: []byte("120bf202-8252-437e-ac12-0e364bee852e"),
|
|
Password: "123a123",
|
|
SignupPromoCode: "promo1",
|
|
}
|
|
|
|
regToken, err := service.CreateRegToken(ctx, 1)
|
|
require.NoError(t, err)
|
|
|
|
rootUser, err := service.CreateUser(ctx, createUser, regToken.Secret)
|
|
require.NoError(t, err)
|
|
require.Equal(t, createUser.UserAgent, rootUser.UserAgent)
|
|
|
|
couponType, err := paymentsService.Accounts().Setup(ctx, rootUser.ID, rootUser.Email, rootUser.SignupPromoCode)
|
|
|
|
var signupCouponType payments.CouponType = payments.SignupCoupon
|
|
|
|
require.NoError(t, err)
|
|
assert.Equal(t, signupCouponType, couponType)
|
|
|
|
activationToken, err := service.GenerateActivationToken(ctx, rootUser.ID, rootUser.Email)
|
|
require.NoError(t, err)
|
|
|
|
_, err = service.ActivateAccount(ctx, activationToken)
|
|
require.NoError(t, err)
|
|
|
|
tokenInfo, err := service.Token(ctx, console.AuthUser{Email: createUser.Email, Password: createUser.Password})
|
|
require.NoError(t, err)
|
|
|
|
userCtx, err := service.TokenAuth(ctx, tokenInfo.Token, time.Now())
|
|
require.NoError(t, err)
|
|
|
|
testQuery := func(t *testing.T, query string) (interface{}, error) {
|
|
result := graphql.Do(graphql.Params{
|
|
Schema: schema,
|
|
Context: userCtx,
|
|
RequestString: query,
|
|
RootObject: rootObject,
|
|
})
|
|
|
|
for _, err := range result.Errors {
|
|
if err.OriginalError() != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
require.False(t, result.HasErrors())
|
|
|
|
return result.Data, nil
|
|
}
|
|
|
|
tokenInfo, err = service.Token(ctx, console.AuthUser{Email: rootUser.Email, Password: createUser.Password})
|
|
require.NoError(t, err)
|
|
|
|
userCtx, err = service.TokenAuth(ctx, tokenInfo.Token, time.Now())
|
|
require.NoError(t, err)
|
|
|
|
var projectIDField string
|
|
var projectPublicIDField string
|
|
t.Run("Create project mutation", func(t *testing.T) {
|
|
projectInfo := console.ProjectInfo{
|
|
Name: "Project name",
|
|
Description: "desc",
|
|
}
|
|
|
|
query := fmt.Sprintf(
|
|
"mutation {createProject(input:{name:\"%s\",description:\"%s\"}){name,description,id,publicId,createdAt}}",
|
|
projectInfo.Name,
|
|
projectInfo.Description,
|
|
)
|
|
|
|
result, err := testQuery(t, query)
|
|
require.NoError(t, err)
|
|
|
|
data := result.(map[string]interface{})
|
|
project := data[consoleql.CreateProjectMutation].(map[string]interface{})
|
|
|
|
assert.Equal(t, projectInfo.Name, project[consoleql.FieldName])
|
|
assert.Equal(t, projectInfo.Description, project[consoleql.FieldDescription])
|
|
|
|
projectIDField = project[consoleql.FieldID].(string)
|
|
projectPublicIDField = project[consoleql.FieldPublicID].(string)
|
|
|
|
_, err = uuid.FromString(projectPublicIDField)
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
projectID, err := uuid.FromString(projectIDField)
|
|
require.NoError(t, err)
|
|
|
|
project, err := service.GetProject(userCtx, projectID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, rootUser.UserAgent, project.UserAgent)
|
|
|
|
regTokenUser1, err := service.CreateRegToken(ctx, 1)
|
|
require.NoError(t, err)
|
|
|
|
user1, err := service.CreateUser(userCtx, console.CreateUser{
|
|
FullName: "User1",
|
|
Email: "u1@mail.test",
|
|
Password: "123a123",
|
|
}, regTokenUser1.Secret)
|
|
require.NoError(t, err)
|
|
|
|
t.Run("Activation", func(t *testing.T) {
|
|
activationToken1, err := service.GenerateActivationToken(
|
|
ctx,
|
|
user1.ID,
|
|
"u1@mail.test",
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
_, err = service.ActivateAccount(ctx, activationToken1)
|
|
require.NoError(t, err)
|
|
|
|
user1.Email = "u1@mail.test"
|
|
})
|
|
|
|
regTokenUser2, err := service.CreateRegToken(ctx, 1)
|
|
require.NoError(t, err)
|
|
|
|
user2, err := service.CreateUser(userCtx, console.CreateUser{
|
|
FullName: "User1",
|
|
Email: "u2@mail.test",
|
|
Password: "123a123",
|
|
}, regTokenUser2.Secret)
|
|
require.NoError(t, err)
|
|
|
|
t.Run("Activation", func(t *testing.T) {
|
|
activationToken2, err := service.GenerateActivationToken(
|
|
ctx,
|
|
user2.ID,
|
|
"u2@mail.test",
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
_, err = service.ActivateAccount(ctx, activationToken2)
|
|
require.NoError(t, err)
|
|
|
|
user2.Email = "u2@mail.test"
|
|
})
|
|
|
|
regTokenUser3, err := service.CreateRegToken(ctx, 1)
|
|
require.NoError(t, err)
|
|
|
|
user3, err := service.CreateUser(userCtx, console.CreateUser{
|
|
FullName: "User3",
|
|
Email: "u3@mail.test",
|
|
Password: "123a123",
|
|
}, regTokenUser3.Secret)
|
|
require.NoError(t, err)
|
|
|
|
t.Run("Activation", func(t *testing.T) {
|
|
activationToken3, err := service.GenerateActivationToken(
|
|
ctx,
|
|
user3.ID,
|
|
"u3@mail.test",
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
_, err = service.ActivateAccount(ctx, activationToken3)
|
|
require.NoError(t, err)
|
|
|
|
user3.Email = "u3@mail.test"
|
|
})
|
|
|
|
testAdd := func(query string, expectedMembers int) {
|
|
result, err := testQuery(t, query)
|
|
require.NoError(t, err)
|
|
|
|
data := result.(map[string]interface{})
|
|
proj := data[consoleql.AddProjectMembersMutation].(map[string]interface{})
|
|
|
|
members := proj[consoleql.FieldMembersAndInvitations].(map[string]interface{})
|
|
projectMembers := members[consoleql.FieldProjectMembers].([]interface{})
|
|
|
|
assert.Equal(t, project.ID.String(), proj[consoleql.FieldID])
|
|
assert.Equal(t, project.PublicID.String(), proj[consoleql.FieldPublicID])
|
|
assert.Equal(t, project.Name, proj[consoleql.FieldName])
|
|
assert.Equal(t, expectedMembers, len(projectMembers))
|
|
}
|
|
|
|
t.Run("Add project members mutation", func(t *testing.T) {
|
|
query := fmt.Sprintf(
|
|
"mutation {addProjectMembers(projectID:\"%s\",email:[\"%s\",\"%s\"]){id,publicId,name,membersAndInvitations(cursor: { limit: 50, search: \"\", page: 1, order: 1, orderDirection: 2 }){projectMembers{joinedAt}}}}",
|
|
project.ID.String(),
|
|
user1.Email,
|
|
user2.Email,
|
|
)
|
|
|
|
testAdd(query, 3)
|
|
})
|
|
|
|
t.Run("Add project members mutation with publicId", func(t *testing.T) {
|
|
query := fmt.Sprintf(
|
|
"mutation {addProjectMembers(publicId:\"%s\",email:[\"%s\"]){id,publicId,name,membersAndInvitations(cursor: { limit: 50, search: \"\", page: 1, order: 1, orderDirection: 2 }){projectMembers{joinedAt}}}}",
|
|
project.PublicID.String(),
|
|
user3.Email,
|
|
)
|
|
|
|
testAdd(query, 4)
|
|
})
|
|
|
|
t.Run("Fail add project members mutation without ID", func(t *testing.T) {
|
|
query := fmt.Sprintf(
|
|
"mutation {addProjectMembers(email:[\"%s\",\"%s\"]){id,publicId,name,membersAndInvitations(cursor: { limit: 50, search: \"\", page: 1, order: 1, orderDirection: 2 }){projectMembers{joinedAt}}}}",
|
|
user1.Email,
|
|
user2.Email,
|
|
)
|
|
|
|
_, err = testQuery(t, query)
|
|
require.Error(t, err)
|
|
})
|
|
|
|
t.Run("Delete project members mutation", func(t *testing.T) {
|
|
query := fmt.Sprintf(
|
|
"mutation {deleteProjectMembers(projectID:\"%s\",email:[\"%s\",\"%s\",\"%s\"]){id,publicId,name,membersAndInvitations(cursor: { limit: 50, search: \"\", page: 1, order: 1, orderDirection: 2 }){projectMembers{user{id}}}}}",
|
|
project.ID.String(),
|
|
user1.Email,
|
|
user2.Email,
|
|
user3.Email,
|
|
)
|
|
|
|
result, err := testQuery(t, query)
|
|
require.NoError(t, err)
|
|
|
|
data := result.(map[string]interface{})
|
|
proj := data[consoleql.DeleteProjectMembersMutation].(map[string]interface{})
|
|
|
|
members := proj[consoleql.FieldMembersAndInvitations].(map[string]interface{})
|
|
projectMembers := members[consoleql.FieldProjectMembers].([]interface{})
|
|
rootMember := projectMembers[0].(map[string]interface{})[consoleql.UserType].(map[string]interface{})
|
|
|
|
assert.Equal(t, project.ID.String(), proj[consoleql.FieldID])
|
|
assert.Equal(t, project.PublicID.String(), proj[consoleql.FieldPublicID])
|
|
assert.Equal(t, project.Name, proj[consoleql.FieldName])
|
|
assert.Equal(t, 1, len(members))
|
|
|
|
assert.Equal(t, rootUser.ID.String(), rootMember[consoleql.FieldID])
|
|
})
|
|
|
|
var keyID string
|
|
t.Run("Create api key mutation", func(t *testing.T) {
|
|
keyName := "key1"
|
|
query := fmt.Sprintf(
|
|
"mutation {createAPIKey(projectID:\"%s\",name:\"%s\"){key,keyInfo{id,name,projectID}}}",
|
|
project.ID.String(),
|
|
keyName,
|
|
)
|
|
|
|
result, err := testQuery(t, query)
|
|
require.NoError(t, err)
|
|
|
|
data := result.(map[string]interface{})
|
|
createAPIKey := data[consoleql.CreateAPIKeyMutation].(map[string]interface{})
|
|
|
|
key := createAPIKey[consoleql.FieldKey].(string)
|
|
keyInfo := createAPIKey[consoleql.APIKeyInfoType].(map[string]interface{})
|
|
|
|
assert.NotEqual(t, "", key)
|
|
|
|
assert.Equal(t, keyName, keyInfo[consoleql.FieldName])
|
|
assert.Equal(t, project.ID.String(), keyInfo[consoleql.FieldProjectID])
|
|
|
|
keyID = keyInfo[consoleql.FieldID].(string)
|
|
})
|
|
|
|
t.Run("Delete api key mutation", func(t *testing.T) {
|
|
id, err := uuid.FromString(keyID)
|
|
require.NoError(t, err)
|
|
|
|
info, err := service.GetAPIKeyInfo(userCtx, id)
|
|
require.NoError(t, err)
|
|
|
|
query := fmt.Sprintf(
|
|
"mutation {deleteAPIKeys(id:[\"%s\"]){name,projectID}}",
|
|
keyID,
|
|
)
|
|
|
|
result, err := testQuery(t, query)
|
|
require.NoError(t, err)
|
|
|
|
data := result.(map[string]interface{})
|
|
keyInfoList := data[consoleql.DeleteAPIKeysMutation].([]interface{})
|
|
|
|
for _, k := range keyInfoList {
|
|
keyInfo := k.(map[string]interface{})
|
|
|
|
assert.Equal(t, info.Name, keyInfo[consoleql.FieldName])
|
|
assert.Equal(t, project.ID.String(), keyInfo[consoleql.FieldProjectID])
|
|
}
|
|
})
|
|
|
|
const testName = "testName"
|
|
const testDescription = "test description"
|
|
const StorageLimit = "100"
|
|
const BandwidthLimit = "100"
|
|
|
|
testUpdate := func(query string) {
|
|
result, err := testQuery(t, query)
|
|
require.NoError(t, err)
|
|
|
|
data := result.(map[string]interface{})
|
|
proj := data[consoleql.UpdateProjectMutation].(map[string]interface{})
|
|
|
|
assert.Equal(t, project.ID.String(), proj[consoleql.FieldID])
|
|
assert.Equal(t, project.PublicID.String(), proj[consoleql.FieldPublicID])
|
|
assert.Equal(t, testName, proj[consoleql.FieldName])
|
|
assert.Equal(t, testDescription, proj[consoleql.FieldDescription])
|
|
}
|
|
|
|
t.Run("Update project mutation", func(t *testing.T) {
|
|
query := fmt.Sprintf(
|
|
"mutation {updateProject(id:\"%s\",projectFields:{name:\"%s\",description:\"%s\"},projectLimits:{storageLimit:\"%s\",bandwidthLimit:\"%s\"}){id,publicId,name,description}}",
|
|
project.ID.String(),
|
|
testName,
|
|
testDescription,
|
|
StorageLimit,
|
|
BandwidthLimit,
|
|
)
|
|
|
|
testUpdate(query)
|
|
})
|
|
|
|
t.Run("Update project mutation with publicId", func(t *testing.T) {
|
|
query := fmt.Sprintf(
|
|
"mutation {updateProject(publicId:\"%s\",projectFields:{name:\"%s\",description:\"%s\"},projectLimits:{storageLimit:\"%s\",bandwidthLimit:\"%s\"}){id,publicId,name,description}}",
|
|
project.PublicID.String(),
|
|
testName,
|
|
testDescription,
|
|
StorageLimit,
|
|
BandwidthLimit,
|
|
)
|
|
|
|
testUpdate(query)
|
|
})
|
|
|
|
t.Run("Fail update project mutation without ID", func(t *testing.T) {
|
|
query := fmt.Sprintf(
|
|
"mutation {updateProject(projectFields:{name:\"%s\",description:\"%s\"},projectLimits:{storageLimit:\"%s\",bandwidthLimit:\"%s\"}){id,publicId,name,description}}",
|
|
testName,
|
|
testDescription,
|
|
StorageLimit,
|
|
BandwidthLimit,
|
|
)
|
|
|
|
_, err := testQuery(t, query)
|
|
require.Error(t, err)
|
|
})
|
|
|
|
t.Run("Delete project mutation", func(t *testing.T) {
|
|
query := fmt.Sprintf(
|
|
"mutation {deleteProject(id:\"%s\"){id,name}}",
|
|
projectID,
|
|
)
|
|
|
|
result, err := testQuery(t, query)
|
|
require.Error(t, err)
|
|
require.Nil(t, result)
|
|
require.Equal(t, console.ErrUnauthorized.New("not implemented").Error(), err.Error())
|
|
})
|
|
})
|
|
}
|