mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-05-06 22:18:28 +00:00
add codecoverage
This commit is contained in:
committed by
André Roth
parent
3c8defa304
commit
5655480e00
+156
-45
@@ -3,6 +3,9 @@ package api
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
. "gopkg.in/check.v1"
|
||||
)
|
||||
@@ -13,6 +16,46 @@ type GPGSuite struct {
|
||||
|
||||
var _ = Suite(&GPGSuite{})
|
||||
|
||||
func (s *GPGSuite) withFakeGPG(c *C, scriptBody string, test func(scriptPath string)) {
|
||||
tempDir, err := os.MkdirTemp("", "aptly-fake-gpg")
|
||||
c.Assert(err, IsNil)
|
||||
defer func() { _ = os.RemoveAll(tempDir) }()
|
||||
|
||||
scriptPath := filepath.Join(tempDir, "gpg")
|
||||
err = os.WriteFile(scriptPath, []byte(scriptBody), 0o755)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
oldPath := os.Getenv("PATH")
|
||||
err = os.Setenv("PATH", tempDir+string(os.PathListSeparator)+oldPath)
|
||||
c.Assert(err, IsNil)
|
||||
defer func() { _ = os.Setenv("PATH", oldPath) }()
|
||||
|
||||
test(scriptPath)
|
||||
}
|
||||
|
||||
func (s *GPGSuite) fakeGPGScript(c *C, listOutput string, deleteOutput string, deleteError string) string {
|
||||
return "#!/bin/sh\n" +
|
||||
"if [ \"$1\" = \"--version\" ]; then\n" +
|
||||
" echo 'gpg (GnuPG) 2.2.27'\n" +
|
||||
" exit 0\n" +
|
||||
"fi\n" +
|
||||
"args=\"$*\"\n" +
|
||||
"if printf '%s' \"$args\" | grep -q -- '--list-keys'; then\n" +
|
||||
" cat <<'EOF'\n" + listOutput + "\nEOF\n" +
|
||||
" exit 0\n" +
|
||||
"fi\n" +
|
||||
"if printf '%s' \"$args\" | grep -q -- '--delete-keys'; then\n" +
|
||||
" if [ -n \"" + strings.ReplaceAll(deleteError, "\n", "") + "\" ]; then\n" +
|
||||
" echo '" + strings.ReplaceAll(deleteError, "'", "'\\''") + "'\n" +
|
||||
" exit 1\n" +
|
||||
" fi\n" +
|
||||
" cat <<'EOF'\n" + deleteOutput + "\nEOF\n" +
|
||||
" exit 0\n" +
|
||||
"fi\n" +
|
||||
"echo 'unexpected invocation' >&2\n" +
|
||||
"exit 1\n"
|
||||
}
|
||||
|
||||
// TestParseGPGOutputEmpty tests parsing of empty GPG output
|
||||
func (s *GPGSuite) TestParseGPGOutputEmpty(c *C) {
|
||||
output := ""
|
||||
@@ -173,50 +216,68 @@ fpr:::::::::D8E8F5A516E7A2C4F3E4B5A6C7D8E9F0:`
|
||||
|
||||
// TestAPIGPGListKeysDefaultKeyring tests the HTTP endpoint with default keyring
|
||||
func (s *GPGSuite) TestAPIGPGListKeysDefaultKeyring(c *C) {
|
||||
c.Skip("Requires GPG binary and test key installation. Run manually if needed.")
|
||||
s.withFakeGPG(c, s.fakeGPGScript(c, `pub:u:4096:1:8B48AD6246925553:1611864000:::::
|
||||
uid:u::::1611864000::1234567890::John Doe <john@example.com>::::::::::0:
|
||||
fpr:::::::::D8E8F5A516E7A2C4F3E4B5A6C7D8E9F0:`, "", ""), func(_ string) {
|
||||
response, err := s.HTTPRequest("GET", "/api/gpg/keys", nil)
|
||||
c.Assert(err, IsNil)
|
||||
c.Check(response.Code, Equals, 200)
|
||||
|
||||
response, err := s.HTTPRequest("GET", "/api/gpg/keys", nil)
|
||||
c.Assert(err, IsNil)
|
||||
c.Check(response.Code, Equals, 200)
|
||||
|
||||
// Verify response is valid JSON
|
||||
var result gpgKeyListResponse
|
||||
err = json.NewDecoder(response.Body).Decode(&result)
|
||||
c.Assert(err, IsNil)
|
||||
c.Check(result.Keys, NotNil)
|
||||
var result gpgKeyListResponse
|
||||
err = json.NewDecoder(response.Body).Decode(&result)
|
||||
c.Assert(err, IsNil)
|
||||
c.Check(result.Keys, HasLen, 1)
|
||||
c.Check(result.Keys[0].KeyID, Equals, "8B48AD6246925553")
|
||||
})
|
||||
}
|
||||
|
||||
// TestAPIGPGListKeysWithKeyringParam tests the HTTP endpoint with custom keyring parameter
|
||||
func (s *GPGSuite) TestAPIGPGListKeysWithKeyringParam(c *C) {
|
||||
c.Skip("Requires GPG binary and test key installation. Run manually if needed.")
|
||||
|
||||
response, err := s.HTTPRequest("GET", "/api/gpg/keys?keyring=custom.gpg", nil)
|
||||
argFile, err := os.CreateTemp("", "aptly-gpg-args")
|
||||
c.Assert(err, IsNil)
|
||||
// May fail if custom.gpg doesn't exist, but endpoint should handle gracefully
|
||||
// Accept either 200 (success) or 400 (file not found)
|
||||
code := response.Code
|
||||
c.Check(code == 200 || code == 400, Equals, true)
|
||||
_ = argFile.Close()
|
||||
defer func() { _ = os.Remove(argFile.Name()) }()
|
||||
|
||||
script := "#!/bin/sh\n" +
|
||||
"if [ \"$1\" = \"--version\" ]; then echo 'gpg (GnuPG) 2.2.27'; exit 0; fi\n" +
|
||||
"printf '%s\n' \"$@\" > '" + argFile.Name() + "'\n" +
|
||||
"if printf '%s' \"$*\" | grep -q -- '--list-keys'; then\n" +
|
||||
"cat <<'EOF'\n" +
|
||||
"pub:u:4096:1:8B48AD6246925553:1611864000:::::\n" +
|
||||
"fpr:::::::::D8E8F5A516E7A2C4F3E4B5A6C7D8E9F0:\n" +
|
||||
"EOF\n" +
|
||||
"exit 0\n" +
|
||||
"fi\n" +
|
||||
"exit 1\n"
|
||||
|
||||
s.withFakeGPG(c, script, func(_ string) {
|
||||
response, reqErr := s.HTTPRequest("GET", "/api/gpg/keys?keyring=/custom.gpg", nil)
|
||||
c.Assert(reqErr, IsNil)
|
||||
c.Check(response.Code, Equals, 200)
|
||||
|
||||
argBytes, readErr := os.ReadFile(argFile.Name())
|
||||
c.Assert(readErr, IsNil)
|
||||
c.Check(string(argBytes), Matches, `(?s).*--keyring\ncustom\.gpg\n.*`)
|
||||
})
|
||||
}
|
||||
|
||||
// TestAPIGPGListKeysResponseFormat tests that the response has the correct structure
|
||||
func (s *GPGSuite) TestAPIGPGListKeysResponseFormat(c *C) {
|
||||
c.Skip("Requires GPG binary and test key installation. Run manually if needed.")
|
||||
s.withFakeGPG(c, s.fakeGPGScript(c, `pub:f:4096:1:A1B2C3D4E5F67890:1611864000:::::
|
||||
uid:f::::1611864000::1234567890::Jane Smith <jane@example.com>::::::::::0:
|
||||
fpr:::::::::E9F0A1B2C3D4E5F6A7B8C9D0E1F2A3B4:`, "", ""), func(_ string) {
|
||||
response, err := s.HTTPRequest("GET", "/api/gpg/keys", nil)
|
||||
c.Assert(err, IsNil)
|
||||
c.Check(response.Code, Equals, 200)
|
||||
|
||||
response, err := s.HTTPRequest("GET", "/api/gpg/keys", nil)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
if response.Code == 200 {
|
||||
var result gpgKeyListResponse
|
||||
err = json.NewDecoder(response.Body).Decode(&result)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
// If there are keys, verify their structure
|
||||
for _, key := range result.Keys {
|
||||
c.Check(key.KeyID, Not(Equals), "")
|
||||
c.Check(key.Validity, Not(Equals), "")
|
||||
c.Check(key.CreatedAt, Not(Equals), "")
|
||||
}
|
||||
}
|
||||
c.Assert(result.Keys, HasLen, 1)
|
||||
c.Check(result.Keys[0].KeyID, Equals, "A1B2C3D4E5F67890")
|
||||
c.Check(result.Keys[0].Validity, Equals, "f")
|
||||
c.Check(result.Keys[0].CreatedAt, Equals, "1611864000")
|
||||
})
|
||||
}
|
||||
|
||||
// TestParseGPGOutputEdgeCaseUIDWithoutFields tests UID record with missing fields
|
||||
@@ -300,8 +361,6 @@ func (s *GPGSuite) TestGPGDeleteKeyParamsValidation(c *C) {
|
||||
|
||||
// TestAPIGPGDeleteKeyMissingKeyID tests delete with missing key ID parameter
|
||||
func (s *GPGSuite) TestAPIGPGDeleteKeyMissingKeyID(c *C) {
|
||||
c.Skip("Requires GPG binary. Run manually if needed.")
|
||||
|
||||
body, err := json.Marshal(map[string]string{
|
||||
"Keyring": "trustedkeys.gpg",
|
||||
// GpgKeyID is missing
|
||||
@@ -315,8 +374,6 @@ func (s *GPGSuite) TestAPIGPGDeleteKeyMissingKeyID(c *C) {
|
||||
|
||||
// TestAPIGPGDeleteKeyInvalidJSON tests delete with invalid JSON request
|
||||
func (s *GPGSuite) TestAPIGPGDeleteKeyInvalidJSON(c *C) {
|
||||
c.Skip("Requires GPG binary. Run manually if needed.")
|
||||
|
||||
response, err := s.HTTPRequest("DELETE", "/api/gpg/key", bytes.NewReader([]byte("invalid json")))
|
||||
c.Assert(err, IsNil)
|
||||
c.Check(response.Code, Equals, 400)
|
||||
@@ -324,17 +381,71 @@ func (s *GPGSuite) TestAPIGPGDeleteKeyInvalidJSON(c *C) {
|
||||
|
||||
// TestAPIGPGDeleteKeySuccess tests successful key deletion
|
||||
func (s *GPGSuite) TestAPIGPGDeleteKeySuccess(c *C) {
|
||||
c.Skip("Requires GPG binary and test key installation. Run manually if needed.")
|
||||
argFile, err := os.CreateTemp("", "aptly-gpg-delete-args")
|
||||
c.Assert(err, IsNil)
|
||||
_ = argFile.Close()
|
||||
defer func() { _ = os.Remove(argFile.Name()) }()
|
||||
|
||||
body, err := json.Marshal(gpgDeleteKeyParams{
|
||||
Keyring: "trustedkeys.gpg",
|
||||
GpgKeyID: "8B48AD6246925553",
|
||||
script := "#!/bin/sh\n" +
|
||||
"if [ \"$1\" = \"--version\" ]; then echo 'gpg (GnuPG) 2.2.27'; exit 0; fi\n" +
|
||||
"printf '%s\n' \"$@\" > '" + argFile.Name() + "'\n" +
|
||||
"if printf '%s' \"$*\" | grep -q -- '--delete-keys'; then\n" +
|
||||
"echo 'deleted'\n" +
|
||||
"exit 0\n" +
|
||||
"fi\n" +
|
||||
"exit 1\n"
|
||||
|
||||
s.withFakeGPG(c, script, func(_ string) {
|
||||
body, marshalErr := json.Marshal(gpgDeleteKeyParams{
|
||||
Keyring: "/trustedkeys.gpg",
|
||||
GpgKeyID: "8B48AD6246925553",
|
||||
})
|
||||
c.Assert(marshalErr, IsNil)
|
||||
|
||||
response, reqErr := s.HTTPRequest("DELETE", "/api/gpg/key", bytes.NewReader(body))
|
||||
c.Assert(reqErr, IsNil)
|
||||
c.Check(response.Code, Equals, 200)
|
||||
c.Check(response.Body.String(), Matches, `"deleted\\n"`)
|
||||
|
||||
argBytes, readErr := os.ReadFile(argFile.Name())
|
||||
c.Assert(readErr, IsNil)
|
||||
argText := string(argBytes)
|
||||
c.Check(argText, Matches, `(?s).*--batch\n--yes\n.*`)
|
||||
c.Check(argText, Matches, `(?s).*--keyring\n/trustedkeys\.gpg\n.*`)
|
||||
c.Check(argText, Matches, `(?s).*--delete-keys\n8B48AD6246925553\n.*`)
|
||||
})
|
||||
}
|
||||
|
||||
// TestAPIGPGListKeysCommandFailure tests list error propagation from gpg
|
||||
func (s *GPGSuite) TestAPIGPGListKeysCommandFailure(c *C) {
|
||||
script := "#!/bin/sh\n" +
|
||||
"if [ \"$1\" = \"--version\" ]; then echo 'gpg (GnuPG) 2.2.27'; exit 0; fi\n" +
|
||||
"if printf '%s' \"$*\" | grep -q -- '--list-keys'; then\n" +
|
||||
"echo 'keyring missing'\n" +
|
||||
"exit 1\n" +
|
||||
"fi\n" +
|
||||
"exit 1\n"
|
||||
|
||||
s.withFakeGPG(c, script, func(_ string) {
|
||||
response, err := s.HTTPRequest("GET", "/api/gpg/keys", nil)
|
||||
c.Assert(err, IsNil)
|
||||
c.Check(response.Code, Equals, 400)
|
||||
c.Check(response.Body.String(), Matches, `(?s).*failed to list keys: keyring missing.*`)
|
||||
})
|
||||
}
|
||||
|
||||
// TestAPIGPGDeleteKeyCommandFailure tests delete error propagation from gpg
|
||||
func (s *GPGSuite) TestAPIGPGDeleteKeyCommandFailure(c *C) {
|
||||
s.withFakeGPG(c, s.fakeGPGScript(c, "", "", "delete failed"), func(_ string) {
|
||||
body, err := json.Marshal(gpgDeleteKeyParams{
|
||||
Keyring: "trustedkeys.gpg",
|
||||
GpgKeyID: "8B48AD6246925553",
|
||||
})
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
response, reqErr := s.HTTPRequest("DELETE", "/api/gpg/key", bytes.NewReader(body))
|
||||
c.Assert(reqErr, IsNil)
|
||||
c.Check(response.Code, Equals, 400)
|
||||
c.Check(response.Body.String(), Matches, `(?s).*failed to delete key: delete failed.*`)
|
||||
})
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
response, err := s.HTTPRequest("DELETE", "/api/gpg/key", bytes.NewReader(body))
|
||||
c.Assert(err, IsNil)
|
||||
// Should succeed (200) or fail gracefully (400) if key doesn't exist
|
||||
code := response.Code
|
||||
c.Check(code == 200 || code == 400, Equals, true)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user