From 3d909bd0bdb32803c5828e2cd5b01060dc02c76b Mon Sep 17 00:00:00 2001 From: Wenkai Yin Date: Wed, 10 Aug 2016 10:48:58 +0800 Subject: [PATCH] add UT for package utils --- api/search.go | 9 +- utils/registry/auth/auth_test.go | 9 -- utils/registry/auth/authorizer_test.go | 91 +++++++++++++++++++++ utils/registry/auth/credential_test.go | 67 +++++++++++++++ utils/registry/auth/tokenauthorizer.go | 4 +- utils/registry/auth/tokenauthorizer_test.go | 81 ++++++++++++++++++ utils/registry/error/error_test.go | 12 ++- utils/utils.go | 11 --- utils/utils_test.go | 41 +++++++++- 9 files changed, 297 insertions(+), 28 deletions(-) delete mode 100644 utils/registry/auth/auth_test.go create mode 100644 utils/registry/auth/authorizer_test.go create mode 100644 utils/registry/auth/credential_test.go create mode 100644 utils/registry/auth/tokenauthorizer_test.go diff --git a/api/search.go b/api/search.go index 4da0068c00..9b98caafa5 100644 --- a/api/search.go +++ b/api/search.go @@ -101,18 +101,19 @@ func filterRepositories(repositories []string, projects []models.Project, keywor i, j := 0, 0 result := []map[string]interface{}{} for i < len(repositories) && j < len(projects) { - r := &utils.Repository{Name: repositories[i]} - d := strings.Compare(r.GetProject(), projects[j].Name) + r := repositories[i] + p, _ := utils.ParseRepository(r) + d := strings.Compare(p, projects[j].Name) if d < 0 { i++ continue } else if d == 0 { i++ - if len(keyword) != 0 && !strings.Contains(r.Name, keyword) { + if len(keyword) != 0 && !strings.Contains(r, keyword) { continue } entry := make(map[string]interface{}) - entry["repository_name"] = r.Name + entry["repository_name"] = r entry["project_name"] = projects[j].Name entry["project_id"] = projects[j].ProjectID entry["project_public"] = projects[j].Public diff --git a/utils/registry/auth/auth_test.go b/utils/registry/auth/auth_test.go deleted file mode 100644 index a5890bd694..0000000000 --- a/utils/registry/auth/auth_test.go +++ /dev/null @@ -1,9 +0,0 @@ -package auth - -import ( - "testing" -) - -func TestMain(t *testing.T) { -} - diff --git a/utils/registry/auth/authorizer_test.go b/utils/registry/auth/authorizer_test.go new file mode 100644 index 0000000000..cfebac3ead --- /dev/null +++ b/utils/registry/auth/authorizer_test.go @@ -0,0 +1,91 @@ +/* + Copyright (c) 2016 VMware, Inc. All Rights Reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package auth + +import ( + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/docker/distribution/registry/client/auth" +) + +func TestNewAuthorizerStore(t *testing.T) { + server := newRegistryServer() + defer server.Close() + + _, err := NewAuthorizerStore(server.URL, false, nil) + if err != nil { + t.Fatalf("failed to create authorizer store: %v", err) + } +} + +type simpleAuthorizer struct { +} + +func (s *simpleAuthorizer) Scheme() string { + return "bearer" +} + +func (s *simpleAuthorizer) Authorize(req *http.Request, + params map[string]string) error { + req.Header.Set("Authorization", "Bearer token") + return nil +} + +func TestModify(t *testing.T) { + authorizer := &simpleAuthorizer{} + challenge := auth.Challenge{ + Scheme: "bearer", + } + + as := &AuthorizerStore{ + authorizers: []Authorizer{authorizer}, + challenges: []auth.Challenge{challenge}, + } + + req, err := http.NewRequest("GET", "http://example.com", nil) + if err != nil { + t.Fatalf("failed to create request: %v", err) + } + + if err = as.Modify(req); err != nil { + t.Fatalf("failed to modify request: %v", err) + } + + header := req.Header.Get("Authorization") + if len(header) == 0 { + t.Fatal("\"Authorization\" header not found") + } + + if !strings.HasPrefix(header, "Bearer") { + t.Fatal("\"Authorization\" header does not start with \"Bearer\"") + } +} + +func newRegistryServer() *httptest.Server { + mux := http.NewServeMux() + mux.HandleFunc("/v2/", handlePing) + + return httptest.NewServer(mux) +} + +func handlePing(w http.ResponseWriter, r *http.Request) { + challenge := "Bearer realm=\"https://auth.docker.io/token\",service=\"registry.docker.io\"" + w.Header().Set("Www-Authenticate", challenge) + w.WriteHeader(http.StatusUnauthorized) +} diff --git a/utils/registry/auth/credential_test.go b/utils/registry/auth/credential_test.go new file mode 100644 index 0000000000..9c36691da2 --- /dev/null +++ b/utils/registry/auth/credential_test.go @@ -0,0 +1,67 @@ +/* + Copyright (c) 2016 VMware, Inc. All Rights Reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package auth + +import ( + "net/http" + "testing" +) + +func TestAddAuthorizationOfBasicAuthCredential(t *testing.T) { + cred := NewBasicAuthCredential("usr", "pwd") + req, err := http.NewRequest("GET", "http://example.com", nil) + if err != nil { + t.Fatalf("failed to create request: %v", err) + } + + cred.AddAuthorization(req) + + usr, pwd, ok := req.BasicAuth() + if !ok { + t.Fatal("basic auth not found") + } + + if usr != "usr" { + t.Errorf("unexpected username: %s != usr", usr) + } + + if pwd != "pwd" { + t.Errorf("unexpected password: %s != pwd", pwd) + } +} + +func TestAddAuthorizationOfCookieCredential(t *testing.T) { + cookie := &http.Cookie{ + Name: "name", + Value: "value", + } + cred := NewCookieCredential(cookie) + req, err := http.NewRequest("GET", "http://example.com", nil) + if err != nil { + t.Fatalf("failed to create request: %v", err) + } + + cred.AddAuthorization(req) + + ck, err := req.Cookie("name") + if err != nil { + t.Fatalf("failed to get cookie: %v", err) + } + + if ck.Value != "value" { + t.Errorf("unexpected value: %s != value", ck.Value) + } +} diff --git a/utils/registry/auth/tokenauthorizer.go b/utils/registry/auth/tokenauthorizer.go index 0abb72fb7f..318ea61295 100644 --- a/utils/registry/auth/tokenauthorizer.go +++ b/utils/registry/auth/tokenauthorizer.go @@ -180,7 +180,9 @@ func (s *standardTokenAuthorizer) generateToken(realm, service string, scopes [] return } - s.credential.AddAuthorization(r) + if s.credential != nil { + s.credential.AddAuthorization(r) + } resp, err := s.client.Do(r) if err != nil { diff --git a/utils/registry/auth/tokenauthorizer_test.go b/utils/registry/auth/tokenauthorizer_test.go new file mode 100644 index 0000000000..6bf8cf34f7 --- /dev/null +++ b/utils/registry/auth/tokenauthorizer_test.go @@ -0,0 +1,81 @@ +/* + Copyright (c) 2016 VMware, Inc. All Rights Reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package auth + +import ( + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + "time" +) + +var ( + token = "token" +) + +func TestAuthorizeOfStandardTokenAuthorizer(t *testing.T) { + tokenServer := newTokenServer() + defer tokenServer.Close() + + authorizer := NewStandardTokenAuthorizer(nil, false, "repository", "library/ubuntu", "pull") + req, err := http.NewRequest("GET", "http://registry", nil) + if err != nil { + t.Fatalf("failed to create request: %v", err) + } + + params := map[string]string{ + "realm": tokenServer.URL + "/token", + } + + if err := authorizer.Authorize(req, params); err != nil { + t.Fatalf("failed to authorize request: %v", err) + } + + tk := req.Header.Get("Authorization") + if tk != "Bearer "+token { + t.Errorf("unexpected token: %s != %s", tk, "Bearer "+token) + } +} + +func TestSchemeOfStandardTokenAuthorizer(t *testing.T) { + authorizer := &standardTokenAuthorizer{} + if authorizer.Scheme() != "bearer" { + t.Errorf("unexpected scheme: %s != %s", authorizer.Scheme(), "bearer") + } + +} + +func newTokenServer() *httptest.Server { + mux := http.NewServeMux() + mux.HandleFunc("/token", handleToken) + + return httptest.NewServer(mux) +} + +func handleToken(w http.ResponseWriter, r *http.Request) { + result := map[string]interface{}{} + result["token"] = token + result["expires_in"] = 300 + result["issued_at"] = time.Now().Format(time.RFC3339) + + encoder := json.NewEncoder(w) + if err := encoder.Encode(result); err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } +} diff --git a/utils/registry/error/error_test.go b/utils/registry/error/error_test.go index 609e0ec3d1..cfae153116 100644 --- a/utils/registry/error/error_test.go +++ b/utils/registry/error/error_test.go @@ -4,6 +4,14 @@ import ( "testing" ) -func TestMain(t *testing.T) { -} +func TestError(t *testing.T) { + err := &Error{ + StatusCode: 404, + Detail: "not found", + } + if err.Error() != "404 not found" { + t.Fatalf("unexpected content: %s != %s", + err.Error(), "404 not found") + } +} diff --git a/utils/utils.go b/utils/utils.go index 7fa1215e4a..8b8dd7d8b9 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -20,17 +20,6 @@ import ( "strings" ) -// Repository holds information about repository -type Repository struct { - Name string -} - -// GetProject parses the repository and return the name of project. -func (r *Repository) GetProject() string { - project, _ := ParseRepository(r.Name) - return project -} - // FormatEndpoint formats endpoint func FormatEndpoint(endpoint string) string { endpoint = strings.TrimSpace(endpoint) diff --git a/utils/utils_test.go b/utils/utils_test.go index d2ab63112c..d151b8452d 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -21,7 +21,36 @@ import ( "testing" ) -func TestMain(t *testing.T) { +func TestParseEndpoint(t *testing.T) { + endpoint := "example.com" + u, err := ParseEndpoint(endpoint) + if err != nil { + t.Fatalf("failed to parse endpoint %s: %v", endpoint, err) + } + + if u.String() != "http://example.com" { + t.Errorf("unexpected endpoint: %s != %s", endpoint, "http://example.com") + } + + endpoint = "https://example.com" + u, err = ParseEndpoint(endpoint) + if err != nil { + t.Fatalf("failed to parse endpoint %s: %v", endpoint, err) + } + + if u.String() != "https://example.com" { + t.Errorf("unexpected endpoint: %s != %s", endpoint, "https://example.com") + } + + endpoint = " example.com/ " + u, err = ParseEndpoint(endpoint) + if err != nil { + t.Fatalf("failed to parse endpoint %s: %v", endpoint, err) + } + + if u.String() != "http://example.com" { + t.Errorf("unexpected endpoint: %s != %s", endpoint, "http://example.com") + } } func TestParseRepository(t *testing.T) { @@ -64,6 +93,16 @@ func TestParseRepository(t *testing.T) { } } +func TestEncrypt(t *testing.T) { + content := "content" + salt := "salt" + result := Encrypt(content, salt) + + if result != "dc79e76c88415c97eb089d9cc80b4ab0" { + t.Errorf("unexpected result: %s != %s", result, "dc79e76c88415c97eb089d9cc80b4ab0") + } +} + func TestReversibleEncrypt(t *testing.T) { password := "password" key := "1234567890123456"