╭ changed ─────────╮ │src/test/event.zig│ ╰──────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭──────────────────────────────╮ │1 const std = @import("std");│ │2 const hx = @import("haxy");│ │3 const evt = hx.event; │ │4 +const usr = evt.user; │ │5 const xit = hx.xit; │ │6 const rp = xit.repo; │ │7 const hash = xit.hash; │ ╰──────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │783 try std.testing.expectError(error.MergeConflict, evt.consume(repo_opts, io, allocator, &repo, .{ .kind = .head, .name = "haxy/meta" })); │ │784 } │ │785 │ │786 +test "user" { │ │787 + const io = std.testing.io; │ │788 + const allocator = std.testing.allocator; │ │789 + const temp_dir_name = "temp-event-user"; │ │790 + │ │791 + // create the temp dir │ │792 + const cwd = std.Io.Dir.cwd(); │ │793 + var temp_dir_or_err = cwd.openDir(io, temp_dir_name, .{}); │ │794 + if (temp_dir_or_err) |*temp_dir| { │ │795 + temp_dir.close(io); │ │796 + try cwd.deleteTree(io, temp_dir_name); │ │797 + } else |_| {} │ │798 + var temp_dir = try cwd.createDirPathOpen(io, temp_dir_name, .{}); │ │799 + defer cwd.deleteTree(io, temp_dir_name) catch {}; │ │800 + defer temp_dir.close(io); │ │801 + │ │802 + const cwd_path = try std.process.currentPathAlloc(io, allocator); │ │803 + defer allocator.free(cwd_path); │ │804 + │ │805 + const work_path = try std.fs.path.join(allocator, &.{ cwd_path, temp_dir_name }); │ │806 + defer allocator.free(work_path); │ │807 + │ │808 + const repo_opts: rp.RepoOpts(.xit) = .{ .is_test = true }; │ │809 + const Repo = rp.Repo(.xit, repo_opts); │ │810 + var repo = try Repo.init(io, allocator, .{ .path = work_path }); │ │811 + defer repo.deinit(io, allocator); │ │812 + │ │813 + var arena = std.heap.ArenaAllocator.init(allocator); │ │814 + defer arena.deinit(); │ │815 + │ │816 + // │ │817 + // define test events │ │818 + // │ │819 + │ │820 + var prng = std.Random.DefaultPrng.init(std.testing.random_seed); │ │821 + const user_event_id = evt.randomId(prng.random()); │ │822 + │ │823 + var first_password_hash_buf: [usr.password_hash_max_len]u8 = undefined; │ │824 + const first_password_hash = try usr.hashPassword("correct horse battery staple", &first_password_hash_buf, io); │ │825 + │ │826 + var second_password_hash_buf: [usr.password_hash_max_len]u8 = undefined; │ │827 + const second_password_hash = try usr.hashPassword("Tr0ub4dor&3", &second_password_hash_buf, io); │ │828 + │ │829 + const events_to_consume = [_]evt.Event{ │ │830 + .{ │ │831 + .id = std.fmt.bytesToHex(user_event_id, .lower), │ │832 + .data = .{ │ │833 + .user = .{ │ │834 + .name = "Alice Example", │ │835 + .email = "alice@example.test", │ │836 + .password_hash = first_password_hash, │ │837 + }, │ │838 + }, │ │839 + }, │ │840 + // this event edits the previous one because it has the same id │ │841 + .{ │ │842 + .id = std.fmt.bytesToHex(user_event_id, .lower), │ │843 + .data = .{ │ │844 + .user = .{ │ │845 + .name = "Alice Example", │ │846 + .email = "alice@example.test", │ │847 + .password_hash = second_password_hash, │ │848 + }, │ │849 + }, │ │850 + }, │ │851 + }; │ │852 + │ │853 + // │ │854 + // insert users as commits in the repo │ │855 + // │ │856 + │ │857 + { │ │858 + var json: std.Io.Writer.Allocating = .init(std.testing.allocator); │ │859 + defer json.deinit(); │ │860 + │ │861 + for (events_to_consume) |event| { │ │862 + json.clearRetainingCapacity(); │ │863 + │ │864 + try std.json.Stringify.value(event, .{}, &json.writer); │ │865 + │ │866 + // commit the event into a special branch │ │867 + _ = try repo.commitAtRef(io, allocator, .{ .message = json.written() }, null, .{ .kind = .head, .name = "haxy/meta" }); │ │868 + } │ │869 + } │ │870 + │ │871 + // │ │872 + // consume events into the database │ │873 + // │ │874 + │ │875 + { │ │876 + try evt.consume(repo_opts, io, allocator, &repo, .{ .kind = .head, .name = "haxy/meta" }); │ │877 + │ │878 + const history = try Repo.DB.ArrayList(.read_only).init(repo.core.db.rootCursor().readOnly()); │ │879 + │ │880 + // read the moment we just created │ │881 + const moment_cursor = try history.getCursor(-1) orelse return error.NotFound; │ │882 + const moment = try Repo.DB.HashMap(.read_only).init(moment_cursor); │ │883 + │ │884 + // get the last object id │ │885 + const last_object_id_cursor = try moment.getCursor(hash.hashInt(repo_opts.hash, "haxy-last-object-id")) orelse return error.NotFound; │ │886 + var last_object_id: [hash.byteLen(repo_opts.hash)]u8 = undefined; │ │887 + _ = try last_object_id_cursor.readBytes(&last_object_id); │ │888 + │ │889 + const haxy_cursor = try moment.getCursor(hash.hashInt(repo_opts.hash, "haxy")) orelse return error.NotFound; │ │890 + const haxy = try Repo.DB.ArrayList(.read_only).init(haxy_cursor); │ │891 + │ │892 + try std.testing.expectEqual(1, try haxy.count()); │ │893 + │ │894 + const haxy_moments_cursor = try haxy.getCursor(-1) orelse return error.NotFound; │ │895 + const haxy_moments = try Repo.DB.HashMap(.read_only).init(haxy_moments_cursor); │ │896 + │ │897 + const haxy_moment_cursor = try haxy_moments.getCursor(hash.bytesToInt(repo_opts.hash, &last_object_id)) orelse return error.NotFound; │ │898 + const haxy_moment = try Repo.DB.HashMap(.read_only).init(haxy_moment_cursor); │ │899 + │ │900 + // get the map of users │ │901 + const event_id_to_user_cursor = try haxy_moment.getCursor(hash.hashInt(repo_opts.hash, "event-id->user")) orelse return error.NotFound;│ │902 + const event_id_to_user = try Repo.DB.HashMap(.read_only).init(event_id_to_user_cursor); │ │903 + │ │904 + // get the user out of the map that was edited │ │905 + const user_cursor = try event_id_to_user.getCursor(hash.hashInt(repo_opts.hash, &user_event_id)) orelse return error.NotFound; │ │906 + const user_map = try Repo.DB.HashMap(.read_only).init(user_cursor); │ │907 + const user = try evt.EventData.read(Repo.DB, repo_opts.hash, arena.allocator(), user_map, .user); │ │908 + │ │909 + // the password was correctly edited │ │910 + try std.testing.expectEqualStrings(events_to_consume[1].data.user.password_hash, user.user.password_hash); │ │911 + } │ │912 +} │ │913 + │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