refactor: move helper functions for setting up test stores into testing package (#22347)

* Move tenant.Service unit tests into its package
* Delete the top-level TenantService interface now that it's not used.
* Move helper funcs for setting up test stores into testing pkg
* Delete duplicate implementations scattered through the codebase
* Move error assertions into store-creation helpers
pull/22358/head
Daniel Moran 2021-08-31 16:43:45 -04:00 committed by GitHub
parent 99cfbfe8cf
commit 01355a068c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 1006 additions and 1631 deletions

View File

@ -21,26 +21,11 @@ import (
"github.com/influxdata/httprouter" "github.com/influxdata/httprouter"
"github.com/influxdata/influxdb/v2" "github.com/influxdata/influxdb/v2"
icontext "github.com/influxdata/influxdb/v2/context" icontext "github.com/influxdata/influxdb/v2/context"
"github.com/influxdata/influxdb/v2/inmem"
"github.com/influxdata/influxdb/v2/kv"
"github.com/influxdata/influxdb/v2/kv/migration/all"
"github.com/influxdata/influxdb/v2/mock" "github.com/influxdata/influxdb/v2/mock"
itesting "github.com/influxdata/influxdb/v2/testing" itesting "github.com/influxdata/influxdb/v2/testing"
"go.uber.org/zap/zaptest" "go.uber.org/zap/zaptest"
) )
func NewTestInmemStore(t *testing.T) (kv.Store, func(), error) {
t.Helper()
store := inmem.NewKVStore()
if err := all.Up(context.Background(), zaptest.NewLogger(t), store); err != nil {
t.Fatal(err)
}
return store, func() {}, nil
}
func TestService_handlePostAuthorization(t *testing.T) { func TestService_handlePostAuthorization(t *testing.T) {
type fields struct { type fields struct {
AuthorizationService influxdb.AuthorizationService AuthorizationService influxdb.AuthorizationService
@ -163,11 +148,7 @@ func TestService_handlePostAuthorization(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
t.Helper() t.Helper()
s, _, err := NewTestInmemStore(t) s := itesting.NewTestInmemStore(t)
if err != nil {
t.Fatal(err)
}
storage, err := NewStore(s) storage, err := NewStore(s)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -738,11 +719,7 @@ func TestService_handleGetAuthorizations(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
t.Helper() t.Helper()
s, _, err := NewTestInmemStore(t) s := itesting.NewTestInmemStore(t)
if err != nil {
t.Fatal(err)
}
storage, err := NewStore(s) storage, err := NewStore(s)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

View File

@ -2,27 +2,17 @@ package authorization_test
import ( import (
"context" "context"
"errors"
"io/ioutil"
"os"
"testing" "testing"
"github.com/influxdata/influxdb/v2" "github.com/influxdata/influxdb/v2"
"github.com/influxdata/influxdb/v2/authorization" "github.com/influxdata/influxdb/v2/authorization"
"github.com/influxdata/influxdb/v2/bolt"
"github.com/influxdata/influxdb/v2/kv" "github.com/influxdata/influxdb/v2/kv"
"github.com/influxdata/influxdb/v2/kv/migration/all"
"github.com/influxdata/influxdb/v2/tenant" "github.com/influxdata/influxdb/v2/tenant"
influxdbtesting "github.com/influxdata/influxdb/v2/testing" influxdbtesting "github.com/influxdata/influxdb/v2/testing"
"go.uber.org/zap/zaptest"
) )
func initBoltAuthService(f influxdbtesting.AuthorizationFields, t *testing.T) (influxdb.AuthorizationService, string, func()) { func initBoltAuthService(f influxdbtesting.AuthorizationFields, t *testing.T) (influxdb.AuthorizationService, string, func()) {
s, closeBolt, err := NewTestBoltStore(t) s, closeBolt := influxdbtesting.NewTestBoltStore(t)
if err != nil {
t.Fatalf("failed to create new kv store: %v", err)
}
svc, closeSvc := initAuthService(s, f, t) svc, closeSvc := initAuthService(s, f, t)
return svc, "service_auth", func() { return svc, "service_auth", func() {
closeSvc() closeSvc()
@ -71,35 +61,6 @@ func initAuthService(s kv.Store, f influxdbtesting.AuthorizationFields, t *testi
} }
} }
func NewTestBoltStore(t *testing.T) (kv.Store, func(), error) {
f, err := ioutil.TempFile("", "influxdata-bolt-")
if err != nil {
return nil, nil, errors.New("unable to open temporary boltdb file")
}
f.Close()
path := f.Name()
ctx := context.Background()
logger := zaptest.NewLogger(t)
s := bolt.NewKVStore(logger, path, bolt.WithNoSync)
if err := s.Open(ctx); err != nil {
return nil, nil, err
}
if err := all.Up(ctx, logger, s); err != nil {
return nil, nil, err
}
close := func() {
s.Close()
os.Remove(path)
}
return s, close, nil
}
func TestBoltAuthService(t *testing.T) { func TestBoltAuthService(t *testing.T) {
t.Parallel() t.Parallel()
influxdbtesting.AuthorizationService(initBoltAuthService, t) influxdbtesting.AuthorizationService(initBoltAuthService, t)

View File

@ -2,17 +2,13 @@ package dashboards
import ( import (
"context" "context"
"errors"
"io/ioutil"
"os"
"testing" "testing"
"github.com/influxdata/influxdb/v2" "github.com/influxdata/influxdb/v2"
"github.com/influxdata/influxdb/v2/bolt"
dashboardtesting "github.com/influxdata/influxdb/v2/dashboards/testing" dashboardtesting "github.com/influxdata/influxdb/v2/dashboards/testing"
"github.com/influxdata/influxdb/v2/kv" "github.com/influxdata/influxdb/v2/kv"
"github.com/influxdata/influxdb/v2/kv/migration/all"
"github.com/influxdata/influxdb/v2/mock" "github.com/influxdata/influxdb/v2/mock"
itesting "github.com/influxdata/influxdb/v2/testing"
"go.uber.org/zap/zaptest" "go.uber.org/zap/zaptest"
) )
@ -21,11 +17,7 @@ func TestBoltDashboardService(t *testing.T) {
} }
func initBoltDashboardService(f dashboardtesting.DashboardFields, t *testing.T) (influxdb.DashboardService, string, func()) { func initBoltDashboardService(f dashboardtesting.DashboardFields, t *testing.T) (influxdb.DashboardService, string, func()) {
s, closeBolt, err := newTestBoltStore(t) s, closeBolt := itesting.NewTestBoltStore(t)
if err != nil {
t.Fatalf("failed to create new kv store: %v", err)
}
svc, op, closeSvc := initDashboardService(s, f, t) svc, op, closeSvc := initDashboardService(s, f, t)
return svc, op, func() { return svc, op, func() {
closeSvc() closeSvc()
@ -60,32 +52,3 @@ func initDashboardService(s kv.SchemaStore, f dashboardtesting.DashboardFields,
} }
} }
} }
func newTestBoltStore(t *testing.T) (kv.SchemaStore, func(), error) {
f, err := ioutil.TempFile("", "influxdata-bolt-")
if err != nil {
return nil, nil, errors.New("unable to open temporary boltdb file")
}
f.Close()
ctx := context.Background()
logger := zaptest.NewLogger(t)
path := f.Name()
// skip fsync to improve test performance
s := bolt.NewKVStore(logger, path, bolt.WithNoSync)
if err := s.Open(context.Background()); err != nil {
return nil, nil, err
}
if err := all.Up(ctx, logger, s); err != nil {
return nil, nil, err
}
close := func() {
s.Close()
os.Remove(path)
}
return s, close, nil
}

View File

@ -12,21 +12,19 @@ import (
"testing" "testing"
"time" "time"
"github.com/influxdata/influxdb/v2/kit/platform"
"github.com/influxdata/influxdb/v2/kit/platform/errors"
"github.com/go-chi/chi" "github.com/go-chi/chi"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/influxdata/influxdb/v2" "github.com/influxdata/influxdb/v2"
"github.com/influxdata/influxdb/v2/dashboards" "github.com/influxdata/influxdb/v2/dashboards"
dashboardstesting "github.com/influxdata/influxdb/v2/dashboards/testing" dashboardstesting "github.com/influxdata/influxdb/v2/dashboards/testing"
ihttp "github.com/influxdata/influxdb/v2/http" ihttp "github.com/influxdata/influxdb/v2/http"
"github.com/influxdata/influxdb/v2/inmem" "github.com/influxdata/influxdb/v2/kit/platform"
"github.com/influxdata/influxdb/v2/kit/platform/errors"
"github.com/influxdata/influxdb/v2/kv" "github.com/influxdata/influxdb/v2/kv"
"github.com/influxdata/influxdb/v2/kv/migration/all"
"github.com/influxdata/influxdb/v2/label" "github.com/influxdata/influxdb/v2/label"
"github.com/influxdata/influxdb/v2/mock" "github.com/influxdata/influxdb/v2/mock"
"github.com/influxdata/influxdb/v2/tenant" "github.com/influxdata/influxdb/v2/tenant"
itesting "github.com/influxdata/influxdb/v2/testing"
"github.com/yudai/gojsondiff" "github.com/yudai/gojsondiff"
"github.com/yudai/gojsondiff/formatter" "github.com/yudai/gojsondiff/formatter"
"go.uber.org/zap" "go.uber.org/zap"
@ -1788,7 +1786,7 @@ func Test_dashboardCellIDPath(t *testing.T) {
func initDashboardService(f dashboardstesting.DashboardFields, t *testing.T) (influxdb.DashboardService, string, func()) { func initDashboardService(f dashboardstesting.DashboardFields, t *testing.T) (influxdb.DashboardService, string, func()) {
t.Helper() t.Helper()
log := zaptest.NewLogger(t) log := zaptest.NewLogger(t)
store := newTestInmemStore(t) store := itesting.NewTestInmemStore(t)
kvsvc := kv.NewService(log, store, &mock.OrganizationService{}) kvsvc := kv.NewService(log, store, &mock.OrganizationService{})
kvsvc.IDGenerator = f.IDGenerator kvsvc.IDGenerator = f.IDGenerator
@ -2000,15 +1998,3 @@ func withLabelService(svc influxdb.LabelService) option {
d.labelService = svc d.labelService = svc
} }
} }
func newTestInmemStore(t *testing.T) kv.Store {
t.Helper()
store := inmem.NewKVStore()
if err := all.Up(context.Background(), zaptest.NewLogger(t), store); err != nil {
t.Fatal(err)
}
return store
}

View File

@ -4,8 +4,6 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"github.com/influxdata/influxdb/v2/kit/platform"
errors2 "github.com/influxdata/influxdb/v2/kit/platform/errors"
"io" "io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
@ -16,6 +14,8 @@ import (
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/influxdata/influxdb/v2" "github.com/influxdata/influxdb/v2"
"github.com/influxdata/influxdb/v2/dbrp" "github.com/influxdata/influxdb/v2/dbrp"
"github.com/influxdata/influxdb/v2/kit/platform"
errors2 "github.com/influxdata/influxdb/v2/kit/platform/errors"
"github.com/influxdata/influxdb/v2/mock" "github.com/influxdata/influxdb/v2/mock"
influxdbtesting "github.com/influxdata/influxdb/v2/testing" influxdbtesting "github.com/influxdata/influxdb/v2/testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -38,11 +38,7 @@ func initHttpService(t *testing.T) (influxdb.DBRPMappingService, *httptest.Serve
}, },
} }
s, closeS, err := NewTestBoltStore(t) s, closeS := influxdbtesting.NewTestBoltStore(t)
if err != nil {
t.Fatal(err)
}
svc := dbrp.NewService(ctx, bucketSvc, s) svc := dbrp.NewService(ctx, bucketSvc, s)
server := httptest.NewServer(dbrp.NewHTTPHandler(zaptest.NewLogger(t), svc, orgSvc)) server := httptest.NewServer(dbrp.NewHTTPHandler(zaptest.NewLogger(t), svc, orgSvc))

View File

@ -2,58 +2,18 @@ package dbrp_test
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"io/ioutil"
"os"
"testing" "testing"
"github.com/influxdata/influxdb/v2" "github.com/influxdata/influxdb/v2"
"github.com/influxdata/influxdb/v2/bolt"
"github.com/influxdata/influxdb/v2/dbrp" "github.com/influxdata/influxdb/v2/dbrp"
"github.com/influxdata/influxdb/v2/kit/platform" "github.com/influxdata/influxdb/v2/kit/platform"
"github.com/influxdata/influxdb/v2/kv"
"github.com/influxdata/influxdb/v2/kv/migration/all"
"github.com/influxdata/influxdb/v2/mock" "github.com/influxdata/influxdb/v2/mock"
itesting "github.com/influxdata/influxdb/v2/testing" itesting "github.com/influxdata/influxdb/v2/testing"
"go.uber.org/zap/zaptest"
) )
func NewTestBoltStore(t *testing.T) (kv.Store, func(), error) {
t.Helper()
f, err := ioutil.TempFile("", "influxdata-bolt-")
if err != nil {
return nil, nil, errors.New("unable to open temporary boltdb file")
}
f.Close()
ctx := context.Background()
logger := zaptest.NewLogger(t)
path := f.Name()
s := bolt.NewKVStore(logger, path, bolt.WithNoSync)
if err := s.Open(context.Background()); err != nil {
return nil, nil, err
}
if err := all.Up(ctx, logger, s); err != nil {
return nil, nil, err
}
close := func() {
s.Close()
os.Remove(path)
}
return s, close, nil
}
func initDBRPMappingService(f itesting.DBRPMappingFields, t *testing.T) (influxdb.DBRPMappingService, func()) { func initDBRPMappingService(f itesting.DBRPMappingFields, t *testing.T) (influxdb.DBRPMappingService, func()) {
s, closeStore, err := NewTestBoltStore(t) s, closeStore := itesting.NewTestBoltStore(t)
if err != nil {
t.Fatalf("failed to create new bolt kv store: %v", err)
}
if f.BucketSvc == nil { if f.BucketSvc == nil {
f.BucketSvc = &mock.BucketService{ f.BucketSvc = &mock.BucketService{
FindBucketByIDFn: func(ctx context.Context, id platform.ID) (*influxdb.Bucket, error) { FindBucketByIDFn: func(ctx context.Context, id platform.ID) (*influxdb.Bucket, error) {

View File

@ -873,7 +873,7 @@ func initAuthorizationService(f platformtesting.AuthorizationFields, t *testing.
t.Skip("HTTP authorization service does not required a user id on the authentication struct. We get the user from the session token.") t.Skip("HTTP authorization service does not required a user id on the authentication struct. We get the user from the session token.")
} }
store := NewTestInmemStore(t) store := platformtesting.NewTestInmemStore(t)
tenantStore := tenant.NewStore(store) tenantStore := tenant.NewStore(store)
tenantStore.OrgIDGen = f.OrgIDGenerator tenantStore.OrgIDGen = f.OrgIDGenerator
tenantService := tenant.NewService(tenantStore) tenantService := tenant.NewService(tenantStore)

View File

@ -32,7 +32,7 @@ type fixture struct {
func setup(t *testing.T) (func(auth influxdb.Authorizer) *httptest.Server, func(serverUrl string) DocumentService, fixture) { func setup(t *testing.T) (func(auth influxdb.Authorizer) *httptest.Server, func(serverUrl string) DocumentService, fixture) {
ctx := context.Background() ctx := context.Background()
store := NewTestInmemStore(t) store := itesting.NewTestInmemStore(t)
tenantStore := tenant.NewStore(store) tenantStore := tenant.NewStore(store)
tenantService := tenant.NewService(tenantStore) tenantService := tenant.NewService(tenantStore)
svc := kv.NewService(zaptest.NewLogger(t), store, tenantService) svc := kv.NewService(zaptest.NewLogger(t), store, tenantService)

View File

@ -597,8 +597,7 @@ func TestService_handlePatchLabel(t *testing.T) {
} }
func initLabelService(f platformtesting.LabelFields, t *testing.T) (platform.LabelService, string, func()) { func initLabelService(f platformtesting.LabelFields, t *testing.T) (platform.LabelService, string, func()) {
store := NewTestInmemStore(t) store := platformtesting.NewTestInmemStore(t)
labelStore, err := label.NewStore(store) labelStore, err := label.NewStore(store)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

View File

@ -1068,7 +1068,7 @@ func TestService_handlePostNotificationEndpointOwner(t *testing.T) {
func initNotificationEndpointService(f endpointTesting.NotificationEndpointFields, t *testing.T) (influxdb.NotificationEndpointService, influxdb.SecretService, func()) { func initNotificationEndpointService(f endpointTesting.NotificationEndpointFields, t *testing.T) (influxdb.NotificationEndpointService, influxdb.SecretService, func()) {
ctx := context.Background() ctx := context.Background()
store := NewTestInmemStore(t) store := influxTesting.NewTestInmemStore(t)
logger := zaptest.NewLogger(t) logger := zaptest.NewLogger(t)
tenantStore := tenant.NewStore(store) tenantStore := tenant.NewStore(store)

View File

@ -15,9 +15,6 @@ import (
"testing" "testing"
"time" "time"
"github.com/influxdata/influxdb/v2/kit/platform"
"github.com/influxdata/influxdb/v2/kit/platform/errors"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/influxdata/flux" "github.com/influxdata/flux"
"github.com/influxdata/flux/csv" "github.com/influxdata/flux/csv"
@ -27,6 +24,8 @@ import (
"github.com/influxdata/influxdb/v2/http/metric" "github.com/influxdata/influxdb/v2/http/metric"
"github.com/influxdata/influxdb/v2/kit/check" "github.com/influxdata/influxdb/v2/kit/check"
"github.com/influxdata/influxdb/v2/kit/feature" "github.com/influxdata/influxdb/v2/kit/feature"
"github.com/influxdata/influxdb/v2/kit/platform"
"github.com/influxdata/influxdb/v2/kit/platform/errors"
tracetesting "github.com/influxdata/influxdb/v2/kit/tracing/testing" tracetesting "github.com/influxdata/influxdb/v2/kit/tracing/testing"
kithttp "github.com/influxdata/influxdb/v2/kit/transport/http" kithttp "github.com/influxdata/influxdb/v2/kit/transport/http"
influxmock "github.com/influxdata/influxdb/v2/mock" influxmock "github.com/influxdata/influxdb/v2/mock"
@ -34,6 +33,7 @@ import (
"github.com/influxdata/influxdb/v2/query/fluxlang" "github.com/influxdata/influxdb/v2/query/fluxlang"
"github.com/influxdata/influxdb/v2/query/mock" "github.com/influxdata/influxdb/v2/query/mock"
"github.com/influxdata/influxdb/v2/tenant" "github.com/influxdata/influxdb/v2/tenant"
itesting "github.com/influxdata/influxdb/v2/testing"
"go.uber.org/zap/zaptest" "go.uber.org/zap/zaptest"
) )
@ -330,7 +330,7 @@ var _ metric.EventRecorder = noopEventRecorder{}
func TestFluxHandler_PostQuery_Errors(t *testing.T) { func TestFluxHandler_PostQuery_Errors(t *testing.T) {
defer tracetesting.SetupInMemoryTracing(t.Name())() defer tracetesting.SetupInMemoryTracing(t.Name())()
store := NewTestInmemStore(t) store := itesting.NewTestInmemStore(t)
orgSVC := tenant.NewService(tenant.NewStore(store)) orgSVC := tenant.NewService(tenant.NewStore(store))
b := &FluxBackend{ b := &FluxBackend{
HTTPErrorHandler: kithttp.ErrorHandler(0), HTTPErrorHandler: kithttp.ErrorHandler(0),

View File

@ -820,7 +820,7 @@ func TestService_handlePatchScraperTarget(t *testing.T) {
func initScraperService(f platformtesting.TargetFields, t *testing.T) (influxdb.ScraperTargetStoreService, string, func()) { func initScraperService(f platformtesting.TargetFields, t *testing.T) (influxdb.ScraperTargetStoreService, string, func()) {
t.Helper() t.Helper()
store := NewTestInmemStore(t) store := platformtesting.NewTestInmemStore(t)
tenantStore := tenant.NewStore(store) tenantStore := tenant.NewStore(store)
tenantService := tenant.NewService(tenantStore) tenantService := tenant.NewService(tenantStore)

View File

@ -1,23 +0,0 @@
package http
import (
"context"
"testing"
"github.com/influxdata/influxdb/v2/inmem"
"github.com/influxdata/influxdb/v2/kv"
"github.com/influxdata/influxdb/v2/kv/migration/all"
"go.uber.org/zap/zaptest"
)
func NewTestInmemStore(t *testing.T) kv.Store {
t.Helper()
store := inmem.NewKVStore()
if err := all.Up(context.Background(), zaptest.NewLogger(t), store); err != nil {
t.Fatal(err)
}
return store
}

View File

@ -33,7 +33,7 @@ import (
// NewMockTaskBackend returns a TaskBackend with mock services. // NewMockTaskBackend returns a TaskBackend with mock services.
func NewMockTaskBackend(t *testing.T) *TaskBackend { func NewMockTaskBackend(t *testing.T) *TaskBackend {
t.Helper() t.Helper()
store := NewTestInmemStore(t) store := influxdbtesting.NewTestInmemStore(t)
tenantService := tenant.NewService(tenant.NewStore(store)) tenantService := tenant.NewService(tenant.NewStore(store))
return &TaskBackend{ return &TaskBackend{
@ -824,7 +824,7 @@ func TestTaskHandler_handleGetRuns(t *testing.T) {
func TestTaskHandler_NotFoundStatus(t *testing.T) { func TestTaskHandler_NotFoundStatus(t *testing.T) {
// Ensure that the HTTP handlers return 404s for missing resources, and OKs for matching. // Ensure that the HTTP handlers return 404s for missing resources, and OKs for matching.
store := NewTestInmemStore(t) store := influxdbtesting.NewTestInmemStore(t)
tenantService := tenant.NewService(tenant.NewStore(store)) tenantService := tenant.NewService(tenant.NewStore(store))
labelStore, _ := label.NewStore(store) labelStore, _ := label.NewStore(store)
@ -1219,7 +1219,7 @@ func TestService_handlePostTaskLabel(t *testing.T) {
// Test that org name to org ID translation happens properly in the HTTP layer. // Test that org name to org ID translation happens properly in the HTTP layer.
// Regression test for https://github.com/influxdata/influxdb/issues/12089. // Regression test for https://github.com/influxdata/influxdb/issues/12089.
func TestTaskHandler_CreateTaskWithOrgName(t *testing.T) { func TestTaskHandler_CreateTaskWithOrgName(t *testing.T) {
i := NewTestInmemStore(t) i := influxdbtesting.NewTestInmemStore(t)
ts := tenant.NewService(tenant.NewStore(i)) ts := tenant.NewService(tenant.NewStore(i))
aStore, _ := authorization.NewStore(i) aStore, _ := authorization.NewStore(i)
@ -1317,7 +1317,7 @@ func TestTaskHandler_CreateTaskWithOrgName(t *testing.T) {
func TestTaskHandler_Sessions(t *testing.T) { func TestTaskHandler_Sessions(t *testing.T) {
t.Skip("rework these") t.Skip("rework these")
// Common setup to get a working base for using tasks. // Common setup to get a working base for using tasks.
st := NewTestInmemStore(t) st := influxdbtesting.NewTestInmemStore(t)
tStore := tenant.NewStore(st) tStore := tenant.NewStore(st)
tSvc := tenant.NewService(tStore) tSvc := tenant.NewService(tStore)

View File

@ -33,7 +33,7 @@ func NewMockUserBackend(t *testing.T) *UserBackend {
func initUserService(f platformtesting.UserFields, t *testing.T) (platform.UserService, string, func()) { func initUserService(f platformtesting.UserFields, t *testing.T) (platform.UserService, string, func()) {
t.Helper() t.Helper()
store := NewTestInmemStore(t) store := platformtesting.NewTestInmemStore(t)
tenantStore := tenant.NewStore(store) tenantStore := tenant.NewStore(store)
tenantStore.IDGen = f.IDGenerator tenantStore.IDGen = f.IDGenerator
tenantService := tenant.NewService(tenantStore) tenantService := tenant.NewService(tenantStore)

View File

@ -998,7 +998,7 @@ func TestService_handlePostVariableLabel(t *testing.T) {
} }
func initVariableService(f itesting.VariableFields, t *testing.T) (platform.VariableService, string, func()) { func initVariableService(f itesting.VariableFields, t *testing.T) (platform.VariableService, string, func()) {
store := NewTestInmemStore(t) store := itesting.NewTestInmemStore(t)
tenantService := tenant.NewService(tenant.NewStore(store)) tenantService := tenant.NewService(tenant.NewStore(store))
svc := kv.NewService(zaptest.NewLogger(t), store, tenantService) svc := kv.NewService(zaptest.NewLogger(t), store, tenantService)

View File

@ -19,20 +19,12 @@ import (
) )
func Test_Inmem_Index(t *testing.T) { func Test_Inmem_Index(t *testing.T) {
s, closeStore, err := NewTestInmemStore(t) s := influxdbtesting.NewTestInmemStore(t)
if err != nil {
t.Fatal(err)
}
defer closeStore()
influxdbtesting.TestIndex(t, s) influxdbtesting.TestIndex(t, s)
} }
func Test_Bolt_Index(t *testing.T) { func Test_Bolt_Index(t *testing.T) {
s, closeBolt, err := NewTestBoltStore(t) s, closeBolt := influxdbtesting.NewTestBoltStore(t)
if err != nil {
t.Fatalf("failed to create new kv store: %v", err)
}
defer closeBolt() defer closeBolt()
influxdbtesting.TestIndex(t, s) influxdbtesting.TestIndex(t, s)

View File

@ -1,52 +0,0 @@
package kv_test
import (
"context"
"errors"
"io/ioutil"
"os"
"testing"
"github.com/influxdata/influxdb/v2/bolt"
"github.com/influxdata/influxdb/v2/inmem"
"github.com/influxdata/influxdb/v2/kv"
"github.com/influxdata/influxdb/v2/kv/migration/all"
"go.uber.org/zap/zaptest"
)
func NewTestBoltStore(t *testing.T) (kv.SchemaStore, func(), error) {
f, err := ioutil.TempFile("", "influxdata-bolt-")
if err != nil {
return nil, nil, errors.New("unable to open temporary boltdb file")
}
f.Close()
ctx := context.Background()
logger := zaptest.NewLogger(t)
path := f.Name()
// skip fsync to improve test performance
s := bolt.NewKVStore(logger, path, bolt.WithNoSync)
if err := s.Open(context.Background()); err != nil {
return nil, nil, err
}
if err := all.Up(ctx, logger, s); err != nil {
return nil, nil, err
}
close := func() {
s.Close()
os.Remove(path)
}
return s, close, nil
}
func NewTestInmemStore(t *testing.T) (kv.SchemaStore, func(), error) {
store := inmem.NewKVStore()
if err := all.Up(context.Background(), zaptest.NewLogger(t), store); err != nil {
return nil, nil, err
}
return store, func() {}, nil
}

View File

@ -16,11 +16,7 @@ func TestBoltKeyValueLog(t *testing.T) {
} }
func initBoltKeyValueLog(f influxdbtesting.KeyValueLogFields, t *testing.T) (influxdb.KeyValueLog, func()) { func initBoltKeyValueLog(f influxdbtesting.KeyValueLogFields, t *testing.T) (influxdb.KeyValueLog, func()) {
s, closeBolt, err := NewTestBoltStore(t) s, closeBolt := influxdbtesting.NewTestBoltStore(t)
if err != nil {
t.Fatalf("failed to create new kv store: %v", err)
}
svc, closeSvc := initKeyValueLog(s, f, t) svc, closeSvc := initKeyValueLog(s, f, t)
return svc, func() { return svc, func() {
closeSvc() closeSvc()

View File

@ -31,7 +31,7 @@ func Test_Inmem_Migrator(t *testing.T) {
} }
func Test_Bolt_Migrator(t *testing.T) { func Test_Bolt_Migrator(t *testing.T) {
store, closeBolt, err := NewTestBoltStore(t) store, closeBolt, err := newTestBoltStoreWithoutMigrations(t)
if err != nil { if err != nil {
t.Fatalf("failed to create new kv store: %v", err) t.Fatalf("failed to create new kv store: %v", err)
} }
@ -40,7 +40,7 @@ func Test_Bolt_Migrator(t *testing.T) {
influxdbtesting.Migrator(t, store, newMigrator) influxdbtesting.Migrator(t, store, newMigrator)
} }
func NewTestBoltStore(t *testing.T) (kv.SchemaStore, func(), error) { func newTestBoltStoreWithoutMigrations(t *testing.T) (kv.SchemaStore, func(), error) {
f, err := ioutil.TempFile("", "influxdata-bolt-") f, err := ioutil.TempFile("", "influxdata-bolt-")
if err != nil { if err != nil {
return nil, nil, errors.New("unable to open temporary boltdb file") return nil, nil, errors.New("unable to open temporary boltdb file")

View File

@ -17,11 +17,7 @@ func TestBoltScraperTargetStoreService(t *testing.T) {
} }
func initBoltTargetService(f influxdbtesting.TargetFields, t *testing.T) (influxdb.ScraperTargetStoreService, string, func()) { func initBoltTargetService(f influxdbtesting.TargetFields, t *testing.T) (influxdb.ScraperTargetStoreService, string, func()) {
s, closeFn, err := NewTestBoltStore(t) s, closeFn := influxdbtesting.NewTestBoltStore(t)
if err != nil {
t.Fatalf("failed to create new kv store: %v", err)
}
svc, op, closeSvc := initScraperTargetStoreService(s, f, t) svc, op, closeSvc := initScraperTargetStoreService(s, f, t)
return svc, op, func() { return svc, op, func() {
closeSvc() closeSvc()

View File

@ -19,11 +19,7 @@ func TestBoltSourceService(t *testing.T) {
} }
func initBoltSourceService(f influxdbtesting.SourceFields, t *testing.T) (influxdb.SourceService, string, func()) { func initBoltSourceService(f influxdbtesting.SourceFields, t *testing.T) (influxdb.SourceService, string, func()) {
s, closeBolt, err := NewTestBoltStore(t) s, closeBolt := influxdbtesting.NewTestBoltStore(t)
if err != nil {
t.Fatalf("failed to create new kv store: %v", err)
}
svc, op, closeSvc := initSourceService(s, f, t) svc, op, closeSvc := initSourceService(s, f, t)
return svc, op, func() { return svc, op, func() {
closeSvc() closeSvc()

View File

@ -4,13 +4,14 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/influxdata/influxdb/v2/kit/platform"
"github.com/influxdata/influxdb/v2/kit/platform/errors"
"testing" "testing"
"time" "time"
"github.com/influxdata/influxdb/v2/kit/platform"
"github.com/influxdata/influxdb/v2/kit/platform/errors"
"github.com/influxdata/influxdb/v2/kv" "github.com/influxdata/influxdb/v2/kv"
"github.com/influxdata/influxdb/v2/kv/migration" "github.com/influxdata/influxdb/v2/kv/migration"
itesting "github.com/influxdata/influxdb/v2/testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -19,8 +20,7 @@ func TestStoreBase(t *testing.T) {
newStoreBase := func(t *testing.T, bktSuffix string, encKeyFn, encBodyFn kv.EncodeEntFn, decFn kv.DecodeBucketValFn, decToEntFn kv.ConvertValToEntFn) (*kv.StoreBase, func(), kv.Store) { newStoreBase := func(t *testing.T, bktSuffix string, encKeyFn, encBodyFn kv.EncodeEntFn, decFn kv.DecodeBucketValFn, decToEntFn kv.ConvertValToEntFn) (*kv.StoreBase, func(), kv.Store) {
t.Helper() t.Helper()
inmemSVC, done, err := NewTestBoltStore(t) svc, done := itesting.NewTestBoltStore(t)
require.NoError(t, err)
bucket := []byte("foo_" + bktSuffix) bucket := []byte("foo_" + bktSuffix)
store := kv.NewStoreBase("foo", bucket, encKeyFn, encBodyFn, decFn, decToEntFn) store := kv.NewStoreBase("foo", bucket, encKeyFn, encBodyFn, decFn, decToEntFn)
@ -29,10 +29,9 @@ func TestStoreBase(t *testing.T) {
defer cancel() defer cancel()
migrationName := fmt.Sprintf("create bucket %q", string(bucket)) migrationName := fmt.Sprintf("create bucket %q", string(bucket))
migration.CreateBuckets(migrationName, bucket).Up(ctx, inmemSVC) migration.CreateBuckets(migrationName, bucket).Up(ctx, svc)
require.NoError(t, err)
return store, done, inmemSVC return store, done, svc
} }
newFooStoreBase := func(t *testing.T, bktSuffix string) (*kv.StoreBase, func(), kv.Store) { newFooStoreBase := func(t *testing.T, bktSuffix string) (*kv.StoreBase, func(), kv.Store) {

View File

@ -2,11 +2,12 @@ package kv_test
import ( import (
"context" "context"
"github.com/influxdata/influxdb/v2/kit/platform/errors"
"testing" "testing"
"github.com/influxdata/influxdb/v2/kit/platform/errors"
"github.com/influxdata/influxdb/v2/kv" "github.com/influxdata/influxdb/v2/kv"
"github.com/influxdata/influxdb/v2/kv/migration" "github.com/influxdata/influxdb/v2/kv/migration"
itesting "github.com/influxdata/influxdb/v2/testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -19,8 +20,7 @@ func TestIndexStore(t *testing.T) {
newFooIndexStore := func(t *testing.T, bktSuffix string) (*kv.IndexStore, func(), kv.Store) { newFooIndexStore := func(t *testing.T, bktSuffix string) (*kv.IndexStore, func(), kv.Store) {
t.Helper() t.Helper()
kvStoreStore, done, err := NewTestBoltStore(t) kvStoreStore, done := itesting.NewTestBoltStore(t)
require.NoError(t, err)
const resource = "foo" const resource = "foo"

View File

@ -20,6 +20,7 @@ import (
"github.com/influxdata/influxdb/v2/task/servicetest" "github.com/influxdata/influxdb/v2/task/servicetest"
"github.com/influxdata/influxdb/v2/task/taskmodel" "github.com/influxdata/influxdb/v2/task/taskmodel"
"github.com/influxdata/influxdb/v2/tenant" "github.com/influxdata/influxdb/v2/tenant"
itesting "github.com/influxdata/influxdb/v2/testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest" "go.uber.org/zap/zaptest"
@ -29,10 +30,7 @@ func TestBoltTaskService(t *testing.T) {
servicetest.TestTaskService( servicetest.TestTaskService(
t, t,
func(t *testing.T) (*servicetest.System, context.CancelFunc) { func(t *testing.T) (*servicetest.System, context.CancelFunc) {
store, close, err := NewTestBoltStore(t) store, close := itesting.NewTestBoltStore(t)
if err != nil {
t.Fatal(err)
}
tenantStore := tenant.NewStore(store) tenantStore := tenant.NewStore(store)
ts := tenant.NewService(tenantStore) ts := tenant.NewService(tenantStore)
@ -72,12 +70,6 @@ type testService struct {
User influxdb.User User influxdb.User
Auth influxdb.Authorization Auth influxdb.Authorization
Clock clock.Clock Clock clock.Clock
storeCloseFn func()
}
func (s *testService) Close() {
s.storeCloseFn()
} }
func newService(t *testing.T, ctx context.Context, c clock.Clock) *testService { func newService(t *testing.T, ctx context.Context, c clock.Clock) *testService {
@ -93,7 +85,7 @@ func newService(t *testing.T, ctx context.Context, c clock.Clock) *testService {
store kv.SchemaStore store kv.SchemaStore
) )
store, ts.storeCloseFn, err = NewTestInmemStore(t) store = itesting.NewTestInmemStore(t)
if err != nil { if err != nil {
t.Fatal("failed to create InmemStore", err) t.Fatal("failed to create InmemStore", err)
} }
@ -147,7 +139,6 @@ func TestRetrieveTaskWithBadAuth(t *testing.T) {
defer cancelFunc() defer cancelFunc()
ts := newService(t, ctx, nil) ts := newService(t, ctx, nil)
defer ts.Close()
ctx = icontext.SetAuthorizer(ctx, &ts.Auth) ctx = icontext.SetAuthorizer(ctx, &ts.Auth)
@ -224,7 +215,6 @@ func TestService_UpdateTask_InactiveToActive(t *testing.T) {
c.Set(time.Unix(1000, 0)) c.Set(time.Unix(1000, 0))
ts := newService(t, ctx, c) ts := newService(t, ctx, c)
defer ts.Close()
ctx = icontext.SetAuthorizer(ctx, &ts.Auth) ctx = icontext.SetAuthorizer(ctx, &ts.Auth)
@ -267,11 +257,8 @@ func TestService_UpdateTask_InactiveToActive(t *testing.T) {
} }
func TestTaskRunCancellation(t *testing.T) { func TestTaskRunCancellation(t *testing.T) {
store, close, err := NewTestBoltStore(t) store, closeSvc := itesting.NewTestBoltStore(t)
if err != nil { defer closeSvc()
t.Fatal(err)
}
defer close()
ctx, cancelFunc := context.WithCancel(context.Background()) ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc() defer cancelFunc()
@ -352,7 +339,6 @@ func TestService_UpdateTask_RecordLatestSuccessAndFailure(t *testing.T) {
c.Set(time.Unix(1000, 0)) c.Set(time.Unix(1000, 0))
ts := newService(t, ctx, c) ts := newService(t, ctx, c)
defer ts.Close()
ctx = icontext.SetAuthorizer(ctx, &ts.Auth) ctx = icontext.SetAuthorizer(ctx, &ts.Auth)

View File

@ -16,11 +16,7 @@ func TestBoltVariableService(t *testing.T) {
} }
func initBoltVariableService(f influxdbtesting.VariableFields, t *testing.T) (influxdb.VariableService, string, func()) { func initBoltVariableService(f influxdbtesting.VariableFields, t *testing.T) (influxdb.VariableService, string, func()) {
s, closeBolt, err := NewTestBoltStore(t) s, closeBolt := influxdbtesting.NewTestBoltStore(t)
if err != nil {
t.Fatalf("failed to create new kv store: %v", err)
}
svc, op, closeSvc := initVariableService(s, f, t) svc, op, closeSvc := initVariableService(s, f, t)
return svc, op, func() { return svc, op, func() {
closeSvc() closeSvc()

View File

@ -2,60 +2,21 @@ package label_test
import ( import (
"context" "context"
"errors"
"io/ioutil"
"os"
"testing" "testing"
"github.com/influxdata/influxdb/v2" "github.com/influxdata/influxdb/v2"
"github.com/influxdata/influxdb/v2/bolt"
"github.com/influxdata/influxdb/v2/kv" "github.com/influxdata/influxdb/v2/kv"
"github.com/influxdata/influxdb/v2/kv/migration/all"
"github.com/influxdata/influxdb/v2/label" "github.com/influxdata/influxdb/v2/label"
"github.com/influxdata/influxdb/v2/mock" "github.com/influxdata/influxdb/v2/mock"
influxdbtesting "github.com/influxdata/influxdb/v2/testing" influxdbtesting "github.com/influxdata/influxdb/v2/testing"
"go.uber.org/zap/zaptest"
) )
func TestBoltLabelService(t *testing.T) { func TestBoltLabelService(t *testing.T) {
influxdbtesting.LabelService(initBoltLabelService, t) influxdbtesting.LabelService(initBoltLabelService, t)
} }
func NewTestBoltStore(t *testing.T) (kv.Store, func(), error) {
t.Helper()
f, err := ioutil.TempFile("", "influxdata-bolt-")
if err != nil {
return nil, nil, errors.New("unable to open temporary boltdb file")
}
f.Close()
path := f.Name()
ctx := context.Background()
logger := zaptest.NewLogger(t)
s := bolt.NewKVStore(logger, path, bolt.WithNoSync)
if err := s.Open(ctx); err != nil {
return nil, nil, err
}
if err := all.Up(ctx, logger, s); err != nil {
return nil, nil, err
}
close := func() {
s.Close()
os.Remove(path)
}
return s, close, nil
}
func initBoltLabelService(f influxdbtesting.LabelFields, t *testing.T) (influxdb.LabelService, string, func()) { func initBoltLabelService(f influxdbtesting.LabelFields, t *testing.T) (influxdb.LabelService, string, func()) {
s, closeBolt, err := NewTestBoltStore(t) s, closeBolt := influxdbtesting.NewTestBoltStore(t)
if err != nil {
t.Fatalf("failed to create new kv store: %v", err)
}
svc, op, closeSvc := initLabelService(s, f, t) svc, op, closeSvc := initLabelService(s, f, t)
return svc, op, func() { return svc, op, func() {
closeSvc() closeSvc()

View File

@ -2,20 +2,17 @@ package service_test
import ( import (
"context" "context"
"io/ioutil"
"os"
"testing" "testing"
influxdb "github.com/influxdata/influxdb/v2" "github.com/influxdata/influxdb/v2"
"github.com/influxdata/influxdb/v2/bolt"
"github.com/influxdata/influxdb/v2/inmem" "github.com/influxdata/influxdb/v2/inmem"
"github.com/influxdata/influxdb/v2/kit/errors"
"github.com/influxdata/influxdb/v2/kv" "github.com/influxdata/influxdb/v2/kv"
"github.com/influxdata/influxdb/v2/kv/migration/all" "github.com/influxdata/influxdb/v2/kv/migration/all"
"github.com/influxdata/influxdb/v2/notification/endpoint/service" "github.com/influxdata/influxdb/v2/notification/endpoint/service"
endpointsTesting "github.com/influxdata/influxdb/v2/notification/endpoint/service/testing" endpointsTesting "github.com/influxdata/influxdb/v2/notification/endpoint/service/testing"
"github.com/influxdata/influxdb/v2/secret" "github.com/influxdata/influxdb/v2/secret"
"github.com/influxdata/influxdb/v2/tenant" "github.com/influxdata/influxdb/v2/tenant"
itesting "github.com/influxdata/influxdb/v2/testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest" "go.uber.org/zap/zaptest"
) )
@ -28,41 +25,8 @@ func TestNotificationEndpointService_WithBolt(t *testing.T) {
endpointsTesting.NotificationEndpointService(initBoltNotificationEndpointService, t) endpointsTesting.NotificationEndpointService(initBoltNotificationEndpointService, t)
} }
func NewTestBoltStore(t *testing.T) (kv.SchemaStore, func(), error) {
f, err := ioutil.TempFile("", "influxdata-bolt-")
if err != nil {
return nil, nil, errors.New("unable to open temporary boltdb file")
}
f.Close()
ctx := context.Background()
logger := zaptest.NewLogger(t)
path := f.Name()
// skip fsync to improve test performance
s := bolt.NewKVStore(logger, path, bolt.WithNoSync)
if err := s.Open(context.Background()); err != nil {
return nil, nil, err
}
if err := all.Up(ctx, logger, s); err != nil {
return nil, nil, err
}
close := func() {
s.Close()
os.Remove(path)
}
return s, close, nil
}
func initBoltNotificationEndpointService(f endpointsTesting.NotificationEndpointFields, t *testing.T) (influxdb.NotificationEndpointService, influxdb.SecretService, func()) { func initBoltNotificationEndpointService(f endpointsTesting.NotificationEndpointFields, t *testing.T) (influxdb.NotificationEndpointService, influxdb.SecretService, func()) {
store, closeStore, err := NewTestBoltStore(t) store, closeStore := itesting.NewTestBoltStore(t)
if err != nil {
t.Fatal(err)
}
svc, secretSVC, closeSvc := initNotificationEndpointService(store, f, t) svc, secretSVC, closeSvc := initNotificationEndpointService(store, f, t)
return svc, secretSVC, func() { return svc, secretSVC, func() {
closeSvc() closeSvc()

View File

@ -2,24 +2,19 @@ package service
import ( import (
"context" "context"
"errors"
"io/ioutil"
"os"
"testing" "testing"
influxdb "github.com/influxdata/influxdb/v2" "github.com/influxdata/influxdb/v2"
"github.com/influxdata/influxdb/v2/bolt"
_ "github.com/influxdata/influxdb/v2/fluxinit/static" _ "github.com/influxdata/influxdb/v2/fluxinit/static"
"github.com/influxdata/influxdb/v2/inmem"
"github.com/influxdata/influxdb/v2/kit/platform" "github.com/influxdata/influxdb/v2/kit/platform"
"github.com/influxdata/influxdb/v2/kv" "github.com/influxdata/influxdb/v2/kv"
"github.com/influxdata/influxdb/v2/kv/migration/all"
"github.com/influxdata/influxdb/v2/mock" "github.com/influxdata/influxdb/v2/mock"
endpointservice "github.com/influxdata/influxdb/v2/notification/endpoint/service" endpointservice "github.com/influxdata/influxdb/v2/notification/endpoint/service"
"github.com/influxdata/influxdb/v2/query/fluxlang" "github.com/influxdata/influxdb/v2/query/fluxlang"
"github.com/influxdata/influxdb/v2/secret" "github.com/influxdata/influxdb/v2/secret"
"github.com/influxdata/influxdb/v2/task/taskmodel" "github.com/influxdata/influxdb/v2/task/taskmodel"
"github.com/influxdata/influxdb/v2/tenant" "github.com/influxdata/influxdb/v2/tenant"
itesting "github.com/influxdata/influxdb/v2/testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest" "go.uber.org/zap/zaptest"
) )
@ -29,23 +24,12 @@ func TestInmemNotificationRuleStore(t *testing.T) {
} }
func initInmemNotificationRuleStore(f NotificationRuleFields, t *testing.T) (influxdb.NotificationRuleStore, taskmodel.TaskService, func()) { func initInmemNotificationRuleStore(f NotificationRuleFields, t *testing.T) (influxdb.NotificationRuleStore, taskmodel.TaskService, func()) {
store := inmem.NewKVStore() store := itesting.NewTestInmemStore(t)
if err := all.Up(context.Background(), zaptest.NewLogger(t), store); err != nil { return initNotificationRuleStore(store, f, t)
t.Fatal(err)
}
svc, tsvc, closeSvc := initNotificationRuleStore(store, f, t)
return svc, tsvc, func() {
closeSvc()
}
} }
func initBoltNotificationRuleStore(f NotificationRuleFields, t *testing.T) (influxdb.NotificationRuleStore, taskmodel.TaskService, func()) { func initBoltNotificationRuleStore(f NotificationRuleFields, t *testing.T) (influxdb.NotificationRuleStore, taskmodel.TaskService, func()) {
store, closeBolt, err := newTestBoltStore(t) store, closeBolt := itesting.NewTestBoltStore(t)
if err != nil {
t.Fatal(err)
}
svc, tsvc, closeSvc := initNotificationRuleStore(store, f, t) svc, tsvc, closeSvc := initNotificationRuleStore(store, f, t)
return svc, tsvc, func() { return svc, tsvc, func() {
closeSvc() closeSvc()
@ -146,32 +130,3 @@ func withOrgID(store *tenant.Store, orgID platform.ID, fn func()) {
fn() fn()
} }
func newTestBoltStore(t *testing.T) (kv.SchemaStore, func(), error) {
f, err := ioutil.TempFile("", "influxdata-bolt-")
if err != nil {
return nil, nil, errors.New("unable to open temporary boltdb file")
}
f.Close()
ctx := context.Background()
logger := zaptest.NewLogger(t)
path := f.Name()
// skip fsync to improve test performance
s := bolt.NewKVStore(logger, path, bolt.WithNoSync)
if err := s.Open(context.Background()); err != nil {
return nil, nil, err
}
if err := all.Up(ctx, logger, s); err != nil {
return nil, nil, err
}
close := func() {
s.Close()
os.Remove(path)
}
return s, close, nil
}

View File

@ -2,59 +2,21 @@ package service_test
import ( import (
"context" "context"
"errors"
"io/ioutil"
"os"
"testing" "testing"
influxdb "github.com/influxdata/influxdb/v2" "github.com/influxdata/influxdb/v2"
"github.com/influxdata/influxdb/v2/bolt"
"github.com/influxdata/influxdb/v2/kv" "github.com/influxdata/influxdb/v2/kv"
"github.com/influxdata/influxdb/v2/kv/migration/all"
telegrafservice "github.com/influxdata/influxdb/v2/telegraf/service" telegrafservice "github.com/influxdata/influxdb/v2/telegraf/service"
telegraftesting "github.com/influxdata/influxdb/v2/telegraf/service/testing" telegraftesting "github.com/influxdata/influxdb/v2/telegraf/service/testing"
"go.uber.org/zap/zaptest" itesting "github.com/influxdata/influxdb/v2/testing"
) )
func TestBoltTelegrafService(t *testing.T) { func TestBoltTelegrafService(t *testing.T) {
telegraftesting.TelegrafConfigStore(initBoltTelegrafService, t) telegraftesting.TelegrafConfigStore(initBoltTelegrafService, t)
} }
func NewTestBoltStore(t *testing.T) (kv.SchemaStore, func(), error) {
f, err := ioutil.TempFile("", "influxdata-bolt-")
if err != nil {
return nil, nil, errors.New("unable to open temporary boltdb file")
}
f.Close()
ctx := context.Background()
logger := zaptest.NewLogger(t)
path := f.Name()
// skip fsync to improve test performance
s := bolt.NewKVStore(logger, path, bolt.WithNoSync)
if err := s.Open(context.Background()); err != nil {
return nil, nil, err
}
if err := all.Up(ctx, logger, s); err != nil {
return nil, nil, err
}
close := func() {
s.Close()
os.Remove(path)
}
return s, close, nil
}
func initBoltTelegrafService(f telegraftesting.TelegrafConfigFields, t *testing.T) (influxdb.TelegrafConfigStore, func()) { func initBoltTelegrafService(f telegraftesting.TelegrafConfigFields, t *testing.T) (influxdb.TelegrafConfigStore, func()) {
s, closeBolt, err := NewTestBoltStore(t) s, closeBolt := itesting.NewTestBoltStore(t)
if err != nil {
t.Fatalf("failed to create new kv store: %v", err)
}
svc, closeSvc := initTelegrafService(s, f, t) svc, closeSvc := initTelegrafService(s, f, t)
return svc, func() { return svc, func() {
closeSvc() closeSvc()

View File

@ -1,10 +0,0 @@
package influxdb
// TenantService is a service that exposes the functionality of the embedded services.
type TenantService interface {
UserService
PasswordsService
UserResourceMappingService
OrganizationService
BucketService
}

View File

@ -2,8 +2,6 @@ package tenant_test
import ( import (
"context" "context"
"github.com/influxdata/influxdb/v2/kit/platform"
"github.com/influxdata/influxdb/v2/kit/platform/errors"
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"time" "time"
@ -13,6 +11,8 @@ import (
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/influxdata/influxdb/v2" "github.com/influxdata/influxdb/v2"
ihttp "github.com/influxdata/influxdb/v2/http" ihttp "github.com/influxdata/influxdb/v2/http"
"github.com/influxdata/influxdb/v2/kit/platform"
"github.com/influxdata/influxdb/v2/kit/platform/errors"
"github.com/influxdata/influxdb/v2/kv" "github.com/influxdata/influxdb/v2/kv"
"github.com/influxdata/influxdb/v2/mock" "github.com/influxdata/influxdb/v2/mock"
"github.com/influxdata/influxdb/v2/tenant" "github.com/influxdata/influxdb/v2/tenant"
@ -23,10 +23,7 @@ import (
func initBucketHttpService(f itesting.BucketFields, t *testing.T) (influxdb.BucketService, string, func()) { func initBucketHttpService(f itesting.BucketFields, t *testing.T) (influxdb.BucketService, string, func()) {
t.Helper() t.Helper()
s, stCloser, err := NewTestInmemStore(t) s := itesting.NewTestInmemStore(t)
if err != nil {
t.Fatal(err)
}
store := tenant.NewStore(s) store := tenant.NewStore(s)
if f.IDGenerator != nil { if f.IDGenerator != nil {
@ -75,10 +72,7 @@ func initBucketHttpService(f itesting.BucketFields, t *testing.T) (influxdb.Buck
Client: httpClient, Client: httpClient,
} }
return &client, "http_tenant", func() { return &client, "http_tenant", server.Close
server.Close()
stCloser()
}
} }
func TestHTTPBucketService(t *testing.T) { func TestHTTPBucketService(t *testing.T) {

View File

@ -18,11 +18,7 @@ import (
func initOnboardHttpService(f itesting.OnboardingFields, t *testing.T) (influxdb.OnboardingService, func()) { func initOnboardHttpService(f itesting.OnboardingFields, t *testing.T) (influxdb.OnboardingService, func()) {
t.Helper() t.Helper()
s, stCloser, err := NewTestInmemStore(t) s := itesting.NewTestInmemStore(t)
if err != nil {
t.Fatal(err)
}
storage := tenant.NewStore(s) storage := tenant.NewStore(s)
ten := tenant.NewService(storage) ten := tenant.NewService(storage)
@ -55,10 +51,7 @@ func initOnboardHttpService(f itesting.OnboardingFields, t *testing.T) (influxdb
Client: httpClient, Client: httpClient,
} }
return &client, func() { return &client, server.Close
server.Close()
stCloser()
}
} }
func TestOnboardService(t *testing.T) { func TestOnboardService(t *testing.T) {

View File

@ -17,11 +17,7 @@ import (
func initHttpOrgService(f itesting.OrganizationFields, t *testing.T) (influxdb.OrganizationService, string, func()) { func initHttpOrgService(f itesting.OrganizationFields, t *testing.T) (influxdb.OrganizationService, string, func()) {
t.Helper() t.Helper()
s, stCloser, err := NewTestInmemStore(t) s := itesting.NewTestInmemStore(t)
if err != nil {
t.Fatal(err)
}
storage := tenant.NewStore(s) storage := tenant.NewStore(s)
if f.OrgBucketIDs != nil { if f.OrgBucketIDs != nil {
@ -55,10 +51,7 @@ func initHttpOrgService(f itesting.OrganizationFields, t *testing.T) (influxdb.O
Client: httpClient, Client: httpClient,
} }
return &orgClient, "http_tenant", func() { return &orgClient, "http_tenant", server.Close
server.Close()
stCloser()
}
} }
func TestHTTPOrgService(t *testing.T) { func TestHTTPOrgService(t *testing.T) {

View File

@ -16,10 +16,7 @@ import (
func initHttpUserService(f platformtesting.UserFields, t *testing.T) (platform.UserService, string, func()) { func initHttpUserService(f platformtesting.UserFields, t *testing.T) (platform.UserService, string, func()) {
t.Helper() t.Helper()
s, stCloser, err := NewTestInmemStore(t) s := platformtesting.NewTestInmemStore(t)
if err != nil {
t.Fatal(err)
}
storage := tenant.NewStore(s) storage := tenant.NewStore(s)
svc := tenant.NewService(storage) svc := tenant.NewService(storage)
@ -46,10 +43,7 @@ func initHttpUserService(f platformtesting.UserFields, t *testing.T) (platform.U
Client: httpClient, Client: httpClient,
} }
return &client, "http_tenant", func() { return &client, "http_tenant", server.Close
server.Close()
stCloser()
}
} }
func TestUserService(t *testing.T) { func TestUserService(t *testing.T) {

View File

@ -15,16 +15,8 @@ func TestInmemBucketService(t *testing.T) {
} }
func initInmemBucketService(f influxdbtesting.BucketFields, t *testing.T) (influxdb.BucketService, string, func()) { func initInmemBucketService(f influxdbtesting.BucketFields, t *testing.T) (influxdb.BucketService, string, func()) {
s, closeBolt, err := NewTestInmemStore(t) s := influxdbtesting.NewTestInmemStore(t)
if err != nil { return initBucketService(s, f, t)
t.Fatalf("failed to create new kv store: %v", err)
}
svc, op, closeSvc := initBucketService(s, f, t)
return svc, op, func() {
closeSvc()
closeBolt()
}
} }
func initBucketService(s kv.SchemaStore, f influxdbtesting.BucketFields, t *testing.T) (influxdb.BucketService, string, func()) { func initBucketService(s kv.SchemaStore, f influxdbtesting.BucketFields, t *testing.T) (influxdb.BucketService, string, func()) {
@ -82,11 +74,7 @@ func initBucketService(s kv.SchemaStore, f influxdbtesting.BucketFields, t *test
} }
func TestBucketFind(t *testing.T) { func TestBucketFind(t *testing.T) {
s, close, err := NewTestInmemStore(t) s := influxdbtesting.NewTestInmemStore(t)
if err != nil {
t.Fatal(err)
}
defer close()
storage := tenant.NewStore(s) storage := tenant.NewStore(s)
svc := tenant.NewService(storage) svc := tenant.NewService(storage)
@ -98,7 +86,7 @@ func TestBucketFind(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
name := "thebucket" name := "thebucket"
_, _, err = svc.FindBuckets(context.Background(), influxdb.BucketFilter{ _, _, err := svc.FindBuckets(context.Background(), influxdb.BucketFilter{
Name: &name, Name: &name,
Org: &o.Name, Org: &o.Name,
}) })
@ -108,11 +96,7 @@ func TestBucketFind(t *testing.T) {
} }
func TestSystemBucketsInNameFind(t *testing.T) { func TestSystemBucketsInNameFind(t *testing.T) {
s, close, err := NewTestInmemStore(t) s := influxdbtesting.NewTestInmemStore(t)
if err != nil {
t.Fatal(err)
}
defer close()
storage := tenant.NewStore(s) storage := tenant.NewStore(s)
svc := tenant.NewService(storage) svc := tenant.NewService(storage)

View File

@ -23,15 +23,9 @@ func TestBoltOnboardingService(t *testing.T) {
} }
func initBoltOnboardingService(f influxdbtesting.OnboardingFields, t *testing.T) (influxdb.OnboardingService, func()) { func initBoltOnboardingService(f influxdbtesting.OnboardingFields, t *testing.T) (influxdb.OnboardingService, func()) {
s, closeStore, err := NewTestInmemStore(t) s := influxdbtesting.NewTestInmemStore(t)
if err != nil {
t.Fatalf("failed to create new bolt kv store: %v", err)
}
svc := initOnboardingService(s, f, t) svc := initOnboardingService(s, f, t)
return svc, func() { return svc, func() {}
closeStore()
}
} }
func initOnboardingService(s kv.Store, f influxdbtesting.OnboardingFields, t *testing.T) influxdb.OnboardingService { func initOnboardingService(s kv.Store, f influxdbtesting.OnboardingFields, t *testing.T) influxdb.OnboardingService {
@ -60,7 +54,7 @@ func initOnboardingService(s kv.Store, f influxdbtesting.OnboardingFields, t *te
} }
func TestOnboardURM(t *testing.T) { func TestOnboardURM(t *testing.T) {
s, _, _ := NewTestInmemStore(t) s := influxdbtesting.NewTestInmemStore(t)
storage := tenant.NewStore(s) storage := tenant.NewStore(s)
ten := tenant.NewService(storage) ten := tenant.NewService(storage)
@ -98,7 +92,7 @@ func TestOnboardURM(t *testing.T) {
} }
func TestOnboardAuth(t *testing.T) { func TestOnboardAuth(t *testing.T) {
s, _, _ := NewTestInmemStore(t) s := influxdbtesting.NewTestInmemStore(t)
storage := tenant.NewStore(s) storage := tenant.NewStore(s)
ten := tenant.NewService(storage) ten := tenant.NewService(storage)
@ -172,7 +166,7 @@ func TestOnboardAuth(t *testing.T) {
} }
func TestOnboardService_RetentionPolicy(t *testing.T) { func TestOnboardService_RetentionPolicy(t *testing.T) {
s, _, _ := NewTestInmemStore(t) s := influxdbtesting.NewTestInmemStore(t)
storage := tenant.NewStore(s) storage := tenant.NewStore(s)
ten := tenant.NewService(storage) ten := tenant.NewService(storage)
@ -204,7 +198,7 @@ func TestOnboardService_RetentionPolicy(t *testing.T) {
} }
func TestOnboardService_RetentionPolicyDeprecated(t *testing.T) { func TestOnboardService_RetentionPolicyDeprecated(t *testing.T) {
s, _, _ := NewTestInmemStore(t) s := influxdbtesting.NewTestInmemStore(t)
storage := tenant.NewStore(s) storage := tenant.NewStore(s)
ten := tenant.NewService(storage) ten := tenant.NewService(storage)
@ -236,7 +230,7 @@ func TestOnboardService_RetentionPolicyDeprecated(t *testing.T) {
} }
func TestOnboardService_WeakPassword(t *testing.T) { func TestOnboardService_WeakPassword(t *testing.T) {
s, _, _ := NewTestInmemStore(t) s := influxdbtesting.NewTestInmemStore(t)
storage := tenant.NewStore(s) storage := tenant.NewStore(s)
ten := tenant.NewService(storage) ten := tenant.NewService(storage)

View File

@ -15,11 +15,7 @@ func TestBoltOrganizationService(t *testing.T) {
} }
func initBoltOrganizationService(f influxdbtesting.OrganizationFields, t *testing.T) (influxdb.OrganizationService, string, func()) { func initBoltOrganizationService(f influxdbtesting.OrganizationFields, t *testing.T) (influxdb.OrganizationService, string, func()) {
s, closeBolt, err := NewTestBoltStore(t) s, closeBolt := influxdbtesting.NewTestBoltStore(t)
if err != nil {
t.Fatalf("failed to create new kv store: %v", err)
}
svc, op, closeSvc := initOrganizationService(s, f, t) svc, op, closeSvc := initOrganizationService(s, f, t)
return svc, op, func() { return svc, op, func() {
closeSvc() closeSvc()

View File

@ -2,69 +2,880 @@ package tenant_test
import ( import (
"context" "context"
"errors" "sort"
"io/ioutil" "strings"
"os"
"testing" "testing"
"github.com/google/go-cmp/cmp"
"github.com/influxdata/influxdb/v2" "github.com/influxdata/influxdb/v2"
"github.com/influxdata/influxdb/v2/bolt" "github.com/influxdata/influxdb/v2/kit/platform"
"github.com/influxdata/influxdb/v2/inmem" "github.com/influxdata/influxdb/v2/mock"
"github.com/influxdata/influxdb/v2/kv"
"github.com/influxdata/influxdb/v2/kv/migration/all"
"github.com/influxdata/influxdb/v2/tenant" "github.com/influxdata/influxdb/v2/tenant"
influxdbtesting "github.com/influxdata/influxdb/v2/testing" itesting "github.com/influxdata/influxdb/v2/testing"
"go.uber.org/zap/zaptest"
) )
func NewTestBoltStore(t *testing.T) (kv.SchemaStore, func(), error) { type tenantFields struct {
f, err := ioutil.TempFile("", "influxdata-bolt-") OrgIDGenerator platform.IDGenerator
if err != nil { BucketIDGenerator platform.IDGenerator
return nil, nil, errors.New("unable to open temporary boltdb file") Users []*influxdb.User
} Passwords []string // passwords are indexed against the Users field
f.Close() UserResourceMappings []*influxdb.UserResourceMapping
Organizations []*influxdb.Organization
path := f.Name() Buckets []*influxdb.Bucket
s := bolt.NewKVStore(zaptest.NewLogger(t), path, bolt.WithNoSync)
if err := s.Open(context.Background()); err != nil {
return nil, nil, err
}
// apply all kv migrations
ctx := context.Background()
if err := all.Up(ctx, zaptest.NewLogger(t), s); err != nil {
return nil, nil, err
}
close := func() {
s.Close()
os.Remove(path)
}
return s, close, nil
}
func NewTestInmemStore(t *testing.T) (kv.SchemaStore, func(), error) {
s := inmem.NewKVStore()
// apply all kv migrations
ctx := context.Background()
if err := all.Up(ctx, zaptest.NewLogger(t), s); err != nil {
return nil, nil, err
}
return s, func() {}, nil
} }
// TestBoltTenantService tests the tenant service functions.
// These tests stress the relation between the services embedded by the TenantService.
// The individual functionality of services is tested elsewhere.
func TestBoltTenantService(t *testing.T) { func TestBoltTenantService(t *testing.T) {
influxdbtesting.TenantService(t, initBoltTenantService) tests := []struct {
name string
fn func(t *testing.T, init func(*testing.T, tenantFields) (*tenant.Service, func()))
}{
{
name: "Create",
fn: Create,
},
{
name: "Delete",
fn: Delete,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.fn(t, initBoltTenantService)
})
}
} }
func initBoltTenantService(t *testing.T, f influxdbtesting.TenantFields) (influxdb.TenantService, func()) { type bucketsByName []*influxdb.Bucket
s, closeBolt, err := NewTestBoltStore(t)
func (b bucketsByName) Len() int {
return len(b)
}
func (b bucketsByName) Less(i, j int) bool {
return strings.Compare(b[i].Name, b[j].Name) < 0
}
func (b bucketsByName) Swap(i, j int) {
b[i], b[j] = b[j], b[i]
}
type urmByResourceID []*influxdb.UserResourceMapping
func (u urmByResourceID) Len() int {
return len(u)
}
func (u urmByResourceID) Less(i, j int) bool {
return u[i].ResourceID < u[j].ResourceID
}
func (u urmByResourceID) Swap(i, j int) {
u[i], u[j] = u[j], u[i]
}
type urmByUserID []*influxdb.UserResourceMapping
func (u urmByUserID) Len() int {
return len(u)
}
func (u urmByUserID) Less(i, j int) bool {
return u[i].UserID < u[j].UserID
}
func (u urmByUserID) Swap(i, j int) {
u[i], u[j] = u[j], u[i]
}
// Create tests various cases of creation for the services in the TenantService.
// For example, when you create a user, do you create system buckets? How are URMs organized?
func Create(t *testing.T, init func(*testing.T, tenantFields) (*tenant.Service, func())) {
t.Helper()
// Blank fields, we are testing creation.
fields := func() tenantFields {
return tenantFields{
OrgIDGenerator: mock.NewIncrementingIDGenerator(1),
BucketIDGenerator: mock.NewIncrementingIDGenerator(1),
}
}
// NOTE(affo)(*kv.Service): tests that contain s.CreateOrganization() generate error in logs:
// Failed to make user owner of organization: {"error": "could not find authorizer on context when adding user to resource type orgs"}.
// This happens because kv requires an authorization to be in context.
// This is a bad dependency pattern (store -> auth) and should not be there.
// Anyways this does not prevent the org to be created. If you add the urm manually you'll obtain the same result.
// NOTE(affo)(*kv.Service): it also creates urms for the non existing user found in context.
t.Run("creating an org creates system buckets", func(t *testing.T) {
data := fields()
s, done := init(t, data)
defer done()
ctx := context.Background()
o := &influxdb.Organization{
// ID(1)
Name: "org1",
}
if err := s.CreateOrganization(ctx, o); err != nil {
t.Fatal(err)
}
// Check existence
orgs, norgs, err := s.FindOrganizations(ctx, influxdb.OrganizationFilter{})
if err != nil { if err != nil {
t.Fatalf("failed to create new kv store: %v", err) t.Fatal(err)
}
if norgs != 1 {
t.Errorf("expected 1 org, got: %v", orgs)
}
usrs, nusrs, err := s.FindUsers(ctx, influxdb.UserFilter{})
if err != nil {
t.Fatal(err)
}
if nusrs > 0 {
t.Errorf("expected no user, got: %v", usrs)
}
urms, nurms, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{})
if err != nil {
t.Fatal(err)
}
if nurms > 0 {
t.Errorf("expected no urm, got: %+v", urms)
}
bs, nbs, err := s.FindBuckets(ctx, influxdb.BucketFilter{})
if err != nil {
t.Fatal(err)
}
if nbs != 2 {
t.Errorf("expected 2 buckets, got: %v", bs)
}
sort.Sort(bucketsByName(bs))
if name := bs[0].Name; name != "_monitoring" {
t.Errorf("unexpected nam for bucket: %s", name)
}
if name := bs[1].Name; name != "_tasks" {
t.Errorf("unexpected nam for bucket: %s", name)
}
})
// NOTE(affo)(*kv.Service): nope, it does create system buckets with invalid OrgIDs.
t.Run("creating user creates only the user", func(t *testing.T) {
data := fields()
s, done := init(t, data)
defer done()
ctx := context.Background()
// Number of buckets prior to user creation.
// This is because, for now, system buckets always get returned for compatibility with the old system.
_, nbs, err := s.FindBuckets(ctx, influxdb.BucketFilter{})
if err != nil {
t.Fatal(err)
} }
u := &influxdb.User{
ID: 1,
Name: "user1",
}
if err := s.CreateUser(ctx, u); err != nil {
t.Fatal(err)
}
// Check existence
orgs, norgs, err := s.FindOrganizations(ctx, influxdb.OrganizationFilter{})
if err != nil {
t.Fatal(err)
}
if norgs != 0 {
t.Errorf("expected no org, got: %v", orgs)
}
usrs, nusrs, err := s.FindUsers(ctx, influxdb.UserFilter{})
if err != nil {
t.Fatal(err)
}
if nusrs != 1 {
t.Errorf("expected 1 user, got: %v", usrs)
}
urms, nurms, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{})
if err != nil {
t.Fatal(err)
}
if nurms > 0 {
t.Errorf("expected no urm, got: %v", urms)
}
bs, nnbs, err := s.FindBuckets(ctx, influxdb.BucketFilter{})
if err != nil {
t.Fatal(err)
}
// Compare new number of buckets with the one prior to user creation.
if nnbs != nbs {
t.Errorf("expected no bucket created, got: %+v", bs)
}
})
// NOTE(affo)(*kv.Service): nope, it does create a useless URM, no existence check.
// Apparently, system buckets are created too :thinking.
t.Run("creating urm pointing to non existing user fails", func(t *testing.T) {
data := fields()
s, done := init(t, data)
defer done()
ctx := context.Background()
// First create an org and a user.
u := &influxdb.User{
ID: 1,
Name: "user1",
}
if err := s.CreateUser(ctx, u); err != nil {
t.Fatal(err)
}
o := &influxdb.Organization{
// ID(1)
Name: "org1",
}
if err := s.CreateOrganization(ctx, o); err != nil {
t.Fatal(err)
}
checkInvariance := func(nurms int) {
orgs, norgs, err := s.FindOrganizations(ctx, influxdb.OrganizationFilter{})
if err != nil {
t.Fatal(err)
}
if norgs != 1 {
t.Errorf("expected 1 org, got: %v", orgs)
}
usrs, nusrs, err := s.FindUsers(ctx, influxdb.UserFilter{})
if err != nil {
t.Fatal(err)
}
if nusrs != 1 {
t.Errorf("expected 1 user, got: %v", usrs)
}
urms, nnurms, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{})
if err != nil {
t.Fatal(err)
}
if nnurms != nurms {
t.Errorf("expected %d urms got %d: %+v", nurms, nnurms, urms)
}
bs, nbs, err := s.FindBuckets(ctx, influxdb.BucketFilter{})
if err != nil {
t.Fatal(err)
}
if nbs != 2 {
t.Errorf("expected 2 buckets, got: %v", bs)
}
}
checkInvariance(0)
// Wrong userID.
urm := &influxdb.UserResourceMapping{
UserID: 2,
UserType: influxdb.Owner,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.OrgsResourceType,
ResourceID: 1,
}
if err := s.CreateUserResourceMapping(ctx, urm); err == nil {
t.Errorf("expected error got none")
}
checkInvariance(0)
// Wrong orgID. The URM gets created successfully.
urm = &influxdb.UserResourceMapping{
UserID: 1,
UserType: influxdb.Owner,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.OrgsResourceType,
ResourceID: 2,
}
if err := s.CreateUserResourceMapping(ctx, urm); err != nil {
t.Errorf("unexpected error: %v", err)
}
checkInvariance(1)
})
// NOTE(affo)(*kv.Service): errors on bucket creation.
// But, apparently, system buckets are created too :thinking.
t.Run("should not be possible to create bucket without org", func(t *testing.T) {
data := fields()
s, done := init(t, data)
defer done()
ctx := context.Background()
// Number of buckets prior to bucket creation.
// This is because, for now, system buckets always get returned for compatibility with the old system.
_, nbs, err := s.FindBuckets(ctx, influxdb.BucketFilter{})
if err != nil {
t.Fatal(err)
}
b := &influxdb.Bucket{
// ID(1)
OrgID: 1,
Name: "bucket1",
}
if err := s.CreateBucket(ctx, b); err == nil {
t.Errorf("expected error got none")
}
// Check existence
orgs, norgs, err := s.FindOrganizations(ctx, influxdb.OrganizationFilter{})
if err != nil {
t.Fatal(err)
}
if norgs != 0 {
t.Errorf("expected no org, got: %v", orgs)
}
usrs, nusrs, err := s.FindUsers(ctx, influxdb.UserFilter{})
if err != nil {
t.Fatal(err)
}
if nusrs != 0 {
t.Errorf("expected no user, got: %v", usrs)
}
urms, nurms, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{})
if err != nil {
t.Fatal(err)
}
if nurms > 0 {
t.Errorf("expected no urm, got: %v", urms)
}
bs, nnbs, err := s.FindBuckets(ctx, influxdb.BucketFilter{})
if err != nil {
t.Fatal(err)
}
// Compare new number of buckets with the one prior to bucket creation.
if nnbs != nbs {
t.Errorf("expected bucket created, got: %+v", bs)
}
})
t.Run("making user part of org creates mapping to org only", func(t *testing.T) {
for _, userType := range []influxdb.UserType{influxdb.Owner, influxdb.Member} {
t.Run(string(userType), func(t *testing.T) {
data := fields()
s, done := init(t, data)
defer done()
ctx := context.Background()
u := &influxdb.User{
ID: 1,
Name: "user1",
}
if err := s.CreateUser(ctx, u); err != nil {
t.Fatal(err)
}
o := &influxdb.Organization{
// ID(1)
Name: "org1",
}
if err := s.CreateOrganization(ctx, o); err != nil {
t.Fatal(err)
}
urm := &influxdb.UserResourceMapping{
UserID: u.ID,
UserType: userType,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.OrgsResourceType,
ResourceID: o.ID,
}
if err := s.CreateUserResourceMapping(ctx, urm); err != nil {
t.Fatal(err)
}
// Check existence
orgs, norgs, err := s.FindOrganizations(ctx, influxdb.OrganizationFilter{})
if err != nil {
t.Fatal(err)
}
if norgs != 1 {
t.Errorf("expected 1 org, got: %v", orgs)
}
usrs, nusrs, err := s.FindUsers(ctx, influxdb.UserFilter{})
if err != nil {
t.Fatal(err)
}
if nusrs != 1 {
t.Errorf("expected 1 user, got: %v", usrs)
}
bs, nbs, err := s.FindBuckets(ctx, influxdb.BucketFilter{})
if err != nil {
t.Fatal(err)
}
if nbs != 2 {
t.Errorf("expected 2 buckets, got: %v", bs)
}
sort.Sort(bucketsByName(bs))
if name := bs[0].Name; name != "_monitoring" {
t.Errorf("unexpected name for bucket: %s", name)
}
if name := bs[1].Name; name != "_tasks" {
t.Errorf("unexpected name for bucket: %v", name)
}
urms, _, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{})
if err != nil {
t.Fatal(err)
}
want := []*influxdb.UserResourceMapping{
{
UserID: u.ID,
UserType: userType,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.OrgsResourceType,
ResourceID: o.ID,
},
}
sort.Sort(urmByResourceID(want))
sort.Sort(urmByResourceID(urms))
if diff := cmp.Diff(want, urms); diff != "" {
t.Errorf("unexpected urms -want/+got:\n\t%s", diff)
}
// Now add a new bucket and check the URMs.
b := &influxdb.Bucket{
// ID(1)
OrgID: o.ID,
Name: "bucket1",
}
if err := s.CreateBucket(ctx, b); err != nil {
t.Fatal(err)
}
urms, _, err = s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{})
if err != nil {
t.Fatal(err)
}
sort.Sort(urmByResourceID(urms))
if diff := cmp.Diff(want, urms); diff != "" {
t.Errorf("unexpected urms -want/+got:\n\t%s", diff)
}
})
}
})
}
// Delete tests various cases of deletion for the services in the TenantService.
// An example: if you delete a bucket the corresponding user resource mapping is not present.
func Delete(t *testing.T, init func(*testing.T, tenantFields) (*tenant.Service, func())) {
t.Helper()
fields := func() tenantFields {
return tenantFields{
OrgIDGenerator: mock.NewIncrementingIDGenerator(1),
// URM are userID + resourceID (they do not include resource type)
// so same IDs across different resources leads to collisions
// therefore, we need to start bucket IDs at higher offset for
// test.
BucketIDGenerator: mock.NewIncrementingIDGenerator(10),
Users: []*influxdb.User{
{
ID: 1,
Name: "user1",
},
{
ID: 2,
Name: "user2",
},
},
Passwords: []string{"password1", "password2"},
Organizations: []*influxdb.Organization{
{
// ID(1)
Name: "org1",
},
{
// ID(2)
Name: "org2",
},
},
// 2 organizations create 2 system buckets each
// so start at 14
Buckets: []*influxdb.Bucket{
{
// ID(14)
OrgID: 1,
Name: "bucket1",
},
{
// ID(15)
OrgID: 2,
Name: "bucket2",
},
},
UserResourceMappings: []*influxdb.UserResourceMapping{
// NOTE(affo): bucket URMs should not be here, create them only for deletion purposes.
// user 1 owns org1 (and so bucket1)
{
UserID: 1,
UserType: influxdb.Owner,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.OrgsResourceType,
ResourceID: 1,
},
{
UserID: 1,
UserType: influxdb.Owner,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.BucketsResourceType,
ResourceID: 14,
},
// user 1 is member of org2 (and so bucket2)
{
UserID: 1,
UserType: influxdb.Member,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.OrgsResourceType,
ResourceID: 2,
},
{
UserID: 1,
UserType: influxdb.Member,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.BucketsResourceType,
ResourceID: 15,
},
// user 2 owns org2 (and so bucket2)
{
UserID: 2,
UserType: influxdb.Owner,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.OrgsResourceType,
ResourceID: 2,
},
{
UserID: 2,
UserType: influxdb.Owner,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.BucketsResourceType,
ResourceID: 15,
},
},
}
}
t.Run("deleting bucket deletes urm", func(t *testing.T) {
data := fields()
s, done := init(t, data)
defer done()
ctx := context.Background()
f := influxdb.UserResourceMappingFilter{
ResourceID: data.Buckets[0].ID,
ResourceType: influxdb.BucketsResourceType,
}
urms, n, err := s.FindUserResourceMappings(ctx, f)
if err != nil {
t.Fatal(err)
}
if n != 1 {
t.Fatalf("expected 1 urm, got: %v", urms)
}
if err := s.DeleteBucket(ctx, data.Buckets[0].ID); err != nil {
t.Fatal(err)
}
f = influxdb.UserResourceMappingFilter{
ResourceID: data.Buckets[0].ID,
ResourceType: influxdb.BucketsResourceType,
}
urms, n, err = s.FindUserResourceMappings(ctx, f)
if err != nil {
t.Fatal(err)
}
if n > 0 {
t.Fatalf("expected no urm, got: %v", urms)
}
})
// NOTE(affo): those resources could not be dangling (URM could be inferred from an user being in the owner org).
// We do not want to automatically propagate this kind of delete because an resource will always have an owner org.
t.Run("deleting bucket urm does create dangling bucket", func(t *testing.T) {
data := fields()
s, done := init(t, data)
defer done()
ctx := context.Background()
// Pre-check the current situation.
// bucket1 is owned by user1.
// Check it.
urms, _, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{
ResourceType: influxdb.BucketsResourceType,
ResourceID: data.Buckets[0].ID,
})
if err != nil {
t.Fatal(err)
}
want := []*influxdb.UserResourceMapping{
{
UserID: data.Users[0].ID,
UserType: influxdb.Owner,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.BucketsResourceType,
ResourceID: data.Buckets[0].ID,
},
}
sort.Sort(urmByUserID(want))
sort.Sort(urmByUserID(urms))
if diff := cmp.Diff(want, urms); diff != "" {
t.Fatalf("unexpected urms -want/+got:\n\t%s", diff)
}
// bucket2 is owned by user2.
// bucket2 is readable by user2.
// Check it.
urms, _, err = s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{
ResourceType: influxdb.BucketsResourceType,
ResourceID: data.Buckets[1].ID,
})
if err != nil {
t.Fatal(err)
}
want = []*influxdb.UserResourceMapping{
{
UserID: data.Users[1].ID,
UserType: influxdb.Owner,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.BucketsResourceType,
ResourceID: data.Buckets[1].ID,
},
{
UserID: data.Users[0].ID,
UserType: influxdb.Member,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.BucketsResourceType,
ResourceID: data.Buckets[1].ID,
},
}
sort.Sort(urmByUserID(want))
sort.Sort(urmByUserID(urms))
if diff := cmp.Diff(want, urms); diff != "" {
t.Fatalf("unexpected urms -want/+got:\n\t%s", diff)
}
// Now delete user2 -> bucket2.
// Still expect bucket2 to exist (user1 still points to it).
if err := s.DeleteUserResourceMapping(ctx, data.Buckets[1].ID, data.Users[1].ID); err != nil {
t.Fatal(err)
}
bs, nbs, err := s.FindBuckets(ctx, influxdb.BucketFilter{ID: &data.Buckets[1].ID})
if err != nil {
t.Fatal(err)
}
if nbs != 1 {
t.Errorf("expected 1 buckets, got: %v", bs)
}
// Now delete user1 -> bucket2.
// Still expect bucket2 to exist (nobody points to it).
if err := s.DeleteUserResourceMapping(ctx, data.Buckets[1].ID, data.Users[0].ID); err != nil {
t.Fatal(err)
}
bs, nbs, err = s.FindBuckets(ctx, influxdb.BucketFilter{ID: &data.Buckets[1].ID})
if err != nil {
t.Fatal(err)
}
if nbs != 1 {
t.Errorf("expected 1 buckets, got: %v", bs)
}
urms, nurms, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{
ResourceType: influxdb.BucketsResourceType,
ResourceID: data.Buckets[1].ID,
})
if err != nil {
t.Fatal(err)
}
if nurms != 0 {
t.Errorf("expected bucket2, to be dangling, got: %+v", urms)
}
// Now delete user1 -> bucket1.
// Still expect bucket1 to exist (nobody points to it).
if err := s.DeleteUserResourceMapping(ctx, data.Buckets[0].ID, data.Users[0].ID); err != nil {
t.Fatal(err)
}
bs, nbs, err = s.FindBuckets(ctx, influxdb.BucketFilter{ID: &data.Buckets[0].ID})
if err != nil {
t.Fatal(err)
}
if nbs != 1 {
t.Errorf("expected 1 buckets, got: %v", bs)
}
urms, nurms, err = s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{
ResourceType: influxdb.BucketsResourceType,
ResourceID: data.Buckets[0].ID,
})
if err != nil {
t.Fatal(err)
}
if nurms != 0 {
t.Errorf("expected bucket1, to be dangling, got: %+v", urms)
}
})
t.Run("deleting a user deletes every related urm and nothing else", func(t *testing.T) {
data := fields()
s, done := init(t, data)
defer done()
ctx := context.Background()
// bucket1 is owned by user1.
// Check it.
urms, _, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{
ResourceType: influxdb.BucketsResourceType,
ResourceID: data.Buckets[0].ID,
})
if err != nil {
t.Fatal(err)
}
want := []*influxdb.UserResourceMapping{
{
UserID: data.Users[0].ID,
UserType: influxdb.Owner,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.BucketsResourceType,
ResourceID: data.Buckets[0].ID,
},
}
sort.Sort(urmByUserID(want))
sort.Sort(urmByUserID(urms))
if diff := cmp.Diff(want, urms); diff != "" {
t.Fatalf("unexpected urms -want/+got:\n\t%s", diff)
}
// Delete user1.
// We expect his urms deleted but not bucket1.
if err := s.DeleteUser(ctx, data.Users[0].ID); err != nil {
t.Fatal(err)
}
urms, nurms, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{
UserID: data.Users[0].ID,
})
if err != nil {
t.Fatal(err)
}
if nurms > 0 {
t.Errorf("expected that user deletion would remove dangling urms, got: %+v", urms)
}
bs, nbs, err := s.FindBuckets(ctx, influxdb.BucketFilter{ID: &data.Buckets[0].ID})
if err != nil {
t.Fatal(err)
}
if nbs != 1 {
t.Errorf("expected 1 buckets, got: %v", bs)
}
})
t.Run("deleting a bucket deletes every related urm", func(t *testing.T) {
data := fields()
s, done := init(t, data)
defer done()
ctx := context.Background()
// Delete bucket2.
// We expect its urms deleted.
if err := s.DeleteBucket(ctx, data.Buckets[1].ID); err != nil {
t.Fatal(err)
}
urms, nurms, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{
ResourceType: influxdb.BucketsResourceType,
ResourceID: data.Buckets[1].ID,
})
if err != nil {
t.Fatal(err)
}
if nurms > 0 {
t.Errorf("expected that bucket deletion would remove dangling urms, got: %+v", urms)
}
})
// NOTE(affo)(*kv.Service): buckets, users, and urms survive.
t.Run("deleting an organization should delete everything that depends on it", func(t *testing.T) {
data := fields()
s, done := init(t, data)
defer done()
ctx := context.Background()
// Delete org1.
// We expect its buckets to be deleted.
// We expect urms to those buckets to be deleted too.
// No user should be deleted.
preDeletionBuckets, _, err := s.FindBuckets(ctx, influxdb.BucketFilter{OrganizationID: &data.Organizations[0].ID})
if err != nil {
t.Fatal(err)
}
if err := s.DeleteOrganization(ctx, data.Organizations[0].ID); err != nil {
t.Fatal(err)
}
bs, nbs, err := s.FindBuckets(ctx, influxdb.BucketFilter{OrganizationID: &data.Organizations[0].ID})
if err != nil {
t.Fatal(err)
}
if nbs != 0 {
t.Errorf("expected org buckets to be deleted, got: %+v", bs)
}
urms, _, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{
UserID: data.Users[0].ID,
ResourceType: influxdb.BucketsResourceType,
})
if err != nil {
t.Fatal(err)
}
for _, urm := range urms {
for _, b := range preDeletionBuckets {
if urm.ResourceID == b.ID {
t.Errorf("expected this urm to be deleted, got %+v instead", urm)
}
}
}
if _, err := s.FindUser(ctx, influxdb.UserFilter{ID: &data.Users[0].ID}); err != nil {
t.Fatal(err)
}
// Delete org2.
// Everything should disappear.
if err := s.DeleteOrganization(ctx, data.Organizations[1].ID); err != nil {
t.Fatal(err)
}
orgs, norgs, err := s.FindOrganizations(ctx, influxdb.OrganizationFilter{})
if err != nil {
t.Fatal(err)
}
if norgs != 0 {
t.Errorf("expected no org, got: %v", orgs)
}
usrs, nusrs, err := s.FindUsers(ctx, influxdb.UserFilter{})
if err != nil {
t.Fatal(err)
}
if nusrs != 2 {
t.Errorf("expected 2 users, got: %v", usrs)
}
urms, nurms, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{})
if err != nil {
t.Fatal(err)
}
if nurms > 0 {
t.Errorf("expected no urm, got: %v", urms)
}
bs, nbs, err = s.FindBuckets(ctx, influxdb.BucketFilter{})
if err != nil {
t.Fatal(err)
}
if nbs != 0 {
t.Errorf("expected buckets to be deleted, got: %+v", bs)
}
})
}
func initBoltTenantService(t *testing.T, f tenantFields) (*tenant.Service, func()) {
s, closeBolt := itesting.NewTestBoltStore(t)
store := tenant.NewStore(s) store := tenant.NewStore(s)
if f.OrgIDGenerator != nil { if f.OrgIDGenerator != nil {

View File

@ -2,10 +2,10 @@ package tenant_test
import ( import (
"context" "context"
"github.com/influxdata/influxdb/v2/kit/platform"
"testing" "testing"
"github.com/influxdata/influxdb/v2" "github.com/influxdata/influxdb/v2"
"github.com/influxdata/influxdb/v2/kit/platform"
"github.com/influxdata/influxdb/v2/kv" "github.com/influxdata/influxdb/v2/kv"
"github.com/influxdata/influxdb/v2/mock" "github.com/influxdata/influxdb/v2/mock"
"github.com/influxdata/influxdb/v2/tenant" "github.com/influxdata/influxdb/v2/tenant"
@ -17,11 +17,7 @@ func TestBoltUserResourceMappingService(t *testing.T) {
} }
func initBoltUserResourceMappingService(f influxdbtesting.UserResourceFields, t *testing.T) (influxdb.UserResourceMappingService, func()) { func initBoltUserResourceMappingService(f influxdbtesting.UserResourceFields, t *testing.T) (influxdb.UserResourceMappingService, func()) {
s, closeBolt, err := NewTestBoltStore(t) s, closeBolt := influxdbtesting.NewTestBoltStore(t)
if err != nil {
t.Fatalf("failed to create new kv store: %v", err)
}
svc, closeSvc := initUserResourceMappingService(s, f, t) svc, closeSvc := initUserResourceMappingService(s, f, t)
return svc, func() { return svc, func() {
closeSvc() closeSvc()

View File

@ -17,11 +17,7 @@ func TestBoltUserService(t *testing.T) {
} }
func initBoltUserService(f influxdbtesting.UserFields, t *testing.T) (influxdb.UserService, string, func()) { func initBoltUserService(f influxdbtesting.UserFields, t *testing.T) (influxdb.UserService, string, func()) {
s, closeBolt, err := NewTestBoltStore(t) s, closeBolt := influxdbtesting.NewTestBoltStore(t)
if err != nil {
t.Fatalf("failed to create new kv store: %v", err)
}
svc, op, closeSvc := initUserService(s, f, t) svc, op, closeSvc := initUserService(s, f, t)
return svc, op, func() { return svc, op, func() {
closeSvc() closeSvc()
@ -53,11 +49,7 @@ func TestBoltPasswordService(t *testing.T) {
} }
func initBoltPasswordsService(f influxdbtesting.PasswordFields, t *testing.T) (influxdb.PasswordsService, func()) { func initBoltPasswordsService(f influxdbtesting.PasswordFields, t *testing.T) (influxdb.PasswordsService, func()) {
s, closeStore, err := NewTestBoltStore(t) s, closeStore := influxdbtesting.NewTestBoltStore(t)
if err != nil {
t.Fatalf("failed to create new bolt kv store: %v", err)
}
svc, closeSvc := initPasswordsService(s, f, t) svc, closeSvc := initPasswordsService(s, f, t)
return svc, func() { return svc, func() {
closeSvc() closeSvc()
@ -91,10 +83,7 @@ func initPasswordsService(s kv.Store, f influxdbtesting.PasswordFields, t *testi
} }
func TestFindPermissionsFromUser(t *testing.T) { func TestFindPermissionsFromUser(t *testing.T) {
s, _, err := NewTestInmemStore(t) s := influxdbtesting.NewTestInmemStore(t)
if err != nil {
t.Fatal(err)
}
storage := tenant.NewStore(s) storage := tenant.NewStore(s)
svc := tenant.NewService(storage) svc := tenant.NewService(storage)
@ -111,7 +100,7 @@ func TestFindPermissionsFromUser(t *testing.T) {
ctx := context.Background() ctx := context.Background()
// createSomeURMS // createSomeURMS
err = svc.CreateUserResourceMapping(ctx, &influxdb.UserResourceMapping{ err := svc.CreateUserResourceMapping(ctx, &influxdb.UserResourceMapping{
UserID: u.ID, UserID: u.ID,
UserType: influxdb.Member, UserType: influxdb.Member,
ResourceType: influxdb.OrgsResourceType, ResourceType: influxdb.OrgsResourceType,

View File

@ -3,15 +3,16 @@ package tenant_test
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/influxdata/influxdb/v2/kit/platform"
"reflect" "reflect"
"testing" "testing"
"time" "time"
"github.com/influxdata/influxdb/v2" "github.com/influxdata/influxdb/v2"
"github.com/influxdata/influxdb/v2/kit/platform"
"github.com/influxdata/influxdb/v2/kv" "github.com/influxdata/influxdb/v2/kv"
"github.com/influxdata/influxdb/v2/mock" "github.com/influxdata/influxdb/v2/mock"
"github.com/influxdata/influxdb/v2/tenant" "github.com/influxdata/influxdb/v2/tenant"
itesting "github.com/influxdata/influxdb/v2/testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -277,12 +278,7 @@ func TestBucket(t *testing.T) {
} }
for _, testScenario := range st { for _, testScenario := range st {
t.Run(testScenario.name, func(t *testing.T) { t.Run(testScenario.name, func(t *testing.T) {
s, closeS, err := NewTestInmemStore(t) s := itesting.NewTestInmemStore(t)
if err != nil {
t.Fatal(err)
}
defer closeS()
ts := tenant.NewStore(s, tenant.WithNow(func() time.Time { ts := tenant.NewStore(s, tenant.WithNow(func() time.Time {
return aTime return aTime
})) }))

View File

@ -3,14 +3,15 @@ package tenant_test
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/influxdata/influxdb/v2/kit/platform"
"testing" "testing"
"time" "time"
"github.com/influxdata/influxdb/v2" "github.com/influxdata/influxdb/v2"
"github.com/influxdata/influxdb/v2/kit/platform"
"github.com/influxdata/influxdb/v2/kv" "github.com/influxdata/influxdb/v2/kv"
"github.com/influxdata/influxdb/v2/mock" "github.com/influxdata/influxdb/v2/mock"
"github.com/influxdata/influxdb/v2/tenant" "github.com/influxdata/influxdb/v2/tenant"
itesting "github.com/influxdata/influxdb/v2/testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -206,12 +207,7 @@ func TestOrg(t *testing.T) {
} }
for _, testScenario := range st { for _, testScenario := range st {
t.Run(testScenario.name, func(t *testing.T) { t.Run(testScenario.name, func(t *testing.T) {
s, closeS, err := NewTestInmemStore(t) s := itesting.NewTestInmemStore(t)
if err != nil {
t.Fatal(err)
}
defer closeS()
ts := tenant.NewStore(s, tenant.WithNow(func() time.Time { ts := tenant.NewStore(s, tenant.WithNow(func() time.Time {
return aTime return aTime
})) }))

View File

@ -3,16 +3,17 @@ package tenant_test
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/influxdata/influxdb/v2/kit/platform"
"github.com/influxdata/influxdb/v2/kit/platform/errors"
"reflect" "reflect"
"sort" "sort"
"testing" "testing"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/influxdata/influxdb/v2" "github.com/influxdata/influxdb/v2"
"github.com/influxdata/influxdb/v2/kit/platform"
"github.com/influxdata/influxdb/v2/kit/platform/errors"
"github.com/influxdata/influxdb/v2/kv" "github.com/influxdata/influxdb/v2/kv"
"github.com/influxdata/influxdb/v2/tenant" "github.com/influxdata/influxdb/v2/tenant"
itesting "github.com/influxdata/influxdb/v2/testing"
) )
func TestURM(t *testing.T) { func TestURM(t *testing.T) {
@ -333,12 +334,7 @@ func TestURM(t *testing.T) {
} }
for _, testScenario := range st { for _, testScenario := range st {
t.Run(testScenario.name, func(t *testing.T) { t.Run(testScenario.name, func(t *testing.T) {
s, closeS, err := NewTestInmemStore(t) s := itesting.NewTestInmemStore(t)
if err != nil {
t.Fatal(err)
}
defer closeS()
ts := tenant.NewStore(s) ts := tenant.NewStore(s)
// setup // setup

View File

@ -3,13 +3,14 @@ package tenant_test
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/influxdata/influxdb/v2/kit/platform"
"reflect" "reflect"
"testing" "testing"
"github.com/influxdata/influxdb/v2" "github.com/influxdata/influxdb/v2"
"github.com/influxdata/influxdb/v2/kit/platform"
"github.com/influxdata/influxdb/v2/kv" "github.com/influxdata/influxdb/v2/kv"
"github.com/influxdata/influxdb/v2/tenant" "github.com/influxdata/influxdb/v2/tenant"
itesting "github.com/influxdata/influxdb/v2/testing"
) )
func TestUser(t *testing.T) { func TestUser(t *testing.T) {
@ -242,12 +243,7 @@ func TestUser(t *testing.T) {
} }
for _, testScenario := range st { for _, testScenario := range st {
t.Run(testScenario.name, func(t *testing.T) { t.Run(testScenario.name, func(t *testing.T) {
s, closeS, err := NewTestInmemStore(t) s := itesting.NewTestInmemStore(t)
if err != nil {
t.Fatal(err)
}
defer closeS()
ts := tenant.NewStore(s) ts := tenant.NewStore(s)
// setup // setup

View File

@ -1,874 +0,0 @@
package testing
import (
"context"
"sort"
"strings"
"testing"
"github.com/influxdata/influxdb/v2/kit/platform"
"github.com/google/go-cmp/cmp"
"github.com/influxdata/influxdb/v2"
"github.com/influxdata/influxdb/v2/mock"
)
type TenantFields struct {
OrgIDGenerator platform.IDGenerator
BucketIDGenerator platform.IDGenerator
Users []*influxdb.User
Passwords []string // passwords are indexed against the Users field
UserResourceMappings []*influxdb.UserResourceMapping
Organizations []*influxdb.Organization
Buckets []*influxdb.Bucket
}
// TenantService tests the tenant service functions.
// These tests stress the relation between the services embedded by the TenantService.
// The individual functionality of services is tested elsewhere.
func TenantService(t *testing.T, init func(*testing.T, TenantFields) (influxdb.TenantService, func())) {
tests := []struct {
name string
fn func(t *testing.T, init func(*testing.T, TenantFields) (influxdb.TenantService, func()))
}{
{
name: "Create",
fn: Create,
},
{
name: "Delete",
fn: Delete,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.fn(t, init)
})
}
}
type bucketsByName []*influxdb.Bucket
func (b bucketsByName) Len() int {
return len(b)
}
func (b bucketsByName) Less(i, j int) bool {
return strings.Compare(b[i].Name, b[j].Name) < 0
}
func (b bucketsByName) Swap(i, j int) {
b[i], b[j] = b[j], b[i]
}
type urmByResourceID []*influxdb.UserResourceMapping
func (u urmByResourceID) Len() int {
return len(u)
}
func (u urmByResourceID) Less(i, j int) bool {
return u[i].ResourceID < u[j].ResourceID
}
func (u urmByResourceID) Swap(i, j int) {
u[i], u[j] = u[j], u[i]
}
type urmByUserID []*influxdb.UserResourceMapping
func (u urmByUserID) Len() int {
return len(u)
}
func (u urmByUserID) Less(i, j int) bool {
return u[i].UserID < u[j].UserID
}
func (u urmByUserID) Swap(i, j int) {
u[i], u[j] = u[j], u[i]
}
// Create tests various cases of creation for the services in the TenantService.
// For example, when you create a user, do you create system buckets? How are URMs organized?
func Create(t *testing.T, init func(*testing.T, TenantFields) (influxdb.TenantService, func())) {
t.Helper()
// Blank fields, we are testing creation.
fields := func() TenantFields {
return TenantFields{
OrgIDGenerator: mock.NewIncrementingIDGenerator(1),
BucketIDGenerator: mock.NewIncrementingIDGenerator(1),
}
}
// NOTE(affo)(*kv.Service): tests that contain s.CreateOrganization() generate error in logs:
// Failed to make user owner of organization: {"error": "could not find authorizer on context when adding user to resource type orgs"}.
// This happens because kv requires an authorization to be in context.
// This is a bad dependency pattern (store -> auth) and should not be there.
// Anyways this does not prevent the org to be created. If you add the urm manually you'll obtain the same result.
// NOTE(affo)(*kv.Service): it also creates urms for the non existing user found in context.
t.Run("creating an org creates system buckets", func(t *testing.T) {
data := fields()
s, done := init(t, data)
defer done()
ctx := context.Background()
o := &influxdb.Organization{
// ID(1)
Name: "org1",
}
if err := s.CreateOrganization(ctx, o); err != nil {
t.Fatal(err)
}
// Check existence
orgs, norgs, err := s.FindOrganizations(ctx, influxdb.OrganizationFilter{})
if err != nil {
t.Fatal(err)
}
if norgs != 1 {
t.Errorf("expected 1 org, got: %v", orgs)
}
usrs, nusrs, err := s.FindUsers(ctx, influxdb.UserFilter{})
if err != nil {
t.Fatal(err)
}
if nusrs > 0 {
t.Errorf("expected no user, got: %v", usrs)
}
urms, nurms, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{})
if err != nil {
t.Fatal(err)
}
if nurms > 0 {
t.Errorf("expected no urm, got: %+v", urms)
}
bs, nbs, err := s.FindBuckets(ctx, influxdb.BucketFilter{})
if err != nil {
t.Fatal(err)
}
if nbs != 2 {
t.Errorf("expected 2 buckets, got: %v", bs)
}
sort.Sort(bucketsByName(bs))
if name := bs[0].Name; name != "_monitoring" {
t.Errorf("unexpected nam for bucket: %s", name)
}
if name := bs[1].Name; name != "_tasks" {
t.Errorf("unexpected nam for bucket: %s", name)
}
})
// NOTE(affo)(*kv.Service): nope, it does create system buckets with invalid OrgIDs.
t.Run("creating user creates only the user", func(t *testing.T) {
data := fields()
s, done := init(t, data)
defer done()
ctx := context.Background()
// Number of buckets prior to user creation.
// This is because, for now, system buckets always get returned for compatibility with the old system.
_, nbs, err := s.FindBuckets(ctx, influxdb.BucketFilter{})
if err != nil {
t.Fatal(err)
}
u := &influxdb.User{
ID: 1,
Name: "user1",
}
if err := s.CreateUser(ctx, u); err != nil {
t.Fatal(err)
}
// Check existence
orgs, norgs, err := s.FindOrganizations(ctx, influxdb.OrganizationFilter{})
if err != nil {
t.Fatal(err)
}
if norgs != 0 {
t.Errorf("expected no org, got: %v", orgs)
}
usrs, nusrs, err := s.FindUsers(ctx, influxdb.UserFilter{})
if err != nil {
t.Fatal(err)
}
if nusrs != 1 {
t.Errorf("expected 1 user, got: %v", usrs)
}
urms, nurms, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{})
if err != nil {
t.Fatal(err)
}
if nurms > 0 {
t.Errorf("expected no urm, got: %v", urms)
}
bs, nnbs, err := s.FindBuckets(ctx, influxdb.BucketFilter{})
if err != nil {
t.Fatal(err)
}
// Compare new number of buckets with the one prior to user creation.
if nnbs != nbs {
t.Errorf("expected no bucket created, got: %+v", bs)
}
})
// NOTE(affo)(*kv.Service): nope, it does create a useless URM, no existence check.
// Apparently, system buckets are created too :thinking.
t.Run("creating urm pointing to non existing user fails", func(t *testing.T) {
data := fields()
s, done := init(t, data)
defer done()
ctx := context.Background()
// First create an org and a user.
u := &influxdb.User{
ID: 1,
Name: "user1",
}
if err := s.CreateUser(ctx, u); err != nil {
t.Fatal(err)
}
o := &influxdb.Organization{
// ID(1)
Name: "org1",
}
if err := s.CreateOrganization(ctx, o); err != nil {
t.Fatal(err)
}
checkInvariance := func(nurms int) {
orgs, norgs, err := s.FindOrganizations(ctx, influxdb.OrganizationFilter{})
if err != nil {
t.Fatal(err)
}
if norgs != 1 {
t.Errorf("expected 1 org, got: %v", orgs)
}
usrs, nusrs, err := s.FindUsers(ctx, influxdb.UserFilter{})
if err != nil {
t.Fatal(err)
}
if nusrs != 1 {
t.Errorf("expected 1 user, got: %v", usrs)
}
urms, nnurms, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{})
if err != nil {
t.Fatal(err)
}
if nnurms != nurms {
t.Errorf("expected %d urms got %d: %+v", nurms, nnurms, urms)
}
bs, nbs, err := s.FindBuckets(ctx, influxdb.BucketFilter{})
if err != nil {
t.Fatal(err)
}
if nbs != 2 {
t.Errorf("expected 2 buckets, got: %v", bs)
}
}
checkInvariance(0)
// Wrong userID.
urm := &influxdb.UserResourceMapping{
UserID: 2,
UserType: influxdb.Owner,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.OrgsResourceType,
ResourceID: 1,
}
if err := s.CreateUserResourceMapping(ctx, urm); err == nil {
t.Errorf("expected error got none")
}
checkInvariance(0)
// Wrong orgID. The URM gets created successfully.
urm = &influxdb.UserResourceMapping{
UserID: 1,
UserType: influxdb.Owner,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.OrgsResourceType,
ResourceID: 2,
}
if err := s.CreateUserResourceMapping(ctx, urm); err != nil {
t.Errorf("unexpected error: %v", err)
}
checkInvariance(1)
})
// NOTE(affo)(*kv.Service): errors on bucket creation.
// But, apparently, system buckets are created too :thinking.
t.Run("should not be possible to create bucket without org", func(t *testing.T) {
data := fields()
s, done := init(t, data)
defer done()
ctx := context.Background()
// Number of buckets prior to bucket creation.
// This is because, for now, system buckets always get returned for compatibility with the old system.
_, nbs, err := s.FindBuckets(ctx, influxdb.BucketFilter{})
if err != nil {
t.Fatal(err)
}
b := &influxdb.Bucket{
// ID(1)
OrgID: 1,
Name: "bucket1",
}
if err := s.CreateBucket(ctx, b); err == nil {
t.Errorf("expected error got none")
}
// Check existence
orgs, norgs, err := s.FindOrganizations(ctx, influxdb.OrganizationFilter{})
if err != nil {
t.Fatal(err)
}
if norgs != 0 {
t.Errorf("expected no org, got: %v", orgs)
}
usrs, nusrs, err := s.FindUsers(ctx, influxdb.UserFilter{})
if err != nil {
t.Fatal(err)
}
if nusrs != 0 {
t.Errorf("expected no user, got: %v", usrs)
}
urms, nurms, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{})
if err != nil {
t.Fatal(err)
}
if nurms > 0 {
t.Errorf("expected no urm, got: %v", urms)
}
bs, nnbs, err := s.FindBuckets(ctx, influxdb.BucketFilter{})
if err != nil {
t.Fatal(err)
}
// Compare new number of buckets with the one prior to bucket creation.
if nnbs != nbs {
t.Errorf("expected bucket created, got: %+v", bs)
}
})
t.Run("making user part of org creates mapping to org only", func(t *testing.T) {
for _, userType := range []influxdb.UserType{influxdb.Owner, influxdb.Member} {
t.Run(string(userType), func(t *testing.T) {
data := fields()
s, done := init(t, data)
defer done()
ctx := context.Background()
u := &influxdb.User{
ID: 1,
Name: "user1",
}
if err := s.CreateUser(ctx, u); err != nil {
t.Fatal(err)
}
o := &influxdb.Organization{
// ID(1)
Name: "org1",
}
if err := s.CreateOrganization(ctx, o); err != nil {
t.Fatal(err)
}
urm := &influxdb.UserResourceMapping{
UserID: u.ID,
UserType: userType,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.OrgsResourceType,
ResourceID: o.ID,
}
if err := s.CreateUserResourceMapping(ctx, urm); err != nil {
t.Fatal(err)
}
// Check existence
orgs, norgs, err := s.FindOrganizations(ctx, influxdb.OrganizationFilter{})
if err != nil {
t.Fatal(err)
}
if norgs != 1 {
t.Errorf("expected 1 org, got: %v", orgs)
}
usrs, nusrs, err := s.FindUsers(ctx, influxdb.UserFilter{})
if err != nil {
t.Fatal(err)
}
if nusrs != 1 {
t.Errorf("expected 1 user, got: %v", usrs)
}
bs, nbs, err := s.FindBuckets(ctx, influxdb.BucketFilter{})
if err != nil {
t.Fatal(err)
}
if nbs != 2 {
t.Errorf("expected 2 buckets, got: %v", bs)
}
sort.Sort(bucketsByName(bs))
if name := bs[0].Name; name != "_monitoring" {
t.Errorf("unexpected name for bucket: %s", name)
}
if name := bs[1].Name; name != "_tasks" {
t.Errorf("unexpected name for bucket: %v", name)
}
urms, _, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{})
if err != nil {
t.Fatal(err)
}
want := []*influxdb.UserResourceMapping{
{
UserID: u.ID,
UserType: userType,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.OrgsResourceType,
ResourceID: o.ID,
},
}
sort.Sort(urmByResourceID(want))
sort.Sort(urmByResourceID(urms))
if diff := cmp.Diff(want, urms); diff != "" {
t.Errorf("unexpected urms -want/+got:\n\t%s", diff)
}
// Now add a new bucket and check the URMs.
b := &influxdb.Bucket{
// ID(1)
OrgID: o.ID,
Name: "bucket1",
}
if err := s.CreateBucket(ctx, b); err != nil {
t.Fatal(err)
}
urms, _, err = s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{})
if err != nil {
t.Fatal(err)
}
sort.Sort(urmByResourceID(urms))
if diff := cmp.Diff(want, urms); diff != "" {
t.Errorf("unexpected urms -want/+got:\n\t%s", diff)
}
})
}
})
}
// Delete tests various cases of deletion for the services in the TenantService.
// An example: if you delete a bucket the corresponding user resource mapping is not present.
func Delete(t *testing.T, init func(*testing.T, TenantFields) (influxdb.TenantService, func())) {
t.Helper()
fields := func() TenantFields {
return TenantFields{
OrgIDGenerator: mock.NewIncrementingIDGenerator(1),
// URM are userID + resourceID (they do not include resource type)
// so same IDs across different resources leads to collisions
// therefore, we need to start bucket IDs at higher offset for
// test.
BucketIDGenerator: mock.NewIncrementingIDGenerator(10),
Users: []*influxdb.User{
{
ID: 1,
Name: "user1",
},
{
ID: 2,
Name: "user2",
},
},
Passwords: []string{"password1", "password2"},
Organizations: []*influxdb.Organization{
{
// ID(1)
Name: "org1",
},
{
// ID(2)
Name: "org2",
},
},
// 2 organizations create 2 system buckets each
// so start at 14
Buckets: []*influxdb.Bucket{
{
// ID(14)
OrgID: 1,
Name: "bucket1",
},
{
// ID(15)
OrgID: 2,
Name: "bucket2",
},
},
UserResourceMappings: []*influxdb.UserResourceMapping{
// NOTE(affo): bucket URMs should not be here, create them only for deletion purposes.
// user 1 owns org1 (and so bucket1)
{
UserID: 1,
UserType: influxdb.Owner,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.OrgsResourceType,
ResourceID: 1,
},
{
UserID: 1,
UserType: influxdb.Owner,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.BucketsResourceType,
ResourceID: 14,
},
// user 1 is member of org2 (and so bucket2)
{
UserID: 1,
UserType: influxdb.Member,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.OrgsResourceType,
ResourceID: 2,
},
{
UserID: 1,
UserType: influxdb.Member,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.BucketsResourceType,
ResourceID: 15,
},
// user 2 owns org2 (and so bucket2)
{
UserID: 2,
UserType: influxdb.Owner,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.OrgsResourceType,
ResourceID: 2,
},
{
UserID: 2,
UserType: influxdb.Owner,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.BucketsResourceType,
ResourceID: 15,
},
},
}
}
t.Run("deleting bucket deletes urm", func(t *testing.T) {
data := fields()
s, done := init(t, data)
defer done()
ctx := context.Background()
f := influxdb.UserResourceMappingFilter{
ResourceID: data.Buckets[0].ID,
ResourceType: influxdb.BucketsResourceType,
}
urms, n, err := s.FindUserResourceMappings(ctx, f)
if err != nil {
t.Fatal(err)
}
if n != 1 {
t.Fatalf("expected 1 urm, got: %v", urms)
}
if err := s.DeleteBucket(ctx, data.Buckets[0].ID); err != nil {
t.Fatal(err)
}
f = influxdb.UserResourceMappingFilter{
ResourceID: data.Buckets[0].ID,
ResourceType: influxdb.BucketsResourceType,
}
urms, n, err = s.FindUserResourceMappings(ctx, f)
if err != nil {
t.Fatal(err)
}
if n > 0 {
t.Fatalf("expected no urm, got: %v", urms)
}
})
// NOTE(affo): those resources could not be dangling (URM could be inferred from an user being in the owner org).
// We do not want to automatically propagate this kind of delete because an resource will always have an owner org.
t.Run("deleting bucket urm does create dangling bucket", func(t *testing.T) {
data := fields()
s, done := init(t, data)
defer done()
ctx := context.Background()
// Pre-check the current situation.
// bucket1 is owned by user1.
// Check it.
urms, _, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{
ResourceType: influxdb.BucketsResourceType,
ResourceID: data.Buckets[0].ID,
})
if err != nil {
t.Fatal(err)
}
want := []*influxdb.UserResourceMapping{
{
UserID: data.Users[0].ID,
UserType: influxdb.Owner,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.BucketsResourceType,
ResourceID: data.Buckets[0].ID,
},
}
sort.Sort(urmByUserID(want))
sort.Sort(urmByUserID(urms))
if diff := cmp.Diff(want, urms); diff != "" {
t.Fatalf("unexpected urms -want/+got:\n\t%s", diff)
}
// bucket2 is owned by user2.
// bucket2 is readable by user2.
// Check it.
urms, _, err = s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{
ResourceType: influxdb.BucketsResourceType,
ResourceID: data.Buckets[1].ID,
})
if err != nil {
t.Fatal(err)
}
want = []*influxdb.UserResourceMapping{
{
UserID: data.Users[1].ID,
UserType: influxdb.Owner,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.BucketsResourceType,
ResourceID: data.Buckets[1].ID,
},
{
UserID: data.Users[0].ID,
UserType: influxdb.Member,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.BucketsResourceType,
ResourceID: data.Buckets[1].ID,
},
}
sort.Sort(urmByUserID(want))
sort.Sort(urmByUserID(urms))
if diff := cmp.Diff(want, urms); diff != "" {
t.Fatalf("unexpected urms -want/+got:\n\t%s", diff)
}
// Now delete user2 -> bucket2.
// Still expect bucket2 to exist (user1 still points to it).
if err := s.DeleteUserResourceMapping(ctx, data.Buckets[1].ID, data.Users[1].ID); err != nil {
t.Fatal(err)
}
bs, nbs, err := s.FindBuckets(ctx, influxdb.BucketFilter{ID: &data.Buckets[1].ID})
if err != nil {
t.Fatal(err)
}
if nbs != 1 {
t.Errorf("expected 1 buckets, got: %v", bs)
}
// Now delete user1 -> bucket2.
// Still expect bucket2 to exist (nobody points to it).
if err := s.DeleteUserResourceMapping(ctx, data.Buckets[1].ID, data.Users[0].ID); err != nil {
t.Fatal(err)
}
bs, nbs, err = s.FindBuckets(ctx, influxdb.BucketFilter{ID: &data.Buckets[1].ID})
if err != nil {
t.Fatal(err)
}
if nbs != 1 {
t.Errorf("expected 1 buckets, got: %v", bs)
}
urms, nurms, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{
ResourceType: influxdb.BucketsResourceType,
ResourceID: data.Buckets[1].ID,
})
if err != nil {
t.Fatal(err)
}
if nurms != 0 {
t.Errorf("expected bucket2, to be dangling, got: %+v", urms)
}
// Now delete user1 -> bucket1.
// Still expect bucket1 to exist (nobody points to it).
if err := s.DeleteUserResourceMapping(ctx, data.Buckets[0].ID, data.Users[0].ID); err != nil {
t.Fatal(err)
}
bs, nbs, err = s.FindBuckets(ctx, influxdb.BucketFilter{ID: &data.Buckets[0].ID})
if err != nil {
t.Fatal(err)
}
if nbs != 1 {
t.Errorf("expected 1 buckets, got: %v", bs)
}
urms, nurms, err = s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{
ResourceType: influxdb.BucketsResourceType,
ResourceID: data.Buckets[0].ID,
})
if err != nil {
t.Fatal(err)
}
if nurms != 0 {
t.Errorf("expected bucket1, to be dangling, got: %+v", urms)
}
})
t.Run("deleting a user deletes every related urm and nothing else", func(t *testing.T) {
data := fields()
s, done := init(t, data)
defer done()
ctx := context.Background()
// bucket1 is owned by user1.
// Check it.
urms, _, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{
ResourceType: influxdb.BucketsResourceType,
ResourceID: data.Buckets[0].ID,
})
if err != nil {
t.Fatal(err)
}
want := []*influxdb.UserResourceMapping{
{
UserID: data.Users[0].ID,
UserType: influxdb.Owner,
MappingType: influxdb.UserMappingType,
ResourceType: influxdb.BucketsResourceType,
ResourceID: data.Buckets[0].ID,
},
}
sort.Sort(urmByUserID(want))
sort.Sort(urmByUserID(urms))
if diff := cmp.Diff(want, urms); diff != "" {
t.Fatalf("unexpected urms -want/+got:\n\t%s", diff)
}
// Delete user1.
// We expect his urms deleted but not bucket1.
if err := s.DeleteUser(ctx, data.Users[0].ID); err != nil {
t.Fatal(err)
}
urms, nurms, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{
UserID: data.Users[0].ID,
})
if err != nil {
t.Fatal(err)
}
if nurms > 0 {
t.Errorf("expected that user deletion would remove dangling urms, got: %+v", urms)
}
bs, nbs, err := s.FindBuckets(ctx, influxdb.BucketFilter{ID: &data.Buckets[0].ID})
if err != nil {
t.Fatal(err)
}
if nbs != 1 {
t.Errorf("expected 1 buckets, got: %v", bs)
}
})
t.Run("deleting a bucket deletes every related urm", func(t *testing.T) {
data := fields()
s, done := init(t, data)
defer done()
ctx := context.Background()
// Delete bucket2.
// We expect its urms deleted.
if err := s.DeleteBucket(ctx, data.Buckets[1].ID); err != nil {
t.Fatal(err)
}
urms, nurms, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{
ResourceType: influxdb.BucketsResourceType,
ResourceID: data.Buckets[1].ID,
})
if err != nil {
t.Fatal(err)
}
if nurms > 0 {
t.Errorf("expected that bucket deletion would remove dangling urms, got: %+v", urms)
}
})
// NOTE(affo)(*kv.Service): buckets, users, and urms survive.
t.Run("deleting an organization should delete everything that depends on it", func(t *testing.T) {
data := fields()
s, done := init(t, data)
defer done()
ctx := context.Background()
// Delete org1.
// We expect its buckets to be deleted.
// We expect urms to those buckets to be deleted too.
// No user should be deleted.
preDeletionBuckets, _, err := s.FindBuckets(ctx, influxdb.BucketFilter{OrganizationID: &data.Organizations[0].ID})
if err != nil {
t.Fatal(err)
}
if err := s.DeleteOrganization(ctx, data.Organizations[0].ID); err != nil {
t.Fatal(err)
}
bs, nbs, err := s.FindBuckets(ctx, influxdb.BucketFilter{OrganizationID: &data.Organizations[0].ID})
if err != nil {
t.Fatal(err)
}
if nbs != 0 {
t.Errorf("expected org buckets to be deleted, got: %+v", bs)
}
urms, _, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{
UserID: data.Users[0].ID,
ResourceType: influxdb.BucketsResourceType,
})
if err != nil {
t.Fatal(err)
}
for _, urm := range urms {
for _, b := range preDeletionBuckets {
if urm.ResourceID == b.ID {
t.Errorf("expected this urm to be deleted, got %+v instead", urm)
}
}
}
if _, err := s.FindUser(ctx, influxdb.UserFilter{ID: &data.Users[0].ID}); err != nil {
t.Fatal(err)
}
// Delete org2.
// Everything should disappear.
if err := s.DeleteOrganization(ctx, data.Organizations[1].ID); err != nil {
t.Fatal(err)
}
orgs, norgs, err := s.FindOrganizations(ctx, influxdb.OrganizationFilter{})
if err != nil {
t.Fatal(err)
}
if norgs != 0 {
t.Errorf("expected no org, got: %v", orgs)
}
usrs, nusrs, err := s.FindUsers(ctx, influxdb.UserFilter{})
if err != nil {
t.Fatal(err)
}
if nusrs != 2 {
t.Errorf("expected 2 users, got: %v", usrs)
}
urms, nurms, err := s.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{})
if err != nil {
t.Fatal(err)
}
if nurms > 0 {
t.Errorf("expected no urm, got: %v", urms)
}
bs, nbs, err = s.FindBuckets(ctx, influxdb.BucketFilter{})
if err != nil {
t.Fatal(err)
}
if nbs != 0 {
t.Errorf("expected buckets to be deleted, got: %+v", bs)
}
})
}

View File

@ -2,22 +2,48 @@ package testing
import ( import (
"context" "context"
"io/ioutil"
"os"
"strings" "strings"
"testing" "testing"
"github.com/influxdata/influxdb/v2"
"github.com/influxdata/influxdb/v2/bolt"
"github.com/influxdata/influxdb/v2/inmem"
"github.com/influxdata/influxdb/v2/kit/platform" "github.com/influxdata/influxdb/v2/kit/platform"
"github.com/influxdata/influxdb/v2/kit/platform/errors" "github.com/influxdata/influxdb/v2/kit/platform/errors"
"github.com/influxdata/influxdb/v2/kv"
"github.com/influxdata/influxdb/v2" "github.com/influxdata/influxdb/v2/kv/migration/all"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest"
) )
func strPtr(s string) *string { func NewTestBoltStore(t *testing.T) (kv.SchemaStore, func()) {
return &s f, err := ioutil.TempFile("", "influxdata-bolt-")
require.NoError(t, err, "unable to create temporary boltdb file")
require.NoError(t, f.Close())
path := f.Name()
s := bolt.NewKVStore(zaptest.NewLogger(t), path, bolt.WithNoSync)
require.NoError(t, s.Open(context.Background()))
// apply all kv migrations
require.NoError(t, all.Up(context.Background(), zaptest.NewLogger(t), s))
close := func() {
s.Close()
os.Remove(path)
} }
func boolPtr(b bool) *bool {
return &b return s, close
}
func NewTestInmemStore(t *testing.T) kv.SchemaStore {
s := inmem.NewKVStore()
// apply all kv migrations
require.NoError(t, all.Up(context.Background(), zaptest.NewLogger(t), s))
return s
} }
// TODO(goller): remove opPrefix argument // TODO(goller): remove opPrefix argument
@ -52,17 +78,17 @@ func ErrorsEqual(t *testing.T, actual, expected error) {
} }
} }
// FloatPtr takes the ref of a float number.
func FloatPtr(f float64) *float64 {
p := new(float64)
*p = f
return p
}
func idPtr(id platform.ID) *platform.ID { func idPtr(id platform.ID) *platform.ID {
return &id return &id
} }
func strPtr(s string) *string {
return &s
}
func boolPtr(b bool) *bool {
return &b
}
// MustIDBase16 is an helper to ensure a correct ID is built during testing. // MustIDBase16 is an helper to ensure a correct ID is built during testing.
func MustIDBase16(s string) platform.ID { func MustIDBase16(s string) platform.ID {
id, err := platform.IDFromString(s) id, err := platform.IDFromString(s)
@ -86,14 +112,6 @@ func MustCreateOrgs(ctx context.Context, svc influxdb.OrganizationService, os ..
} }
} }
func MustCreateLabels(ctx context.Context, svc influxdb.LabelService, labels ...*influxdb.Label) {
for _, l := range labels {
if err := svc.CreateLabel(ctx, l); err != nil {
panic(err)
}
}
}
func MustCreateUsers(ctx context.Context, svc influxdb.UserService, us ...*influxdb.User) { func MustCreateUsers(ctx context.Context, svc influxdb.UserService, us ...*influxdb.User) {
for _, u := range us { for _, u := range us {
if err := svc.CreateUser(ctx, u); err != nil { if err := svc.CreateUser(ctx, u); err != nil {
@ -102,40 +120,6 @@ func MustCreateUsers(ctx context.Context, svc influxdb.UserService, us ...*influ
} }
} }
func MustCreateMappings(ctx context.Context, svc influxdb.UserResourceMappingService, ms ...*influxdb.UserResourceMapping) {
for _, m := range ms {
if err := svc.CreateUserResourceMapping(ctx, m); err != nil {
panic(err)
}
}
}
func MustMakeUsersOrgOwner(ctx context.Context, svc influxdb.UserResourceMappingService, oid platform.ID, uids ...platform.ID) {
ms := make([]*influxdb.UserResourceMapping, len(uids))
for i, uid := range uids {
ms[i] = &influxdb.UserResourceMapping{
UserID: uid,
UserType: influxdb.Owner,
ResourceType: influxdb.OrgsResourceType,
ResourceID: oid,
}
}
MustCreateMappings(ctx, svc, ms...)
}
func MustMakeUsersOrgMember(ctx context.Context, svc influxdb.UserResourceMappingService, oid platform.ID, uids ...platform.ID) {
ms := make([]*influxdb.UserResourceMapping, len(uids))
for i, uid := range uids {
ms[i] = &influxdb.UserResourceMapping{
UserID: uid,
UserType: influxdb.Member,
ResourceType: influxdb.OrgsResourceType,
ResourceID: oid,
}
}
MustCreateMappings(ctx, svc, ms...)
}
func MustNewPermissionAtID(id platform.ID, a influxdb.Action, rt influxdb.ResourceType, orgID platform.ID) *influxdb.Permission { func MustNewPermissionAtID(id platform.ID, a influxdb.Action, rt influxdb.ResourceType, orgID platform.ID) *influxdb.Permission {
perm, err := influxdb.NewPermissionAtID(id, a, rt, orgID) perm, err := influxdb.NewPermissionAtID(id, a, rt, orgID)
if err != nil { if err != nil {

View File

@ -20,26 +20,11 @@ import (
"github.com/influxdata/httprouter" "github.com/influxdata/httprouter"
"github.com/influxdata/influxdb/v2" "github.com/influxdata/influxdb/v2"
icontext "github.com/influxdata/influxdb/v2/context" icontext "github.com/influxdata/influxdb/v2/context"
"github.com/influxdata/influxdb/v2/inmem"
"github.com/influxdata/influxdb/v2/kv"
"github.com/influxdata/influxdb/v2/kv/migration/all"
"github.com/influxdata/influxdb/v2/mock" "github.com/influxdata/influxdb/v2/mock"
itesting "github.com/influxdata/influxdb/v2/testing" itesting "github.com/influxdata/influxdb/v2/testing"
"go.uber.org/zap/zaptest" "go.uber.org/zap/zaptest"
) )
func NewTestInmemStore(t *testing.T) (kv.Store, func(), error) {
t.Helper()
store := inmem.NewKVStore()
if err := all.Up(context.Background(), zaptest.NewLogger(t), store); err != nil {
t.Fatal(err)
}
return store, func() {}, nil
}
func TestService_handlePostAuthorization(t *testing.T) { func TestService_handlePostAuthorization(t *testing.T) {
type fields struct { type fields struct {
AuthorizationService influxdb.AuthorizationService AuthorizationService influxdb.AuthorizationService
@ -201,11 +186,7 @@ func TestService_handlePostAuthorization(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
t.Helper() t.Helper()
s, _, err := NewTestInmemStore(t) s := itesting.NewTestInmemStore(t)
if err != nil {
t.Fatal(err)
}
storage, err := NewStore(s) storage, err := NewStore(s)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -745,11 +726,7 @@ func TestService_handleGetAuthorizations(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
t.Helper() t.Helper()
s, _, err := NewTestInmemStore(t) s := itesting.NewTestInmemStore(t)
if err != nil {
t.Fatal(err)
}
storage, err := NewStore(s) storage, err := NewStore(s)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)