mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-09 00:56:37 +08:00
feat(pages): pull latest by project and keep a single edge release
Agents now treat pages_project_id as the stable anchor and fetch the
control-plane active package via project latest APIs, so activating a
deployment updates edges without republishing main config. Local roots use
projects/{id}/current, only the newest release is retained after a successful
switch, hash/package races retry, and per-project failures no longer block
siblings.
This commit is contained in:
@@ -337,6 +337,16 @@ func TestOpenDeploymentPackageRequiresActiveConfigSnapshot(t *testing.T) {
|
||||
defer packageObj.Body.Close()
|
||||
assert.Equal(t, fmt.Sprintf("pages-deployment-%d.zip", deployment.ID), packageObj.FileName)
|
||||
|
||||
// Latest-by-project resolves the active package once the project is on active config.
|
||||
depID, hash, err := GetProjectLatestPackageHash(ctx, project.ID)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, deployment.ID, depID)
|
||||
assert.NotEmpty(t, hash)
|
||||
|
||||
latestPkg, err := OpenProjectLatestPackage(ctx, project.ID)
|
||||
require.NoError(t, err)
|
||||
defer latestPkg.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(packageObj.Body)
|
||||
require.NoError(t, err)
|
||||
reader, err := zip.NewReader(bytes.NewReader(body), int64(len(body)))
|
||||
@@ -345,6 +355,53 @@ func TestOpenDeploymentPackageRequiresActiveConfigSnapshot(t *testing.T) {
|
||||
assert.Equal(t, "index.html", reader.File[0].Name)
|
||||
}
|
||||
|
||||
func TestProjectLatestRejectsWhenNotOnActiveConfigOrNotActive(t *testing.T) {
|
||||
cleanup := setupPagesTestDB(t)
|
||||
defer cleanup()
|
||||
_, disableStorage := setupPagesStorageMock(t)
|
||||
defer disableStorage()
|
||||
ctx := context.Background()
|
||||
|
||||
project, err := CreateProject(ctx, Input{Name: "Gate", Slug: "gate", Enabled: true})
|
||||
require.NoError(t, err)
|
||||
d1, err := UploadDeployment(ctx, project.ID, testPagesMultipartFile(t, "a.zip", testPagesZip(t, map[string]string{"index.html": "a"})), "root")
|
||||
require.NoError(t, err)
|
||||
d2, err := UploadDeployment(ctx, project.ID, testPagesMultipartFile(t, "b.zip", testPagesZip(t, map[string]string{"index.html": "b"})), "root")
|
||||
require.NoError(t, err)
|
||||
_, err = ActivateDeployment(ctx, project.ID, d2.ID)
|
||||
require.NoError(t, err)
|
||||
|
||||
// No active main config → reject.
|
||||
_, _, err = GetProjectLatestPackageHash(ctx, project.ID)
|
||||
require.Error(t, err)
|
||||
|
||||
require.NoError(t, db.DB(ctx).Create(&model.ConfigVersion{
|
||||
Version: "v-gate",
|
||||
SnapshotJSON: fmt.Sprintf(
|
||||
`{"routes":[{"upstream_type":"pages","pages_project_id":%d,"pages_deployment":{"project_id":%d,"deployment_id":%d}}]}`,
|
||||
project.ID, project.ID, d2.ID,
|
||||
),
|
||||
SupportFilesJSON: "[]",
|
||||
Checksum: "c-gate",
|
||||
IsActive: true,
|
||||
CreatedBy: "test",
|
||||
}).Error)
|
||||
|
||||
// Non-active historical deployment must not be downloadable.
|
||||
_, err = OpenDeploymentPackage(ctx, d1.ID)
|
||||
require.Error(t, err)
|
||||
|
||||
// Active latest works.
|
||||
_, hash, err := GetProjectLatestPackageHash(ctx, project.ID)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, hash)
|
||||
|
||||
// Disabled project rejects.
|
||||
require.NoError(t, db.DB(ctx).Model(&model.PagesProject{}).Where("id = ?", project.ID).Update("enabled", false).Error)
|
||||
_, _, err = GetProjectLatestPackageHash(ctx, project.ID)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func testPagesZip(t *testing.T, files map[string]string) []byte {
|
||||
t.Helper()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user