From a5d689eb366f45c5c0edf5a7bedd3c328b48971b Mon Sep 17 00:00:00 2001 From: Jarek Kowalski Date: Sat, 20 Nov 2021 11:43:03 -0800 Subject: [PATCH] ui: Added test to verify #1057 (#1526) --- internal/server/api_sources_test.go | 75 +++++++++++++++++++++ internal/server/server_test.go | 37 ++++++----- internal/server/util_test.go | 95 +++++++++++++++++++++++++++ internal/serverapi/client_wrappers.go | 26 ++++++++ 4 files changed, 217 insertions(+), 16 deletions(-) create mode 100644 internal/server/api_sources_test.go create mode 100644 internal/server/util_test.go diff --git a/internal/server/api_sources_test.go b/internal/server/api_sources_test.go new file mode 100644 index 000000000..5cfc92425 --- /dev/null +++ b/internal/server/api_sources_test.go @@ -0,0 +1,75 @@ +package server_test + +import ( + "os" + "path/filepath" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/kopia/kopia/internal/apiclient" + "github.com/kopia/kopia/internal/repotesting" + "github.com/kopia/kopia/internal/serverapi" + "github.com/kopia/kopia/internal/testutil" + "github.com/kopia/kopia/internal/uitask" + "github.com/kopia/kopia/snapshot" + "github.com/kopia/kopia/snapshot/policy" +) + +func TestSnapshotCounters(t *testing.T) { + ctx, env := repotesting.NewEnvironment(t, repotesting.FormatNotImportant) + srvInfo := startServer(t, env, false) + + cli, err := apiclient.NewKopiaAPIClient(apiclient.Options{ + BaseURL: srvInfo.BaseURL, + TrustedServerCertificateFingerprint: srvInfo.TrustedServerCertificateFingerprint, + Username: testUIUsername, + Password: testUIPassword, + }) + + require.NoError(t, err) + + dir := testutil.TempDirectory(t) + si := localSource(env, dir) + + mustCreateSource(t, cli, dir) + require.Len(t, mustListSources(t, cli, &snapshot.SourceInfo{}), 1) + + mustSetPolicy(t, cli, si, &policy.Policy{ + FilesPolicy: policy.FilesPolicy{ + IgnoreRules: []string{"*.i"}, + }, + }) + + require.NoError(t, os.WriteFile(filepath.Join(dir, "file-a"), []byte{1, 2}, 0o644)) + require.NoError(t, os.WriteFile(filepath.Join(dir, "file-b"), []byte{1, 2, 3}, 0o644)) + require.NoError(t, os.WriteFile(filepath.Join(dir, "file-c"), []byte{1, 2, 3, 4}, 0o644)) + require.NoError(t, os.WriteFile(filepath.Join(dir, "file2.i"), []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 0o644)) + require.NoError(t, os.MkdirAll(filepath.Join(dir, "dir.i"), 0o755)) + + eti, err := serverapi.Estimate(ctx, cli, &serverapi.EstimateRequest{ + Root: dir, + }) + require.NoError(t, err) + et := waitForTask(t, cli, eti.TaskID, 15*time.Second) + + require.Equal(t, et.Counters["Bytes"], uitask.BytesCounter(9)) + require.Equal(t, et.Counters["Directories"], uitask.SimpleCounter(1)) + require.Equal(t, et.Counters["Files"], uitask.SimpleCounter(3)) + require.Equal(t, et.Counters["Excluded Directories"], uitask.SimpleCounter(1)) + require.Equal(t, et.Counters["Excluded Files"], uitask.SimpleCounter(1)) + + uresp, err := serverapi.UploadSnapshots(ctx, cli, &si) + + require.True(t, uresp.Sources[si.String()].Success) + require.NoError(t, err) + + ut := waitForTask(t, cli, mustGetLatestTask(t, cli).TaskID, 15*time.Second) + + require.Equal(t, ut.Counters["Hashed Files"], uitask.SimpleCounter(3)) + require.Equal(t, ut.Counters["Hashed Bytes"], uitask.BytesCounter(9)) + require.Equal(t, ut.Counters["Excluded Directories"], uitask.SimpleCounter(1)) + require.Equal(t, ut.Counters["Excluded Files"], uitask.SimpleCounter(1)) + require.Equal(t, ut.Counters["Processed Files"], uitask.SimpleCounter(3)) +} diff --git a/internal/server/server_test.go b/internal/server/server_test.go index 4c808a3a3..dd047c6b5 100644 --- a/internal/server/server_test.go +++ b/internal/server/server_test.go @@ -41,8 +41,8 @@ ) // nolint:thelper -func startServer(ctx context.Context, t *testing.T) *repo.APIServerInfo { - _, env := repotesting.NewEnvironment(t, repotesting.FormatNotImportant) +func startServer(t *testing.T, env *repotesting.Environment, tls bool) *repo.APIServerInfo { + ctx := testlogging.Context(t) s, err := server.New(ctx, server.Options{ ConfigFile: env.ConfigFile(), @@ -67,18 +67,23 @@ func startServer(ctx context.Context, t *testing.T) *repo.APIServerInfo { t.Fatal(err) } + asi := &repo.APIServerInfo{} + hs := httptest.NewUnstartedServer(s.GRPCRouterHandler(s.APIHandlers(true))) - hs.EnableHTTP2 = true - hs.StartTLS() + if tls { + hs.EnableHTTP2 = true + hs.StartTLS() + serverHash := sha256.Sum256(hs.Certificate().Raw) + asi.BaseURL = hs.URL + asi.TrustedServerCertificateFingerprint = hex.EncodeToString(serverHash[:]) + } else { + hs.Start() + asi.BaseURL = hs.URL + } t.Cleanup(hs.Close) - serverHash := sha256.Sum256(hs.Certificate().Raw) - - return &repo.APIServerInfo{ - BaseURL: hs.URL, - TrustedServerCertificateFingerprint: hex.EncodeToString(serverHash[:]), - } + return asi } func TestServer_REST(t *testing.T) { @@ -91,8 +96,8 @@ func TestServer_GRPC(t *testing.T) { // nolint:thelper func testServer(t *testing.T, disableGRPC bool) { - ctx := testlogging.ContextWithLevel(t, testlogging.LevelDebug) - apiServerInfo := startServer(ctx, t) + ctx, env := repotesting.NewEnvironment(t, repotesting.FormatNotImportant) + apiServerInfo := startServer(t, env, true) apiServerInfo.DisableGRPC = disableGRPC @@ -113,8 +118,8 @@ func testServer(t *testing.T, disableGRPC bool) { } func TestGPRServer_AuthenticationError(t *testing.T) { - ctx := testlogging.ContextWithLevel(t, testlogging.LevelDebug) - apiServerInfo := startServer(ctx, t) + ctx, env := repotesting.NewEnvironment(t, repotesting.FormatNotImportant) + apiServerInfo := startServer(t, env, true) if _, err := repo.OpenGRPCAPIRepository(ctx, apiServerInfo, repo.ClientOptions{ Username: "bad-username", @@ -125,8 +130,8 @@ func TestGPRServer_AuthenticationError(t *testing.T) { } func TestServerUIAccessDeniedToRemoteUser(t *testing.T) { - ctx := testlogging.ContextWithLevel(t, testlogging.LevelDebug) - si := startServer(ctx, t) + ctx, env := repotesting.NewEnvironment(t, repotesting.FormatNotImportant) + si := startServer(t, env, true) remoteUserClient, err := apiclient.NewKopiaAPIClient(apiclient.Options{ BaseURL: si.BaseURL, diff --git a/internal/server/util_test.go b/internal/server/util_test.go new file mode 100644 index 000000000..c9906d437 --- /dev/null +++ b/internal/server/util_test.go @@ -0,0 +1,95 @@ +package server_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/kopia/kopia/internal/apiclient" + "github.com/kopia/kopia/internal/clock" + "github.com/kopia/kopia/internal/repotesting" + "github.com/kopia/kopia/internal/serverapi" + "github.com/kopia/kopia/internal/testlogging" + "github.com/kopia/kopia/internal/uitask" + "github.com/kopia/kopia/snapshot" + "github.com/kopia/kopia/snapshot/policy" +) + +func mustCreateSource(t *testing.T, cli *apiclient.KopiaAPIClient, path string) { + t.Helper() + + _, err := serverapi.CreateSnapshotSource(testlogging.Context(t), cli, &serverapi.CreateSnapshotSourceRequest{ + Path: path, + }) + require.NoError(t, err) +} + +func mustSetPolicy(t *testing.T, cli *apiclient.KopiaAPIClient, si snapshot.SourceInfo, pol *policy.Policy) { + t.Helper() + + require.NoError(t, serverapi.SetPolicy(testlogging.Context(t), cli, si, pol)) +} + +func mustListSources(t *testing.T, cli *apiclient.KopiaAPIClient, match *snapshot.SourceInfo) []*serverapi.SourceStatus { + t.Helper() + + resp, err := serverapi.ListSources(testlogging.Context(t), cli, match) + require.NoError(t, err) + + return resp.Sources +} + +func mustGetTask(t *testing.T, cli *apiclient.KopiaAPIClient, taskID string) uitask.Info { + t.Helper() + + resp, err := serverapi.GetTask(testlogging.Context(t), cli, taskID) + require.NoError(t, err) + + return *resp +} + +func mustListTasks(t *testing.T, cli *apiclient.KopiaAPIClient) []uitask.Info { + t.Helper() + + resp, err := serverapi.ListTasks(testlogging.Context(t), cli) + require.NoError(t, err) + + return resp.Tasks +} + +func mustGetLatestTask(t *testing.T, cli *apiclient.KopiaAPIClient) uitask.Info { + t.Helper() + + tl := mustListTasks(t, cli) + require.NotEmpty(t, tl) + + return tl[0] +} + +func waitForTask(t *testing.T, cli *apiclient.KopiaAPIClient, taskID string, timeout time.Duration) uitask.Info { + t.Helper() + + var lastInfo uitask.Info + + deadline := clock.Now().Add(timeout) + for clock.Now().Before(deadline) { + lastInfo = mustGetTask(t, cli, taskID) + + if lastInfo.Status.IsFinished() { + return lastInfo + } + } + + t.Fatalf("task %v did not complete in %v, last: %v", taskID, timeout, lastInfo) + + return lastInfo +} + +func localSource(env *repotesting.Environment, path string) snapshot.SourceInfo { + return snapshot.SourceInfo{ + UserName: env.Repository.ClientOptions().Username, + Host: env.Repository.ClientOptions().Hostname, + Path: path, + } +} diff --git a/internal/serverapi/client_wrappers.go b/internal/serverapi/client_wrappers.go index 820ff33e9..3d62322d5 100644 --- a/internal/serverapi/client_wrappers.go +++ b/internal/serverapi/client_wrappers.go @@ -2,6 +2,7 @@ import ( "context" + "fmt" "strings" "github.com/pkg/errors" @@ -11,6 +12,7 @@ "github.com/kopia/kopia/repo/blob/throttling" "github.com/kopia/kopia/repo/object" "github.com/kopia/kopia/snapshot" + "github.com/kopia/kopia/snapshot/policy" ) // CreateSnapshotSource creates snapshot source with a given path. @@ -146,6 +148,30 @@ func ListPolicies(ctx context.Context, c *apiclient.KopiaAPIClient, match *snaps return resp, nil } +func policyTargetURLParamters(si snapshot.SourceInfo) string { + return fmt.Sprintf("userName=%v&host=%v&path=%v", si.UserName, si.Host, si.Path) +} + +// SetPolicy sets the policy. +func SetPolicy(ctx context.Context, c *apiclient.KopiaAPIClient, si snapshot.SourceInfo, pol *policy.Policy) error { + resp := &Empty{} + if err := c.Put(ctx, "policy?"+policyTargetURLParamters(si), pol, resp); err != nil { + return errors.Wrap(err, "SetPolicy") + } + + return nil +} + +// ListTasks lists the tasks. +func ListTasks(ctx context.Context, c *apiclient.KopiaAPIClient) (*TaskListResponse, error) { + resp := &TaskListResponse{} + if err := c.Get(ctx, "tasks", nil, resp); err != nil { + return nil, errors.Wrap(err, "ListTasks") + } + + return resp, nil +} + // GetObject returns the object payload. func GetObject(ctx context.Context, c *apiclient.KopiaAPIClient, objectID string) ([]byte, error) { var b []byte