1// +build postgres
2
3package praefect
4
5import (
6	"context"
7	"net"
8	"path/filepath"
9	"testing"
10
11	"github.com/stretchr/testify/require"
12	"gitlab.com/gitlab-org/gitaly/v14/internal/praefect/config"
13	"gitlab.com/gitlab-org/gitaly/v14/internal/praefect/datastore"
14	"gitlab.com/gitlab-org/gitaly/v14/internal/praefect/grpc-proxy/proxy"
15	"gitlab.com/gitlab-org/gitaly/v14/internal/praefect/protoregistry"
16	"gitlab.com/gitlab-org/gitaly/v14/internal/testhelper"
17	"gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb"
18	"google.golang.org/grpc"
19	"google.golang.org/grpc/codes"
20	"google.golang.org/grpc/status"
21)
22
23func TestRepositoryExistsStreamInterceptor(t *testing.T) {
24	errServedByGitaly := status.Error(codes.Unknown, "request passed to Gitaly")
25
26	for _, tc := range []struct {
27		desc          string
28		routeToGitaly bool
29		repository    *gitalypb.Repository
30		response      *gitalypb.RepositoryExistsResponse
31		error         error
32	}{
33		{
34			desc:  "missing repository",
35			error: errMissingRepository,
36		},
37		{
38			desc:       "missing storage name",
39			repository: &gitalypb.Repository{RelativePath: "relative-path"},
40			error:      errMissingStorageName,
41		},
42		{
43			desc:       "missing relative path",
44			repository: &gitalypb.Repository{StorageName: "virtual-storage"},
45			error:      errMissingRelativePath,
46		},
47		{
48			desc:       "invalid virtual storage",
49			repository: &gitalypb.Repository{StorageName: "invalid virtual storage", RelativePath: "relative-path"},
50			response:   &gitalypb.RepositoryExistsResponse{Exists: false},
51		},
52		{
53			desc:       "invalid relative path",
54			repository: &gitalypb.Repository{StorageName: "virtual-storage", RelativePath: "invalid relative path"},
55			response:   &gitalypb.RepositoryExistsResponse{Exists: false},
56		},
57		{
58			desc:       "repository found",
59			repository: &gitalypb.Repository{StorageName: "virtual-storage", RelativePath: "relative-path"},
60			response:   &gitalypb.RepositoryExistsResponse{Exists: true},
61		},
62		{
63			desc:          "routed to gitaly",
64			routeToGitaly: true,
65			error:         errServedByGitaly,
66		},
67	} {
68		t.Run(tc.desc, func(t *testing.T) {
69			db := getDB(t)
70			rs := datastore.NewPostgresRepositoryStore(db, map[string][]string{"virtual-storage": {"storage"}})
71
72			ctx, cancel := testhelper.Context()
73			defer cancel()
74
75			require.NoError(t, rs.CreateRepository(ctx, "virtual-storage", "relative-path", "storage", nil, nil, false, false))
76
77			electionStrategy := config.ElectionStrategyPerRepository
78			if tc.routeToGitaly {
79				electionStrategy = config.ElectionStrategySQL
80			}
81
82			tmp := testhelper.TempDir(t)
83
84			ln, err := net.Listen("unix", filepath.Join(tmp, "praefect"))
85			require.NoError(t, err)
86
87			srv := NewGRPCServer(
88				config.Config{
89					Failover: config.Failover{
90						ElectionStrategy: electionStrategy,
91					},
92				},
93				testhelper.DiscardTestEntry(t),
94				protoregistry.GitalyProtoPreregistered,
95				func(ctx context.Context, fullMethodName string, peeker proxy.StreamPeeker) (*proxy.StreamParameters, error) {
96					return nil, errServedByGitaly
97				},
98				nil,
99				nil,
100				nil,
101				rs,
102				nil,
103				nil,
104				nil,
105			)
106			defer srv.Stop()
107
108			go func() { srv.Serve(ln) }()
109
110			clientConn, err := grpc.DialContext(ctx, "unix://"+ln.Addr().String(), grpc.WithInsecure())
111			require.NoError(t, err)
112
113			client := gitalypb.NewRepositoryServiceClient(clientConn)
114			_, err = client.RepositorySize(ctx, &gitalypb.RepositorySizeRequest{Repository: tc.repository})
115			require.Equal(t, errServedByGitaly, err, "other RPCs should be passed through")
116
117			resp, err := client.RepositoryExists(ctx, &gitalypb.RepositoryExistsRequest{Repository: tc.repository})
118			require.Equal(t, tc.error, err)
119			require.Equal(t, tc.response, resp)
120		})
121	}
122}
123