Skip to content

Commit b342596

Browse files
Merge pull request containers#27269 from Honny1/fix-unmarshal-prunereport
fix: system prune JSON unmarshalling error in remote client
2 parents d906918 + 56fee79 commit b342596

File tree

3 files changed

+200
-0
lines changed

3 files changed

+200
-0
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package bindings_test
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"errors"
7+
"io"
8+
"net/http"
9+
10+
"github.com/containers/podman/v5/pkg/bindings"
11+
"github.com/containers/podman/v5/pkg/domain/entities/reports"
12+
"github.com/containers/podman/v5/pkg/domain/entities/types"
13+
. "github.com/onsi/ginkgo/v2"
14+
. "github.com/onsi/gomega"
15+
)
16+
17+
var _ = Describe("APIResponse Process method", func() {
18+
19+
createMockResponse := func(jsonResponse []byte, statusCode int) *bindings.APIResponse {
20+
response := &http.Response{
21+
StatusCode: statusCode,
22+
Body: io.NopCloser(bytes.NewBuffer(jsonResponse)),
23+
Header: make(http.Header),
24+
}
25+
response.Header.Set("Content-Type", "application/json")
26+
return &bindings.APIResponse{Response: response}
27+
}
28+
29+
It("unmarshal the response with ContainerPruneReport with error", func() {
30+
errorStr := `replacing mount point "/tmp/CI_7Qsy/podman-e2e/b33ae357af1/merged": directory not empty`
31+
responseReport := types.SystemPruneReport{
32+
ContainerPruneReports: []*reports.PruneReport{
33+
{Id: "aec04392e9b2fe7c4a3", Size: 8219},
34+
{
35+
Id: "3d8a8789524a0c44a61",
36+
Size: 7238,
37+
Err: errors.New(errorStr),
38+
},
39+
{Id: "e9ef46f3a3cd43c929b", Size: 0},
40+
},
41+
PodPruneReport: nil,
42+
ImagePruneReports: nil,
43+
NetworkPruneReports: nil,
44+
VolumePruneReports: nil,
45+
ReclaimedSpace: 15457,
46+
}
47+
48+
jsonResponse, err := json.Marshal(responseReport)
49+
Expect(err).ToNot(HaveOccurred())
50+
apiResponse := createMockResponse(jsonResponse, 200)
51+
52+
var report types.SystemPruneReport
53+
err = apiResponse.Process(&report)
54+
Expect(err).ToNot(HaveOccurred())
55+
56+
Expect(report.ContainerPruneReports).To(HaveLen(3))
57+
Expect(report.ReclaimedSpace).To(Equal(uint64(15457)))
58+
59+
first := report.ContainerPruneReports[0]
60+
Expect(first.Id).To(Equal("aec04392e9b2fe7c4a3"))
61+
Expect(first.Size).To(Equal(uint64(8219)))
62+
Expect(first.Err).ToNot(HaveOccurred())
63+
64+
second := report.ContainerPruneReports[1]
65+
Expect(second.Id).To(Equal("3d8a8789524a0c44a61"))
66+
Expect(second.Size).To(Equal(uint64(7238)))
67+
Expect(second.Err).To(HaveOccurred())
68+
Expect(second.Err.Error()).To(Equal(errorStr))
69+
70+
third := report.ContainerPruneReports[2]
71+
Expect(third.Id).To(Equal("e9ef46f3a3cd43c929b"))
72+
Expect(third.Size).To(Equal(uint64(0)))
73+
Expect(third.Err).ToNot(HaveOccurred())
74+
})
75+
})

pkg/domain/entities/reports/prune.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,49 @@
11
package reports
22

3+
import (
4+
"encoding/json"
5+
"errors"
6+
)
7+
38
type PruneReport struct {
49
Id string `json:"Id"`
510
Err error `json:"Err,omitempty"`
611
Size uint64 `json:"Size"`
712
}
813

