feat: centralize app release configuration

This commit is contained in:
richjohnrambo
2026-09-12 17:07:49 +08:00
parent 2728f35069
commit e5fbca735d
13 changed files with 257 additions and 104 deletions
+63 -5
View File
@@ -1094,7 +1094,7 @@ func (s *testProfilesStore) UpdatePrivacy(_ types.TenantID, uid types.Uid, patch
return privacy, nil
}
func (s *testAppReleaseStore) Latest(_ types.TenantID, platform, channel string) (*types.AppRelease, error) {
func (s *testAppReleaseStore) Latest(platform, channel string) (*types.AppRelease, error) {
if s.release == nil {
now := time.Now().UTC().Round(time.Millisecond)
s.release = &types.AppRelease{
@@ -1102,7 +1102,7 @@ func (s *testAppReleaseStore) Latest(_ types.TenantID, platform, channel string)
Channel: channel,
LatestVersion: "1.0.1",
MinSupportedVersion: "1.0.0",
UpdateType: "optional",
UpdateType: "recommended",
ReleaseNotes: "修复已知问题。",
PublishedAt: now,
CreatedAt: now,
@@ -3787,12 +3787,9 @@ func TestIMCanViewLastSeen(t *testing.T) {
}
func TestServeIMAppReleaseLatest(t *testing.T) {
oldTenants := store.Tenants
oldReleases := store.AppReleases
store.Tenants = testTenantStore{tenant: &types.Tenant{ID: 7, Code: "default", Name: "Default", State: types.TenantStateActive}}
store.AppReleases = &testAppReleaseStore{}
defer func() {
store.Tenants = oldTenants
store.AppReleases = oldReleases
}()
@@ -3807,6 +3804,67 @@ func TestServeIMAppReleaseLatest(t *testing.T) {
if data["platform"] != "ios" || data["latest_version"] != "1.0.1" || data["channel"] != "stable" {
t.Fatalf("unexpected release payload: %#v", data)
}
if data["has_update"] != true || data["update_type"] != "recommended" || data["force_update"] != false {
t.Fatalf("unexpected update decision: %#v", data)
}
}
func TestServeIMAppReleaseLatestForcesUnsupportedVersion(t *testing.T) {
oldReleases := store.AppReleases
store.AppReleases = &testAppReleaseStore{release: &types.AppRelease{
Platform: "ios", Channel: "stable", LatestVersion: "2.0.0", MinSupportedVersion: "1.5.0",
UpdateType: "recommended", PublishedAt: time.Now().UTC(),
}}
defer func() { store.AppReleases = oldReleases }()
req := httptest.NewRequest(http.MethodGet, "/v1/im/app/releases/latest?platform=ios&current_version=1.4.9", nil)
rec := httptest.NewRecorder()
serveIMAppReleaseLatest(rec, req)
data := decodeIMHTTPResponse(t, rec).Data.(map[string]any)
if data["has_update"] != true || data["update_type"] != "force" || data["force_update"] != true {
t.Fatalf("unexpected forced update decision: %#v", data)
}
}
func TestServeIMAppReleaseLatestRequiresCurrentVersion(t *testing.T) {
oldReleases := store.AppReleases
store.AppReleases = &testAppReleaseStore{}
defer func() { store.AppReleases = oldReleases }()
req := httptest.NewRequest(http.MethodGet, "/v1/im/app/releases/latest?platform=ios", nil)
rec := httptest.NewRecorder()
serveIMAppReleaseLatest(rec, req)
if rec.Code != http.StatusBadRequest {
t.Fatalf("status: got %d, want %d; body=%s", rec.Code, http.StatusBadRequest, rec.Body.String())
}
}
func TestServeIMAppReleaseLatestReturnsNoUpdateForCurrentVersion(t *testing.T) {
oldReleases := store.AppReleases
store.AppReleases = &testAppReleaseStore{release: &types.AppRelease{
Platform: "ios", Channel: "stable", LatestVersion: "1.2.0", MinSupportedVersion: "1.0.0",
UpdateType: "force", PublishedAt: time.Now().UTC(),
}}
defer func() { store.AppReleases = oldReleases }()
req := httptest.NewRequest(http.MethodGet, "/v1/im/app/releases/latest?platform=ios&current_version=1.2.0", nil)
rec := httptest.NewRecorder()
serveIMAppReleaseLatest(rec, req)
data := decodeIMHTTPResponse(t, rec).Data.(map[string]any)
if data["has_update"] != false || data["update_type"] != "none" || data["force_update"] != false {
t.Fatalf("unexpected no-update decision: %#v", data)
}
}
func TestNumericAppVersionComparison(t *testing.T) {
left, err := parseNumericAppVersion("v1.10.0")
if err != nil {
t.Fatal(err)
}
right, err := parseNumericAppVersion("1.9.9")
if err != nil {
t.Fatal(err)
}
if compareNumericAppVersion(left, right) <= 0 {
t.Fatal("expected 1.10.0 to be newer than 1.9.9")
}
}
func TestServeIMYouthModeEnableDisable(t *testing.T) {