11// Update method tests cover update.run/status, restart sentinel metadata,
22// managed-service handoff, restart scheduling, and delivery context preservation.
33import { beforeEach , describe , expect , it , vi } from "vitest" ;
4+ import type { ConfigFileSnapshot , OpenClawConfig } from "../../config/types.openclaw.js" ;
45import type { RestartSentinelPayload } from "../../infra/restart-sentinel.js" ;
56import type { RespawnSupervisor } from "../../infra/supervisor-markers.js" ;
67import type { UpdateInstallSurface , UpdateRunResult } from "../../infra/update-runner.js" ;
@@ -24,6 +25,7 @@ const isRestartEnabledMock = vi.fn(() => true);
2425const readPackageVersionMock = vi . fn ( async ( ) => "1.0.0" ) ;
2526const detectRespawnSupervisorMock = vi . fn < ( ) => RespawnSupervisor | null > ( ( ) => null ) ;
2627const normalizeUpdateChannelMock = vi . fn ( ( ) : "stable" | "beta" | "dev" | null => null ) ;
28+ const readConfigFileSnapshotMock = vi . fn < ( ) => Promise < ConfigFileSnapshot > > ( ) ;
2729const startManagedServiceUpdateHandoffMock = vi . fn ( async ( ) => ( {
2830 status : "started" as const ,
2931 pid : 12345 ,
@@ -52,6 +54,7 @@ type UpdateRunPayload = {
5254
5355vi . mock ( "../../config/config.js" , ( ) => ( {
5456 getRuntimeConfig : ( ) => ( { update : { } } ) ,
57+ readConfigFileSnapshot : readConfigFileSnapshotMock ,
5558} ) ) ;
5659
5760vi . mock ( "../../config/commands.flags.js" , ( ) => ( {
@@ -179,6 +182,21 @@ beforeEach(() => {
179182 readPackageVersionMock . mockResolvedValue ( "1.0.0" ) ;
180183 normalizeUpdateChannelMock . mockReset ( ) ;
181184 normalizeUpdateChannelMock . mockReturnValue ( null ) ;
185+ readConfigFileSnapshotMock . mockReset ( ) ;
186+ readConfigFileSnapshotMock . mockResolvedValue ( {
187+ path : "/tmp/openclaw.json" ,
188+ exists : true ,
189+ raw : "{}" ,
190+ parsed : { } ,
191+ resolved : { } as OpenClawConfig ,
192+ sourceConfig : { } as OpenClawConfig ,
193+ valid : true ,
194+ config : { } as OpenClawConfig ,
195+ runtimeConfig : { } as OpenClawConfig ,
196+ issues : [ ] ,
197+ warnings : [ ] ,
198+ legacyIssues : [ ] ,
199+ } ) ;
182200 detectRespawnSupervisorMock . mockReset ( ) ;
183201 detectRespawnSupervisorMock . mockReturnValue ( null ) ;
184202 runGatewayUpdateMock . mockClear ( ) ;
@@ -724,6 +742,46 @@ describe("update.run post-core plugin finalize", () => {
724742 expect ( payload ?. result ?. status ) . toBe ( "ok" ) ;
725743 } ) ;
726744
745+ it ( "carries the pre-doctor source config into the git finalizer" , async ( ) => {
746+ const preUpdateConfig = {
747+ channels : {
748+ whatsapp : {
749+ enabled : true ,
750+ } ,
751+ } ,
752+ } as OpenClawConfig ;
753+ readConfigFileSnapshotMock . mockResolvedValueOnce ( {
754+ path : "/tmp/openclaw.json" ,
755+ exists : true ,
756+ raw : JSON . stringify ( preUpdateConfig ) ,
757+ parsed : preUpdateConfig ,
758+ resolved : preUpdateConfig ,
759+ sourceConfig : preUpdateConfig ,
760+ valid : true ,
761+ config : preUpdateConfig ,
762+ runtimeConfig : preUpdateConfig ,
763+ issues : [ ] ,
764+ warnings : [ ] ,
765+ legacyIssues : [ ] ,
766+ } ) ;
767+ runPostCoreFinalizeAfterGatewayUpdateMock . mockResolvedValueOnce ( {
768+ status : "ok" ,
769+ entrypoint : "/tmp/openclaw-git/dist/index.mjs" ,
770+ } ) ;
771+ mockGitOkUpdate ( "/tmp/openclaw-git" ) ;
772+
773+ await captureUpdateRunPayload ( ) ;
774+
775+ const [ finalizeParams ] = firstMockCall (
776+ runPostCoreFinalizeAfterGatewayUpdateMock ,
777+ "post-core finalize" ,
778+ ) as [ { preUpdateConfig ?: { sourceConfig ?: OpenClawConfig ; authoredConfig ?: OpenClawConfig } } ] ;
779+ expect ( finalizeParams . preUpdateConfig ) . toEqual ( {
780+ sourceConfig : preUpdateConfig ,
781+ authoredConfig : preUpdateConfig ,
782+ } ) ;
783+ } ) ;
784+
727785 it ( "blocks the restart when post-core plugin finalize fails" , async ( ) => {
728786 runPostCoreFinalizeAfterGatewayUpdateMock . mockResolvedValueOnce ( {
729787 status : "error" ,
0 commit comments