mirror of
https://github.com/hanzoai/team.git
synced 2026-09-30 01:57:35 +00:00
The server module named github.com/hanzoai/team/server/v8 — a path that resolves to the retired workspace's repository, not this one — while server/public still published github.com/mattermost/mattermost/server/public. Both are github.com/hanzoteam/server/... now, which is where this code actually lives. That second half is what made the binary unbootable. Upstream's public path stayed claimed by upstream, mattermost-plugin-ai imported it, and the build linked public/model twice; public/plugin's gob.Register then ran twice under one name and panicked at init, before main. Reverting the rename traded the brand for a working binary. Rebranding the plugin alongside it needs no such trade: the agents fork is github.com/hanzoteam/agents/v2 against our public module, so no module named mattermost/mattermost is in the graph at all. Measured: `go list -deps ./cmd/mattermost` names exactly one public/model, and it is ours.
190 lines
6.0 KiB
Go
190 lines
6.0 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
package properties
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/hanzoteam/server/server/public/model"
|
|
"github.com/hanzoteam/server/server/public/shared/mlog"
|
|
"github.com/hanzoteam/server/server/public/shared/request"
|
|
"github.com/hanzoteam/server/server/v8/channels/store"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
type TestHelper struct {
|
|
service *PropertyService
|
|
dbStore store.Store
|
|
Context *request.Context
|
|
CPAGroupID string
|
|
}
|
|
|
|
func Setup(tb testing.TB) *TestHelper {
|
|
if testing.Short() {
|
|
tb.SkipNow()
|
|
}
|
|
dbStore := mainHelper.GetStore()
|
|
dbStore.DropAllTables()
|
|
dbStore.MarkSystemRanUnitTests()
|
|
mainHelper.PreloadMigrations()
|
|
|
|
return setupTestHelper(dbStore, tb)
|
|
}
|
|
|
|
func setupTestHelper(s store.Store, tb testing.TB) *TestHelper {
|
|
logger := mlog.CreateConsoleTestLogger(tb)
|
|
service, err := New(ServiceConfig{
|
|
PropertyGroupStore: s.PropertyGroup(),
|
|
PropertyFieldStore: s.PropertyField(),
|
|
PropertyValueStore: s.PropertyValue(),
|
|
CallerIDExtractor: func(rctx request.CTX) string {
|
|
if rctx == nil {
|
|
return ""
|
|
}
|
|
callerID, _ := model.CallerIDFromContext(rctx.Context())
|
|
return callerID
|
|
},
|
|
RequestOptionsExtractor: func(rctx request.CTX) model.PropertyRequestOptions {
|
|
if rctx == nil {
|
|
return model.PropertyRequestOptions{}
|
|
}
|
|
return model.PropertyRequestOptionsFromContext(rctx.Context())
|
|
},
|
|
})
|
|
require.NoError(tb, err)
|
|
|
|
tb.Cleanup(func() {
|
|
s.Close()
|
|
})
|
|
|
|
return &TestHelper{
|
|
service: service,
|
|
dbStore: s,
|
|
Context: request.EmptyContext(logger),
|
|
}
|
|
}
|
|
|
|
// RequestContextWithCallerID adds the caller ID to a request.CTX for access control purposes.
|
|
func RequestContextWithCallerID(rctx request.CTX, callerID string) request.CTX {
|
|
ctx := model.WithCallerID(rctx.Context(), callerID)
|
|
return rctx.WithContext(ctx)
|
|
}
|
|
|
|
// RequestContextWithCallerIDAndOptions adds the caller ID and per-call
|
|
// declarations to a request.CTX for access control purposes.
|
|
func RequestContextWithCallerIDAndOptions(rctx request.CTX, callerID string, options model.PropertyRequestOptions) request.CTX {
|
|
ctx := model.WithCallerID(rctx.Context(), callerID)
|
|
ctx = model.WithPropertyRequestOptions(ctx, options)
|
|
return rctx.WithContext(ctx)
|
|
}
|
|
|
|
// setPluginCheckerForTests sets the plugin checker on the AccessControlHook for testing.
|
|
func (ps *PropertyService) setPluginCheckerForTests(pluginChecker PluginChecker) {
|
|
for _, hook := range ps.hooks {
|
|
if ach, ok := hook.(*AccessControlHook); ok {
|
|
ach.setPluginCheckerForTests(pluginChecker)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (h *AccessControlHook) setPluginCheckerForTests(pluginChecker PluginChecker) {
|
|
h.pluginChecker = pluginChecker
|
|
}
|
|
|
|
func (th *TestHelper) RegisterCPAPropertyGroup(tb testing.TB) *TestHelper {
|
|
// Register the CPA group so requiresAccessControl can always look it up
|
|
group, groupErr := th.service.RegisterPropertyGroup(&model.PropertyGroup{Name: model.AccessControlPropertyGroupName, Version: model.PropertyGroupVersionV2})
|
|
require.NoError(tb, groupErr)
|
|
th.CPAGroupID = group.ID
|
|
|
|
// Create and register the access control hook now that the group ID is known
|
|
hook := NewAccessControlHook(th.service, nil, group.ID)
|
|
th.service.AddHook(hook)
|
|
|
|
return th
|
|
}
|
|
|
|
// RegisterPropertyGroup registers a new property group with the given version and a unique name.
|
|
func (th *TestHelper) RegisterPropertyGroup(tb testing.TB, version int) *model.PropertyGroup {
|
|
tb.Helper()
|
|
group, err := th.service.RegisterPropertyGroup(&model.PropertyGroup{
|
|
Name: model.NewId(),
|
|
Version: version,
|
|
})
|
|
require.NoError(tb, err)
|
|
return group
|
|
}
|
|
|
|
// CreateTeam creates a team for testing hierarchy
|
|
func (th *TestHelper) CreateTeam(tb testing.TB) *model.Team {
|
|
team := &model.Team{
|
|
DisplayName: "Test Team " + model.NewId(),
|
|
Name: "team" + model.NewId(),
|
|
Type: model.TeamOpen,
|
|
}
|
|
team, err := th.dbStore.Team().Save(team)
|
|
require.NoError(tb, err)
|
|
return team
|
|
}
|
|
|
|
// CreateChannel creates a channel in the given team
|
|
func (th *TestHelper) CreateChannel(tb testing.TB, teamID string) *model.Channel {
|
|
channel := &model.Channel{
|
|
TeamId: teamID,
|
|
DisplayName: "Test Channel " + model.NewId(),
|
|
Name: "channel" + model.NewId(),
|
|
Type: model.ChannelTypeOpen,
|
|
}
|
|
channel, err := th.dbStore.Channel().Save(th.Context, channel, 10000)
|
|
require.NoError(tb, err)
|
|
return channel
|
|
}
|
|
|
|
// CreateDMChannel creates a DM channel (no team association)
|
|
func (th *TestHelper) CreateDMChannel(tb testing.TB) *model.Channel {
|
|
// Create two users for the DM
|
|
user1 := th.CreateUser(tb)
|
|
user2 := th.CreateUser(tb)
|
|
|
|
channel, err := th.dbStore.Channel().CreateDirectChannel(th.Context, user1, user2)
|
|
require.NoError(tb, err)
|
|
return channel
|
|
}
|
|
|
|
// CreateUser creates a user for testing
|
|
func (th *TestHelper) CreateUser(tb testing.TB) *model.User {
|
|
id := model.NewId()
|
|
user := &model.User{
|
|
Email: "success+" + id + "@simulator.amazonses.com",
|
|
Username: "un_" + id,
|
|
Nickname: "nn_" + id,
|
|
Password: model.NewTestPassword(),
|
|
EmailVerified: true,
|
|
}
|
|
user, err := th.dbStore.User().Save(th.Context, user)
|
|
require.NoError(tb, err)
|
|
return user
|
|
}
|
|
|
|
// CreatePropertyField creates a property field using the service (with access control routing)
|
|
func (th *TestHelper) CreatePropertyField(tb testing.TB, rctx request.CTX, field *model.PropertyField) *model.PropertyField {
|
|
result, err := th.service.CreatePropertyField(rctx, field)
|
|
require.NoError(tb, err)
|
|
return result
|
|
}
|
|
|
|
// CreatePropertyFieldDirect creates a property field directly via store (bypasses conflict check and access control)
|
|
func (th *TestHelper) CreatePropertyFieldDirect(tb testing.TB, field *model.PropertyField) *model.PropertyField {
|
|
result, err := th.dbStore.PropertyField().Create(field)
|
|
require.NoError(tb, err)
|
|
return result
|
|
}
|
|
|
|
// CreatePropertyValue creates a property value using the service (with access control routing)
|
|
func (th *TestHelper) CreatePropertyValue(tb testing.TB, rctx request.CTX, value *model.PropertyValue) *model.PropertyValue {
|
|
result, err := th.service.CreatePropertyValue(rctx, value)
|
|
require.NoError(tb, err)
|
|
return result
|
|
}
|