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.
162 lines
6.2 KiB
Go
162 lines
6.2 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
package app
|
|
|
|
import (
|
|
"net/http"
|
|
"testing"
|
|
|
|
"github.com/hanzoteam/server/server/public/model"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestResolveValueBroadcastParams(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
t.Run("post object type returns channel ID from the post", func(t *testing.T) {
|
|
post := &model.Post{
|
|
UserId: th.BasicUser.Id,
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "test post for broadcast",
|
|
}
|
|
created, _, appErr := th.App.CreatePost(th.Context, post, th.BasicChannel, model.CreatePostFlags{})
|
|
require.Nil(t, appErr)
|
|
|
|
teamID, channelID, err := th.App.resolveValueBroadcastParams(th.Context, model.PropertyFieldObjectTypePost, created.Id)
|
|
require.Nil(t, err)
|
|
assert.Empty(t, teamID)
|
|
assert.Equal(t, th.BasicChannel.Id, channelID)
|
|
})
|
|
|
|
t.Run("channel object type returns the target ID as channel ID", func(t *testing.T) {
|
|
teamID, channelID, err := th.App.resolveValueBroadcastParams(th.Context, model.PropertyFieldObjectTypeChannel, "chan123")
|
|
require.Nil(t, err)
|
|
assert.Empty(t, teamID)
|
|
assert.Equal(t, "chan123", channelID)
|
|
})
|
|
|
|
t.Run("user object type returns empty strings for system-wide broadcast", func(t *testing.T) {
|
|
teamID, channelID, err := th.App.resolveValueBroadcastParams(th.Context, model.PropertyFieldObjectTypeUser, "user123")
|
|
require.Nil(t, err)
|
|
assert.Empty(t, teamID)
|
|
assert.Empty(t, channelID)
|
|
})
|
|
|
|
t.Run("system object type returns empty strings for system-wide broadcast", func(t *testing.T) {
|
|
teamID, channelID, err := th.App.resolveValueBroadcastParams(th.Context, model.PropertyFieldObjectTypeSystem, model.PropertyValueSystemTargetID)
|
|
require.Nil(t, err)
|
|
assert.Empty(t, teamID)
|
|
assert.Empty(t, channelID)
|
|
})
|
|
|
|
t.Run("unknown object type returns an error", func(t *testing.T) {
|
|
_, _, err := th.App.resolveValueBroadcastParams(th.Context, "unknown_type", "target123")
|
|
require.NotNil(t, err)
|
|
assert.Equal(t, "app.property_value.resolve_broadcast_params.unknown_object_type.app_error", err.Id)
|
|
assert.Equal(t, http.StatusBadRequest, err.StatusCode)
|
|
})
|
|
}
|
|
|
|
func TestUpsertPropertyValues_Invariants(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
groupID := registerTestPropertyGroup(t, th)
|
|
|
|
// Create a target user-typed field for the happy paths.
|
|
field := &model.PropertyField{
|
|
GroupID: groupID,
|
|
Name: "upsert-target-" + model.NewId(),
|
|
Type: model.PropertyFieldTypeText,
|
|
ObjectType: model.PropertyFieldObjectTypeUser,
|
|
TargetType: string(model.PropertyFieldTargetLevelSystem),
|
|
}
|
|
createdField, appErr := th.App.CreatePropertyField(th.Context, field, false, "")
|
|
require.Nil(t, appErr)
|
|
|
|
makeValue := func(fieldID string) *model.PropertyValue {
|
|
return &model.PropertyValue{
|
|
TargetID: th.BasicUser.Id,
|
|
TargetType: model.PropertyFieldObjectTypeUser,
|
|
GroupID: groupID,
|
|
FieldID: fieldID,
|
|
Value: []byte("\"v\""),
|
|
CreatedBy: th.BasicUser.Id,
|
|
UpdatedBy: th.BasicUser.Id,
|
|
}
|
|
}
|
|
|
|
t.Run("rejects duplicate FieldID", func(t *testing.T) {
|
|
v := []*model.PropertyValue{makeValue(createdField.ID), makeValue(createdField.ID)}
|
|
result, err := th.App.UpsertPropertyValues(th.Context, v, model.PropertyFieldObjectTypeUser, th.BasicUser.Id, "")
|
|
require.NotNil(t, err)
|
|
assert.Nil(t, result)
|
|
assert.Equal(t, "app.property_value.upsert.duplicate_field_id.app_error", err.Id)
|
|
assert.Equal(t, http.StatusBadRequest, err.StatusCode)
|
|
})
|
|
|
|
t.Run("rejects invalid FieldID", func(t *testing.T) {
|
|
v := []*model.PropertyValue{makeValue("not-an-id")}
|
|
result, err := th.App.UpsertPropertyValues(th.Context, v, model.PropertyFieldObjectTypeUser, th.BasicUser.Id, "")
|
|
require.NotNil(t, err)
|
|
assert.Nil(t, result)
|
|
assert.Equal(t, "app.property_value.upsert.invalid_field_id.app_error", err.Id)
|
|
assert.Equal(t, http.StatusBadRequest, err.StatusCode)
|
|
})
|
|
|
|
t.Run("rejects mixed group IDs as a clean 400", func(t *testing.T) {
|
|
altGroup, appErr := th.App.RegisterPropertyGroup(th.Context, &model.PropertyGroup{
|
|
Name: "alt_mix_" + model.NewId(),
|
|
Version: model.PropertyGroupVersionV2,
|
|
})
|
|
require.Nil(t, appErr)
|
|
|
|
altField := &model.PropertyField{
|
|
GroupID: altGroup.ID,
|
|
Name: "alt-field-" + model.NewId(),
|
|
Type: model.PropertyFieldTypeText,
|
|
ObjectType: model.PropertyFieldObjectTypeUser,
|
|
TargetType: string(model.PropertyFieldTargetLevelSystem),
|
|
}
|
|
createdAlt, appErr := th.App.CreatePropertyField(th.Context, altField, false, "")
|
|
require.Nil(t, appErr)
|
|
|
|
v1 := makeValue(createdField.ID)
|
|
v2 := makeValue(createdAlt.ID)
|
|
v2.GroupID = altGroup.ID
|
|
result, err := th.App.UpsertPropertyValues(th.Context, []*model.PropertyValue{v1, v2}, model.PropertyFieldObjectTypeUser, th.BasicUser.Id, "")
|
|
require.NotNil(t, err)
|
|
assert.Nil(t, result)
|
|
assert.Equal(t, "app.property_value.upsert.mixed_groups.app_error", err.Id)
|
|
assert.Equal(t, http.StatusBadRequest, err.StatusCode)
|
|
})
|
|
|
|
t.Run("rejects ObjectType mismatch when objectType is non-empty", func(t *testing.T) {
|
|
// Field is ObjectType=user; request specifies channel.
|
|
v := []*model.PropertyValue{makeValue(createdField.ID)}
|
|
result, err := th.App.UpsertPropertyValues(th.Context, v, model.PropertyFieldObjectTypeChannel, "ch1", "")
|
|
require.NotNil(t, err)
|
|
assert.Nil(t, result)
|
|
assert.Equal(t, "app.property_value.upsert.object_type_mismatch.app_error", err.Id)
|
|
assert.Equal(t, http.StatusNotFound, err.StatusCode)
|
|
})
|
|
|
|
t.Run("plugin path: empty objectType skips ObjectType match", func(t *testing.T) {
|
|
// We don't actually need the upsert to succeed (target/etc may not
|
|
// satisfy schema), only to bypass the ObjectType-mismatch reject.
|
|
// Confirm by passing a wrong-typed field with objectType="" — the
|
|
// app-layer reject should not fire; any error must come from
|
|
// downstream layers, not "object_type_mismatch".
|
|
v := []*model.PropertyValue{makeValue(createdField.ID)}
|
|
_, err := th.App.UpsertPropertyValues(th.Context, v, "", "", "")
|
|
// Either succeeds, or fails for a different reason — never the
|
|
// object_type_mismatch reject.
|
|
if err != nil {
|
|
assert.NotEqual(t, "app.property_value.upsert.object_type_mismatch.app_error", err.Id)
|
|
}
|
|
})
|
|
}
|