14+
type pruneReportHelper struct {
15+
Id string `json:"Id"`
16+
Err string `json:"Err,omitempty"`
17+
Size uint64 `json:"Size"`
18+
}
19+
20+
func (pr *PruneReport) MarshalJSON() ([]byte, error) {
21+
helper := pruneReportHelper{
22+
Id: pr.Id,
23+
Size: pr.Size,
24+
}
25+
if pr.Err != nil {
26+
helper.Err = pr.Err.Error()
27+
}
28+
return json.Marshal(helper)
29+
}
30+
31+
func (pr *PruneReport) UnmarshalJSON(data []byte) error {
32+
var helper pruneReportHelper
33+
if err := json.Unmarshal(data, &helper); err != nil {
34+
return err
35+
}
36+
37+
pr.Id = helper.Id
38+
pr.Size = helper.Size
39+
if helper.Err != "" {
40+
pr.Err = errors.New(helper.Err)
41+
} else {
42+
pr.Err = nil
43+
}
44+
return nil
45+
}
46+
947
func PruneReportsIds(r []*PruneReport) []string {
1048
ids := make([]string, 0, len(r))
1149
for _, v := range r {
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package reports
2+
3+
import (
4+
"encoding/json"
5+
"errors"
6+
"testing"
7+
8+
. "github.com/onsi/ginkgo/v2"
9+
. "github.com/onsi/gomega"
10+
)
11+
12+
func TestReports(t *testing.T) {
13+
RegisterFailHandler(Fail)
14+
RunSpecs(t, "Reports Suite")
15+
}
16+
17+
var _ = Describe("PruneReport JSON", func() {
18+
Context("when marshaling and unmarshaling", func() {
19+
tests := []struct {
20+
name string
21+
report *PruneReport
22+
wantErr bool
23+
}{
24+
{
25+
name: "report with error",
26+
report: &PruneReport{
27+
Id: "test-container-id",
28+
Err: errors.New("test error message"),
29+
Size: 1024,
30+
},
31+
},
32+
{
33+
name: "report without error",
34+
report: &PruneReport{
35+
Id: "test-container-id",
36+
Err: nil,
37+
Size: 2048,
38+
},
39+
},
40+
{
41+
name: "empty report",
42+
report: &PruneReport{
43+
Id: "",
44+
Err: nil,
45+
Size: 0,
46+
},
47+
},
48+
{
49+
name: "report with complex error message from failing test case",
50+
report: &PruneReport{
51+
Id: "3d8a8789524a0c44a61baa49ceedda7be069b0b3d01255b24013d2fb82168c7e",
52+
Err: errors.New(`replacing mount point "/tmp/CI_7Qsy/podman-e2e-213135586/subtest-1767990215/p/root/overlay/d9f554276b923c07bf708858b5f35774f9d2924fa4094b1583e56b33ae357af1/merged": directory not empty`),
53+
Size: 7238,
54+
},
55+
},
56+
{
57+
name: "report with special characters in error",
58+
report: &PruneReport{
59+
Id: "container-special",
60+
Err: errors.New(`error with "quotes" and \backslashes\ and newlines`),
61+
Size: 512,
62+
},
63+
},
64+
}
65+
66+
for _, tt := range tests {
67+
It("should handle "+tt.name, func() {
68+
jsonData, err := json.Marshal(tt.report)
69+
Expect(err).ToNot(HaveOccurred())
70+
71+
var unmarshalled PruneReport
72+
err = json.Unmarshal(jsonData, &unmarshalled)
73+
Expect(err).ToNot(HaveOccurred())
74+
75+
Expect(unmarshalled.Id).To(Equal(tt.report.Id))
76+
Expect(unmarshalled.Size).To(Equal(tt.report.Size))
77+
78+
if tt.report.Err == nil {
79+
Expect(unmarshalled.Err).ToNot(HaveOccurred())
80+
} else {
81+
Expect(unmarshalled.Err).To(HaveOccurred())
82+
Expect(unmarshalled.Err.Error()).To(Equal(tt.report.Err.Error()))
83+
}
84+
})
85+
}
86+
})
87+
})

0 commit comments

Comments
 (0)