repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources16d ago| #1 | import { describe, it, expect, vi, beforeEach } from 'vitest'; |
| #2 | import { syncToR2 } from './sync'; |
| #3 | import { |
| #4 | createMockEnv, |
| #5 | createMockEnvWithR2, |
| #6 | createMockProcess, |
| #7 | createMockSandbox, |
| #8 | suppressConsole |
| #9 | } from '../test-utils'; |
| #10 | |
| #11 | describe('syncToR2', () => { |
| #12 | beforeEach(() => { |
| #13 | suppressConsole(); |
| #14 | }); |
| #15 | |
| #16 | describe('configuration checks', () => { |
| #17 | it('returns error when R2 is not configured', async () => { |
| #18 | const { sandbox } = createMockSandbox(); |
| #19 | const env = createMockEnv(); |
| #20 | |
| #21 | const result = await syncToR2(sandbox, env); |
| #22 | |
| #23 | expect(result.success).toBe(false); |
| #24 | expect(result.error).toBe('R2 storage is not configured'); |
| #25 | }); |
| #26 | |
| #27 | it('returns error when mount fails', async () => { |
| #28 | const { sandbox, startProcessMock, mountBucketMock } = createMockSandbox(); |
| #29 | startProcessMock.mockResolvedValue(createMockProcess('')); |
| #30 | mountBucketMock.mockRejectedValue(new Error('Mount failed')); |
| #31 | |
| #32 | const env = createMockEnvWithR2(); |
| #33 | |
| #34 | const result = await syncToR2(sandbox, env); |
| #35 | |
| #36 | expect(result.success).toBe(false); |
| #37 | expect(result.error).toBe('Failed to mount R2 storage'); |
| #38 | }); |
| #39 | }); |
| #40 | |
| #41 | describe('sanity checks', () => { |
| #42 | it('returns error when source is missing clawdbot.json', async () => { |
| #43 | const { sandbox, startProcessMock } = createMockSandbox(); |
| #44 | startProcessMock |
| #45 | .mockResolvedValueOnce(createMockProcess('s3fs on /data/moltbot type fuse.s3fs\n')) |
| #46 | .mockResolvedValueOnce(createMockProcess('')); // No "ok" output |
| #47 | |
| #48 | const env = createMockEnvWithR2(); |
| #49 | |
| #50 | const result = await syncToR2(sandbox, env); |
| #51 | |
| #52 | // Error message still references clawdbot.json since that's the actual file name |
| #53 | expect(result.success).toBe(false); |
| #54 | expect(result.error).toBe('Sync aborted: source missing clawdbot.json'); |
| #55 | expect(result.details).toContain('missing critical files'); |
| #56 | }); |
| #57 | }); |
| #58 | |
| #59 | describe('sync execution', () => { |
| #60 | it('returns success when sync completes', async () => { |
| #61 | const { sandbox, startProcessMock } = createMockSandbox(); |
| #62 | const timestamp = '2026-01-27T12:00:00+00:00'; |
| #63 | |
| #64 | // Calls: mount check, sanity check, rsync, cat timestamp |
| #65 | startProcessMock |
| #66 | .mockResolvedValueOnce(createMockProcess('s3fs on /data/moltbot type fuse.s3fs\n')) |
| #67 | .mockResolvedValueOnce(createMockProcess('ok')) |
| #68 | .mockResolvedValueOnce(createMockProcess('')) |
| #69 | .mockResolvedValueOnce(createMockProcess(timestamp)); |
| #70 | |
| #71 | const env = createMockEnvWithR2(); |
| #72 | |
| #73 | const result = await syncToR2(sandbox, env); |
| #74 | |
| #75 | expect(result.success).toBe(true); |
| #76 | expect(result.lastSync).toBe(timestamp); |
| #77 | }); |
| #78 | |
| #79 | it('returns error when rsync fails (no timestamp created)', async () => { |
| #80 | const { sandbox, startProcessMock } = createMockSandbox(); |
| #81 | |
| #82 | // Calls: mount check, sanity check, rsync (fails), cat timestamp (empty) |
| #83 | startProcessMock |
| #84 | .mockResolvedValueOnce(createMockProcess('s3fs on /data/moltbot type fuse.s3fs\n')) |
| #85 | .mockResolvedValueOnce(createMockProcess('ok')) |
| #86 | .mockResolvedValueOnce(createMockProcess('', { exitCode: 1 })) |
| #87 | .mockResolvedValueOnce(createMockProcess('')); |
| #88 | |
| #89 | const env = createMockEnvWithR2(); |
| #90 | |
| #91 | const result = await syncToR2(sandbox, env); |
| #92 | |
| #93 | expect(result.success).toBe(false); |
| #94 | expect(result.error).toBe('Sync failed'); |
| #95 | }); |
| #96 | |
| #97 | it('verifies rsync command is called with correct flags', async () => { |
| #98 | const { sandbox, startProcessMock } = createMockSandbox(); |
| #99 | const timestamp = '2026-01-27T12:00:00+00:00'; |
| #100 | |
| #101 | startProcessMock |
| #102 | .mockResolvedValueOnce(createMockProcess('s3fs on /data/moltbot type fuse.s3fs\n')) |
| #103 | .mockResolvedValueOnce(createMockProcess('ok')) |
| #104 | .mockResolvedValueOnce(createMockProcess('')) |
| #105 | .mockResolvedValueOnce(createMockProcess(timestamp)); |
| #106 | |
| #107 | const env = createMockEnvWithR2(); |
| #108 | |
| #109 | await syncToR2(sandbox, env); |
| #110 | |
| #111 | // Third call should be rsync (paths still use clawdbot internally) |
| #112 | const rsyncCall = startProcessMock.mock.calls[2][0]; |
| #113 | expect(rsyncCall).toContain('rsync'); |
| #114 | expect(rsyncCall).toContain('--no-times'); |
| #115 | expect(rsyncCall).toContain('--delete'); |
| #116 | expect(rsyncCall).toContain('/root/.clawdbot/'); |
| #117 | expect(rsyncCall).toContain('/data/moltbot/'); |
| #118 | }); |
| #119 | }); |
| #120 | }); |
| #121 |