╭ changed ───────╮ │src/test/net.zig│ ╰────────────────╯ ╭────────────────────────────────────────────────╮ │ 8 const hash = xit.hash; │ │ 9 const net = xit.net; │ │10 │ │11 +const http_port: u16 = 3000; │ │12 +const ssh_port: u16 = 3001; │ │13 + │ │14 test "fetch small" { │ │15 const io = std.testing.io; │ │16 const allocator = std.testing.allocator;│ ╰────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────╮ │14 - try testFetch(.xit, .{ .wire = .http }, 3000, io, allocator); │ │17 + try testFetch(.xit, .{ .wire = .http }, io, allocator); │ │18 if (.windows != builtin.os.tag) { │ │16 - try testFetch(.xit, .{ .wire = .ssh }, 3001, io, allocator);│ │19 + try testFetch(.xit, .{ .wire = .ssh }, io, allocator); │ │20 } │ │21 } │ │22 │ ╰────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────╮ │23 test "push small" { │ │24 const io = std.testing.io; │ │25 const allocator = std.testing.allocator; │ │23 - try testPush(.xit, .{ .wire = .http }, 3010, io, allocator); │ │26 + try testPush(.xit, .{ .wire = .http }, io, allocator); │ │27 if (.windows != builtin.os.tag) { │ │25 - try testPush(.xit, .{ .wire = .ssh }, 3011, io, allocator);│ │28 + try testPush(.xit, .{ .wire = .ssh }, io, allocator); │ │29 } │ │30 } │ │31 │ ╰───────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────╮ │32 test "push creates missing repo under serve" { │ │33 const io = std.testing.io; │ │34 const allocator = std.testing.allocator; │ │32 - try testPushCreatesMissingRepo(.xit, .{ .wire = .http }, 3020, io, allocator); │ │35 + try testPushCreatesMissingRepo(.xit, .{ .wire = .http }, io, allocator); │ │36 if (.windows != builtin.os.tag) { │ │34 - try testPushCreatesMissingRepo(.xit, .{ .wire = .ssh }, 3021, io, allocator);│ │37 + try testPushCreatesMissingRepo(.xit, .{ .wire = .ssh }, io, allocator); │ │38 } │ │39 } │ │40 │ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────╮ │41 test "clone small" { │ │42 const io = std.testing.io; │ │43 const allocator = std.testing.allocator; │ │41 - try testClone(.xit, .{ .wire = .http }, 3030, false, io, allocator); │ │44 + try testClone(.xit, .{ .wire = .http }, false, io, allocator); │ │45 if (.windows != builtin.os.tag) { │ │43 - try testClone(.xit, .{ .wire = .ssh }, 3031, false, io, allocator);│ │46 + try testClone(.xit, .{ .wire = .ssh }, false, io, allocator); │ │47 } │ │48 } │ │49 │ ╰───────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────╮ │50 test "clone small subprocess" { │ │51 const io = std.testing.io; │ │52 const allocator = std.testing.allocator; │ │50 - try testClone(.git, .{ .wire = .http }, 3040, true, io, allocator); │ │53 + try testClone(.git, .{ .wire = .http }, true, io, allocator); │ │54 if (.windows != builtin.os.tag) { │ │52 - try testClone(.git, .{ .wire = .ssh }, 3041, true, io, allocator);│ │55 + try testClone(.git, .{ .wire = .ssh }, true, io, allocator); │ │56 } │ │57 } │ │58 + │ │59 test "fetch large subprocess" { │ │60 const io = std.testing.io; │ │61 const allocator = std.testing.allocator; │ ╰──────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │58 - try testFetchLarge(.git, .{ .wire = .http }, 3050, true, io, allocator); │ │62 + try testFetchLarge(.git, .{ .wire = .http }, true, io, allocator); │ │63 if (.windows != builtin.os.tag) { │ │60 - try testFetchLarge(.git, .{ .wire = .ssh }, 3051, true, io, allocator);│ │64 + try testFetchLarge(.git, .{ .wire = .ssh }, true, io, allocator); │ │65 } │ │66 } │ │67 + │ │68 test "push large subprocess" { │ │69 const io = std.testing.io; │ │70 const allocator = std.testing.allocator; │ ╰───────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────╮ │66 - try testPushLarge(.git, .{ .wire = .http }, 3060, true, io, allocator); │ │71 + try testPushLarge(.git, .{ .wire = .http }, true, io, allocator); │ │72 if (.windows != builtin.os.tag) { │ │68 - try testPushLarge(.git, .{ .wire = .ssh }, 3061, true, io, allocator);│ │73 + try testPushLarge(.git, .{ .wire = .ssh }, true, io, allocator); │ │74 } │ │75 } │ │76 │ ╰──────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 72 -fn Server( │ │ 73 - comptime transport_def: net.TransportDefinition, │ │ 77 +fn runServer( │ │ 78 + io: std.Io, │ │ 79 + allocator: std.mem.Allocator, │ │ 80 comptime temp_dir_name: []const u8, │ │ 75 - comptime port: u16, │ │ 76 -) type { │ │ 77 - return struct { │ │ 78 - core: Core, │ │ 79 - │ │ 80 - const Core = switch (transport_def) { │ │ 81 - .file => void, │ │ 82 - .wire => |wire_kind| switch (wire_kind) { │ │ 83 - .http => struct { │ │ 84 - io: std.Io, │ │ 85 - allocator: std.mem.Allocator, │ │ 86 - process: ?std.process.Child, │ │ 87 - }, │ │ 88 - .raw => unreachable, │ │ 89 - .ssh => struct { │ │ 90 - io: std.Io, │ │ 91 - allocator: std.mem.Allocator, │ │ 92 - serve_process: ?std.process.Child, │ │ 93 - }, │ │ 94 - }, │ │ 95 - }; │ │ 96 - │ │ 97 - fn init( │ │ 98 - io: std.Io, │ │ 99 - allocator: std.mem.Allocator, │ │100 - ) !Server(transport_def, temp_dir_name, port) { │ │101 - switch (transport_def) { │ │102 - .file => return .{ .core = {} }, │ │103 - .wire => |wire_kind| switch (wire_kind) { │ │104 - .http => return .{ │ │105 - .core = .{ │ │106 - .io = io, │ │107 - .allocator = allocator, │ │108 - .process = null, │ │109 - }, │ │110 - }, │ │111 - .raw => unreachable, │ │112 - .ssh => { │ │113 - // generate a fresh client ed25519 key. haxy's │ │114 - // in-process SSH accepts any ed25519 key whose │ │115 - // signature verifies, so there's no authorized_keys │ │116 - // file or sshd setup to do. │ │117 - const priv_key_path = try std.fs.path.join(allocator, &.{ temp_dir_name, "key" }); │ │118 - defer allocator.free(priv_key_path); │ │119 - │ │120 - var keygen = try std.process.spawn(io, .{ │ │121 - .argv = &.{ "ssh-keygen", "-t", "ed25519", "-N", "", "-q", "-f", priv_key_path }, │ │122 - .stdin = .ignore, │ │123 - .stdout = .ignore, │ │124 - .stderr = .ignore, │ │125 - }); │ │126 - const term = try keygen.wait(io); │ │127 - try std.testing.expect(term == .exited and term.exited == 0); │ │128 - │ │129 - return .{ │ │130 - .core = .{ │ │131 - .io = io, │ │132 - .allocator = allocator, │ │133 - .serve_process = null, │ │134 - }, │ │135 - }; │ │136 - }, │ │137 - }, │ │138 - } │ │ 81 +) !std.process.Child { │ │ 82 + { │ │ 83 + const priv_key_file = try std.Io.Dir.cwd().createFile(io, temp_dir_name ++ "/key", .{}); │ │ 84 + defer priv_key_file.close(io); │ │ 85 + try priv_key_file.writeStreamingAll(io, │ │ 86 + \\-----BEGIN OPENSSH PRIVATE KEY----- │ │ 87 + \\b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW │ │ 88 + \\QyNTUxOQAAACCniLPJiaooAWecvOCeAjoJwCSeWxzysvpTNkpYjF22JgAAAJA+7hikPu4Y │ │ 89 + \\pAAAAAtzc2gtZWQyNTUxOQAAACCniLPJiaooAWecvOCeAjoJwCSeWxzysvpTNkpYjF22Jg │ │ 90 + \\AAAEDVlopOMnKt/7by/IA8VZvQXUS/O6VLkixOqnnahUdPCKeIs8mJqigBZ5y84J4COgnA │ │ 91 + \\JJ5bHPKy+lM2SliMXbYmAAAAC3JhZGFyQHJvYXJrAQI= │ │ 92 + \\-----END OPENSSH PRIVATE KEY----- │ │ 93 + \\ │ │ 94 + ); │ │ 95 + if (.windows != builtin.os.tag) { │ │ 96 + try priv_key_file.setPermissions(io, @enumFromInt(0o600)); │ │ 97 } │ │ 98 + } │ │ 99 │ │141 - fn start(self: *Server(transport_def, temp_dir_name, port)) !void { │ │142 - switch (transport_def) { │ │143 - .file => {}, │ │144 - .wire => |wire_kind| switch (wire_kind) { │ │145 - .http => { │ │146 - std.debug.assert(self.core.process == null); │ │100 + const cwd_path = try std.process.currentPathAlloc(io, allocator); │ │101 + defer allocator.free(cwd_path); │ │102 + const haxy_path = try std.fs.path.join(allocator, &.{ cwd_path, "zig-out/bin/haxy" }); │ │103 + defer allocator.free(haxy_path); │ │104 │ │148 - const cwd_path = try std.process.currentPathAlloc(self.core.io, self.core.allocator); │ │149 - defer self.core.allocator.free(cwd_path); │ │150 - const haxy_path = try std.fs.path.join(self.core.allocator, &.{ cwd_path, "zig-out/bin/haxy" }); │ │151 - defer self.core.allocator.free(haxy_path); │ │152 - const listen_arg = std.fmt.comptimePrint("127.0.0.1:{}", .{port}); │ │105 + const http_listen_arg = std.fmt.comptimePrint("127.0.0.1:{}", .{http_port}); │ │106 + const ssh_listen_arg = std.fmt.comptimePrint("127.0.0.1:{}", .{ssh_port}); │ │107 │ │154 - self.core.process = try std.process.spawn(self.core.io, .{ │ │155 - .argv = &.{ haxy_path, "serve", "--http-listen", listen_arg, "--data-dir", temp_dir_name }, │ │156 - .stdin = .ignore, │ │157 - .stdout = .ignore, │ │158 - .stderr = .ignore, │ │159 - }); │ │160 - }, │ │161 - .raw => unreachable, │ │162 - .ssh => { │ │163 - std.debug.assert(self.core.serve_process == null); │ │108 + const process = try std.process.spawn(io, .{ │ │109 + .argv = &.{ haxy_path, "serve", "--http-listen", http_listen_arg, "--ssh-listen", ssh_listen_arg, "--data-dir", temp_dir_name }, │ │110 + .stdin = .ignore, │ │111 + .stdout = .ignore, │ │112 + .stderr = .ignore, │ │113 + }); │ │114 │ │165 - const cwd_path = try std.process.currentPathAlloc(self.core.io, self.core.allocator); │ │166 - defer self.core.allocator.free(cwd_path); │ │167 - const haxy_path = try std.fs.path.join(self.core.allocator, &.{ cwd_path, "zig-out/bin/haxy" }); │ │168 - defer self.core.allocator.free(haxy_path); │ │169 - // haxy's in-process SSH listens on `port`. give the │ │170 - // (unused-by-this-test) HTTP listener a unique port │ │171 - // too, so concurrent tests don't collide on 8080. │ │172 - const ssh_listen_arg = std.fmt.comptimePrint("127.0.0.1:{}", .{port}); │ │173 - const http_listen_arg = std.fmt.comptimePrint("127.0.0.1:{}", .{port + 1000}); │ │174 - │ │175 - self.core.serve_process = try std.process.spawn(self.core.io, .{ │ │176 - .argv = &.{ haxy_path, "serve", "--http-listen", http_listen_arg, "--ssh-listen", ssh_listen_arg, "--data-dir", temp_dir_name },│ │177 - .stdin = .ignore, │ │178 - .stdout = .ignore, │ │179 - .stderr = .ignore, │ │180 - }); │ │181 - }, │ │182 - }, │ │183 - } │ │184 - │ │185 - if (transport_def == .wire) { │ │186 - const address = try std.Io.net.IpAddress.parseIp4("127.0.0.1", port); │ │187 - for (0..50) |_| { │ │188 - const stream = address.connect(self.core.io, .{ .mode = .stream }) catch { │ │189 - try std.Io.sleep(self.core.io, .fromMilliseconds(100), .real); │ │190 - continue; │ │191 - }; │ │192 - stream.close(self.core.io); │ │193 - break; │ │194 - } │ │195 - } │ │196 - } │ │115 + const address = try std.Io.net.IpAddress.parseIp4("127.0.0.1", http_port); │ │116 + for (0..50) |_| { │ │117 + const stream = address.connect(io, .{ .mode = .stream }) catch { │ │118 + try std.Io.sleep(io, .fromMilliseconds(100), .real); │ │119 + continue; │ │120 + }; │ │121 + stream.close(io); │ │122 + break; │ │123 + } │ │124 │ │198 - fn stop(self: *Server(transport_def, temp_dir_name, port)) void { │ │199 - switch (transport_def) { │ │200 - .file => {}, │ │201 - .wire => |wire_kind| switch (wire_kind) { │ │202 - .http => if (self.core.process) |*process| { │ │203 - _ = process.kill(self.core.io); │ │204 - self.core.process = null; │ │205 - }, │ │206 - .raw => unreachable, │ │207 - .ssh => { │ │208 - if (self.core.serve_process) |*process| { │ │209 - _ = process.kill(self.core.io); │ │210 - self.core.serve_process = null; │ │211 - } │ │212 - }, │ │213 - }, │ │214 - } │ │215 - } │ │216 - }; │ │125 + return process; │ │126 } │ │127 │ │128 fn testFetch( │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────╮ │129 comptime repo_kind: rp.RepoKind, │ │130 comptime transport_def: net.TransportDefinition,│ │222 - comptime port: u16, │ │131 io: std.Io, │ │132 allocator: std.mem.Allocator, │ │133 ) !void { │ ╰─────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