// Copyright 2019 Drone.IO Inc. All rights reserved. // Use of this source code is governed by the Drone Non-Commercial License // that can be found in the LICENSE file. package acl import ( "context" "database/sql" "net/http" "net/http/httptest" "testing" "time" "github.com/drone/drone/handler/api/request" "github.com/drone/drone/mock" "github.com/drone/drone/core" "github.com/go-chi/chi" "github.com/golang/mock/gomock" ) // this unit test ensures that the http request returns a // 401 unauthorized if the session does not exist, and the // repository is not found. func TestInjectRepository_RepoNotFound_Guest(t *testing.T) { controller := gomock.NewController(t) defer controller.Finish() repos := mock.NewMockRepositoryStore(controller) repos.EXPECT().FindName(gomock.Any(), "octocat", "hello-world").Return(nil, sql.ErrNoRows) c := new(chi.Context) c.URLParams.Add("owner", "octocat") c.URLParams.Add("name", "hello-world") w := httptest.NewRecorder() r := httptest.NewRequest("GET", "/", nil) r = r.WithContext( context.WithValue(r.Context(), chi.RouteCtxKey, c), ) next := http.HandlerFunc(func(http.ResponseWriter, *http.Request) { t.Fail() }) InjectRepository(nil, repos, nil)(next).ServeHTTP(w, r) if got, want := w.Code, http.StatusUnauthorized; want != got { t.Errorf("Want response code %d, got %d", want, got) } } // this unit test ensures that the http request returns a // 404 not found if the session does exist, but the // repository is not found. func TestInjectRepository_RepoNotFound_User(t *testing.T) { controller := gomock.NewController(t) defer controller.Finish() repos := mock.NewMockRepositoryStore(controller) repos.EXPECT().FindName(gomock.Any(), "octocat", "hello-world").Return(nil, sql.ErrNoRows) c := new(chi.Context) c.URLParams.Add("owner", "octocat") c.URLParams.Add("name", "hello-world") w := httptest.NewRecorder() r := httptest.NewRequest("GET", "/", nil) r = r.WithContext( context.WithValue( request.WithUser(r.Context(), &core.User{}), chi.RouteCtxKey, c), ) next := http.HandlerFunc(func(http.ResponseWriter, *http.Request) { t.Fail() }) InjectRepository(nil, repos, nil)(next).ServeHTTP(w, r) if got, want := w.Code, 404; want != got { t.Errorf("Want response code %d, got %d", want, got) } } // this unit test ensures that the middleware function // invokes the next handler in the chain if the repository // is found, but no user session exists. func TestInjectRepository_RepoFound_Guest(t *testing.T) { controller := gomock.NewController(t) defer controller.Finish() repos := mock.NewMockRepositoryStore(controller) repos.EXPECT().FindName(gomock.Any(), "octocat", "hello-world").Return(&core.Repository{}, nil) c := new(chi.Context) c.URLParams.Add("owner", "octocat") c.URLParams.Add("name", "hello-world") w := httptest.NewRecorder() r := httptest.NewRequest("GET", "/", nil) r = r.WithContext( context.WithValue( r.Context(), chi.RouteCtxKey, c), ) invoked := false next := http.HandlerFunc(func(http.ResponseWriter, *http.Request) { invoked = true }) InjectRepository(nil, repos, nil)(next).ServeHTTP(w, r) if !invoked { t.Errorf("Expect middleware invoked") } } // this unit test ensures that the middleware function // invokes the next handler and stores the permissions // in the context if found. func TestInjectRepository_PermsFound(t *testing.T) { controller := gomock.NewController(t) defer controller.Finish() mockUser := &core.User{ID: 1} mockRepo := &core.Repository{UID: "1"} mockPerm := &core.Perm{Synced: time.Now().Unix()} repos := mock.NewMockRepositoryStore(controller) repos.EXPECT().FindName(gomock.Any(), "octocat", "hello-world").Return(mockRepo, nil) perms := mock.NewMockPermStore(controller) perms.EXPECT().Find(gomock.Any(), mockRepo.UID, mockUser.ID).Return(mockPerm, nil) c := new(chi.Context) c.URLParams.Add("owner", "octocat") c.URLParams.Add("name", "hello-world") w := httptest.NewRecorder() r := httptest.NewRequest("GET", "/", nil) r = r.WithContext( context.WithValue( request.WithUser(r.Context(), mockUser), chi.RouteCtxKey, c), ) invoked := false next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { invoked = true _, ok := request.PermFrom(r.Context()) if !ok { t.Errorf("Expect perm from context") } }) InjectRepository(nil, repos, perms)(next).ServeHTTP(w, r) if !invoked { t.Errorf("Expect middleware invoked") } } // this unit test ensures that the middleware function // invokes the next handler even if the permissions are // not found. It is the responsibility to downstream // middleware and handlers to decide if the request // should be rejected. func TestInjectRepository_PermsNotFound(t *testing.T) { controller := gomock.NewController(t) defer controller.Finish() mockUser := &core.User{ID: 1} mockRepo := &core.Repository{UID: "1"} repos := mock.NewMockRepositoryStore(controller) repos.EXPECT().FindName(gomock.Any(), "octocat", "hello-world").Return(mockRepo, nil) perms := mock.NewMockPermStore(controller) perms.EXPECT().Find(gomock.Any(), mockRepo.UID, mockUser.ID).Return(nil, sql.ErrNoRows) c := new(chi.Context) c.URLParams.Add("owner", "octocat") c.URLParams.Add("name", "hello-world") w := httptest.NewRecorder() r := httptest.NewRequest("GET", "/", nil) r = r.WithContext( context.WithValue( request.WithUser(r.Context(), mockUser), chi.RouteCtxKey, c), ) invoked := false next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { invoked = true _, ok := request.PermFrom(r.Context()) if ok { t.Errorf("Expect nil perm from context") } }) InjectRepository(nil, repos, perms)(next).ServeHTTP(w, r) if !invoked { t.Errorf("Expect middleware invoked") } }