mirror of
https://github.com/nabbar/golib.git
synced 2026-04-22 23:17:12 +08:00
d565204d20
- FIX: encode ms with call of millisecond instead of uint64 - UPDATE Info interface: rename Info(), RegisterInfo() function to avoid confusion between data and interface - UPDATE Info Encode model to add json tag to avoid unwaiting Uppercase of field name - UPDATE testing following Package Config: - UPDATE aws component following change of monitor Info interface Package Database: - UPDATE Gorm following change of monitor Info interface Package HTTP Server: - UPDATE following change of monitor Info interface Package Mail: - UPDATE smtp following change of monitor Info interface Package Nats: - UPDATE following change of monitor Info interface Package Request: - UPDATE following change of monitor Info interface Package Static: - UPDATE following change of monitor Info interface Package Status: - UPDATE following change of monitor Info interface
384 lines
11 KiB
Go
384 lines
11 KiB
Go
/*
|
|
* MIT License
|
|
*
|
|
* Copyright (c) 2022 Nicolas JUHEL
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*
|
|
*
|
|
*/
|
|
|
|
package info_test
|
|
|
|
import (
|
|
"encoding/json"
|
|
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
|
|
"github.com/nabbar/golib/monitor/info"
|
|
)
|
|
|
|
var _ = Describe("Info Encoding and Marshaling", func() {
|
|
var i info.Info
|
|
|
|
BeforeEach(func() {
|
|
var err error
|
|
i, err = info.New("test-service")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
})
|
|
|
|
Describe("MarshalText", func() {
|
|
Context("with only default name", func() {
|
|
It("should marshal to text successfully", func() {
|
|
text, err := i.MarshalText()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(text).NotTo(BeEmpty())
|
|
Expect(string(text)).To(Equal("test-service"))
|
|
})
|
|
})
|
|
|
|
Context("with registered name function", func() {
|
|
It("should marshal the dynamic name", func() {
|
|
i.RegisterName(func() (string, error) {
|
|
return "dynamic-service", nil
|
|
})
|
|
|
|
text, err := i.MarshalText()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(string(text)).To(Equal("dynamic-service"))
|
|
})
|
|
})
|
|
|
|
Context("with registered info function", func() {
|
|
It("should include info in the marshaled text", func() {
|
|
i.RegisterData(func() (map[string]interface{}, error) {
|
|
return map[string]interface{}{
|
|
"version": "1.0.0",
|
|
"status": "running",
|
|
}, nil
|
|
})
|
|
|
|
text, err := i.MarshalText()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
textStr := string(text)
|
|
Expect(textStr).To(ContainSubstring("test-service"))
|
|
// data should be included
|
|
Expect(textStr).To(MatchRegexp("version.*1.0.0"))
|
|
Expect(textStr).To(MatchRegexp("status.*running"))
|
|
})
|
|
|
|
It("should format info as key-value pairs", func() {
|
|
i.RegisterData(func() (map[string]interface{}, error) {
|
|
return map[string]interface{}{
|
|
"key1": "value1",
|
|
}, nil
|
|
})
|
|
|
|
text, err := i.MarshalText()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
textStr := string(text)
|
|
Expect(textStr).To(ContainSubstring("("))
|
|
Expect(textStr).To(ContainSubstring(")"))
|
|
})
|
|
})
|
|
|
|
Context("with special characters", func() {
|
|
It("should handle newlines in info", func() {
|
|
i.RegisterData(func() (map[string]interface{}, error) {
|
|
return map[string]interface{}{
|
|
"multiline": "line1\nline2",
|
|
}, nil
|
|
})
|
|
|
|
text, err := i.MarshalText()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
textStr := string(text)
|
|
// Newlines should be removed or replaced with spaces
|
|
Expect(textStr).NotTo(ContainSubstring("\n"))
|
|
})
|
|
|
|
It("should handle carriage returns in info", func() {
|
|
i.RegisterData(func() (map[string]interface{}, error) {
|
|
return map[string]interface{}{
|
|
"text": "content\r\nmore",
|
|
}, nil
|
|
})
|
|
|
|
text, err := i.MarshalText()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
textStr := string(text)
|
|
// Carriage returns should be removed
|
|
Expect(textStr).NotTo(ContainSubstring("\r"))
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("MarshalJSON", func() {
|
|
Context("with only default name", func() {
|
|
It("should marshal to JSON successfully", func() {
|
|
jsonBytes, err := i.MarshalJSON()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(jsonBytes).NotTo(BeEmpty())
|
|
|
|
// Parse JSON to verify structure
|
|
var result map[string]interface{}
|
|
err = json.Unmarshal(jsonBytes, &result)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(result).To(HaveKey("name"))
|
|
Expect(result["name"]).To(Equal("test-service"))
|
|
})
|
|
|
|
It("should have data as empty or null", func() {
|
|
jsonBytes, err := i.MarshalJSON()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
var result map[string]interface{}
|
|
err = json.Unmarshal(jsonBytes, &result)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
// data should be present but might be null or empty
|
|
if info, ok := result["data"]; ok && info != nil {
|
|
infoMap := info.(map[string]interface{})
|
|
Expect(infoMap).To(BeEmpty())
|
|
}
|
|
})
|
|
})
|
|
|
|
Context("with registered name function", func() {
|
|
It("should marshal the dynamic name to JSON", func() {
|
|
i.RegisterName(func() (string, error) {
|
|
return "json-service", nil
|
|
})
|
|
|
|
jsonBytes, err := i.MarshalJSON()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
var result map[string]interface{}
|
|
err = json.Unmarshal(jsonBytes, &result)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(result["name"]).To(Equal("json-service"))
|
|
})
|
|
})
|
|
|
|
Context("with registered info function", func() {
|
|
It("should include info in JSON", func() {
|
|
i.RegisterData(func() (map[string]interface{}, error) {
|
|
return map[string]interface{}{
|
|
"version": "2.0.0",
|
|
"environment": "production",
|
|
}, nil
|
|
})
|
|
|
|
jsonBytes, err := i.MarshalJSON()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
var result map[string]interface{}
|
|
err = json.Unmarshal(jsonBytes, &result)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(result).To(HaveKey("data"))
|
|
|
|
infoMap := result["data"].(map[string]interface{})
|
|
Expect(infoMap).To(HaveKey("version"))
|
|
Expect(infoMap["version"]).To(Equal("2.0.0"))
|
|
Expect(infoMap).To(HaveKey("environment"))
|
|
Expect(infoMap["environment"]).To(Equal("production"))
|
|
})
|
|
|
|
It("should handle nested structures in JSON", func() {
|
|
i.RegisterData(func() (map[string]interface{}, error) {
|
|
return map[string]interface{}{
|
|
"config": map[string]interface{}{
|
|
"port": float64(8080),
|
|
"host": "localhost",
|
|
},
|
|
}, nil
|
|
})
|
|
|
|
jsonBytes, err := i.MarshalJSON()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
var result map[string]interface{}
|
|
err = json.Unmarshal(jsonBytes, &result)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
infoMap := result["data"].(map[string]interface{})
|
|
Expect(infoMap).To(HaveKey("config"))
|
|
config := infoMap["config"].(map[string]interface{})
|
|
Expect(config["port"]).To(Equal(float64(8080)))
|
|
Expect(config["host"]).To(Equal("localhost"))
|
|
})
|
|
|
|
It("should handle arrays in JSON", func() {
|
|
i.RegisterData(func() (map[string]interface{}, error) {
|
|
return map[string]interface{}{
|
|
"tags": []string{"web", "api", "v1"},
|
|
}, nil
|
|
})
|
|
|
|
jsonBytes, err := i.MarshalJSON()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
var result map[string]interface{}
|
|
err = json.Unmarshal(jsonBytes, &result)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
infoMap := result["data"].(map[string]interface{})
|
|
Expect(infoMap).To(HaveKey("tags"))
|
|
})
|
|
})
|
|
|
|
Context("JSON validity", func() {
|
|
It("should produce valid JSON", func() {
|
|
i.RegisterData(func() (map[string]interface{}, error) {
|
|
return map[string]interface{}{
|
|
"key": "value",
|
|
}, nil
|
|
})
|
|
|
|
jsonBytes, err := i.MarshalJSON()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
// Should be parsable JSON
|
|
Expect(json.Valid(jsonBytes)).To(BeTrue())
|
|
})
|
|
|
|
It("should handle special JSON characters", func() {
|
|
i.RegisterData(func() (map[string]interface{}, error) {
|
|
return map[string]interface{}{
|
|
"quote": `"quoted"`,
|
|
"backslash": `\path\to\file`,
|
|
"unicode": "unicode: \u2764",
|
|
}, nil
|
|
})
|
|
|
|
jsonBytes, err := i.MarshalJSON()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(json.Valid(jsonBytes)).To(BeTrue())
|
|
|
|
var result map[string]interface{}
|
|
err = json.Unmarshal(jsonBytes, &result)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("Encoding interface compliance", func() {
|
|
It("should implement encoding.TextMarshaler", func() {
|
|
_, err := i.MarshalText()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
})
|
|
|
|
It("should implement json.Marshaler", func() {
|
|
_, err := i.MarshalJSON()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
})
|
|
|
|
It("should work with json.Marshal", func() {
|
|
i.RegisterName(func() (string, error) {
|
|
return "marshaled-service", nil
|
|
})
|
|
i.RegisterData(func() (map[string]interface{}, error) {
|
|
return map[string]interface{}{"test": true}, nil
|
|
})
|
|
|
|
// Using standard json.Marshal should work
|
|
jsonBytes, err := json.Marshal(i)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(jsonBytes).NotTo(BeEmpty())
|
|
|
|
var result map[string]interface{}
|
|
err = json.Unmarshal(jsonBytes, &result)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(result["name"]).To(Equal("marshaled-service"))
|
|
})
|
|
})
|
|
|
|
Describe("Edge cases", func() {
|
|
Context("with empty info map", func() {
|
|
It("should handle empty info correctly in text", func() {
|
|
i.RegisterData(func() (map[string]interface{}, error) {
|
|
return map[string]interface{}{}, nil
|
|
})
|
|
|
|
text, err := i.MarshalText()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
// Should just show the name without parentheses or with empty parentheses
|
|
Expect(string(text)).To(Equal("test-service"))
|
|
})
|
|
|
|
It("should handle empty info correctly in JSON", func() {
|
|
i.RegisterData(func() (map[string]interface{}, error) {
|
|
return map[string]interface{}{}, nil
|
|
})
|
|
|
|
jsonBytes, err := i.MarshalJSON()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
var result map[string]interface{}
|
|
err = json.Unmarshal(jsonBytes, &result)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(result["name"]).To(Equal("test-service"))
|
|
})
|
|
})
|
|
|
|
Context("with nil values in info", func() {
|
|
It("should handle nil values in JSON", func() {
|
|
i.RegisterData(func() (map[string]interface{}, error) {
|
|
return map[string]interface{}{
|
|
"nil_value": nil,
|
|
"key": "value",
|
|
}, nil
|
|
})
|
|
|
|
jsonBytes, err := i.MarshalJSON()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
var result map[string]interface{}
|
|
err = json.Unmarshal(jsonBytes, &result)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
infoMap := result["data"].(map[string]interface{})
|
|
Expect(infoMap).To(HaveKey("nil_value"))
|
|
Expect(infoMap["nil_value"]).To(BeNil())
|
|
})
|
|
})
|
|
|
|
Context("with large info data", func() {
|
|
It("should handle large info maps", func() {
|
|
i.RegisterData(func() (map[string]interface{}, error) {
|
|
largeMap := make(map[string]interface{})
|
|
for n := 0; n < 1000; n++ {
|
|
largeMap[string(rune('a'+n%26))+string(rune('0'+n%10))] = n
|
|
}
|
|
return largeMap, nil
|
|
})
|
|
|
|
jsonBytes, err := i.MarshalJSON()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(len(jsonBytes)).To(BeNumerically(">", 100))
|
|
|
|
var result map[string]interface{}
|
|
err = json.Unmarshal(jsonBytes, &result)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
})
|
|
})
|
|
})
|
|
})
|