influxdb/http/backup_service_test.go

131 lines
3.6 KiB
Go

package http
import (
"context"
"io"
"mime"
"mime/multipart"
"net/http"
"net/http/httptest"
"testing"
"github.com/golang/mock/gomock"
"github.com/influxdata/influxdb/v2"
influxdbcontext "github.com/influxdata/influxdb/v2/context"
kithttp "github.com/influxdata/influxdb/v2/kit/transport/http"
"github.com/influxdata/influxdb/v2/mock"
"github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest"
)
func TestBackupMetaService(t *testing.T) {
ctrlr := gomock.NewController(t)
backupSvc := mock.NewMockBackupService(ctrlr)
sqlBackupSvc := mock.NewMockSqlBackupRestoreService(ctrlr)
bucketManifestWriter := mock.NewMockBucketManifestWriter(ctrlr)
b := &BackupBackend{
BackupService: backupSvc,
SqlBackupRestoreService: sqlBackupSvc,
BucketManifestWriter: bucketManifestWriter,
}
h := NewBackupHandler(b)
rr := httptest.NewRecorder()
r, err := http.NewRequest(http.MethodGet, "/", nil)
require.NoError(t, err)
backupSvc.EXPECT().
BackupKVStore(gomock.Any(), gomock.Any()).
Return(nil)
backupSvc.EXPECT().RLockKVStore()
backupSvc.EXPECT().UnlockKVStore()
sqlBackupSvc.EXPECT().
BackupSqlStore(gomock.Any(), gomock.Any()).
Return(nil)
sqlBackupSvc.EXPECT().RLockSqlStore()
sqlBackupSvc.EXPECT().RUnlockSqlStore()
bucketManifestWriter.EXPECT().
WriteManifest(gomock.Any(), gomock.Any()).
Return(nil)
h.handleBackupMetadata(rr, r)
rs := rr.Result()
require.Equal(t, rs.StatusCode, http.StatusOK)
// Parse the multi-part response
// First get the boundary from the header
_, params, err := mime.ParseMediaType(rs.Header.Get("Content-Type"))
require.NoError(t, err)
mr := multipart.NewReader(rs.Body, params["boundary"])
// Go through the parts of the response and verify the part names appear in the correct order
wantContentTypes := []string{"application/octet-stream", "application/octet-stream", "application/json; charset=utf-8"}
wantPartNames := []string{"kv", "sql", "buckets"}
for i := 0; ; i++ {
p, err := mr.NextPart()
if err == io.EOF {
break
}
require.NoError(t, err)
require.Equal(t, wantContentTypes[i], p.Header.Get("Content-Type"))
_, params, err := mime.ParseMediaType(p.Header.Get("Content-Disposition"))
require.NoError(t, err)
require.Equal(t, wantPartNames[i], params["name"])
}
}
func TestRequireOperPermissions(t *testing.T) {
tests := []struct {
name string
permList []influxdb.Permission
wantStatus int
wantContentType string
}{
{
"authorized to do the backup",
influxdb.OperPermissions(),
http.StatusOK,
"text/plain; charset=utf-8",
},
{
"not authorized to do the backup",
influxdb.ReadAllPermissions(),
http.StatusUnauthorized,
"application/json; charset=utf-8",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// next will only be called if the authorization allows it. this is a dummy function
// that will set the content-type header to something other than application/json
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.Write([]byte("OK"))
})
rr := httptest.NewRecorder()
r, err := http.NewRequest(http.MethodGet, "/", nil)
require.NoError(t, err)
ctx := influxdbcontext.SetAuthorizer(context.Background(), mock.NewMockAuthorizer(false, tt.permList))
r = r.WithContext(ctx)
h := BackupHandler{
HTTPErrorHandler: kithttp.NewErrorHandler(zaptest.NewLogger(t)),
}
h.requireOperPermissions(next).ServeHTTP(rr, r)
rs := rr.Result()
require.Equal(t, tt.wantStatus, rs.StatusCode)
require.Equal(t, tt.wantContentType, rs.Header.Get("Content-Type"))
})
}
}