X-Git-Url: https://ruderich.org/simon/gitweb/?a=blobdiff_plain;ds=sidebyside;f=main_test.go;h=2b48bcc7c9d37315910f8efdac80633ed269a6af;hb=3393730a802af2c7d0849287c12f55f35ed6a09b;hp=d28c822ac3bbb8ef65e44c221ed8fb054b691d85;hpb=2395707d26985ec9a280a940faea0e52b51d69ef;p=nsscash%2Fnsscash.git diff --git a/main_test.go b/main_test.go index d28c822..2b48bcc 100644 --- a/main_test.go +++ b/main_test.go @@ -191,10 +191,28 @@ func TestMainFetch(t *testing.T) { fetchPasswdInvalid, fetchPasswdLimits, fetchPasswd, + // Tests for plain and group + fetchPlainEmpty, + fetchPlain, + fetchGroupEmpty, + fetchGroupInvalid, + fetchGroupLimits, + fetchGroup, // Special tests fetchNoConfig, + fetchStateCannotRead, + fetchStateInvalid, + fetchStateCannotWrite, + fetchCannotDeploy, + fetchSecondFetchFails, } + for _, f := range tests { + runMainTest(t, f) + } +} + +func runMainTest(t *testing.T, f func(args)) { cleanup := []string{ configPath, statePath, @@ -203,39 +221,37 @@ func TestMainFetch(t *testing.T) { groupPath, } - for _, f := range tests { - // NOTE: This is not guaranteed to work according to reflect's - // documentation but seems to work reliable for normal - // functions. - fn := runtime.FuncForPC(reflect.ValueOf(f).Pointer()) - name := fn.Name() - name = name[strings.LastIndex(name, ".")+1:] - - t.Run(name, func(t *testing.T) { - // Preparation & cleanup - for _, p := range cleanup { - err := os.Remove(p) - if err != nil && !os.IsNotExist(err) { - t.Fatal(err) - } - // Remove the file at the end of this test - // run, if it was created - defer os.Remove(p) + // NOTE: This is not guaranteed to work according to reflect's + // documentation but seems to work reliable for normal functions. + fn := runtime.FuncForPC(reflect.ValueOf(f).Pointer()) + name := fn.Name() + name = name[strings.LastIndex(name, ".")+1:] + + t.Run(name, func(t *testing.T) { + // Preparation & cleanup + for _, p := range cleanup { + err := os.Remove(p) + if err != nil && !os.IsNotExist(err) { + t.Fatal(err) } + // Remove the file at the end of this test run, if it + // was created + defer os.Remove(p) + } - var handler func(http.ResponseWriter, *http.Request) - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var handler func(http.ResponseWriter, *http.Request) + ts := httptest.NewServer(http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { handler(w, r) })) - defer ts.Close() + defer ts.Close() - f(args{ - t: t, - url: ts.URL, - handler: &handler, - }) + f(args{ + t: t, + url: ts.URL, + handler: &handler, }) - } + }) } func fetchPasswdCacheFileDoesNotExist(a args) { @@ -439,6 +455,154 @@ func fetchPasswd(a args) { mustHaveHash(t, passwdPath, "bbb7db67469b111200400e2470346d5515d64c23") } +func fetchPlainEmpty(a args) { + t := a.t + mustWriteConfig(t, fmt.Sprintf(` +statepath = "%[1]s" + +[[file]] +type = "plain" +url = "%[2]s/plain" +path = "%[3]s" +`, statePath, a.url, plainPath)) + mustCreate(t, plainPath) + + *a.handler = func(w http.ResponseWriter, r *http.Request) { + // Empty response + } + + err := mainFetch(configPath) + mustBeErrorWithSubstring(t, err, + "refusing to use empty response") + + mustNotExist(t, statePath, passwdPath, groupPath) + mustBeOld(t, plainPath) +} + +func fetchPlain(a args) { + t := a.t + mustWriteConfig(t, fmt.Sprintf(` +statepath = "%[1]s" + +[[file]] +type = "plain" +url = "%[2]s/plain" +path = "%[3]s" +`, statePath, a.url, plainPath)) + mustCreate(t, plainPath) + mustHaveHash(t, plainPath, "da39a3ee5e6b4b0d3255bfef95601890afd80709") + + *a.handler = func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/plain" { + return + } + + fmt.Fprintln(w, "some file") + } + + err := mainFetch(configPath) + if err != nil { + t.Error(err) + } + + mustNotExist(t, passwdPath, groupPath) + mustBeNew(t, plainPath, statePath) + mustHaveHash(t, plainPath, "0e08b5e8c10abc3e455b75286ba4a1fbd56e18a5") + + // Remaining functionality already tested in fetchPasswd() +} + +func fetchGroupEmpty(a args) { + t := a.t + mustWriteGroupConfig(t, a.url) + mustCreate(t, groupPath) + + *a.handler = func(w http.ResponseWriter, r *http.Request) { + // Empty response + } + + err := mainFetch(configPath) + mustBeErrorWithSubstring(t, err, + "refusing to use empty group file") + + mustNotExist(t, statePath, passwdPath, plainPath) + mustBeOld(t, groupPath) +} + +func fetchGroupInvalid(a args) { + t := a.t + mustWriteGroupConfig(t, a.url) + mustCreate(t, groupPath) + + *a.handler = func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/group" { + return + } + + fmt.Fprintln(w, "root:x::") + } + + err := mainFetch(configPath) + mustBeErrorWithSubstring(t, err, + "invalid gid in line") + + mustNotExist(t, statePath, passwdPath, plainPath) + mustBeOld(t, groupPath) +} + +func fetchGroupLimits(a args) { + t := a.t + mustWriteGroupConfig(t, a.url) + mustCreate(t, groupPath) + + *a.handler = func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/group" { + return + } + + fmt.Fprint(w, "root:x:0:") + for i := 0; i < 65536; i++ { + fmt.Fprint(w, "x") + } + fmt.Fprint(w, "\n") + } + + err := mainFetch(configPath) + mustBeErrorWithSubstring(t, err, + "group too large to serialize") + + mustNotExist(t, statePath, passwdPath, plainPath) + mustBeOld(t, groupPath) +} + +func fetchGroup(a args) { + t := a.t + mustWriteGroupConfig(t, a.url) + mustCreate(t, groupPath) + mustHaveHash(t, groupPath, "da39a3ee5e6b4b0d3255bfef95601890afd80709") + + *a.handler = func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/group" { + return + } + + fmt.Fprintln(w, "root:x:0:") + fmt.Fprintln(w, "daemon:x:1:andariel,duriel,mephisto,diablo,baal") + } + + err := mainFetch(configPath) + if err != nil { + t.Error(err) + } + + mustNotExist(t, passwdPath, plainPath) + mustBeNew(t, groupPath, statePath) + // The actual content of groupPath is verified by the NSS tests + mustHaveHash(t, groupPath, "8c27a8403278ba2e392b86d98d4dff1fdefcafdd") + + // Remaining functionality already tested in fetchPasswd() +} + func fetchNoConfig(a args) { t := a.t @@ -448,3 +612,127 @@ func fetchNoConfig(a args) { mustNotExist(t, configPath, statePath, passwdPath, plainPath, groupPath) } + +func fetchStateCannotRead(a args) { + t := a.t + mustWritePasswdConfig(t, a.url) + + mustCreate(t, statePath) + err := os.Chmod(statePath, 0000) + if err != nil { + t.Fatal(err) + } + + err = mainFetch(configPath) + mustBeErrorWithSubstring(t, err, + statePath+": permission denied") + + mustNotExist(t, passwdPath, plainPath, groupPath) +} + +func fetchStateInvalid(a args) { + t := a.t + mustWriteGroupConfig(t, a.url) + mustCreate(t, statePath) + + err := mainFetch(configPath) + mustBeErrorWithSubstring(t, err, + "unexpected end of JSON input") + + mustNotExist(t, groupPath, passwdPath, plainPath) + mustBeOld(t, statePath) +} + +func fetchStateCannotWrite(a args) { + t := a.t + mustWriteGroupConfig(t, a.url) + mustCreate(t, groupPath) + mustHaveHash(t, groupPath, "da39a3ee5e6b4b0d3255bfef95601890afd80709") + + *a.handler = func(w http.ResponseWriter, r *http.Request) { + // To prevent mainFetch() from trying to update groupPath + // which will also fail + w.WriteHeader(http.StatusNotModified) + } + + err := os.Chmod("testdata", 0500) + if err != nil { + t.Fatal(err) + } + defer os.Chmod("testdata", 0755) + + err = mainFetch(configPath) + mustBeErrorWithSubstring(t, err, + "permission denied") + + mustNotExist(t, statePath, passwdPath, plainPath) + mustBeOld(t, groupPath) +} + +func fetchCannotDeploy(a args) { + t := a.t + mustWriteGroupConfig(t, a.url) + mustCreate(t, groupPath) + mustHaveHash(t, groupPath, "da39a3ee5e6b4b0d3255bfef95601890afd80709") + + *a.handler = func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/group" { + return + } + + fmt.Fprintln(w, "root:x:0:") + fmt.Fprintln(w, "daemon:x:1:andariel,duriel,mephisto,diablo,baal") + } + + err := os.Chmod("testdata", 0500) + if err != nil { + t.Fatal(err) + } + defer os.Chmod("testdata", 0755) + + err = mainFetch(configPath) + mustBeErrorWithSubstring(t, err, + "permission denied") + + mustNotExist(t, statePath, passwdPath, plainPath) + mustBeOld(t, groupPath) +} + +func fetchSecondFetchFails(a args) { + t := a.t + mustWriteConfig(t, fmt.Sprintf(` +statepath = "%[1]s" + +[[file]] +type = "passwd" +url = "%[2]s/passwd" +path = "%[3]s" + +[[file]] +type = "group" +url = "%[2]s/group" +path = "%[4]s" +`, statePath, a.url, passwdPath, groupPath)) + mustCreate(t, passwdPath) + mustCreate(t, groupPath) + mustHaveHash(t, passwdPath, "da39a3ee5e6b4b0d3255bfef95601890afd80709") + mustHaveHash(t, groupPath, "da39a3ee5e6b4b0d3255bfef95601890afd80709") + + *a.handler = func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/passwd" { + fmt.Fprintln(w, "root:x:0:0:root:/root:/bin/bash") + } + if r.URL.Path == "/group" { + w.WriteHeader(http.StatusNotFound) + } + } + + err := mainFetch(configPath) + mustBeErrorWithSubstring(t, err, + "status code 404") + + mustNotExist(t, statePath, plainPath) + // Even though passwd was successfully fetched, no files were modified + // because the second fetch failed + mustBeOld(t, passwdPath, groupPath) +}