Merge pull request #824 from influxdata/feat/default_ids
feat: add onboarding defaultspull/10616/head
commit
fdbca49c2e
|
@ -98,6 +98,11 @@ func (c *Client) initialize(ctx context.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Always create Onboarding bucket.
|
||||||
|
if err := c.initializeOnboarding(ctx, tx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Always create Source bucket.
|
// Always create Source bucket.
|
||||||
if err := c.initializeSources(ctx, tx); err != nil {
|
if err := c.initializeSources(ctx, tx); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
package bolt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
bolt "github.com/coreos/bbolt"
|
||||||
|
"github.com/influxdata/platform"
|
||||||
|
)
|
||||||
|
|
||||||
|
var onboardingBucket = []byte("onboardingv1")
|
||||||
|
var onboardingKey = []byte("onboarding_key")
|
||||||
|
|
||||||
|
var _ platform.OnboardingService = (*Client)(nil)
|
||||||
|
|
||||||
|
func (c *Client) initializeOnboarding(ctx context.Context, tx *bolt.Tx) error {
|
||||||
|
if _, err := tx.CreateBucketIfNotExists([]byte(onboardingBucket)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsOnboarding checks onboardingBucket
|
||||||
|
// to see if the onboarding key is true.
|
||||||
|
func (c *Client) IsOnboarding(ctx context.Context) (isOnboarding bool, err error) {
|
||||||
|
err = c.db.View(func(tx *bolt.Tx) error {
|
||||||
|
result := tx.Bucket(onboardingBucket).Get(onboardingKey)
|
||||||
|
isOnboarding = len(result) == 0
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return isOnboarding, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// PutOnboardingStatus will update the flag,
|
||||||
|
// so future onboarding request will be denied.
|
||||||
|
func (c *Client) PutOnboardingStatus(ctx context.Context, v bool) error {
|
||||||
|
if v {
|
||||||
|
return c.db.Update(func(tx *bolt.Tx) error {
|
||||||
|
return tx.Bucket(onboardingBucket).Put(onboardingKey, []byte{0x1})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate OnboardingResults from onboarding request,
|
||||||
|
// update db so this request will be disabled for the second run.
|
||||||
|
func (c *Client) Generate(ctx context.Context, req *platform.OnboardingRequest) (*platform.OnboardingResults, error) {
|
||||||
|
isOnboarding, err := c.IsOnboarding(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !isOnboarding {
|
||||||
|
return nil, &platform.Error{
|
||||||
|
Code: platform.EConflict,
|
||||||
|
Msg: "onboarding has already been completed",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Password == "" {
|
||||||
|
return nil, &platform.Error{
|
||||||
|
Code: platform.EEmptyValue,
|
||||||
|
Msg: "password is empty",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.User == "" {
|
||||||
|
return nil, &platform.Error{
|
||||||
|
Code: platform.EEmptyValue,
|
||||||
|
Msg: "username is empty",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Org == "" {
|
||||||
|
return nil, &platform.Error{
|
||||||
|
Code: platform.EEmptyValue,
|
||||||
|
Msg: "org name is empty",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Bucket == "" {
|
||||||
|
return nil, &platform.Error{
|
||||||
|
Code: platform.EEmptyValue,
|
||||||
|
Msg: "bucket name is empty",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u := &platform.User{Name: req.User}
|
||||||
|
if err := c.CreateUser(ctx, u); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = c.SetPassword(ctx, u.Name, req.Password); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
o := &platform.Organization{
|
||||||
|
Name: req.Org,
|
||||||
|
}
|
||||||
|
if err = c.CreateOrganization(ctx, o); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
bucket := &platform.Bucket{
|
||||||
|
Name: req.Bucket,
|
||||||
|
Organization: o.Name,
|
||||||
|
OrganizationID: o.ID,
|
||||||
|
}
|
||||||
|
if err = c.CreateBucket(ctx, bucket); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
auth := &platform.Authorization{
|
||||||
|
User: u.Name,
|
||||||
|
UserID: u.ID,
|
||||||
|
Permissions: []platform.Permission{
|
||||||
|
platform.CreateUserPermission,
|
||||||
|
platform.DeleteUserPermission,
|
||||||
|
platform.Permission{
|
||||||
|
Resource: platform.OrganizationResource,
|
||||||
|
Action: platform.WriteAction,
|
||||||
|
},
|
||||||
|
platform.WriteBucketPermission(bucket.ID),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if err = c.CreateAuthorization(ctx, auth); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = c.PutOnboardingStatus(ctx, true); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &platform.OnboardingResults{
|
||||||
|
User: u,
|
||||||
|
Org: o,
|
||||||
|
Bucket: bucket,
|
||||||
|
Auth: auth,
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package bolt_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
platformtesting "github.com/influxdata/platform/testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func initOnboardingService(f platformtesting.OnboardingFields, t *testing.T) (platformtesting.OnBoardingNBasicAuthService, func()) {
|
||||||
|
c, closeFn, err := NewTestClient()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new bolt client: %v", err)
|
||||||
|
}
|
||||||
|
c.IDGenerator = f.IDGenerator
|
||||||
|
c.TokenGenerator = f.TokenGenerator
|
||||||
|
ctx := context.TODO()
|
||||||
|
if err = c.PutOnboardingStatus(ctx, !f.IsOnboarding); err != nil {
|
||||||
|
t.Fatalf("failed to set new onboarding finished: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, func() {
|
||||||
|
defer closeFn()
|
||||||
|
if err := c.PutOnboardingStatus(ctx, false); err != nil {
|
||||||
|
t.Logf("failed to remove onboarding finished: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenerate(t *testing.T) {
|
||||||
|
platformtesting.Generate(initOnboardingService, t)
|
||||||
|
}
|
|
@ -189,6 +189,8 @@ func platformF(cmd *cobra.Command, args []string) {
|
||||||
macroSvc = c
|
macroSvc = c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var onboardingSvc platform.OnboardingService = c
|
||||||
|
|
||||||
var queryService query.QueryService
|
var queryService query.QueryService
|
||||||
{
|
{
|
||||||
// TODO(lh): this is temporary until query endpoint is added here.
|
// TODO(lh): this is temporary until query endpoint is added here.
|
||||||
|
@ -309,6 +311,9 @@ func platformF(cmd *cobra.Command, args []string) {
|
||||||
sourceHandler.NewBucketService = source.NewBucketService
|
sourceHandler.NewBucketService = source.NewBucketService
|
||||||
sourceHandler.NewQueryService = source.NewQueryService
|
sourceHandler.NewQueryService = source.NewQueryService
|
||||||
|
|
||||||
|
setupHandler := http.NewSetupHandler()
|
||||||
|
setupHandler.OnboardingService = onboardingSvc
|
||||||
|
|
||||||
taskHandler := http.NewTaskHandler(logger)
|
taskHandler := http.NewTaskHandler(logger)
|
||||||
taskHandler.TaskService = taskSvc
|
taskHandler.TaskService = taskSvc
|
||||||
|
|
||||||
|
@ -346,6 +351,7 @@ func platformF(cmd *cobra.Command, args []string) {
|
||||||
MacroHandler: macroHandler,
|
MacroHandler: macroHandler,
|
||||||
QueryHandler: queryHandler,
|
QueryHandler: queryHandler,
|
||||||
WriteHandler: writeHandler,
|
WriteHandler: writeHandler,
|
||||||
|
SetupHandler: setupHandler,
|
||||||
}
|
}
|
||||||
reg.MustRegister(platformHandler.PrometheusCollectors()...)
|
reg.MustRegister(platformHandler.PrometheusCollectors()...)
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ type Error struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error implement the error interface by outputing the Code and Err.
|
// Error implement the error interface by outputing the Code and Err.
|
||||||
func (e Error) Error() string {
|
func (e *Error) Error() string {
|
||||||
var b strings.Builder
|
var b strings.Builder
|
||||||
|
|
||||||
// Print the current operation in our stack, if any.
|
// Print the current operation in our stack, if any.
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/influxdata/platform"
|
||||||
|
"github.com/julienschmidt/httprouter"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetupHandler represents an HTTP API handler for onboarding setup.
|
||||||
|
type SetupHandler struct {
|
||||||
|
*httprouter.Router
|
||||||
|
|
||||||
|
OnboardingService platform.OnboardingService
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSetupHandler returns a new instance of SetupHandler.
|
||||||
|
func NewSetupHandler() *SetupHandler {
|
||||||
|
h := &SetupHandler{
|
||||||
|
Router: httprouter.New(),
|
||||||
|
}
|
||||||
|
h.HandlerFunc("POST", "/setup", h.handlePostSetup)
|
||||||
|
h.HandlerFunc("GET", "/setup", h.isOnboarding)
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// isOnboarding is the HTTP handler for the GET /setup route.
|
||||||
|
// returns true/false
|
||||||
|
func (h *SetupHandler) isOnboarding(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
result, err := h.OnboardingService.IsOnboarding(ctx)
|
||||||
|
if err != nil {
|
||||||
|
EncodeError(ctx, err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
fmt.Fprintf(w, `{"allowed": %v}`, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *SetupHandler) handlePostSetup(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
|
||||||
|
req, err := decodePostSetupRequest(ctx, r)
|
||||||
|
if err != nil {
|
||||||
|
EncodeError(ctx, err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
results, err := h.OnboardingService.Generate(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
EncodeError(ctx, err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := encodeResponse(ctx, w, http.StatusCreated, newOnboardingResponse(results)); err != nil {
|
||||||
|
EncodeError(ctx, err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type onboardingResponse struct {
|
||||||
|
User *userResponse `json:"user"`
|
||||||
|
Bucket *bucketResponse `json:"bucket"`
|
||||||
|
Organization *orgResponse `json:"org"`
|
||||||
|
Auth *authResponse `json:"auth"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func newOnboardingResponse(results *platform.OnboardingResults) *onboardingResponse {
|
||||||
|
return &onboardingResponse{
|
||||||
|
User: newUserResponse(results.User),
|
||||||
|
Bucket: newBucketResponse(results.Bucket),
|
||||||
|
Organization: newOrgResponse(results.Org),
|
||||||
|
Auth: newAuthResponse(results.Auth),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodePostSetupRequest(ctx context.Context, r *http.Request) (*platform.OnboardingRequest, error) {
|
||||||
|
req := &platform.OnboardingRequest{}
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return req, nil
|
||||||
|
}
|
|
@ -25,6 +25,7 @@ type PlatformHandler struct {
|
||||||
FluxLangHandler *FluxLangHandler
|
FluxLangHandler *FluxLangHandler
|
||||||
QueryHandler *FluxHandler
|
QueryHandler *FluxHandler
|
||||||
WriteHandler *WriteHandler
|
WriteHandler *WriteHandler
|
||||||
|
SetupHandler *SetupHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
func setCORSResponseHeaders(w nethttp.ResponseWriter, r *nethttp.Request) {
|
func setCORSResponseHeaders(w nethttp.ResponseWriter, r *nethttp.Request) {
|
||||||
|
@ -36,6 +37,7 @@ func setCORSResponseHeaders(w nethttp.ResponseWriter, r *nethttp.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var platformLinks = map[string]interface{}{
|
var platformLinks = map[string]interface{}{
|
||||||
|
"setup": "/setup",
|
||||||
"sources": "/v2/sources",
|
"sources": "/v2/sources",
|
||||||
"dashboards": "/v2/dashboards",
|
"dashboards": "/v2/dashboards",
|
||||||
"query": "/v2/query",
|
"query": "/v2/query",
|
||||||
|
@ -79,7 +81,8 @@ func (h *PlatformHandler) ServeHTTP(w nethttp.ResponseWriter, r *nethttp.Request
|
||||||
// of the platform API.
|
// of the platform API.
|
||||||
if !strings.HasPrefix(r.URL.Path, "/v1") &&
|
if !strings.HasPrefix(r.URL.Path, "/v1") &&
|
||||||
!strings.HasPrefix(r.URL.Path, "/v2") &&
|
!strings.HasPrefix(r.URL.Path, "/v2") &&
|
||||||
!strings.HasPrefix(r.URL.Path, "/chronograf/") {
|
!strings.HasPrefix(r.URL.Path, "/chronograf/") &&
|
||||||
|
!strings.HasPrefix(r.URL.Path, "/setup") {
|
||||||
h.AssetHandler.ServeHTTP(w, r)
|
h.AssetHandler.ServeHTTP(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -90,6 +93,11 @@ func (h *PlatformHandler) ServeHTTP(w nethttp.ResponseWriter, r *nethttp.Request
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(r.URL.Path, "/setup") {
|
||||||
|
h.SetupHandler.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
var err error
|
var err error
|
||||||
if ctx, err = extractAuthorization(ctx, r); err != nil {
|
if ctx, err = extractAuthorization(ctx, r); err != nil {
|
||||||
|
|
|
@ -15,6 +15,38 @@ paths:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/components/schemas/Routes"
|
$ref: "#/components/schemas/Routes"
|
||||||
|
/setup:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- Setup
|
||||||
|
summary: check if database has default user, org, bucket created, returns true if not.
|
||||||
|
response:
|
||||||
|
'200':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
allowed:
|
||||||
|
type: boolean
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Setup
|
||||||
|
summary: post onboarding request, to setup initial user, org and bucket
|
||||||
|
requestBody:
|
||||||
|
description: source to create
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/OnboardingRequest"
|
||||||
|
responses:
|
||||||
|
'201':
|
||||||
|
description: Created default user, bucket, org
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/OnboardingResponse"
|
||||||
|
|
||||||
/macros:
|
/macros:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
|
@ -3230,6 +3262,28 @@ components:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: "#/components/schemas/Source"
|
$ref: "#/components/schemas/Source"
|
||||||
|
OnboardingRequest:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
password:
|
||||||
|
type: string
|
||||||
|
org:
|
||||||
|
type: string
|
||||||
|
bucket:
|
||||||
|
type: string
|
||||||
|
OnboardingResponse:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
user:
|
||||||
|
$ref: "#/components/schemas/User"
|
||||||
|
org:
|
||||||
|
$ref: "#/components/schemas/Organization"
|
||||||
|
bucket:
|
||||||
|
$ref: "#/components/schemas/Bucket"
|
||||||
|
auth:
|
||||||
|
$ref: "#/components/schemas/Authorization"
|
||||||
Health:
|
Health:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
package platform
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
// OnboardingResults is a group of elements required for first run.
|
||||||
|
type OnboardingResults struct {
|
||||||
|
User *User `json:"user"`
|
||||||
|
Org *Organization `json:"org"`
|
||||||
|
Bucket *Bucket `json:"bucket"`
|
||||||
|
Auth *Authorization `json:"auth"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnboardingRequest is the request
|
||||||
|
// to setup defaults.
|
||||||
|
type OnboardingRequest struct {
|
||||||
|
User string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
Org string `json:"org"`
|
||||||
|
Bucket string `json:"bucket"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnboardingService represents a service for the first run.
|
||||||
|
type OnboardingService interface {
|
||||||
|
// IsOnboarding determine if onboarding request is allowed.
|
||||||
|
IsOnboarding(ctx context.Context) (bool, error)
|
||||||
|
// Generate OnboardingResults.
|
||||||
|
Generate(ctx context.Context, req *OnboardingRequest) (*OnboardingResults, error)
|
||||||
|
}
|
|
@ -0,0 +1,244 @@
|
||||||
|
package testing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"github.com/influxdata/platform"
|
||||||
|
"github.com/influxdata/platform/mock"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OnboardingFields will include the IDGenerator, TokenGenerator
|
||||||
|
// and IsOnboarding
|
||||||
|
type OnboardingFields struct {
|
||||||
|
IDGenerator platform.IDGenerator
|
||||||
|
TokenGenerator platform.TokenGenerator
|
||||||
|
IsOnboarding bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnBoardingNBasicAuthService includes onboarding service
|
||||||
|
// and basic auth service.
|
||||||
|
type OnBoardingNBasicAuthService interface {
|
||||||
|
platform.OnboardingService
|
||||||
|
platform.BasicAuthService
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate testing
|
||||||
|
func Generate(
|
||||||
|
init func(OnboardingFields, *testing.T) (OnBoardingNBasicAuthService, func()),
|
||||||
|
t *testing.T,
|
||||||
|
) {
|
||||||
|
type args struct {
|
||||||
|
request *platform.OnboardingRequest
|
||||||
|
}
|
||||||
|
type wants struct {
|
||||||
|
errCode string
|
||||||
|
results *platform.OnboardingResults
|
||||||
|
password string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields OnboardingFields
|
||||||
|
args args
|
||||||
|
wants wants
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "denied",
|
||||||
|
fields: OnboardingFields{
|
||||||
|
IDGenerator: &loopIDGenerator{
|
||||||
|
s: []string{oneID, twoID, threeID, fourID},
|
||||||
|
t: t,
|
||||||
|
},
|
||||||
|
TokenGenerator: mock.NewTokenGenerator(oneToken, nil),
|
||||||
|
IsOnboarding: false,
|
||||||
|
},
|
||||||
|
wants: wants{
|
||||||
|
errCode: platform.EConflict,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "missing password",
|
||||||
|
fields: OnboardingFields{
|
||||||
|
IDGenerator: &loopIDGenerator{
|
||||||
|
s: []string{oneID, twoID, threeID, fourID},
|
||||||
|
t: t,
|
||||||
|
},
|
||||||
|
TokenGenerator: mock.NewTokenGenerator(oneToken, nil),
|
||||||
|
IsOnboarding: true,
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
request: &platform.OnboardingRequest{
|
||||||
|
User: "admin",
|
||||||
|
Org: "org1",
|
||||||
|
Bucket: "bucket1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wants: wants{
|
||||||
|
errCode: platform.EEmptyValue,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "missing username",
|
||||||
|
fields: OnboardingFields{
|
||||||
|
IDGenerator: &loopIDGenerator{
|
||||||
|
s: []string{oneID, twoID, threeID, fourID},
|
||||||
|
t: t,
|
||||||
|
},
|
||||||
|
TokenGenerator: mock.NewTokenGenerator(oneToken, nil),
|
||||||
|
IsOnboarding: true,
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
request: &platform.OnboardingRequest{
|
||||||
|
Org: "org1",
|
||||||
|
Bucket: "bucket1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wants: wants{
|
||||||
|
errCode: platform.EEmptyValue,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "missing org",
|
||||||
|
fields: OnboardingFields{
|
||||||
|
IDGenerator: &loopIDGenerator{
|
||||||
|
s: []string{oneID, twoID, threeID, fourID},
|
||||||
|
t: t,
|
||||||
|
},
|
||||||
|
TokenGenerator: mock.NewTokenGenerator(oneToken, nil),
|
||||||
|
IsOnboarding: true,
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
request: &platform.OnboardingRequest{
|
||||||
|
User: "admin",
|
||||||
|
Bucket: "bucket1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wants: wants{
|
||||||
|
errCode: platform.EEmptyValue,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "missing bucket",
|
||||||
|
fields: OnboardingFields{
|
||||||
|
IDGenerator: &loopIDGenerator{
|
||||||
|
s: []string{oneID, twoID, threeID, fourID},
|
||||||
|
t: t,
|
||||||
|
},
|
||||||
|
TokenGenerator: mock.NewTokenGenerator(oneToken, nil),
|
||||||
|
IsOnboarding: true,
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
request: &platform.OnboardingRequest{
|
||||||
|
User: "admin",
|
||||||
|
Org: "org1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wants: wants{
|
||||||
|
errCode: platform.EEmptyValue,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "regular",
|
||||||
|
fields: OnboardingFields{
|
||||||
|
IDGenerator: &loopIDGenerator{
|
||||||
|
s: []string{oneID, twoID, threeID, fourID},
|
||||||
|
t: t,
|
||||||
|
},
|
||||||
|
TokenGenerator: mock.NewTokenGenerator(oneToken, nil),
|
||||||
|
IsOnboarding: true,
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
request: &platform.OnboardingRequest{
|
||||||
|
User: "admin",
|
||||||
|
Org: "org1",
|
||||||
|
Bucket: "bucket1",
|
||||||
|
Password: "pass1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wants: wants{
|
||||||
|
password: "pass1",
|
||||||
|
results: &platform.OnboardingResults{
|
||||||
|
User: &platform.User{
|
||||||
|
ID: idFromString(t, oneID),
|
||||||
|
Name: "admin",
|
||||||
|
},
|
||||||
|
Org: &platform.Organization{
|
||||||
|
ID: idFromString(t, twoID),
|
||||||
|
Name: "org1",
|
||||||
|
},
|
||||||
|
Bucket: &platform.Bucket{
|
||||||
|
ID: idFromString(t, threeID),
|
||||||
|
Name: "bucket1",
|
||||||
|
Organization: "org1",
|
||||||
|
OrganizationID: idFromString(t, twoID),
|
||||||
|
},
|
||||||
|
Auth: &platform.Authorization{
|
||||||
|
ID: idFromString(t, fourID),
|
||||||
|
Token: oneToken,
|
||||||
|
Status: platform.Active,
|
||||||
|
User: "admin",
|
||||||
|
UserID: idFromString(t, oneID),
|
||||||
|
Permissions: []platform.Permission{
|
||||||
|
platform.CreateUserPermission,
|
||||||
|
platform.DeleteUserPermission,
|
||||||
|
platform.Permission{
|
||||||
|
Resource: platform.OrganizationResource,
|
||||||
|
Action: platform.WriteAction,
|
||||||
|
},
|
||||||
|
platform.WriteBucketPermission(idFromString(t, threeID)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
s, done := init(tt.fields, t)
|
||||||
|
defer done()
|
||||||
|
ctx := context.Background()
|
||||||
|
results, err := s.Generate(ctx, tt.args.request)
|
||||||
|
if (err != nil) != (tt.wants.errCode != "") {
|
||||||
|
t.Fatalf("expected error code '%s' got '%v'", tt.wants.errCode, err)
|
||||||
|
}
|
||||||
|
if err != nil && tt.wants.errCode != "" {
|
||||||
|
if code := platform.ErrorCode(err); code != tt.wants.errCode {
|
||||||
|
t.Fatalf("expected error code to match '%s' got '%v'", tt.wants.errCode, code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(results, tt.wants.results); diff != "" {
|
||||||
|
t.Errorf("onboarding results are different -got/+want\ndiff %s", diff)
|
||||||
|
}
|
||||||
|
if results != nil {
|
||||||
|
if err = s.ComparePassword(ctx, results.User.Name, tt.wants.password); err != nil {
|
||||||
|
t.Errorf("onboarding set password is wrong")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
oneID = "020f755c3c082000"
|
||||||
|
twoID = "020f755c3c082001"
|
||||||
|
threeID = "020f755c3c082002"
|
||||||
|
fourID = "020f755c3c082003"
|
||||||
|
oneToken = "020f755c3c082008"
|
||||||
|
)
|
||||||
|
|
||||||
|
type loopIDGenerator struct {
|
||||||
|
s []string
|
||||||
|
p int
|
||||||
|
t *testing.T
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *loopIDGenerator) ID() platform.ID {
|
||||||
|
if g.p == len(g.s) {
|
||||||
|
g.p = 0
|
||||||
|
}
|
||||||
|
id := idFromString(g.t, g.s[g.p])
|
||||||
|
g.p++
|
||||||
|
return id
|
||||||
|
}
|
Loading…
Reference in New Issue