influxdb/authorizer/annotation_test.go

726 lines
19 KiB
Go

package authorizer_test
import (
"context"
"fmt"
"testing"
"github.com/golang/mock/gomock"
"github.com/influxdata/influxdb/v2"
"github.com/influxdata/influxdb/v2/authorizer"
influxdbcontext "github.com/influxdata/influxdb/v2/context"
"github.com/influxdata/influxdb/v2/kit/platform"
"github.com/influxdata/influxdb/v2/kit/platform/errors"
"github.com/influxdata/influxdb/v2/mock"
influxdbtesting "github.com/influxdata/influxdb/v2/testing"
"github.com/stretchr/testify/require"
)
var (
annOrgID1 = influxdbtesting.IDPtr(1)
annOrgID2 = influxdbtesting.IDPtr(10)
rID = influxdbtesting.IDPtr(2)
)
func Test_CreateAnnotations(t *testing.T) {
t.Parallel()
tests := []struct {
name string
wantRet []influxdb.AnnotationEvent
wantErr error
}{
{
"authorized to create annotation(s) with the specified org",
[]influxdb.AnnotationEvent{{ID: *rID}},
nil,
},
{
"not authorized to create annotation(s) with the specified org",
nil,
&errors.Error{
Msg: fmt.Sprintf("write:orgs/%s/annotations is unauthorized", annOrgID1),
Code: errors.EUnauthorized,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctrlr := gomock.NewController(t)
svc := mock.NewMockAnnotationService(ctrlr)
s := authorizer.NewAnnotationService(svc)
var perm influxdb.Permission
if tt.wantErr == nil {
perm = newTestAnnotationsPermission(influxdb.WriteAction, annOrgID1)
svc.EXPECT().
CreateAnnotations(gomock.Any(), *annOrgID1, []influxdb.AnnotationCreate{{}}).
Return(tt.wantRet, nil)
} else {
perm = newTestAnnotationsPermission(influxdb.ReadAction, annOrgID1)
}
ctx := influxdbcontext.SetAuthorizer(context.Background(), mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
got, err := s.CreateAnnotations(ctx, *annOrgID1, []influxdb.AnnotationCreate{{}})
require.Equal(t, tt.wantErr, err)
require.Equal(t, tt.wantRet, got)
})
}
}
func Test_ListAnnotations(t *testing.T) {
t.Parallel()
tests := []struct {
name string
wantRet []influxdb.StoredAnnotation
wantErr error
}{
{
"authorized to list annotations for the specified org",
[]influxdb.StoredAnnotation{},
nil,
},
{
"not authorized to list annotations for the specified org",
nil,
&errors.Error{
Msg: fmt.Sprintf("read:orgs/%s/annotations is unauthorized", annOrgID1),
Code: errors.EUnauthorized,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctrlr := gomock.NewController(t)
svc := mock.NewMockAnnotationService(ctrlr)
s := authorizer.NewAnnotationService(svc)
var perm influxdb.Permission
if tt.wantErr == nil {
perm = newTestAnnotationsPermission(influxdb.ReadAction, annOrgID1)
svc.EXPECT().
ListAnnotations(gomock.Any(), *annOrgID1, influxdb.AnnotationListFilter{}).
Return(tt.wantRet, nil)
}
ctx := influxdbcontext.SetAuthorizer(context.Background(), mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
got, err := s.ListAnnotations(ctx, *annOrgID1, influxdb.AnnotationListFilter{})
require.Equal(t, tt.wantErr, err)
require.Equal(t, tt.wantRet, got)
})
}
}
func Test_GetAnnotation(t *testing.T) {
t.Parallel()
tests := []struct {
name string
permissionOrg *platform.ID
wantRet *influxdb.StoredAnnotation
wantErr error
}{
{
"authorized to access annotation by id",
annOrgID1,
&influxdb.StoredAnnotation{
ID: *rID,
OrgID: *annOrgID1,
},
nil,
},
{
"not authorized to access annotation by id",
annOrgID2,
nil,
&errors.Error{
Msg: fmt.Sprintf("read:orgs/%s/annotations/%s is unauthorized", annOrgID1, rID),
Code: errors.EUnauthorized,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctrlr := gomock.NewController(t)
svc := mock.NewMockAnnotationService(ctrlr)
s := authorizer.NewAnnotationService(svc)
svc.EXPECT().
GetAnnotation(gomock.Any(), *rID).
Return(&influxdb.StoredAnnotation{
ID: *rID,
OrgID: *annOrgID1,
}, nil)
perm := newTestAnnotationsPermission(influxdb.ReadAction, tt.permissionOrg)
ctx := context.Background()
ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
got, err := s.GetAnnotation(ctx, *rID)
require.Equal(t, tt.wantErr, err)
require.Equal(t, tt.wantRet, got)
})
}
}
func Test_DeleteAnnotations(t *testing.T) {
t.Parallel()
tests := []struct {
name string
wantErr error
}{
{
"authorized to delete annotations with the specified org",
nil,
},
{
"not authorized to delete annotations with the specified org",
&errors.Error{
Msg: fmt.Sprintf("write:orgs/%s/annotations is unauthorized", annOrgID1),
Code: errors.EUnauthorized,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctrlr := gomock.NewController(t)
svc := mock.NewMockAnnotationService(ctrlr)
s := authorizer.NewAnnotationService(svc)
var perm influxdb.Permission
if tt.wantErr == nil {
perm = newTestAnnotationsPermission(influxdb.WriteAction, annOrgID1)
svc.EXPECT().
DeleteAnnotations(gomock.Any(), *annOrgID1, influxdb.AnnotationDeleteFilter{}).
Return(nil)
} else {
perm = newTestAnnotationsPermission(influxdb.ReadAction, annOrgID1)
}
ctx := influxdbcontext.SetAuthorizer(context.Background(), mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
err := s.DeleteAnnotations(ctx, *annOrgID1, influxdb.AnnotationDeleteFilter{})
require.Equal(t, tt.wantErr, err)
})
}
}
func Test_DeleteAnnotation(t *testing.T) {
t.Parallel()
tests := []struct {
name string
permissionOrg *platform.ID
wantErr error
}{
{
"authorized to delete annotation by id",
annOrgID1,
nil,
},
{
"not authorized to delete annotation by id",
annOrgID2,
&errors.Error{
Msg: fmt.Sprintf("write:orgs/%s/annotations/%s is unauthorized", annOrgID1, rID),
Code: errors.EUnauthorized,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctrlr := gomock.NewController(t)
svc := mock.NewMockAnnotationService(ctrlr)
s := authorizer.NewAnnotationService(svc)
svc.EXPECT().
GetAnnotation(gomock.Any(), *rID).
Return(&influxdb.StoredAnnotation{
ID: *rID,
OrgID: *annOrgID1,
}, nil)
perm := newTestAnnotationsPermission(influxdb.WriteAction, tt.permissionOrg)
if tt.wantErr == nil {
svc.EXPECT().
DeleteAnnotation(gomock.Any(), *rID).
Return(nil)
}
ctx := context.Background()
ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
err := s.DeleteAnnotation(ctx, *rID)
require.Equal(t, tt.wantErr, err)
})
}
}
func Test_UpdateAnnotation(t *testing.T) {
t.Parallel()
tests := []struct {
name string
permissionOrg *platform.ID
wantRet *influxdb.AnnotationEvent
wantErr error
}{
{
"authorized to update annotation by id",
annOrgID1,
&influxdb.AnnotationEvent{},
nil,
},
{
"not authorized to update annotation by id",
annOrgID2,
nil,
&errors.Error{
Msg: fmt.Sprintf("write:orgs/%s/annotations/%s is unauthorized", annOrgID1, rID),
Code: errors.EUnauthorized,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctrlr := gomock.NewController(t)
svc := mock.NewMockAnnotationService(ctrlr)
s := authorizer.NewAnnotationService(svc)
svc.EXPECT().
GetAnnotation(gomock.Any(), *rID).
Return(&influxdb.StoredAnnotation{
ID: *rID,
OrgID: *annOrgID1,
}, nil)
perm := newTestAnnotationsPermission(influxdb.WriteAction, tt.permissionOrg)
if tt.wantErr == nil {
svc.EXPECT().
UpdateAnnotation(gomock.Any(), *rID, influxdb.AnnotationCreate{}).
Return(tt.wantRet, nil)
}
ctx := context.Background()
ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
got, err := s.UpdateAnnotation(ctx, *rID, influxdb.AnnotationCreate{})
require.Equal(t, tt.wantErr, err)
require.Equal(t, tt.wantRet, got)
})
}
}
func Test_ListStreams(t *testing.T) {
t.Parallel()
tests := []struct {
name string
wantRet []influxdb.StoredStream
wantErr error
}{
{
"authorized to list streams for the specified org",
[]influxdb.StoredStream{},
nil,
},
{
"not authorized to list streams for the specified org",
nil,
&errors.Error{
Msg: fmt.Sprintf("read:orgs/%s/annotations is unauthorized", annOrgID1),
Code: errors.EUnauthorized,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctrlr := gomock.NewController(t)
svc := mock.NewMockAnnotationService(ctrlr)
s := authorizer.NewAnnotationService(svc)
var perm influxdb.Permission
if tt.wantErr == nil {
perm = newTestAnnotationsPermission(influxdb.ReadAction, annOrgID1)
svc.EXPECT().
ListStreams(gomock.Any(), *annOrgID1, influxdb.StreamListFilter{}).
Return(tt.wantRet, nil)
}
ctx := influxdbcontext.SetAuthorizer(context.Background(), mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
got, err := s.ListStreams(ctx, *annOrgID1, influxdb.StreamListFilter{})
require.Equal(t, tt.wantErr, err)
require.Equal(t, tt.wantRet, got)
})
}
}
func Test_GetStream(t *testing.T) {
t.Parallel()
tests := []struct {
name string
permissionOrg *platform.ID
wantRet *influxdb.StoredStream
wantErr error
}{
{
"authorized to access stream by id",
annOrgID1,
&influxdb.StoredStream{
ID: *rID,
OrgID: *annOrgID1,
},
nil,
},
{
"not authorized to access stream by id",
annOrgID2,
nil,
&errors.Error{
Msg: fmt.Sprintf("read:orgs/%s/annotations/%s is unauthorized", annOrgID1, rID),
Code: errors.EUnauthorized,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctrlr := gomock.NewController(t)
svc := mock.NewMockAnnotationService(ctrlr)
s := authorizer.NewAnnotationService(svc)
svc.EXPECT().
GetStream(gomock.Any(), *rID).
Return(&influxdb.StoredStream{
ID: *rID,
OrgID: *annOrgID1,
}, nil)
perm := newTestAnnotationsPermission(influxdb.ReadAction, tt.permissionOrg)
ctx := context.Background()
ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
got, err := s.GetStream(ctx, *rID)
require.Equal(t, tt.wantErr, err)
require.Equal(t, tt.wantRet, got)
})
}
}
func Test_CreateOrUpdateStream(t *testing.T) {
t.Parallel()
var (
testStreamName = "test stream"
testStream = influxdb.Stream{
Name: testStreamName,
}
)
t.Run("updating a stream", func(t *testing.T) {
tests := []struct {
name string
permissionOrg *platform.ID
existingStreams []influxdb.StoredStream
getStreamRet *influxdb.StoredStream
wantRet *influxdb.ReadStream
wantErr error
}{
{
"authorized to update an existing stream",
annOrgID1,
[]influxdb.StoredStream{{ID: *rID, OrgID: *annOrgID1}},
&influxdb.StoredStream{ID: *rID, OrgID: *annOrgID1},
&influxdb.ReadStream{ID: *rID},
nil,
},
{
"not authorized to update an existing stream",
annOrgID2,
[]influxdb.StoredStream{{ID: *rID, OrgID: *annOrgID1}},
&influxdb.StoredStream{ID: *rID, OrgID: *annOrgID1},
nil,
&errors.Error{
Msg: fmt.Sprintf("write:orgs/%s/annotations/%s is unauthorized", annOrgID1, rID),
Code: errors.EUnauthorized,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctrlr := gomock.NewController(t)
svc := mock.NewMockAnnotationService(ctrlr)
s := authorizer.NewAnnotationService(svc)
svc.EXPECT().
ListStreams(gomock.Any(), *tt.permissionOrg, influxdb.StreamListFilter{
StreamIncludes: []string{testStreamName},
}).
Return(tt.existingStreams, nil)
svc.EXPECT().
GetStream(gomock.Any(), tt.existingStreams[0].ID).
Return(tt.getStreamRet, nil)
if tt.wantErr == nil {
svc.EXPECT().
UpdateStream(gomock.Any(), tt.existingStreams[0].ID, testStream).
Return(tt.wantRet, tt.wantErr)
}
perm := newTestAnnotationsPermission(influxdb.WriteAction, tt.permissionOrg)
ctx := influxdbcontext.SetAuthorizer(context.Background(), mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
got, err := s.CreateOrUpdateStream(ctx, *tt.permissionOrg, testStream)
require.Equal(t, tt.wantErr, err)
require.Equal(t, tt.wantRet, got)
})
}
})
t.Run("creating a stream", func(t *testing.T) {
tests := []struct {
name string
existingStreams []influxdb.StoredStream
wantRet *influxdb.ReadStream
wantErr error
}{
{
"authorized to create a stream with the specified org",
[]influxdb.StoredStream{},
&influxdb.ReadStream{},
nil,
},
{
"not authorized to create a stream with the specified org",
[]influxdb.StoredStream{},
nil,
&errors.Error{
Msg: fmt.Sprintf("write:orgs/%s/annotations is unauthorized", annOrgID1),
Code: errors.EUnauthorized,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctrlr := gomock.NewController(t)
svc := mock.NewMockAnnotationService(ctrlr)
s := authorizer.NewAnnotationService(svc)
svc.EXPECT().
ListStreams(gomock.Any(), *annOrgID1, influxdb.StreamListFilter{
StreamIncludes: []string{testStreamName},
}).
Return(tt.existingStreams, nil)
var perm influxdb.Permission
if tt.wantErr == nil {
perm = newTestAnnotationsPermission(influxdb.WriteAction, annOrgID1)
svc.EXPECT().
CreateOrUpdateStream(gomock.Any(), *annOrgID1, testStream).
Return(tt.wantRet, nil)
} else {
perm = newTestAnnotationsPermission(influxdb.ReadAction, annOrgID1)
}
ctx := influxdbcontext.SetAuthorizer(context.Background(), mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
got, err := s.CreateOrUpdateStream(ctx, *annOrgID1, testStream)
require.Equal(t, tt.wantErr, err)
require.Equal(t, tt.wantRet, got)
})
}
})
t.Run("stream list longer than 1 returns a server error", func(t *testing.T) {
ctrlr := gomock.NewController(t)
svc := mock.NewMockAnnotationService(ctrlr)
s := authorizer.NewAnnotationService(svc)
svc.EXPECT().
ListStreams(gomock.Any(), *annOrgID1, influxdb.StreamListFilter{
StreamIncludes: []string{testStreamName},
}).
Return([]influxdb.StoredStream{{Name: testStreamName}, {Name: testStreamName}}, nil)
wantErr := &errors.Error{
Code: errors.EInternal,
Msg: fmt.Sprintf("more than one stream named %q for org %q", testStreamName, annOrgID1),
}
got, err := s.CreateOrUpdateStream(context.Background(), *annOrgID1, testStream)
require.Nil(t, got)
require.Equal(t, err, wantErr)
})
}
func Test_UpdateStream(t *testing.T) {
t.Parallel()
tests := []struct {
name string
permissionOrg *platform.ID
wantRet *influxdb.ReadStream
wantErr error
}{
{
"authorized to update stream by id",
annOrgID1,
&influxdb.ReadStream{},
nil,
},
{
"not authorized to update stream by id",
annOrgID2,
nil,
&errors.Error{
Msg: fmt.Sprintf("write:orgs/%s/annotations/%s is unauthorized", annOrgID1, rID),
Code: errors.EUnauthorized,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctrlr := gomock.NewController(t)
svc := mock.NewMockAnnotationService(ctrlr)
s := authorizer.NewAnnotationService(svc)
svc.EXPECT().
GetStream(gomock.Any(), *rID).
Return(&influxdb.StoredStream{
ID: *rID,
OrgID: *annOrgID1,
}, nil)
perm := newTestAnnotationsPermission(influxdb.WriteAction, tt.permissionOrg)
if tt.wantErr == nil {
svc.EXPECT().
UpdateStream(gomock.Any(), *rID, influxdb.Stream{}).
Return(tt.wantRet, nil)
}
ctx := context.Background()
ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
got, err := s.UpdateStream(ctx, *rID, influxdb.Stream{})
require.Equal(t, tt.wantErr, err)
require.Equal(t, tt.wantRet, got)
})
}
}
func Test_DeleteStreams(t *testing.T) {
t.Parallel()
tests := []struct {
name string
wantErr error
}{
{
"authorized to delete streams with the specified org",
nil,
},
{
"not authorized to delete streams with the specified org",
&errors.Error{
Msg: fmt.Sprintf("write:orgs/%s/annotations is unauthorized", annOrgID1),
Code: errors.EUnauthorized,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctrlr := gomock.NewController(t)
svc := mock.NewMockAnnotationService(ctrlr)
s := authorizer.NewAnnotationService(svc)
var perm influxdb.Permission
if tt.wantErr == nil {
perm = newTestAnnotationsPermission(influxdb.WriteAction, annOrgID1)
svc.EXPECT().
DeleteStreams(gomock.Any(), *annOrgID1, influxdb.BasicStream{}).
Return(nil)
} else {
perm = newTestAnnotationsPermission(influxdb.ReadAction, annOrgID1)
}
ctx := influxdbcontext.SetAuthorizer(context.Background(), mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
err := s.DeleteStreams(ctx, *annOrgID1, influxdb.BasicStream{})
require.Equal(t, tt.wantErr, err)
})
}
}
func Test_DeleteStreamByID(t *testing.T) {
t.Parallel()
tests := []struct {
name string
permissionOrg *platform.ID
wantErr error
}{
{
"authorized to delete stream by id",
annOrgID1,
nil,
},
{
"not authorized to delete stream by id",
annOrgID2,
&errors.Error{
Msg: fmt.Sprintf("write:orgs/%s/annotations/%s is unauthorized", annOrgID1, rID),
Code: errors.EUnauthorized,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctrlr := gomock.NewController(t)
svc := mock.NewMockAnnotationService(ctrlr)
s := authorizer.NewAnnotationService(svc)
svc.EXPECT().
GetStream(gomock.Any(), *rID).
Return(&influxdb.StoredStream{
ID: *rID,
OrgID: *annOrgID1,
}, nil)
perm := newTestAnnotationsPermission(influxdb.WriteAction, tt.permissionOrg)
if tt.wantErr == nil {
svc.EXPECT().
DeleteStreamByID(gomock.Any(), *rID).
Return(nil)
}
ctx := context.Background()
ctx = influxdbcontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(false, []influxdb.Permission{perm}))
err := s.DeleteStreamByID(ctx, *rID)
require.Equal(t, tt.wantErr, err)
})
}
}
func newTestAnnotationsPermission(action influxdb.Action, orgID *platform.ID) influxdb.Permission {
return influxdb.Permission{
Action: action,
Resource: influxdb.Resource{
Type: influxdb.AnnotationsResourceType,
OrgID: orgID,
},
}
}