File: bark_test.go

package info (click to toggle)
golang-github-nicholas-fedor-shoutrrr 0.8.17-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 4,332 kB
  • sloc: sh: 61; makefile: 5
file content (181 lines) | stat: -rw-r--r-- 6,719 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
package bark_test

import (
	"log"
	"net/http"
	"net/url"
	"os"
	"testing"

	"github.com/jarcoal/httpmock"
	"github.com/onsi/ginkgo/v2"
	"github.com/onsi/gomega"
	"github.com/onsi/gomega/format"

	"github.com/nicholas-fedor/shoutrrr/internal/testutils"
	"github.com/nicholas-fedor/shoutrrr/pkg/services/bark"
)

// TestBark runs the Ginkgo test suite for the bark package.
func TestBark(t *testing.T) {
	format.CharactersAroundMismatchToInclude = 20 // Show more context in failure output

	gomega.RegisterFailHandler(ginkgo.Fail)
	ginkgo.RunSpecs(t, "Shoutrrr Bark Suite")
}

var (
	service    *bark.Service = &bark.Service{}        // Bark service instance for testing
	envBarkURL *url.URL                               // Environment-provided URL for integration tests
	logger     *log.Logger   = testutils.TestLogger() // Shared logger for tests
	_                        = ginkgo.BeforeSuite(func() {
		// Load the integration test URL from environment, if available
		var err error
		envBarkURL, err = url.Parse(os.Getenv("SHOUTRRR_BARK_URL"))
		if err != nil {
			envBarkURL = &url.URL{} // Default to empty URL if parsing fails
		}
	})
)

