Publish gonexapp v1 with Credentials, OCSClient, and parameterized AppAPIPreferences so ExApps share Nextcloud ExApp plumbing per ADR 0013. Co-authored-by: Cursor <cursoragent@cursor.com>
127 lines
3.7 KiB
Go
127 lines
3.7 KiB
Go
package gonexapp_test
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"gitea.neitzel.de/konrad/go-nc-exapp"
|
|
)
|
|
|
|
func TestOCSCallIncludesFormatJSON(t *testing.T) {
|
|
var gotPath string
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
gotPath = r.URL.String()
|
|
_ = json.NewEncoder(w).Encode(map[string]string{"ok": "true"})
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
|
|
cred := gonexapp.Credentials{
|
|
BaseURL: srv.URL, AppID: "app", AppVersion: "0.1.0", AAVersion: "1.0.0", AppSecret: "s", UserID: "alice",
|
|
}
|
|
client := gonexapp.OCSClient{Cred: cred, Client: srv.Client()}
|
|
raw, err := client.Call(http.MethodGet, "apps/app_api/api/v1/ex-app/preference/get-values", nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !json.Valid(raw) {
|
|
t.Fatalf("not json: %s", raw)
|
|
}
|
|
if !strings.Contains(gotPath, "format=json") {
|
|
t.Fatalf("path missing format=json: %s", gotPath)
|
|
}
|
|
}
|
|
|
|
func TestOCSCallRejectsNonJSON(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
_, _ = io.WriteString(w, "<xml/>")
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
|
|
cred := gonexapp.Credentials{BaseURL: srv.URL, AppID: "app", AppVersion: "0.1.0", AAVersion: "1.0.0", AppSecret: "s", UserID: "alice"}
|
|
client := gonexapp.OCSClient{Cred: cred, Client: srv.Client()}
|
|
_, err := client.Call(http.MethodGet, "apps/example", nil)
|
|
if err == nil || !strings.Contains(err.Error(), "not JSON") {
|
|
t.Fatalf("got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestOCSCallSurfacesHTTPError(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
http.Error(w, "nope", http.StatusBadRequest)
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
|
|
cred := gonexapp.Credentials{BaseURL: srv.URL, AppID: "app", AppVersion: "0.1.0", AAVersion: "1.0.0", AppSecret: "s", UserID: "alice"}
|
|
client := gonexapp.OCSClient{Cred: cred, Client: srv.Client()}
|
|
_, err := client.Call(http.MethodPost, "apps/example", []byte(`{}`))
|
|
if err == nil || !strings.Contains(err.Error(), "400") {
|
|
t.Fatalf("got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestAppAPIPreferencesGetSet(t *testing.T) {
|
|
const prefKey = "savedDefault"
|
|
prefsVals := map[string]string{}
|
|
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
switch {
|
|
case strings.Contains(r.URL.Path, "ex-app/preference/get-values"):
|
|
_ = json.NewEncoder(w).Encode(map[string]any{
|
|
"ocs": map[string]any{
|
|
"data": []map[string]string{{
|
|
"configkey": prefKey,
|
|
"configvalue": prefsVals[prefKey],
|
|
}},
|
|
},
|
|
})
|
|
case strings.HasSuffix(r.URL.Path, "ex-app/preference") && r.Method == http.MethodPost:
|
|
var body struct {
|
|
ConfigKey string `json:"configKey"`
|
|
ConfigValue string `json:"configValue"`
|
|
}
|
|
_ = json.NewDecoder(r.Body).Decode(&body)
|
|
prefsVals[body.ConfigKey] = body.ConfigValue
|
|
w.WriteHeader(http.StatusOK)
|
|
_ = json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
|
|
default:
|
|
http.Error(w, "unhandled "+r.Method+" "+r.URL.Path, http.StatusInternalServerError)
|
|
}
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
|
|
cred := gonexapp.Credentials{
|
|
BaseURL: srv.URL, AppID: "myexapp", AppVersion: "0.1.0", AAVersion: "1.0.0", AppSecret: "s", UserID: "alice",
|
|
}
|
|
store := gonexapp.NewAppAPIPreferences(cred, "myexapp", prefKey)
|
|
store.Client = srv.Client()
|
|
store.OCS.Client = srv.Client()
|
|
|
|
got, err := store.Get()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got != "" {
|
|
t.Fatalf("initial value=%q", got)
|
|
}
|
|
|
|
if err := store.Set("Zones"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if prefsVals[prefKey] != "Zones" {
|
|
t.Fatalf("prefs not written: %#v", prefsVals)
|
|
}
|
|
|
|
got, err = store.Get()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got != "Zones" {
|
|
t.Fatalf("got %q", got)
|
|
}
|
|
}
|