f21fa5b5e8
Commilitia Drop:自托管的跨设备剪贴板同步与点对点文件传输。 - 后端 Go(chi / SQLite WAL / SSE Hub / WebRTC signaling + 状态机 / Relay ring buffer),编译进单个 distroless 镜像(前端 go:embed)。 - 前端 React + TanStack Router + Zustand,自实现 SSE + WebRTC P2P,NAT 受阻时回退服务端中继;聚珍(Juzhen)CJK 综合排版。 - 桌面端 Wails v2(macOS / Windows),瘦客户端复用 web。 - 鉴权 OIDC PKCE(自建 Casdoor 等),refresh_token 信封加密存系统密钥库;iOS Shortcut 用 HS256 scoped token。 架构文档与变更记录见 docs 分支(PROJECT_BRIEF / FRONTEND_DESIGN / CHANGELOG)。 本次为公开发布初始提交:完整开发历史(含部署细节)留存于私有归档,公开仓库自此干净起步。
91 lines
2.6 KiB
Go
91 lines
2.6 KiB
Go
package platform
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestPutClipboard(t *testing.T) {
|
|
var gotAuth, gotDevice, gotCT string
|
|
var gotBody map[string]string
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPut || r.URL.Path != "/api/clipboard" {
|
|
t.Errorf("method/path = %s %s", r.Method, r.URL.Path)
|
|
}
|
|
gotAuth = r.Header.Get("Authorization")
|
|
gotDevice = r.Header.Get("X-Device-Name")
|
|
gotCT = r.Header.Get("Content-Type")
|
|
_ = json.NewDecoder(r.Body).Decode(&gotBody)
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := NewClient(srv.URL, "tok-abc", "my-mac")
|
|
if err := c.PutClipboard(context.Background(), "hello world"); err != nil {
|
|
t.Fatalf("PutClipboard: %v", err)
|
|
}
|
|
if gotAuth != "Bearer tok-abc" {
|
|
t.Errorf("Authorization = %q, want Bearer tok-abc", gotAuth)
|
|
}
|
|
if gotDevice != "my-mac" {
|
|
t.Errorf("X-Device-Name = %q, want my-mac", gotDevice)
|
|
}
|
|
if gotCT != "application/json" {
|
|
t.Errorf("Content-Type = %q", gotCT)
|
|
}
|
|
if gotBody["content"] != "hello world" || gotBody["content_type"] != "text/plain" {
|
|
t.Errorf("body = %v", gotBody)
|
|
}
|
|
}
|
|
|
|
func TestPutClipboard_TooLarge(t *testing.T) {
|
|
c := NewClient("https://example", "tok", "dev")
|
|
big := strings.Repeat("x", ClipboardMaxBytes+1)
|
|
if err := c.PutClipboard(context.Background(), big); err == nil {
|
|
t.Fatal("want error for oversized content, got nil")
|
|
}
|
|
}
|
|
|
|
func TestClipboard_Get(t *testing.T) {
|
|
var gotAuth string
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
gotAuth = r.Header.Get("Authorization")
|
|
w.Header().Set("Content-Type", "application/json")
|
|
_ = json.NewEncoder(w).Encode(ClipboardContent{
|
|
Content: "from cloud",
|
|
ContentType: "text/plain",
|
|
SourceDevice: "other-device",
|
|
UpdatedAt: 1700000000,
|
|
})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := NewClient(srv.URL, "tok-xyz", "my-mac")
|
|
cc, err := c.Clipboard(context.Background())
|
|
if err != nil {
|
|
t.Fatalf("Clipboard: %v", err)
|
|
}
|
|
if gotAuth != "Bearer tok-xyz" {
|
|
t.Errorf("Authorization = %q", gotAuth)
|
|
}
|
|
if cc.Content != "from cloud" || cc.SourceDevice != "other-device" || cc.UpdatedAt != 1700000000 {
|
|
t.Errorf("clipboard = %+v", cc)
|
|
}
|
|
}
|
|
|
|
func TestClipboard_Unauthorized(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := NewClient(srv.URL, "bad", "dev")
|
|
if _, err := c.Clipboard(context.Background()); err == nil {
|
|
t.Fatal("want error for 401, got nil")
|
|
}
|
|
}
|