var _ = ginkgo.Describe("the bark service", func() {
	ginkgo.When("running integration tests", func() {
		ginkgo.It("sends a message successfully with a valid ENV URL", func() {
			if envBarkURL.String() == "" {
				ginkgo.Skip("No integration test ENV URL was set")

				return
			}

			configURL := testutils.URLMust(envBarkURL.String())
			gomega.Expect(service.Initialize(configURL, logger)).To(gomega.Succeed())
			gomega.Expect(service.Send("This is an integration test message", nil)).
				To(gomega.Succeed())
		})
	})

	ginkgo.Describe("the config", func() {
		ginkgo.When("getting an API URL", func() {
			ginkgo.It("constructs the expected URL for various path formats", func() {
				gomega.Expect(getAPIForPath("path")).To(gomega.Equal("https://host/path/endpoint"))
				gomega.Expect(getAPIForPath("/path")).To(gomega.Equal("https://host/path/endpoint"))
				gomega.Expect(getAPIForPath("/path/")).
					To(gomega.Equal("https://host/path/endpoint"))
				gomega.Expect(getAPIForPath("path/")).To(gomega.Equal("https://host/path/endpoint"))
				gomega.Expect(getAPIForPath("/")).To(gomega.Equal("https://host/endpoint"))
				gomega.Expect(getAPIForPath("")).To(gomega.Equal("https://host/endpoint"))
			})
		})

		ginkgo.When("only required fields are set", func() {
			ginkgo.It("applies default values to optional fields", func() {
				serviceURL := testutils.URLMust("bark://:devicekey@hostname")
				gomega.Expect(service.Initialize(serviceURL, logger)).To(gomega.Succeed())
				gomega.Expect(*service.Config).To(gomega.Equal(bark.Config{
					Host:      "hostname",
					DeviceKey: "devicekey",
					Scheme:    "https",
				}))
			})
		})

		ginkgo.When("parsing the configuration URL", func() {
			ginkgo.It("preserves all fields after de-/serialization", func() {
				testURL := "bark://:device-key@example.com:2225/?badge=5&category=CAT&group=GROUP&scheme=http&title=TITLE&url=URL"
				config := &bark.Config{}
				gomega.Expect(config.SetURL(testutils.URLMust(testURL))).
					To(gomega.Succeed(), "verifying")
				gomega.Expect(config.GetURL().String()).To(gomega.Equal(testURL))
			})
		})
	})

	ginkgo.When("sending the push payload", func() {
		ginkgo.BeforeEach(func() {
			httpmock.Activate()
		})
		ginkgo.AfterEach(func() {
			httpmock.DeactivateAndReset()
		})

		ginkgo.It("sends successfully when the server accepts the payload", func() {
			serviceURL := testutils.URLMust("bark://:devicekey@hostname")
			gomega.Expect(service.Initialize(serviceURL, logger)).To(gomega.Succeed())
			httpmock.RegisterResponder("POST", service.Config.GetAPIURL("push"),
				testutils.JSONRespondMust(200, bark.APIResponse{
					Code:    http.StatusOK,
					Message: "OK",
				}))
			gomega.Expect(service.Send("Message", nil)).To(gomega.Succeed())
		})

		ginkgo.It("reports an error for a server error response", func() {
			serviceURL := testutils.URLMust("bark://:devicekey@hostname")
			gomega.Expect(service.Initialize(serviceURL, logger)).To(gomega.Succeed())
			httpmock.RegisterResponder("POST", service.Config.GetAPIURL("push"),
				testutils.JSONRespondMust(500, bark.APIResponse{
					Code:    500,
					Message: "someone turned off the internet",
				}))
			gomega.Expect(service.Send("Message", nil)).To(gomega.HaveOccurred())
		})

		ginkgo.It("handles an unexpected server response gracefully", func() {
			serviceURL := testutils.URLMust("bark://:devicekey@hostname")
			gomega.Expect(service.Initialize(serviceURL, logger)).To(gomega.Succeed())
			httpmock.RegisterResponder("POST", service.Config.GetAPIURL("push"),
				testutils.JSONRespondMust(200, bark.APIResponse{
					Code:    500,
					Message: "For some reason, the response code and HTTP code is different?",
				}))
			gomega.Expect(service.Send("Message", nil)).To(gomega.HaveOccurred())
		})

		ginkgo.It("handles communication errors without panicking", func() {
			httpmock.DeactivateAndReset() // Ensure no mocks interfere
			serviceURL := testutils.URLMust("bark://:devicekey@nonresolvablehostname")
			gomega.Expect(service.Initialize(serviceURL, logger)).To(gomega.Succeed())
			gomega.Expect(service.Send("Message", nil)).To(gomega.HaveOccurred())
		})
	})

	ginkgo.Describe("the basic service API", func() {
		ginkgo.Describe("the service config", func() {
			ginkgo.It("implements basic service config API methods correctly", func() {
				testutils.TestConfigGetInvalidQueryValue(&bark.Config{})
				testutils.TestConfigSetInvalidQueryValue(
					&bark.Config{},
					"bark://:mock-device@host/?foo=bar",
				)
				testutils.TestConfigSetDefaultValues(&bark.Config{})
				testutils.TestConfigGetEnumsCount(&bark.Config{}, 0)
				testutils.TestConfigGetFieldsCount(&bark.Config{}, 9)
			})
		})

		ginkgo.Describe("the service instance", func() {
			ginkgo.BeforeEach(func() {
				httpmock.Activate()
			})
			ginkgo.AfterEach(func() {
				httpmock.DeactivateAndReset()
			})
			ginkgo.It("implements basic service API methods correctly", func() {
				serviceURL := testutils.URLMust("bark://:devicekey@hostname")
				gomega.Expect(service.Initialize(serviceURL, logger)).To(gomega.Succeed())
				testutils.TestServiceSetInvalidParamValue(service, "foo", "bar")
			})
			ginkgo.It("returns the correct service identifier", func() {
				// No initialization needed since GetID is static
				gomega.Expect(service.GetID()).To(gomega.Equal("bark"))
			})
		})
	})
})

// getAPIForPath is a helper to construct an API URL for testing.
func getAPIForPath(path string) string {
	c := bark.Config{Host: "host", Path: path, Scheme: "https"}

	return c.GetAPIURL("endpoint")
}