cmd_doctor_test.v

4.8 KB · raw

1module cli23import os4import compress.zlib5import crypto.sha2566import json27import src.exchange8import src.release9import src.remote10import src.events11import src.history12import src.snapshot13import src.storage1415fn test_doctor_checks_cycles_and_missing_heads_without_walking_forever() {16	saves := [history.Save{ id: 'aaaaaaaaaaaa', parent: 'bbbbbbbbbbbb' },17		history.Save{ id: 'bbbbbbbbbbbb', parent: 'aaaaaaaaaaaa' }]18	assert doctor_history(saves, 'cccccccccccc').any(it.contains('head'))19	assert doctor_history(saves, 'aaaaaaaaaaaa').any(it.contains('cycle'))20	assert doctor_history([history.Save{ id: 'aaaaaaaaaaaa', parent: 'cccccccccccc' }],21		'aaaaaaaaaaaa').any(it.contains('missing parent'))22	assert doctor_history([]history.Save{}, '').len == 023	assert doctor_history([history.Save{ id: 'aaaaaaaaaaaa' }], '').any(it.contains('no head'))24}2526fn test_doctor_checks_off_line_paths_and_file_directory_collisions() {27	mut report := DoctorJson{}28	doctor_files('aaaaaaaaaaaa', [snapshot.FileEntry{ path: '../unsafe' },29		snapshot.FileEntry{ path: 'a' }, snapshot.FileEntry{ path: 'a/b' }], []events.Event{},30		mut report)31	assert report.problems.any(it.contains('unsafe path'))32	assert report.problems.any(it.contains('file and a directory'))33}3435fn test_doctor_reports_unsafe_save_paths_with_a_quoted_strip_command() {36	dir := os.join_path(os.temp_dir(), 'koh3_doctor_paths_${os.getpid()}')37	os.rmdir_all(dir) or {}38	os.mkdir_all(dir)!39	defer {40		os.rmdir_all(dir) or {}41	}42	store := storage.create(dir)!43	defer {44		store.close()45	}46	hash := store.put_object('unsafe'.bytes())!47	store.begin()!48	history.import_save(store, history.Save{49		id: 'badbadbadbad'50	}, [snapshot.FileEntry{51		path: "../June's file"52		hash: hash53	}])!54	history.set_head(store, 'badbadbadbad')!55	store.end()!56	mut report := DoctorJson{}57	doctor_files('badbadbadbad', history.files_of(store, 'badbadbadbad')!, []events.Event{}, mut report)58	assert report.problems == [59		"save [badbadbadbad] has unsafe path ../June's file — koh strip '../June'\\''s file'",60	]61}6263struct DoctorReadOnly {64mut:65	items map[string][]u866}6768fn (mut backend DoctorReadOnly) get(key string) !remote.Object {69	if body := backend.items[key] {70		return remote.Object{ found: true, body: body }71	}72	return remote.Object{}73}7475fn (mut backend DoctorReadOnly) list(prefix string) ![]string {76	return backend.items.keys().filter(it.starts_with('${prefix}/'))77}7879fn (mut backend DoctorReadOnly) put_if_absent(key string, body []u8) !bool {80	panic('Doctor attempted a remote write')81}8283fn (mut backend DoctorReadOnly) put_if_match(key string, body []u8, tag string) !bool {84	panic('Doctor attempted a remote write')85}8687fn (mut backend DoctorReadOnly) delete(key string) ! {88	panic('Doctor attempted a remote delete')89}9091fn test_doctor_remote_audits_unreferenced_objects_and_release_checksums_without_writes() {92	data := 'file'.bytes()93	hash := storage.hash_hex(data)94	mut backend := DoctorReadOnly{95		items: {96			'repo/head':                             'aaaaaaaaaaaa'.bytes()97			'repo/saves/aaaaaaaaaaaa':               json2.encode(exchange.SaveRecord{98				id:    'aaaaaaaaaaaa'99				files: [exchange.FileRecord{ path: 'file', hash: hash }]100			}).bytes()101			'repo/objects/${hash}':                  zlib.compress(data)!102			'repo/releases/latest':                  '1.0.0'.bytes()103			'repo/releases/1.0.0/release.json':      json2.encode(release.Record{104				repo:    'repo'105				version: '1.0.0'106				save:    'aaaaaaaaaaaa'107				files:   [release.File{108					platform: 'linux-aarch64'109					name:     'app'110					size:     data.len111					blake3:   hash112					sha256:   sha256.sum256(data).hex()113				}]114			}).bytes()115			'repo/releases/1.0.0/linux-aarch64/app': data116		}117	}118	mut report := DoctorJson{ head_id: 'aaaaaaaaaaaa' }119	doctor_remote_content(mut backend, 'repo', mut report)!120	assert report.problems.len == 0121	assert report.remote_saves == 1122	assert report.remote_releases == 1123	backend.items['repo/objects/${storage.hash_hex('unreferenced'.bytes())}'] = 'bad zlib'.bytes()124	backend.items['repo/releases/1.0.0/linux-aarch64/app'] = 'corrupt'.bytes()125	mut damaged := DoctorJson{}126	doctor_remote_content(mut backend, 'repo', mut damaged)!127	assert damaged.problems.any(it.contains('damaged remote object'))128	assert damaged.problems.any(it.contains('checksum verification'))129}130131fn test_doctor_reports_event_errors_strip_residue_and_flags() {132	mut report := DoctorJson{}133	saves := [history.Save{ id: 'aaaaaaaaaaaa' }]134	event_list := [events.Event{ id: 'strip', kind: 'strip', path: 'private' },135		events.Event{ id: 'flag', kind: 'flag', save_id: 'aaaaaaaaaaaa' },136		events.Event{ id: 'bad', kind: 'unknown' }]137	doctor_events(event_list, saves, mut report)138	doctor_files(saves[0].id, [snapshot.FileEntry{ path: 'private/file' }], event_list, mut report)139	assert report.flagged_saves == 1140	assert report.problems.any(it.contains('unknown kind'))141	assert report.problems.any(it.contains('stripped path'))142}