mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-07-13 09:02:09 -04:00
groupware: add test for vacation responses, and fix issue found during testing
This commit is contained in:
@@ -29,10 +29,10 @@ type VacationResponseChange struct {
|
||||
IsEnabled bool `json:"isEnabled"`
|
||||
// If "isEnabled" is true, messages that arrive on or after this date-time (but before the "toDate" if defined) should receive the
|
||||
// user's vacation response. If null, the vacation response is effective immediately.
|
||||
FromDate time.Time `json:"fromDate,omitzero"`
|
||||
FromDate *time.Time `json:"fromDate,omitzero"`
|
||||
// If "isEnabled" is true, messages that arrive before this date-time but on or after the "fromDate" if defined) should receive the
|
||||
// user's vacation response. If null, the vacation response is effective indefinitely.
|
||||
ToDate time.Time `json:"toDate,omitzero"`
|
||||
ToDate *time.Time `json:"toDate,omitzero"`
|
||||
// The subject that will be used by the message sent in response to messages when the vacation response is enabled.
|
||||
// If null, an appropriate subject SHOULD be set by the server.
|
||||
Subject string `json:"subject,omitempty"`
|
||||
|
||||
@@ -4163,11 +4163,11 @@ type VacationResponse struct {
|
||||
|
||||
// If "isEnabled" is true, messages that arrive on or after this date-time (but before the "toDate" if defined) should receive the
|
||||
// user's vacation response. If null, the vacation response is effective immediately.
|
||||
FromDate time.Time `json:"fromDate,omitzero"`
|
||||
FromDate *time.Time `json:"fromDate,omitzero"`
|
||||
|
||||
// If "isEnabled" is true, messages that arrive before this date-time but on or after the "fromDate" if defined) should receive the
|
||||
// user's vacation response. If null, the vacation response is effective indefinitely.
|
||||
ToDate time.Time `json:"toDate,omitzero"`
|
||||
ToDate *time.Time `json:"toDate,omitzero"`
|
||||
|
||||
// The subject that will be used by the message sent in response to messages when the vacation response is enabled.
|
||||
// If null, an appropriate subject SHOULD be set by the server.
|
||||
|
||||
@@ -883,8 +883,8 @@ func (e Exemplar) VacationResponse() VacationResponse {
|
||||
return VacationResponse{
|
||||
Id: "aefee7ae",
|
||||
IsEnabled: true,
|
||||
FromDate: from,
|
||||
ToDate: to,
|
||||
FromDate: &from,
|
||||
ToDate: &to,
|
||||
Subject: "On PTO",
|
||||
TextBody: "I am currently on PTO, please contact info@example.com for any urgent matters.",
|
||||
}
|
||||
|
||||
@@ -451,38 +451,6 @@ func ptr[T any | int | uint | bool | string](t T) *T {
|
||||
return &t
|
||||
}
|
||||
|
||||
func dumpHttpRequest(req *http.Request, maxBodySize int64, closure func(method string, uri string, content string, truncated bool)) error {
|
||||
var logBuilder bytes.Buffer
|
||||
uri := req.URL.String()
|
||||
fmt.Fprintf(&logBuilder, "%s %s\n", req.Method, uri)
|
||||
for key, values := range req.Header {
|
||||
if key == "Authorization" {
|
||||
continue
|
||||
}
|
||||
for _, value := range values {
|
||||
fmt.Fprintf(&logBuilder, "%s: %s\n", key, value)
|
||||
}
|
||||
}
|
||||
truncated := false
|
||||
if maxBodySize >= 0 && req.Body != nil && req.Body != http.NoBody {
|
||||
peekBuffer := new(bytes.Buffer)
|
||||
limitedReader := io.LimitReader(req.Body, maxBodySize)
|
||||
tee := io.TeeReader(limitedReader, peekBuffer)
|
||||
if _, err := io.Copy(io.Discard, tee); err != nil {
|
||||
return fmt.Errorf("failed to peek at the request body for tracing: %v", err)
|
||||
} else {
|
||||
logBuilder.Write(peekBuffer.Bytes())
|
||||
if int64(peekBuffer.Len()) >= maxBodySize {
|
||||
truncated = true
|
||||
}
|
||||
fullBodyReader := io.MultiReader(peekBuffer, req.Body)
|
||||
req.Body = io.NopCloser(fullBodyReader)
|
||||
}
|
||||
}
|
||||
closure(req.Method, uri, logBuilder.String(), truncated)
|
||||
return nil
|
||||
}
|
||||
|
||||
type nullReader struct {
|
||||
}
|
||||
|
||||
@@ -543,6 +511,38 @@ func peekResponse(body io.ReadCloser, size int64,
|
||||
}, peek, truncated, nil
|
||||
}
|
||||
|
||||
func dumpHttpRequest(req *http.Request, maxBodySize int64, closure func(method string, uri string, content string, truncated bool)) error {
|
||||
var logBuilder bytes.Buffer
|
||||
uri := req.URL.String()
|
||||
fmt.Fprintf(&logBuilder, "%s %s\n", req.Method, uri)
|
||||
for key, values := range req.Header {
|
||||
if key == "Authorization" {
|
||||
continue
|
||||
}
|
||||
for _, value := range values {
|
||||
fmt.Fprintf(&logBuilder, "%s: %s\n", key, value)
|
||||
}
|
||||
}
|
||||
truncated := false
|
||||
if maxBodySize >= 0 && req.Body != nil && req.Body != http.NoBody {
|
||||
peekBuffer := new(bytes.Buffer)
|
||||
limitedReader := io.LimitReader(req.Body, maxBodySize)
|
||||
tee := io.TeeReader(limitedReader, peekBuffer)
|
||||
if _, err := io.Copy(io.Discard, tee); err != nil {
|
||||
return fmt.Errorf("failed to peek at the request body for tracing: %v", err)
|
||||
} else {
|
||||
logBuilder.Write(peekBuffer.Bytes())
|
||||
if int64(peekBuffer.Len()) >= maxBodySize {
|
||||
truncated = true
|
||||
}
|
||||
fullBodyReader := io.MultiReader(peekBuffer, req.Body)
|
||||
req.Body = io.NopCloser(fullBodyReader)
|
||||
}
|
||||
}
|
||||
closure(req.Method, uri, logBuilder.String(), truncated)
|
||||
return nil
|
||||
}
|
||||
|
||||
func dumpHttpResponse(req *http.Request, resp *http.Response, body io.ReadCloser, maxBodySize int64,
|
||||
closure func(method string, uri string, content string, truncated bool),
|
||||
closeErrorClosure func(err error)) (io.ReadCloser, error) {
|
||||
|
||||
@@ -14,14 +14,10 @@ func TestGroupwareIndex(t *testing.T) {
|
||||
require.NoError(err)
|
||||
|
||||
index := IndexResponse{}
|
||||
u := gget(g, "/", &index)
|
||||
u := gget("get-index", g, "/", &index)
|
||||
require.Len(index.Accounts, 1)
|
||||
require.Equal(u.Email, index.Accounts[0].Name)
|
||||
require.Len(index.Accounts[0].Identities, 2) // email + alias
|
||||
require.Len(structs.Filter(index.Accounts[0].Identities, func(i jmap.Identity) bool {
|
||||
return i.Email == u.Email
|
||||
}), 1)
|
||||
require.Len(structs.Filter(index.Accounts[0].Identities, func(i jmap.Identity) bool {
|
||||
return i.Email == u.Alias
|
||||
}), 1)
|
||||
require.Len(structs.Filter(index.Accounts[0].Identities, func(i jmap.Identity) bool { return i.Email == u.Email }), 1)
|
||||
require.Len(structs.Filter(index.Accounts[0].Identities, func(i jmap.Identity) bool { return i.Email == u.Alias }), 1)
|
||||
}
|
||||
|
||||
44
services/groupware/pkg/groupware/api_vacation_test.go
Normal file
44
services/groupware/pkg/groupware/api_vacation_test.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package groupware
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/jmap"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGroupwareVacation(t *testing.T) {
|
||||
require := require.New(t)
|
||||
g, err := newGroupwareTest(t)
|
||||
require.NoError(err)
|
||||
|
||||
{
|
||||
resp := jmap.VacationResponse{}
|
||||
gget("get-initial-vacation", g, "/accounts/_/vacation", &resp)
|
||||
require.Equal("singleton", resp.Id)
|
||||
require.False(resp.IsEnabled)
|
||||
require.Empty(resp.Subject)
|
||||
require.Empty(resp.TextBody)
|
||||
require.Empty(resp.HtmlBody)
|
||||
require.Nil(resp.FromDate)
|
||||
require.Nil(resp.ToDate)
|
||||
}
|
||||
|
||||
{
|
||||
resp := jmap.VacationResponse{}
|
||||
req := jmap.VacationResponseChange{
|
||||
IsEnabled: true,
|
||||
Subject: "testing",
|
||||
TextBody: "text",
|
||||
HtmlBody: "html",
|
||||
}
|
||||
gput("set-vacation", g, "/accounts/_/vacation", req, &resp)
|
||||
require.Equal("singleton", resp.Id)
|
||||
require.True(resp.IsEnabled)
|
||||
require.Equal("testing", resp.Subject)
|
||||
require.Equal("text", resp.TextBody)
|
||||
require.Equal("html", resp.HtmlBody)
|
||||
require.Nil(resp.FromDate)
|
||||
require.Nil(resp.ToDate)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package groupware
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
@@ -38,7 +39,9 @@ type GroupwareTest struct {
|
||||
Users []jmaptest.User
|
||||
}
|
||||
|
||||
func gget[T any](g GroupwareTest, path string, result *T) jmaptest.User {
|
||||
func gget[T any](id string, g GroupwareTest, path string, result *T) jmaptest.User {
|
||||
id = g.t.Name() + "/" + id
|
||||
|
||||
u, err := url.JoinPath(g.BaseURL, path)
|
||||
require.NoError(g.t, err)
|
||||
req, err := http.NewRequest(http.MethodGet, u, nil)
|
||||
@@ -58,6 +61,32 @@ func gget[T any](g GroupwareTest, path string, result *T) jmaptest.User {
|
||||
return user
|
||||
}
|
||||
|
||||
func gput[B any, T any](id string, g GroupwareTest, path string, body B, result *T) jmaptest.User {
|
||||
id = g.t.Name() + "/" + id
|
||||
|
||||
u, err := url.JoinPath(g.BaseURL, path)
|
||||
require.NoError(g.t, err)
|
||||
|
||||
jsonBody, err := json.Marshal(body)
|
||||
require.NoError(g.t, err)
|
||||
|
||||
req, err := http.NewRequest(http.MethodPut, u, bytes.NewBuffer(jsonBody))
|
||||
require.NoError(g.t, err)
|
||||
user := g.Users[rand.Intn(len(g.Users))] // pick a user at random
|
||||
req.SetBasicAuth(user.Name, user.Password)
|
||||
rid := uuid.New().String()
|
||||
req.Header.Add("X-Request-Id", id)
|
||||
req.Header.Add("Trace-Id", rid)
|
||||
client := http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(g.t, err)
|
||||
require.Equal(g.t, 200, resp.StatusCode)
|
||||
defer resp.Body.Close()
|
||||
err = json.NewDecoder(resp.Body).Decode(result)
|
||||
require.NoError(g.t, err)
|
||||
return user
|
||||
}
|
||||
|
||||
func newGroupwareTest(t *testing.T) (GroupwareTest, error) {
|
||||
require := require.New(t)
|
||||
s, err := jmaptest.NewStalwartTest(t)
|
||||
|
||||
@@ -661,19 +661,22 @@ func modify[T jmap.Foo, CHANGE jmap.Change[T], CHANGES jmap.Changes[T]](
|
||||
return resp
|
||||
}
|
||||
l := req.logger.With().Str(logAccountId, log.SafeString(accountId))
|
||||
id, err := req.PathParamDoc(o.uriParamName, "The unique identifier of the object to modify")
|
||||
if err != nil {
|
||||
return req.errorV(accountId, err)
|
||||
id := ""
|
||||
if o.uriParamName != "" {
|
||||
value, err := req.PathParamDoc(o.uriParamName, "The unique identifier of the object to modify")
|
||||
if err != nil {
|
||||
return req.errorV(accountId, err)
|
||||
}
|
||||
l.Str(o.uriParamName, log.SafeString(value))
|
||||
id = value
|
||||
}
|
||||
l.Str(o.uriParamName, log.SafeString(id))
|
||||
|
||||
if notok, resp := req.unsupportedQueryParams(single(accountId), noSupportedQueryParams); notok {
|
||||
return resp
|
||||
}
|
||||
|
||||
var change CHANGE
|
||||
err = req.body(&change)
|
||||
if err != nil {
|
||||
if err := req.body(&change); err != nil {
|
||||
return req.errorV(accountId, err)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user