mirror of
https://github.com/mattermost/mattermost.git
synced 2026-08-27 05:37:15 -05:00
[MM-64683] Implement property field counting functionality in Plugin API (#33438)
* Implement property field limit enforcement and counting functionality in Plugin API - Added a limit of 20 property fields per group in the CreatePropertyField method. - Introduced CountPropertyFields method to count active and all property fields, including deleted ones. - Enhanced tests to validate the new property field limit and counting behavior. - Updated related API and service methods to support the new functionality. * Update server/channels/app/properties/property_field.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix vet * fix lint error * fix test * fix tests * fix test * count properties + targets * Update server/channels/app/plugin_api.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * remove test for limit * fix more tests * improve testing messages now that the limit is removed * Apply suggestion from @calebroseland Co-authored-by: Caleb Roseland <caleb@calebroseland.com> * Apply suggestion from @calebroseland Co-authored-by: Caleb Roseland <caleb@calebroseland.com> * Apply suggestion from @calebroseland Co-authored-by: Caleb Roseland <caleb@calebroseland.com> * Apply suggestion from @calebroseland Co-authored-by: Caleb Roseland <caleb@calebroseland.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Mattermost Build <build@mattermost.com> Co-authored-by: Julien Tant <785518+JulienTant@users.noreply.github.com> Co-authored-by: Caleb Roseland <caleb@calebroseland.com>
This commit is contained in:
co-authored by
Copilot
Caleb Roseland
Mattermost Build
Julien Tant
parent
316712522c
commit
d15b933888
@@ -1503,6 +1503,10 @@ func (api *PluginAPI) DeleteGroupConstrainedMemberships() *model.AppError {
|
||||
}
|
||||
|
||||
func (api *PluginAPI) CreatePropertyField(field *model.PropertyField) (*model.PropertyField, error) {
|
||||
if field == nil {
|
||||
return nil, fmt.Errorf("invalid input: property field parameter is required")
|
||||
}
|
||||
|
||||
return api.app.PropertyService().CreatePropertyField(field)
|
||||
}
|
||||
|
||||
@@ -1526,6 +1530,20 @@ func (api *PluginAPI) SearchPropertyFields(groupID, targetID string, opts model.
|
||||
return api.app.PropertyService().SearchPropertyFields(groupID, targetID, opts)
|
||||
}
|
||||
|
||||
func (api *PluginAPI) CountPropertyFields(groupID string, includeDeleted bool) (int64, error) {
|
||||
if includeDeleted {
|
||||
return api.app.PropertyService().CountAllPropertyFieldsForGroup(groupID)
|
||||
}
|
||||
return api.app.PropertyService().CountActivePropertyFieldsForGroup(groupID)
|
||||
}
|
||||
|
||||
func (api *PluginAPI) CountPropertyFieldsForTarget(groupID, targetType, targetID string, includeDeleted bool) (int64, error) {
|
||||
if includeDeleted {
|
||||
return api.app.PropertyService().CountAllPropertyFieldsForTarget(groupID, targetType, targetID)
|
||||
}
|
||||
return api.app.PropertyService().CountActivePropertyFieldsForTarget(groupID, targetType, targetID)
|
||||
}
|
||||
|
||||
func (api *PluginAPI) CreatePropertyValue(value *model.PropertyValue) (*model.PropertyValue, error) {
|
||||
return api.app.PropertyService().CreatePropertyValue(value)
|
||||
}
|
||||
|
||||
@@ -2892,3 +2892,216 @@ func TestPluginServeHTTPCompatibility(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPluginAPICreatePropertyField(t *testing.T) {
|
||||
mainHelper.Parallel(t)
|
||||
|
||||
t.Run("should allow creation after deleting fields", func(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
api := th.SetupPluginAPI()
|
||||
|
||||
// Create 20 property fields
|
||||
groupID := model.NewId()
|
||||
var createdFields []*model.PropertyField
|
||||
for i := 1; i <= 20; i++ {
|
||||
field := &model.PropertyField{
|
||||
GroupID: groupID,
|
||||
Name: fmt.Sprintf("field_%d", i),
|
||||
Type: model.PropertyFieldTypeText,
|
||||
CreateAt: model.GetMillis(),
|
||||
UpdateAt: model.GetMillis(),
|
||||
}
|
||||
|
||||
created, err := api.CreatePropertyField(field)
|
||||
require.NoError(t, err)
|
||||
createdFields = append(createdFields, created)
|
||||
}
|
||||
|
||||
// Delete one field
|
||||
err := api.DeletePropertyField(groupID, createdFields[0].ID)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Should now be able to create another field
|
||||
newField := &model.PropertyField{
|
||||
GroupID: groupID,
|
||||
Name: "new_field",
|
||||
Type: model.PropertyFieldTypeText,
|
||||
CreateAt: model.GetMillis(),
|
||||
UpdateAt: model.GetMillis(),
|
||||
}
|
||||
|
||||
created, err := api.CreatePropertyField(newField)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, newField.Name, created.Name)
|
||||
})
|
||||
|
||||
t.Run("should not count deleted fields", func(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
api := th.SetupPluginAPI()
|
||||
|
||||
groupID := model.NewId()
|
||||
|
||||
// Create and delete 5 fields
|
||||
for i := 1; i <= 5; i++ {
|
||||
field := &model.PropertyField{
|
||||
GroupID: groupID,
|
||||
Name: fmt.Sprintf("deleted_field_%d", i),
|
||||
Type: model.PropertyFieldTypeText,
|
||||
CreateAt: model.GetMillis(),
|
||||
UpdateAt: model.GetMillis(),
|
||||
}
|
||||
|
||||
created, err := api.CreatePropertyField(field)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = api.DeletePropertyField(groupID, created.ID)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// Should be able to create multiple active fields
|
||||
for i := 1; i <= 20; i++ {
|
||||
field := &model.PropertyField{
|
||||
GroupID: groupID,
|
||||
Name: fmt.Sprintf("active_field_%d", i),
|
||||
Type: model.PropertyFieldTypeText,
|
||||
CreateAt: model.GetMillis(),
|
||||
UpdateAt: model.GetMillis(),
|
||||
}
|
||||
|
||||
created, err := api.CreatePropertyField(field)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, field.Name, created.Name)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("should reject empty or invalid group ID", func(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
api := th.SetupPluginAPI()
|
||||
|
||||
// Test with empty group ID - should fail validation
|
||||
field := &model.PropertyField{
|
||||
GroupID: "",
|
||||
Name: "test_field",
|
||||
Type: model.PropertyFieldTypeText,
|
||||
CreateAt: model.GetMillis(),
|
||||
UpdateAt: model.GetMillis(),
|
||||
}
|
||||
|
||||
created, err := api.CreatePropertyField(field)
|
||||
require.Error(t, err) // Should fail due to invalid GroupID
|
||||
assert.Nil(t, created)
|
||||
assert.Contains(t, err.Error(), "group_id")
|
||||
|
||||
// Test with nil field - should fail gracefully
|
||||
created, err = api.CreatePropertyField(nil)
|
||||
require.Error(t, err) // Should fail when given nil input
|
||||
assert.Nil(t, created)
|
||||
assert.Contains(t, err.Error(), "invalid input: property field parameter is required")
|
||||
})
|
||||
}
|
||||
|
||||
func TestPluginAPICountPropertyFields(t *testing.T) {
|
||||
mainHelper.Parallel(t)
|
||||
|
||||
t.Run("should count active property fields only", func(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
api := th.SetupPluginAPI()
|
||||
|
||||
groupID := model.NewId()
|
||||
|
||||
// Create 5 fields
|
||||
var createdFields []*model.PropertyField
|
||||
for i := 1; i <= 5; i++ {
|
||||
field := &model.PropertyField{
|
||||
GroupID: groupID,
|
||||
Name: fmt.Sprintf("field_%d", i),
|
||||
Type: model.PropertyFieldTypeText,
|
||||
CreateAt: model.GetMillis(),
|
||||
UpdateAt: model.GetMillis(),
|
||||
}
|
||||
|
||||
created, err := api.CreatePropertyField(field)
|
||||
require.NoError(t, err)
|
||||
createdFields = append(createdFields, created)
|
||||
}
|
||||
|
||||
// Count active fields
|
||||
count, err := api.CountPropertyFields(groupID, false)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(5), count)
|
||||
|
||||
// Delete 2 fields
|
||||
err = api.DeletePropertyField(groupID, createdFields[0].ID)
|
||||
require.NoError(t, err)
|
||||
err = api.DeletePropertyField(groupID, createdFields[1].ID)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Count should now be 3
|
||||
count, err = api.CountPropertyFields(groupID, false)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(3), count)
|
||||
})
|
||||
|
||||
t.Run("should count all property fields including deleted", func(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
api := th.SetupPluginAPI()
|
||||
|
||||
groupID := model.NewId()
|
||||
|
||||
// Create 5 fields
|
||||
var createdFields []*model.PropertyField
|
||||
for i := 1; i <= 5; i++ {
|
||||
field := &model.PropertyField{
|
||||
GroupID: groupID,
|
||||
Name: fmt.Sprintf("field_%d", i),
|
||||
Type: model.PropertyFieldTypeText,
|
||||
CreateAt: model.GetMillis(),
|
||||
UpdateAt: model.GetMillis(),
|
||||
}
|
||||
|
||||
created, err := api.CreatePropertyField(field)
|
||||
require.NoError(t, err)
|
||||
createdFields = append(createdFields, created)
|
||||
}
|
||||
|
||||
// Count all fields
|
||||
count, err := api.CountPropertyFields(groupID, true)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(5), count)
|
||||
|
||||
// Delete 2 fields
|
||||
err = api.DeletePropertyField(groupID, createdFields[0].ID)
|
||||
require.NoError(t, err)
|
||||
err = api.DeletePropertyField(groupID, createdFields[1].ID)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Count all should still be 5
|
||||
count, err = api.CountPropertyFields(groupID, true)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(5), count)
|
||||
|
||||
// Count active should be 3
|
||||
count, err = api.CountPropertyFields(groupID, false)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(3), count)
|
||||
})
|
||||
|
||||
t.Run("should return 0 for empty group", func(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
api := th.SetupPluginAPI()
|
||||
|
||||
count, err := api.CountPropertyFields("non-existent-group", false)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(0), count)
|
||||
|
||||
count, err = api.CountPropertyFields("non-existent-group", true)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(0), count)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -38,9 +38,10 @@ func TestPluginProperties(t *testing.T) {
|
||||
}
|
||||
|
||||
// Create a property field
|
||||
fieldName := "Test Field " + model.NewId()
|
||||
field := &model.PropertyField{
|
||||
GroupID: group.ID,
|
||||
Name: "Test Field",
|
||||
Name: fieldName,
|
||||
Type: model.PropertyFieldTypeText,
|
||||
TargetType: "user",
|
||||
}
|
||||
@@ -55,8 +56,8 @@ func TestPluginProperties(t *testing.T) {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get property field: %w", err)
|
||||
}
|
||||
if retrievedField.Name != "Test Field" {
|
||||
return fmt.Errorf("field name mismatch: expected 'Test Field', got '%s'", retrievedField.Name)
|
||||
if retrievedField.Name != fieldName {
|
||||
return fmt.Errorf("field name mismatch: expected '%s', got '%s'", fieldName, retrievedField.Name)
|
||||
}
|
||||
|
||||
// Update the field
|
||||
@@ -70,7 +71,7 @@ func TestPluginProperties(t *testing.T) {
|
||||
}
|
||||
|
||||
// Search for fields
|
||||
fields, err := p.API.SearchPropertyFields(group.ID, "", model.PropertyFieldSearchOpts{})
|
||||
fields, err := p.API.SearchPropertyFields(group.ID, "", model.PropertyFieldSearchOpts{PerPage: 50})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to search property fields: %w", err)
|
||||
}
|
||||
@@ -85,7 +86,7 @@ func TestPluginProperties(t *testing.T) {
|
||||
}
|
||||
|
||||
// Verify deletion
|
||||
fields, err = p.API.SearchPropertyFields(group.ID, "", model.PropertyFieldSearchOpts{})
|
||||
fields, err = p.API.SearchPropertyFields(group.ID, "", model.PropertyFieldSearchOpts{PerPage: 50})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to search property fields after deletion: %w", err)
|
||||
}
|
||||
@@ -102,7 +103,7 @@ func TestPluginProperties(t *testing.T) {
|
||||
`}, th.App, th.NewPluginAPI)
|
||||
defer tearDown()
|
||||
require.Len(t, activationErrors, 1)
|
||||
require.Nil(t, nil, activationErrors[0])
|
||||
require.NoError(t, activationErrors[0])
|
||||
|
||||
// Clean up
|
||||
err2 := th.App.DisablePlugin(pluginIDs[0])
|
||||
@@ -134,9 +135,10 @@ func TestPluginProperties(t *testing.T) {
|
||||
}
|
||||
|
||||
// Create a property field
|
||||
fieldName := "Test Field " + model.NewId()
|
||||
field := &model.PropertyField{
|
||||
GroupID: group.ID,
|
||||
Name: "Test Field",
|
||||
Name: fieldName,
|
||||
Type: model.PropertyFieldTypeText,
|
||||
TargetType: "user",
|
||||
}
|
||||
@@ -148,7 +150,7 @@ func TestPluginProperties(t *testing.T) {
|
||||
|
||||
// Create a property value
|
||||
targetId := model.NewId()
|
||||
valueJson := []byte("test-value")
|
||||
valueJson := []byte("\"test-value\"")
|
||||
value := &model.PropertyValue{
|
||||
GroupID: group.ID,
|
||||
FieldID: createdField.ID,
|
||||
@@ -167,22 +169,22 @@ func TestPluginProperties(t *testing.T) {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get property value: %w", err)
|
||||
}
|
||||
if string(retrievedValue.Value) != "test-value" {
|
||||
return fmt.Errorf("value mismatch: expected 'test-value', got '%s'", string(retrievedValue.Value))
|
||||
if string(retrievedValue.Value) != "\"test-value\"" {
|
||||
return fmt.Errorf("value mismatch: expected '\"test-value\"', got '%s'", string(retrievedValue.Value))
|
||||
}
|
||||
|
||||
// Update the value
|
||||
retrievedValue.Value = []byte("updated-test-value")
|
||||
retrievedValue.Value = []byte("\"updated-test-value\"")
|
||||
updatedValue, err := p.API.UpdatePropertyValue(group.ID, retrievedValue)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update property value: %w", err)
|
||||
}
|
||||
if string(updatedValue.Value) != "updated-test-value" {
|
||||
return fmt.Errorf("updated value mismatch: expected 'updated-test-value', got '%s'", string(updatedValue.Value))
|
||||
if string(updatedValue.Value) != "\"updated-test-value\"" {
|
||||
return fmt.Errorf("updated value mismatch: expected '\"updated-test-value\"', got '%s'", string(updatedValue.Value))
|
||||
}
|
||||
|
||||
// Upsert the value
|
||||
upsertValueJson := []byte("upserted-value")
|
||||
upsertValueJson := []byte("\"upserted-value\"")
|
||||
upsertValue := &model.PropertyValue{
|
||||
GroupID: group.ID,
|
||||
FieldID: createdField.ID,
|
||||
@@ -197,7 +199,7 @@ func TestPluginProperties(t *testing.T) {
|
||||
}
|
||||
|
||||
// Search for values
|
||||
values, err := p.API.SearchPropertyValues(group.ID, targetId, model.PropertyValueSearchOpts{})
|
||||
values, err := p.API.SearchPropertyValues(group.ID, targetId, model.PropertyValueSearchOpts{PerPage: 50})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to search property values: %w", err)
|
||||
}
|
||||
@@ -212,7 +214,7 @@ func TestPluginProperties(t *testing.T) {
|
||||
}
|
||||
|
||||
// Verify deletion
|
||||
values, err = p.API.SearchPropertyValues(group.ID, targetId, model.PropertyValueSearchOpts{})
|
||||
values, err = p.API.SearchPropertyValues(group.ID, targetId, model.PropertyValueSearchOpts{PerPage: 50})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to search property values after deletion: %w", err)
|
||||
}
|
||||
@@ -229,7 +231,7 @@ func TestPluginProperties(t *testing.T) {
|
||||
`}, th.App, th.NewPluginAPI)
|
||||
defer tearDown()
|
||||
require.Len(t, activationErrors, 1)
|
||||
require.Nil(t, nil, activationErrors[0])
|
||||
require.NoError(t, activationErrors[0])
|
||||
|
||||
// Clean up
|
||||
err2 := th.App.DisablePlugin(pluginIDs[0])
|
||||
@@ -277,7 +279,155 @@ func TestPluginProperties(t *testing.T) {
|
||||
`}, th.App, th.NewPluginAPI)
|
||||
defer tearDown()
|
||||
require.Len(t, activationErrors, 1)
|
||||
require.Nil(t, nil, activationErrors[0])
|
||||
require.NoError(t, activationErrors[0])
|
||||
|
||||
// Clean up
|
||||
err2 := th.App.DisablePlugin(pluginIDs[0])
|
||||
require.Nil(t, err2)
|
||||
appErr := th.App.ch.RemovePlugin(pluginIDs[0])
|
||||
require.Nil(t, appErr)
|
||||
})
|
||||
|
||||
t.Run("test property field counting", func(t *testing.T) {
|
||||
groupName := model.NewId()
|
||||
tearDown, pluginIDs, activationErrors := SetAppEnvironmentWithPlugins(t, []string{`
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mattermost/mattermost/server/public/plugin"
|
||||
"github.com/mattermost/mattermost/server/public/model"
|
||||
)
|
||||
|
||||
type MyPlugin struct {
|
||||
plugin.MattermostPlugin
|
||||
}
|
||||
|
||||
func (p *MyPlugin) OnActivate() error {
|
||||
// Register a property group
|
||||
group, err := p.API.RegisterPropertyGroup("` + groupName + `")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to register property group: %w", err)
|
||||
}
|
||||
|
||||
// Create multiple property fields for the same target
|
||||
targetId := model.NewId()
|
||||
for i := 1; i <= 20; i++ {
|
||||
field := &model.PropertyField{
|
||||
GroupID: group.ID,
|
||||
Name: fmt.Sprintf("Field %d", i),
|
||||
Type: model.PropertyFieldTypeText,
|
||||
TargetType: "user",
|
||||
TargetID: targetId,
|
||||
}
|
||||
|
||||
_, err := p.API.CreatePropertyField(field)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create property field %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Count active fields - should be 20
|
||||
count, err := p.API.CountPropertyFields(group.ID, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to count property fields: %w", err)
|
||||
}
|
||||
if count != 20 {
|
||||
return fmt.Errorf("expected 20 active fields (test creates 20), got %d", count)
|
||||
}
|
||||
|
||||
// Search for fields to get one to delete
|
||||
fields, err := p.API.SearchPropertyFields(group.ID, "", model.PropertyFieldSearchOpts{PerPage: 1})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to search property fields: %w", err)
|
||||
}
|
||||
if len(fields) == 0 {
|
||||
return fmt.Errorf("no fields found to delete")
|
||||
}
|
||||
|
||||
// Delete one field
|
||||
err = p.API.DeletePropertyField(group.ID, fields[0].ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete property field: %w", err)
|
||||
}
|
||||
|
||||
// Count active fields - should be 19
|
||||
count, err = p.API.CountPropertyFields(group.ID, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to count property fields after deletion: %w", err)
|
||||
}
|
||||
if count != 19 {
|
||||
return fmt.Errorf("expected 19 active fields after deletion, got %d", count)
|
||||
}
|
||||
|
||||
// Count all fields including deleted - should be 20
|
||||
totalCount, err := p.API.CountPropertyFields(group.ID, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to count all property fields: %w", err)
|
||||
}
|
||||
if totalCount != 20 {
|
||||
return fmt.Errorf("expected 20 total fields including deleted (test created 20), got %d", totalCount)
|
||||
}
|
||||
|
||||
// Now creating a new field for the same target should work again
|
||||
newField := &model.PropertyField{
|
||||
GroupID: group.ID,
|
||||
Name: "New Field",
|
||||
Type: model.PropertyFieldTypeText,
|
||||
TargetType: "user",
|
||||
TargetID: targetId,
|
||||
}
|
||||
|
||||
_, err = p.API.CreatePropertyField(newField)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create new field after deletion: %w", err)
|
||||
}
|
||||
|
||||
// Count should be back to 20
|
||||
count, err = p.API.CountPropertyFields(group.ID, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to count property fields after new creation: %w", err)
|
||||
}
|
||||
if count != 20 {
|
||||
return fmt.Errorf("expected 20 active fields after new creation (19 + 1), got %d", count)
|
||||
}
|
||||
|
||||
// Test that we can create fields for a different target
|
||||
differentTargetId := model.NewId()
|
||||
for i := 1; i <= 20; i++ {
|
||||
field := &model.PropertyField{
|
||||
GroupID: group.ID,
|
||||
Name: fmt.Sprintf("Different Target Field %d", i),
|
||||
Type: model.PropertyFieldTypeText,
|
||||
TargetType: "user",
|
||||
TargetID: differentTargetId,
|
||||
}
|
||||
|
||||
_, err := p.API.CreatePropertyField(field)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create property field %d for different target: %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Total count should now be 40 (20 for each target)
|
||||
totalCount, err = p.API.CountPropertyFields(group.ID, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to count total property fields: %w", err)
|
||||
}
|
||||
if totalCount != 40 {
|
||||
return fmt.Errorf("expected 40 total active fields, got %d", totalCount)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
plugin.ClientMain(&MyPlugin{})
|
||||
}
|
||||
`}, th.App, th.NewPluginAPI)
|
||||
defer tearDown()
|
||||
require.Len(t, activationErrors, 1)
|
||||
require.NoError(t, activationErrors[0])
|
||||
|
||||
// Clean up
|
||||
err2 := th.App.DisablePlugin(pluginIDs[0])
|
||||
|
||||
@@ -29,6 +29,18 @@ func (ps *PropertyService) CountActivePropertyFieldsForGroup(groupID string) (in
|
||||
return ps.fieldStore.CountForGroup(groupID, false)
|
||||
}
|
||||
|
||||
func (ps *PropertyService) CountAllPropertyFieldsForGroup(groupID string) (int64, error) {
|
||||
return ps.fieldStore.CountForGroup(groupID, true)
|
||||
}
|
||||
|
||||
func (ps *PropertyService) CountActivePropertyFieldsForTarget(groupID, targetType, targetID string) (int64, error) {
|
||||
return ps.fieldStore.CountForTarget(groupID, targetType, targetID, false)
|
||||
}
|
||||
|
||||
func (ps *PropertyService) CountAllPropertyFieldsForTarget(groupID, targetType, targetID string) (int64, error) {
|
||||
return ps.fieldStore.CountForTarget(groupID, targetType, targetID, true)
|
||||
}
|
||||
|
||||
func (ps *PropertyService) SearchPropertyFields(groupID, targetID string, opts model.PropertyFieldSearchOpts) ([]*model.PropertyField, error) {
|
||||
// groupID and targetID are part of the search method signature to
|
||||
// incentivize the use of the database indexes in searches
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package properties
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mattermost/mattermost/server/public/model"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// mockPropertyFieldStore is a mock implementation of PropertyFieldStore interface
|
||||
type mockPropertyFieldStore struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
func (m *mockPropertyFieldStore) Create(field *model.PropertyField) (*model.PropertyField, error) {
|
||||
args := m.Called(field)
|
||||
return args.Get(0).(*model.PropertyField), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *mockPropertyFieldStore) Get(groupID, id string) (*model.PropertyField, error) {
|
||||
args := m.Called(groupID, id)
|
||||
return args.Get(0).(*model.PropertyField), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *mockPropertyFieldStore) GetMany(groupID string, ids []string) ([]*model.PropertyField, error) {
|
||||
args := m.Called(groupID, ids)
|
||||
return args.Get(0).([]*model.PropertyField), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *mockPropertyFieldStore) GetFieldByName(groupID, targetID, name string) (*model.PropertyField, error) {
|
||||
args := m.Called(groupID, targetID, name)
|
||||
return args.Get(0).(*model.PropertyField), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *mockPropertyFieldStore) CountForGroup(groupID string, includeDeleted bool) (int64, error) {
|
||||
args := m.Called(groupID, includeDeleted)
|
||||
return args.Get(0).(int64), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *mockPropertyFieldStore) CountForTarget(groupID, targetType, targetID string, includeDeleted bool) (int64, error) {
|
||||
args := m.Called(groupID, targetType, targetID, includeDeleted)
|
||||
return args.Get(0).(int64), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *mockPropertyFieldStore) SearchPropertyFields(opts model.PropertyFieldSearchOpts) ([]*model.PropertyField, error) {
|
||||
args := m.Called(opts)
|
||||
return args.Get(0).([]*model.PropertyField), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *mockPropertyFieldStore) Update(groupID string, fields []*model.PropertyField) ([]*model.PropertyField, error) {
|
||||
args := m.Called(groupID, fields)
|
||||
return args.Get(0).([]*model.PropertyField), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *mockPropertyFieldStore) Delete(groupID string, id string) error {
|
||||
args := m.Called(groupID, id)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
func TestPropertyService_CountActivePropertyFieldsForGroup(t *testing.T) {
|
||||
t.Run("should return count of active property fields for a group", func(t *testing.T) {
|
||||
// Create a mock store
|
||||
mockStore := &mockPropertyFieldStore{}
|
||||
mockStore.On("CountForGroup", "group1", false).Return(int64(5), nil)
|
||||
|
||||
// Create the service
|
||||
service := &PropertyService{
|
||||
fieldStore: mockStore,
|
||||
}
|
||||
|
||||
// Call the method
|
||||
count, err := service.CountActivePropertyFieldsForGroup("group1")
|
||||
|
||||
// Verify the results
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(5), count)
|
||||
mockStore.AssertExpectations(t)
|
||||
})
|
||||
|
||||
t.Run("should return error when store fails", func(t *testing.T) {
|
||||
// Create a mock store
|
||||
mockStore := &mockPropertyFieldStore{}
|
||||
mockStore.On("CountForGroup", "group1", false).Return(int64(0), model.NewAppError("test", "test.error", nil, "", 500))
|
||||
|
||||
// Create the service
|
||||
service := &PropertyService{
|
||||
fieldStore: mockStore,
|
||||
}
|
||||
|
||||
// Call the method
|
||||
count, err := service.CountActivePropertyFieldsForGroup("group1")
|
||||
|
||||
// Verify the results
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, int64(0), count)
|
||||
mockStore.AssertExpectations(t)
|
||||
})
|
||||
|
||||
t.Run("should return 0 for empty group", func(t *testing.T) {
|
||||
// Create a mock store
|
||||
mockStore := &mockPropertyFieldStore{}
|
||||
mockStore.On("CountForGroup", "empty-group", false).Return(int64(0), nil)
|
||||
|
||||
// Create the service
|
||||
service := &PropertyService{
|
||||
fieldStore: mockStore,
|
||||
}
|
||||
|
||||
// Call the method
|
||||
count, err := service.CountActivePropertyFieldsForGroup("empty-group")
|
||||
|
||||
// Verify the results
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(0), count)
|
||||
mockStore.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPropertyService_CountAllPropertyFieldsForGroup(t *testing.T) {
|
||||
t.Run("should return count of all property fields including deleted for a group", func(t *testing.T) {
|
||||
// Create a mock store
|
||||
mockStore := &mockPropertyFieldStore{}
|
||||
mockStore.On("CountForGroup", "group1", true).Return(int64(8), nil)
|
||||
|
||||
// Create the service
|
||||
service := &PropertyService{
|
||||
fieldStore: mockStore,
|
||||
}
|
||||
|
||||
// Call the method
|
||||
count, err := service.CountAllPropertyFieldsForGroup("group1")
|
||||
|
||||
// Verify the results
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(8), count)
|
||||
mockStore.AssertExpectations(t)
|
||||
})
|
||||
|
||||
t.Run("should return error when store fails", func(t *testing.T) {
|
||||
// Create a mock store
|
||||
mockStore := &mockPropertyFieldStore{}
|
||||
mockStore.On("CountForGroup", "group1", true).Return(int64(0), model.NewAppError("test", "test.error", nil, "", 500))
|
||||
|
||||
// Create the service
|
||||
service := &PropertyService{
|
||||
fieldStore: mockStore,
|
||||
}
|
||||
|
||||
// Call the method
|
||||
count, err := service.CountAllPropertyFieldsForGroup("group1")
|
||||
|
||||
// Verify the results
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, int64(0), count)
|
||||
mockStore.AssertExpectations(t)
|
||||
})
|
||||
|
||||
t.Run("should return 0 for empty group", func(t *testing.T) {
|
||||
// Create a mock store
|
||||
mockStore := &mockPropertyFieldStore{}
|
||||
mockStore.On("CountForGroup", "empty-group", true).Return(int64(0), nil)
|
||||
|
||||
// Create the service
|
||||
service := &PropertyService{
|
||||
fieldStore: mockStore,
|
||||
}
|
||||
|
||||
// Call the method
|
||||
count, err := service.CountAllPropertyFieldsForGroup("empty-group")
|
||||
|
||||
// Verify the results
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(0), count)
|
||||
mockStore.AssertExpectations(t)
|
||||
})
|
||||
|
||||
t.Run("should return higher count than active fields when there are deleted fields", func(t *testing.T) {
|
||||
// Create a mock store
|
||||
mockStore := &mockPropertyFieldStore{}
|
||||
mockStore.On("CountForGroup", "group1", false).Return(int64(5), nil)
|
||||
mockStore.On("CountForGroup", "group1", true).Return(int64(8), nil)
|
||||
|
||||
// Create the service
|
||||
service := &PropertyService{
|
||||
fieldStore: mockStore,
|
||||
}
|
||||
|
||||
// Call both methods
|
||||
activeCount, err := service.CountActivePropertyFieldsForGroup("group1")
|
||||
require.NoError(t, err)
|
||||
|
||||
allCount, err := service.CountAllPropertyFieldsForGroup("group1")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify that all count is higher than active count
|
||||
assert.Equal(t, int64(5), activeCount)
|
||||
assert.Equal(t, int64(8), allCount)
|
||||
assert.True(t, allCount > activeCount)
|
||||
mockStore.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
@@ -118,6 +118,25 @@ func (s *SqlPropertyFieldStore) CountForGroup(groupID string, includeDeleted boo
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (s *SqlPropertyFieldStore) CountForTarget(groupID, targetType, targetID string, includeDeleted bool) (int64, error) {
|
||||
var count int64
|
||||
builder := s.getQueryBuilder().
|
||||
Select("COUNT(id)").
|
||||
From("PropertyFields").
|
||||
Where(sq.Eq{"GroupID": groupID}).
|
||||
Where(sq.Eq{"TargetType": targetType}).
|
||||
Where(sq.Eq{"TargetID": targetID})
|
||||
|
||||
if !includeDeleted {
|
||||
builder = builder.Where(sq.Eq{"DeleteAt": 0})
|
||||
}
|
||||
|
||||
if err := s.GetReplica().GetBuilder(&count, builder); err != nil {
|
||||
return int64(0), errors.Wrap(err, "failed to count property fields for target")
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (s *SqlPropertyFieldStore) SearchPropertyFields(opts model.PropertyFieldSearchOpts) ([]*model.PropertyField, error) {
|
||||
if err := opts.Cursor.IsValid(); err != nil {
|
||||
return nil, fmt.Errorf("cursor is invalid: %w", err)
|
||||
|
||||
@@ -1108,6 +1108,7 @@ type PropertyFieldStore interface {
|
||||
GetMany(groupID string, ids []string) ([]*model.PropertyField, error)
|
||||
GetFieldByName(groupID, targetID, name string) (*model.PropertyField, error)
|
||||
CountForGroup(groupID string, includeDeleted bool) (int64, error)
|
||||
CountForTarget(groupID, targetType, targetID string, includeDeleted bool) (int64, error)
|
||||
SearchPropertyFields(opts model.PropertyFieldSearchOpts) ([]*model.PropertyField, error)
|
||||
Update(groupID string, fields []*model.PropertyField) ([]*model.PropertyField, error)
|
||||
Delete(groupID string, id string) error
|
||||
|
||||
@@ -42,6 +42,34 @@ func (_m *PropertyFieldStore) CountForGroup(groupID string, includeDeleted bool)
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// CountForTarget provides a mock function with given fields: groupID, targetType, targetID, includeDeleted
|
||||
func (_m *PropertyFieldStore) CountForTarget(groupID string, targetType string, targetID string, includeDeleted bool) (int64, error) {
|
||||
ret := _m.Called(groupID, targetType, targetID, includeDeleted)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for CountForTarget")
|
||||
}
|
||||
|
||||
var r0 int64
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(string, string, string, bool) (int64, error)); ok {
|
||||
return rf(groupID, targetType, targetID, includeDeleted)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(string, string, string, bool) int64); ok {
|
||||
r0 = rf(groupID, targetType, targetID, includeDeleted)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int64)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(string, string, string, bool) error); ok {
|
||||
r1 = rf(groupID, targetType, targetID, includeDeleted)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Create provides a mock function with given fields: field
|
||||
func (_m *PropertyFieldStore) Create(field *model.PropertyField) (*model.PropertyField, error) {
|
||||
ret := _m.Called(field)
|
||||
|
||||
@@ -1451,6 +1451,18 @@ type API interface {
|
||||
// Minimum server version: 10.10
|
||||
SearchPropertyFields(groupID, targetID string, opts model.PropertyFieldSearchOpts) ([]*model.PropertyField, error)
|
||||
|
||||
// CountPropertyFields counts property fields for a group.
|
||||
//
|
||||
// @tag PropertyField
|
||||
// Minimum server version: 11.0
|
||||
CountPropertyFields(groupID string, includeDeleted bool) (int64, error)
|
||||
|
||||
// CountPropertyFieldsForTarget counts property fields for a specific target.
|
||||
//
|
||||
// @tag PropertyField
|
||||
// Minimum server version: 11.0
|
||||
CountPropertyFieldsForTarget(groupID, targetType, targetID string, includeDeleted bool) (int64, error)
|
||||
|
||||
// CreatePropertyValue creates a new property value.
|
||||
//
|
||||
// @tag PropertyValue
|
||||
|
||||
@@ -1541,6 +1541,20 @@ func (api *apiTimerLayer) SearchPropertyFields(groupID, targetID string, opts mo
|
||||
return _returnsA, _returnsB
|
||||
}
|
||||
|
||||
func (api *apiTimerLayer) CountPropertyFields(groupID string, includeDeleted bool) (int64, error) {
|
||||
startTime := timePkg.Now()
|
||||
_returnsA, _returnsB := api.apiImpl.CountPropertyFields(groupID, includeDeleted)
|
||||
api.recordTime(startTime, "CountPropertyFields", _returnsB == nil)
|
||||
return _returnsA, _returnsB
|
||||
}
|
||||
|
||||
func (api *apiTimerLayer) CountPropertyFieldsForTarget(groupID, targetType, targetID string, includeDeleted bool) (int64, error) {
|
||||
startTime := timePkg.Now()
|
||||
_returnsA, _returnsB := api.apiImpl.CountPropertyFieldsForTarget(groupID, targetType, targetID, includeDeleted)
|
||||
api.recordTime(startTime, "CountPropertyFieldsForTarget", _returnsB == nil)
|
||||
return _returnsA, _returnsB
|
||||
}
|
||||
|
||||
func (api *apiTimerLayer) CreatePropertyValue(value *model.PropertyValue) (*model.PropertyValue, error) {
|
||||
startTime := timePkg.Now()
|
||||
_returnsA, _returnsB := api.apiImpl.CreatePropertyValue(value)
|
||||
|
||||
@@ -7389,6 +7389,70 @@ func (s *apiRPCServer) SearchPropertyFields(args *Z_SearchPropertyFieldsArgs, re
|
||||
return nil
|
||||
}
|
||||
|
||||
type Z_CountPropertyFieldsArgs struct {
|
||||
A string
|
||||
B bool
|
||||
}
|
||||
|
||||
type Z_CountPropertyFieldsReturns struct {
|
||||
A int64
|
||||
B error
|
||||
}
|
||||
|
||||
func (g *apiRPCClient) CountPropertyFields(groupID string, includeDeleted bool) (int64, error) {
|
||||
_args := &Z_CountPropertyFieldsArgs{groupID, includeDeleted}
|
||||
_returns := &Z_CountPropertyFieldsReturns{}
|
||||
if err := g.client.Call("Plugin.CountPropertyFields", _args, _returns); err != nil {
|
||||
log.Printf("RPC call to CountPropertyFields API failed: %s", err.Error())
|
||||
}
|
||||
return _returns.A, _returns.B
|
||||
}
|
||||
|
||||
func (s *apiRPCServer) CountPropertyFields(args *Z_CountPropertyFieldsArgs, returns *Z_CountPropertyFieldsReturns) error {
|
||||
if hook, ok := s.impl.(interface {
|
||||
CountPropertyFields(groupID string, includeDeleted bool) (int64, error)
|
||||
}); ok {
|
||||
returns.A, returns.B = hook.CountPropertyFields(args.A, args.B)
|
||||
returns.B = encodableError(returns.B)
|
||||
} else {
|
||||
return encodableError(fmt.Errorf("API CountPropertyFields called but not implemented."))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Z_CountPropertyFieldsForTargetArgs struct {
|
||||
A string
|
||||
B string
|
||||
C string
|
||||
D bool
|
||||
}
|
||||
|
||||
type Z_CountPropertyFieldsForTargetReturns struct {
|
||||
A int64
|
||||
B error
|
||||
}
|
||||
|
||||
func (g *apiRPCClient) CountPropertyFieldsForTarget(groupID, targetType, targetID string, includeDeleted bool) (int64, error) {
|
||||
_args := &Z_CountPropertyFieldsForTargetArgs{groupID, targetType, targetID, includeDeleted}
|
||||
_returns := &Z_CountPropertyFieldsForTargetReturns{}
|
||||
if err := g.client.Call("Plugin.CountPropertyFieldsForTarget", _args, _returns); err != nil {
|
||||
log.Printf("RPC call to CountPropertyFieldsForTarget API failed: %s", err.Error())
|
||||
}
|
||||
return _returns.A, _returns.B
|
||||
}
|
||||
|
||||
func (s *apiRPCServer) CountPropertyFieldsForTarget(args *Z_CountPropertyFieldsForTargetArgs, returns *Z_CountPropertyFieldsForTargetReturns) error {
|
||||
if hook, ok := s.impl.(interface {
|
||||
CountPropertyFieldsForTarget(groupID, targetType, targetID string, includeDeleted bool) (int64, error)
|
||||
}); ok {
|
||||
returns.A, returns.B = hook.CountPropertyFieldsForTarget(args.A, args.B, args.C, args.D)
|
||||
returns.B = encodableError(returns.B)
|
||||
} else {
|
||||
return encodableError(fmt.Errorf("API CountPropertyFieldsForTarget called but not implemented."))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Z_CreatePropertyValueArgs struct {
|
||||
A *model.PropertyValue
|
||||
}
|
||||
|
||||
@@ -148,6 +148,62 @@ func (_m *API) CopyFileInfos(userID string, fileIds []string) ([]string, *model.
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// CountPropertyFields provides a mock function with given fields: groupID, includeDeleted
|
||||
func (_m *API) CountPropertyFields(groupID string, includeDeleted bool) (int64, error) {
|
||||
ret := _m.Called(groupID, includeDeleted)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for CountPropertyFields")
|
||||
}
|
||||
|
||||
var r0 int64
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(string, bool) (int64, error)); ok {
|
||||
return rf(groupID, includeDeleted)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(string, bool) int64); ok {
|
||||
r0 = rf(groupID, includeDeleted)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int64)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(string, bool) error); ok {
|
||||
r1 = rf(groupID, includeDeleted)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// CountPropertyFieldsForTarget provides a mock function with given fields: groupID, targetType, targetID, includeDeleted
|
||||
func (_m *API) CountPropertyFieldsForTarget(groupID string, targetType string, targetID string, includeDeleted bool) (int64, error) {
|
||||
ret := _m.Called(groupID, targetType, targetID, includeDeleted)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for CountPropertyFieldsForTarget")
|
||||
}
|
||||
|
||||
var r0 int64
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(string, string, string, bool) (int64, error)); ok {
|
||||
return rf(groupID, targetType, targetID, includeDeleted)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(string, string, string, bool) int64); ok {
|
||||
r0 = rf(groupID, targetType, targetID, includeDeleted)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int64)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(string, string, string, bool) error); ok {
|
||||
r1 = rf(groupID, targetType, targetID, includeDeleted)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// CreateBot provides a mock function with given fields: bot
|
||||
func (_m *API) CreateBot(bot *model.Bot) (*model.Bot, *model.AppError) {
|
||||
ret := _m.Called(bot)
|
||||
|
||||
@@ -52,6 +52,20 @@ func (p *PropertyService) SearchPropertyFields(groupID, targetID string, opts mo
|
||||
return p.api.SearchPropertyFields(groupID, targetID, opts)
|
||||
}
|
||||
|
||||
// CountPropertyFields counts property fields for a group.
|
||||
//
|
||||
// Minimum server version: 11.0
|
||||
func (p *PropertyService) CountPropertyFields(groupID string, includeDeleted bool) (int64, error) {
|
||||
return p.api.CountPropertyFields(groupID, includeDeleted)
|
||||
}
|
||||
|
||||
// CountPropertyFieldsForTarget counts property fields for a specific target.
|
||||
//
|
||||
// Minimum server version: 11.0
|
||||
func (p *PropertyService) CountPropertyFieldsForTarget(groupID, targetType, targetID string, includeDeleted bool) (int64, error) {
|
||||
return p.api.CountPropertyFieldsForTarget(groupID, targetType, targetID, includeDeleted)
|
||||
}
|
||||
|
||||
// CreatePropertyValue creates a new property value.
|
||||
//
|
||||
// Minimum server version: 10.10
|
||||
|
||||
@@ -172,6 +172,82 @@ func TestPropertyFieldAPI(t *testing.T) {
|
||||
assert.Equal(t, fields, result)
|
||||
api.AssertExpectations(t)
|
||||
})
|
||||
|
||||
t.Run("CountPropertyFields", func(t *testing.T) {
|
||||
// Setup
|
||||
api := &plugintest.API{}
|
||||
|
||||
// Mock the API call for active fields only
|
||||
api.On("CountPropertyFields", "group1", false).Return(int64(5), nil)
|
||||
|
||||
// Create the client
|
||||
client := NewClient(api, nil)
|
||||
|
||||
// Call the method
|
||||
result, err := client.Property.CountPropertyFields("group1", false)
|
||||
|
||||
// Verify the results
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(5), result)
|
||||
api.AssertExpectations(t)
|
||||
})
|
||||
|
||||
t.Run("CountPropertyFields with deleted", func(t *testing.T) {
|
||||
// Setup
|
||||
api := &plugintest.API{}
|
||||
|
||||
// Mock the API call for all fields including deleted
|
||||
api.On("CountPropertyFields", "group1", true).Return(int64(8), nil)
|
||||
|
||||
// Create the client
|
||||
client := NewClient(api, nil)
|
||||
|
||||
// Call the method
|
||||
result, err := client.Property.CountPropertyFields("group1", true)
|
||||
|
||||
// Verify the results
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(8), result)
|
||||
api.AssertExpectations(t)
|
||||
})
|
||||
|
||||
t.Run("CountPropertyFieldsForTarget", func(t *testing.T) {
|
||||
// Setup
|
||||
api := &plugintest.API{}
|
||||
|
||||
// Mock the API call for active fields for a specific target
|
||||
api.On("CountPropertyFieldsForTarget", "group1", "user", "target123", false).Return(int64(3), nil)
|
||||
|
||||
// Create the client
|
||||
client := NewClient(api, nil)
|
||||
|
||||
// Call the method
|
||||
result, err := client.Property.CountPropertyFieldsForTarget("group1", "user", "target123", false)
|
||||
|
||||
// Verify the results
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(3), result)
|
||||
api.AssertExpectations(t)
|
||||
})
|
||||
|
||||
t.Run("CountPropertyFieldsForTarget with deleted", func(t *testing.T) {
|
||||
// Setup
|
||||
api := &plugintest.API{}
|
||||
|
||||
// Mock the API call for all fields including deleted for a specific target
|
||||
api.On("CountPropertyFieldsForTarget", "group1", "user", "target123", true).Return(int64(5), nil)
|
||||
|
||||
// Create the client
|
||||
client := NewClient(api, nil)
|
||||
|
||||
// Call the method
|
||||
result, err := client.Property.CountPropertyFieldsForTarget("group1", "user", "target123", true)
|
||||
|
||||
// Verify the results
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(5), result)
|
||||
api.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPropertyValueAPI(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user