123module remote45import net6import net.http78struct FakeMirror {9mut:10 asked []string11}1213fn (mut h FakeMirror) handle(req http.Request) http.Response {14 h.asked << req.url15 if req.url == '/repo/koh/format' {16 return http.Response{ status_code: 200, status_msg: 'OK', body: 'koh-remote 1' }17 }18 if req.url == '/repo/koh/head' {19 return http.Response{ status_code: 200, status_msg: 'OK', body: 'abc123abc123' }20 }21 if req.url == '/repo/koh/saves/abc123abc123' {22 return http.Response{ status_code: 200, status_msg: 'OK', body: '{"id":"abc123abc123","files":[]}' }23 }24 if req.url == '/repo/koh/objects/dead' {25 26 return http.Response{ status_code: 200, status_msg: 'OK', body: '\x01\x02\x03' }27 }28 if req.url == '/repo/koh/events' {29 return http.Response{ status_code: 200, status_msg: 'OK', body: 'e1\ne2\n' }30 }31 if req.url == '/repo/koh/broken' {32 return http.Response{ status_code: 500, status_msg: 'Internal Server Error' }33 }34 return http.Response{ status_code: 404, status_msg: 'Not Found' }35}3637fn start_fake_mirror() !(int, &http.Server, &FakeMirror) {38 for port in 19321 .. 19331 {39 listener := net.listen_tcp(.ip, '127.0.0.1:${port}') or { continue }40 fake := &FakeMirror{}41 mut server := &http.Server{42 listener: listener43 handler: fake44 show_startup_message: false45 }46 spawn server.listen_and_serve()47 server.wait_till_running()!48 return port, server, fake49 }50 return error('no free fake mirror port')51}5253fn test_a_public_repo_reads_through_the_web_backend() {54 port, mut server, _ := start_fake_mirror()!55 defer {56 server.stop()57 }58 mut web := new_web('http://127.0.0.1:${port}')!59 format := web.get('repo/format')!60 assert format.found61 assert format.body.bytestr() == 'koh-remote 1'62 assert web.get('repo/head')!.body.bytestr() == 'abc123abc123'63 assert web.get('repo/saves/abc123abc123')!.body.bytestr() == '{"id":"abc123abc123","files":[]}'64 65 blob := web.get('repo/objects/dead')!66 assert blob.found67 assert blob.body == [u8(1), 2, 3]68 69 assert web.list('repo/events')! == ['repo/events/e1', 'repo/events/e2']70 71 assert !web.get('repo/objects/nope')!.found72 assert web.list('repo/events/none')! == []string{}73}7475fn test_a_broken_mirror_and_every_write_are_refused() {76 port, mut server, _ := start_fake_mirror()!77 defer {78 server.stop()79 }80 mut web := new_web('http://127.0.0.1:${port}')!81 if _ := web.get('repo/broken') {82 assert false, 'a 500 must not read as a missing key'83 } else {84 assert err.msg().contains('500')85 }86 read_only := 'http://127.0.0.1:${port}/repo is read-only.'87 if _ := web.put_if_absent('repo/head', 'x'.bytes()) {88 assert false, 'a public repo is never written to'89 } else {90 assert err.msg() == read_only91 }92 if _ := web.put_if_match('repo/head', 'x'.bytes(), '"tag"') {93 assert false, 'a public repo is never written to'94 } else {95 assert err.msg() == read_only96 }97 if _ := web.delete('repo/head') {98 assert false, 'a public repo is never written to'99 } else {100 assert err.msg() == read_only101 }102}103104fn test_only_a_bare_host_becomes_a_base() {105 assert kepr_host('kepr.uk')! == 'https://kepr.uk'106 assert kepr_host('https://kepr.uk/')! == 'https://kepr.uk'107 assert kepr_host('http://127.0.0.1:3917')! == 'http://127.0.0.1:3917'108 for bad in ['kepr.uk/foo', 'kepr.uk?x=1', '[email protected]', 'kepr uk', 'https://'] {109 if _ := kepr_host(bad) {110 assert false, '${bad} is not a host'111 }112 }113}114115116fn test_the_base_is_normalised_once() {117 port, mut server, fake := start_fake_mirror()!118 defer {119 server.stop()120 }121 mut web := new_web('http://127.0.0.1:${port}/')!122 assert web.base == 'http://127.0.0.1:${port}'123 assert web.get('repo/head')!.found124 assert fake.asked[0] == '/repo/koh/head'125}