From b37c9d49c900af7f4a61812ba5ba3c2afc5e15bc Mon Sep 17 00:00:00 2001 From: sectasy0 Date: Fri, 10 May 2024 19:40:06 +0200 Subject: [PATCH] refactor: project structure --- src/main.zig | 21 ++-- src/protocol/types.zig | 4 +- src/server/access_control.zig | 39 ------ src/server/logger.zig | 2 +- src/server/middleware/access.zig | 47 +++++++ src/server/{ => network}/connection.zig | 0 src/server/{ => network}/listener.zig | 24 ++-- src/server/{ => network}/stream_server.zig | 0 .../commands.zig} | 79 ++++++------ src/server/{ => processing}/employer.zig | 17 +-- .../errors.zig} | 4 +- .../requests.zig} | 29 ++--- src/server/{ => processing}/worker.zig | 2 +- .../{storage.zig => storage/memory.zig} | 37 +++--- src/server/{ => storage}/persistance.zig | 28 ++--- src/server/utils.zig | 12 -- src/test.zig | 6 +- src/tests/fixtures.zig | 17 +-- src/tests/helper.zig | 13 +- .../server/{access_control.zig => access.zig} | 6 +- .../server/{cmd_handler.zig => commands.zig} | 118 +++++++++--------- src/tests/server/config.zig | 2 +- .../server/{err_handler.zig => errors.zig} | 20 +-- src/tests/server/persistance.zig | 38 +++--- src/tests/server/storage.zig | 70 +++++------ src/tests/server/utils.zig | 82 ------------ 26 files changed, 320 insertions(+), 397 deletions(-) delete mode 100644 src/server/access_control.zig create mode 100644 src/server/middleware/access.zig rename src/server/{ => network}/connection.zig (100%) rename src/server/{ => network}/listener.zig (92%) rename src/server/{ => network}/stream_server.zig (100%) rename src/server/{cmd_handler.zig => processing/commands.zig} (65%) rename src/server/{ => processing}/employer.zig (87%) rename src/server/{err_handler.zig => processing/errors.zig} (95%) rename src/server/{request_processor.zig => processing/requests.zig} (82%) rename src/server/{ => processing}/worker.zig (91%) rename src/server/{storage.zig => storage/memory.zig} (74%) rename src/server/{ => storage}/persistance.zig (88%) rename src/tests/server/{access_control.zig => access.zig} (82%) rename src/tests/server/{cmd_handler.zig => commands.zig} (69%) rename src/tests/server/{err_handler.zig => errors.zig} (81%) diff --git a/src/main.zig b/src/main.zig index bba541e..bd54301 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,17 +1,18 @@ const std = @import("std"); const builtin = @import("builtin"); -const server = @import("server/listener.zig"); const Config = @import("server/config.zig"); -const MemoryStorage = @import("server/storage.zig"); const cli = @import("server/cli.zig"); -const Logger = @import("server/logger.zig"); const log = @import("server/logger.zig"); const TracingAllocator = @import("server/tracing.zig"); -const persistance = @import("server/persistance.zig"); -const Employer = @import("server/employer.zig"); +const persistance = @import("server/storage/persistance.zig"); +const Memory = @import("server/storage/memory.zig"); + +const server = @import("server/network/listener.zig"); + +const Employer = @import("server/processing/employer.zig"); pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, ret_addr: ?usize) noreturn { @setCold(true); @@ -70,7 +71,7 @@ pub fn main() void { handle_arguments(result.args) orelse return; - var logger = Logger.init( + var logger = log.Logger.init( allocator, result.args.@"log-path", result.args.sout, @@ -113,14 +114,14 @@ pub fn main() void { defer _ = dbgpa.deinit(); var tracing = TracingAllocator.init(dbgpa.allocator()); - var mem_storage = MemoryStorage.init( + var memory = Memory.init( tracing.allocator(), config, &persister, ); - defer mem_storage.deinit(); + defer memory.deinit(); - persister.load(&mem_storage) catch |err| { + persister.load(&memory) catch |err| { if (err != error.FileNotFound) { logger.log( .Warning, @@ -133,7 +134,7 @@ pub fn main() void { const context = Employer.Context{ .config = &config, .logger = &logger, - .storage = &mem_storage, + .memory = &memory, }; run_supervisor(allocator, context); diff --git a/src/protocol/types.zig b/src/protocol/types.zig index 5e4d98a..eadf4a0 100644 --- a/src/protocol/types.zig +++ b/src/protocol/types.zig @@ -10,7 +10,7 @@ pub const ZType = union(enum) { array: array, null: void, // ClientError only for compatibility with ProtocolHandler - // and it will not be stored in MemoryStorage but will be returned + // and it will not be stored in Memory but will be returned err: ClientError, pub const array = std.ArrayList(ZType); @@ -51,7 +51,7 @@ pub fn ztype_copy(value: ZType, allocator: std.mem.Allocator) anyerror!ZType { return .{ .map = result }; }, - // we do not implement for err because errors wont be stored in MemoryStorage + // we do not implement for err because errors wont be stored in Memory else => return error.UnsuportedType, } diff --git a/src/server/access_control.zig b/src/server/access_control.zig deleted file mode 100644 index 25ee58b..0000000 --- a/src/server/access_control.zig +++ /dev/null @@ -1,39 +0,0 @@ -const std = @import("std"); - -const Logger = @import("logger.zig"); -const Config = @import("config.zig"); -const utils = @import("utils.zig"); - -const AccessControl = @This(); - -logger: *Logger, -config: *const Config, - -pub fn init(config: *const Config, logger: *Logger) AccessControl { - return AccessControl{ .logger = logger, .config = config }; -} - -// Check whether a new connection, represented by the provided network address, can be established. -pub fn verify(self: AccessControl, address: std.net.Address) !void { - try self.check_whitelist(address); -} - -// Checks whether the provided network address is whitelisted. -// If whitelisting is enabled (whitelist capacity is greater than 0) and the given address is not whitelisted. -fn check_whitelist( - self: AccessControl, - address: std.net.Address, -) !void { - if (self.config.whitelist.capacity > 0 and !utils.is_whitelisted( - self.config.whitelist, - address, - )) { - self.logger.log( - .Info, - "* connection from {any} is not whitelisted, rejected", - .{address}, - ); - - return error.NotPermitted; - } -} diff --git a/src/server/logger.zig b/src/server/logger.zig index e6eef55..0adcb8d 100644 --- a/src/server/logger.zig +++ b/src/server/logger.zig @@ -1,7 +1,7 @@ const std = @import("std"); const utils = @import("utils.zig"); -const Logger = @This(); +pub const Logger = @This(); pub const DEFAULT_PATH: []const u8 = "./logs/zcached.log"; const MAX_FILE_SIZE: usize = 30 * 1048576; // 30Mb in binary. diff --git a/src/server/middleware/access.zig b/src/server/middleware/access.zig new file mode 100644 index 0000000..7af49bc --- /dev/null +++ b/src/server/middleware/access.zig @@ -0,0 +1,47 @@ +const std = @import("std"); + +const Logger = @import("../logger.zig"); +const Config = @import("../config.zig"); +const utils = @import("../utils.zig"); + +pub const AccessMiddleware = @This(); + +logger: *Logger, +config: *const Config, + +pub fn init(config: *const Config, logger: *Logger) AccessMiddleware { + return AccessMiddleware{ .logger = logger, .config = config }; +} + +// Check whether a new connection, represented by the provided network address, can be established. +pub fn verify(self: AccessMiddleware, address: std.net.Address) !void { + try self.check_whitelist(address); +} + +// Checks whether the provided network address is whitelisted. +// If whitelisting is enabled (whitelist capacity is greater than 0) and the given address is not whitelisted. +fn check_whitelist( + self: AccessMiddleware, + address: std.net.Address, +) !void { + if (self.config.whitelist.capacity > 0 and !is_whitelisted( + self.config.whitelist, + address, + )) { + self.logger.log( + .Info, + "* connection from {any} is not whitelisted, rejected", + .{address}, + ); + + return error.NotPermitted; + } +} + +// Checks if the provided network address is present in the given whitelist. +fn is_whitelisted(whitelist: std.ArrayList(std.net.Address), addr: std.net.Address) bool { + for (whitelist.items) |whitelisted| { + if (std.meta.eql(whitelisted.any.data[2..].*, addr.any.data[2..].*)) return true; + } + return false; +} diff --git a/src/server/connection.zig b/src/server/network/connection.zig similarity index 100% rename from src/server/connection.zig rename to src/server/network/connection.zig diff --git a/src/server/listener.zig b/src/server/network/listener.zig similarity index 92% rename from src/server/listener.zig rename to src/server/network/listener.zig index 694b9ad..24fe6b3 100644 --- a/src/server/listener.zig +++ b/src/server/network/listener.zig @@ -1,16 +1,18 @@ const std = @import("std"); -const Worker = @import("worker.zig"); -const StreamServer = @import("stream_server.zig"); -const Connection = @import("connection.zig"); -const MemoryStorage = @import("storage.zig"); -const Context = @import("employer.zig").Context; +const StreamServer = @import("../network/stream_server.zig"); +const Connection = @import("../network/connection.zig"); -const AccessControl = @import("access_control.zig"); -const RequestProcessor = @import("request_processor.zig"); +const Worker = @import("../processing/worker.zig"); +const Context = @import("../processing/employer.zig").Context; +const requests = @import("../processing/requests.zig"); -const utils = @import("utils.zig"); -const Logger = @import("logger.zig"); +const Memory = @import("../storage/memory.zig"); + +const AccessMiddleware = @import("../middleware/access.zig"); + +const utils = @import("../utils.zig"); +const Logger = @import("../logger.zig"); const DEFAULT_CLIENT_BUFFER: usize = 4096; @@ -144,7 +146,7 @@ fn handle_incoming(self: *Listener, worker: *Worker) AcceptResult { }, }; - const access_control = AccessControl.init(self.context.config, self.context.logger); + const access_control = AccessMiddleware.init(self.context.config, self.context.logger); access_control.verify(incoming.address) catch return .{ .err = .{ .etype = error.NotPermitted, @@ -285,7 +287,7 @@ fn handle_request(self: *const Listener, worker: *Worker, connection: *Connectio connection.position = 0; - var processor = RequestProcessor.init( + var processor = requests.Processor.init( worker.allocator, self.context, ); diff --git a/src/server/stream_server.zig b/src/server/network/stream_server.zig similarity index 100% rename from src/server/stream_server.zig rename to src/server/network/stream_server.zig diff --git a/src/server/cmd_handler.zig b/src/server/processing/commands.zig similarity index 65% rename from src/server/cmd_handler.zig rename to src/server/processing/commands.zig index 5a96c99..044259f 100644 --- a/src/server/cmd_handler.zig +++ b/src/server/processing/commands.zig @@ -1,15 +1,16 @@ const std = @import("std"); -const MemoryStorage = @import("storage.zig"); -const ZType = @import("../protocol/types.zig").ZType; -const Config = @import("config.zig"); -const utils = @import("utils.zig"); -const Logger = @import("logger.zig"); +const ZType = @import("../../protocol/types.zig").ZType; -const TracingAllocator = @import("tracing.zig").TracingAllocator; -const PersistanceHandler = @import("persistance.zig").PersistanceHandler; +const Memory = @import("../storage/memory.zig"); +const PersistanceHandler = @import("../storage/persistance.zig"); -const Commands = enum { +const TracingAllocator = @import("../tracing.zig").TracingAllocator; +const Config = @import("../config.zig"); +const utils = @import("../utils.zig"); +const Logger = @import("../logger.zig"); + +const CommandType = enum { PING, GET, SET, @@ -22,27 +23,27 @@ const Commands = enum { KEYS, LASTSAVE, }; -pub const CMDHandler = struct { +pub const Handler = struct { allocator: std.mem.Allocator, - storage: *MemoryStorage, + memory: *Memory, logger: *Logger, - pub const HandlerResult = union(enum) { ok: ZType, err: anyerror }; + pub const Result = union(enum) { ok: ZType, err: anyerror }; pub fn init( allocator: std.mem.Allocator, - mstorage: *MemoryStorage, + memory: *Memory, logger: *Logger, - ) CMDHandler { - return CMDHandler{ + ) Handler { + return Handler{ .allocator = allocator, - .storage = mstorage, + .memory = memory, .logger = logger, }; } - pub fn process(self: *CMDHandler, command_set: *const std.ArrayList(ZType)) HandlerResult { + pub fn process(self: *Handler, command_set: *const std.ArrayList(ZType)) Result { if (command_set.capacity == 0) return .{ .err = error.UnknownCommand }; // first element in command_set is command name and should be always str @@ -51,7 +52,7 @@ pub const CMDHandler = struct { } const cmd_upper: []u8 = utils.to_uppercase(command_set.items[0].str); - const command_type = std.meta.stringToEnum(Commands, cmd_upper) orelse { + const command_type = std.meta.stringToEnum(CommandType, cmd_upper) orelse { return .{ .err = error.UnknownCommand }; }; try switch (command_type) { @@ -72,36 +73,36 @@ pub const CMDHandler = struct { return self.delete(command_set.items[1]); }, .FLUSH => return self.flush(), - .DBSIZE => return .{ .ok = .{ .int = self.storage.size() } }, + .DBSIZE => return .{ .ok = .{ .int = self.memory.size() } }, .SAVE => return self.save(), .MGET => return self.mget(command_set.items[1..command_set.items.len]), .MSET => return self.mset(command_set.items[1..command_set.items.len]), .KEYS => return self.zkeys(), - .LASTSAVE => return .{ .ok = .{ .int = self.storage.last_save } }, + .LASTSAVE => return .{ .ok = .{ .int = self.memory.last_save } }, }; } - fn get(self: *CMDHandler, key: ZType) HandlerResult { - const value = self.storage.get(key.str) catch |err| { + fn get(self: *Handler, key: ZType) Result { + const value = self.memory.get(key.str) catch |err| { return .{ .err = err }; }; return .{ .ok = value }; } - fn set(self: *CMDHandler, key: ZType, value: ZType) HandlerResult { + fn set(self: *Handler, key: ZType, value: ZType) Result { // second element in command_set is key and should be always str if (key != .str) return .{ .err = error.KeyNotString }; - self.storage.put(key.str, value) catch |err| { + self.memory.put(key.str, value) catch |err| { return .{ .err = err }; }; return .{ .ok = .{ .sstr = @constCast("OK") } }; } - fn delete(self: *CMDHandler, key: ZType) HandlerResult { - const result = self.storage.delete(key.str); + fn delete(self: *Handler, key: ZType) Result { + const result = self.memory.delete(key.str); if (result) { return .{ .ok = .{ .sstr = @constCast("OK") } }; @@ -110,20 +111,20 @@ pub const CMDHandler = struct { } } - fn flush(self: *CMDHandler) HandlerResult { - self.storage.flush(); + fn flush(self: *Handler) Result { + self.memory.flush(); return .{ .ok = .{ .sstr = @constCast("OK") } }; } - fn ping(self: *CMDHandler) HandlerResult { + fn ping(self: *Handler) Result { _ = self; return .{ .ok = .{ .sstr = @constCast("PONG") } }; } - fn save(self: *CMDHandler) HandlerResult { - if (self.storage.size() == 0) return .{ .err = error.SaveFailure }; + fn save(self: *Handler) Result { + if (self.memory.size() == 0) return .{ .err = error.SaveFailure }; - const size = self.storage.save() catch |err| { + const size = self.memory.save() catch |err| { self.logger.log(.Error, "# failed to save data: {?}", .{err}); return .{ .err = error.SaveFailure }; @@ -136,13 +137,13 @@ pub const CMDHandler = struct { return .{ .err = error.SaveFailure }; } - fn mget(self: *CMDHandler, keys: []ZType) HandlerResult { + fn mget(self: *Handler, keys: []ZType) Result { var result = std.StringHashMap(ZType).init(self.allocator); for (keys) |key| { if (key != .str) return .{ .err = error.KeyNotString }; - const value: ZType = self.storage.get(key.str) catch .{ .null = void{} }; + const value: ZType = self.memory.get(key.str) catch .{ .null = void{} }; result.put(key.str, value) catch |err| { return .{ .err = err }; @@ -152,7 +153,7 @@ pub const CMDHandler = struct { return .{ .ok = .{ .map = result } }; } - fn mset(self: *CMDHandler, entries: []ZType) HandlerResult { + fn mset(self: *Handler, entries: []ZType) Result { if (entries.len == 0 or entries.len & 1 == 1) return .{ .err = error.InvalidArgs }; for (entries, 0..) |entry, index| { @@ -162,15 +163,15 @@ pub const CMDHandler = struct { const value = entries[index + 1]; - self.storage.put(entry.str, value) catch |err| { + self.memory.put(entry.str, value) catch |err| { return .{ .err = err }; }; } return .{ .ok = .{ .sstr = @constCast("OK") } }; } - fn zkeys(self: *CMDHandler) HandlerResult { - const result = self.storage.keys() catch |err| { + fn zkeys(self: *Handler) Result { + const result = self.memory.keys() catch |err| { return .{ .err = err }; }; return .{ .ok = .{ .array = result } }; @@ -178,10 +179,10 @@ pub const CMDHandler = struct { // method to free data needs to be freeded, for example keys command // is creating std.ArrayList so it have to be freed after - pub fn free(self: *CMDHandler, command_set: *const std.ArrayList(ZType), result: *HandlerResult) void { + pub fn free(self: *Handler, command_set: *const std.ArrayList(ZType), result: *Result) void { _ = self; const cmd_upper: []u8 = utils.to_uppercase(command_set.items[0].str); - const command_type = std.meta.stringToEnum(Commands, cmd_upper) orelse return; + const command_type = std.meta.stringToEnum(CommandType, cmd_upper) orelse return; switch (command_type) { .KEYS => result.ok.array.deinit(), diff --git a/src/server/employer.zig b/src/server/processing/employer.zig similarity index 87% rename from src/server/employer.zig rename to src/server/processing/employer.zig index e02d342..ce0e3b0 100644 --- a/src/server/employer.zig +++ b/src/server/processing/employer.zig @@ -1,13 +1,14 @@ const std = @import("std"); -const Worker = @import("worker.zig"); -const Listener = @import("listener.zig"); -const Logger = @import("logger.zig"); -const utils = @import("utils.zig"); +const Listener = @import("../network/listener.zig"); +const StreamServer = @import("../network/stream_server.zig"); -const StreamServer = @import("stream_server.zig"); -const MemoryStorage = @import("storage.zig"); -const Config = @import("config.zig"); +const Logger = @import("../logger.zig"); +const Config = @import("../config.zig"); +const utils = @import("../utils.zig"); + +const Memory = @import("../storage/memory.zig"); +const Worker = @import("../processing/worker.zig"); const Allocator = std.mem.Allocator; const Employer = @This(); @@ -22,7 +23,7 @@ threads: []std.Thread, allocator: std.mem.Allocator, pub const Context = struct { - storage: *MemoryStorage, + memory: *Memory, config: *const Config, logger: *Logger, }; diff --git a/src/server/err_handler.zig b/src/server/processing/errors.zig similarity index 95% rename from src/server/err_handler.zig rename to src/server/processing/errors.zig index 92ea8e1..41e03d3 100644 --- a/src/server/err_handler.zig +++ b/src/server/processing/errors.zig @@ -1,7 +1,7 @@ const std = @import("std"); -const Logger = @import("logger.zig"); +const Logger = @import("../logger.zig"); -const ZType = @import("../protocol/types.zig").ZType; +const ZType = @import("../../protocol/types.zig").ZType; // That handler exists because I wanna have control over what is sent to the client const Args = struct { diff --git a/src/server/request_processor.zig b/src/server/processing/requests.zig similarity index 82% rename from src/server/request_processor.zig rename to src/server/processing/requests.zig index e7e52ea..65d6228 100644 --- a/src/server/request_processor.zig +++ b/src/server/processing/requests.zig @@ -1,26 +1,27 @@ const std = @import("std"); -const Context = @import("employer.zig").Context; -const Connection = @import("connection.zig"); -const proto = @import("../protocol/handler.zig"); -const CMDHandler = @import("cmd_handler.zig").CMDHandler; +const Connection = @import("../network/connection.zig"); + +const Logger = @import("../logger.zig"); +const utils = @import("../utils.zig"); -const Logger = @import("logger.zig"); -const errors = @import("err_handler.zig"); -const utils = @import("utils.zig"); +const proto = @import("../../protocol/handler.zig"); +const ZType = @import("../../protocol/types.zig").ZType; -const ZType = @import("../protocol/types.zig").ZType; +const Context = @import("employer.zig").Context; +const commands = @import("commands.zig"); +const errors = @import("errors.zig"); -const RequestProcessor = @This(); +pub const Processor = @This(); -cmd_handler: CMDHandler, +cmd_handler: commands.Handler, context: Context, allocator: std.mem.Allocator, -pub fn init(allocator: std.mem.Allocator, context: Context) RequestProcessor { +pub fn init(allocator: std.mem.Allocator, context: Context) Processor { return .{ - .cmd_handler = CMDHandler.init( + .cmd_handler = commands.Handler.init( allocator, - context.storage, + context.memory, context.logger, ), .context = context, @@ -28,7 +29,7 @@ pub fn init(allocator: std.mem.Allocator, context: Context) RequestProcessor { }; } -pub fn process(self: *RequestProcessor, connection: *Connection) void { +pub fn process(self: *Processor, connection: *Connection) void { var stream = std.io.fixedBufferStream(connection.buffer); var reader = stream.reader(); diff --git a/src/server/worker.zig b/src/server/processing/worker.zig similarity index 91% rename from src/server/worker.zig rename to src/server/processing/worker.zig index b129406..ee5dd6c 100644 --- a/src/server/worker.zig +++ b/src/server/processing/worker.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const Connection = @import("connection.zig"); +const Connection = @import("../network/connection.zig"); const Worker = @This(); diff --git a/src/server/storage.zig b/src/server/storage/memory.zig similarity index 74% rename from src/server/storage.zig rename to src/server/storage/memory.zig index c05cc15..541a4d9 100644 --- a/src/server/storage.zig +++ b/src/server/storage/memory.zig @@ -1,15 +1,14 @@ const std = @import("std"); -const Config = @import("config.zig"); -const types = @import("../protocol/types.zig"); -const TracingAllocator = @import("tracing.zig"); -const PersistanceHandler = @import("persistance.zig").PersistanceHandler; +const types = @import("../../protocol/types.zig"); +const TracingAllocator = @import("../tracing.zig"); +const PersistanceHandler = @import("../storage/persistance.zig").PersistanceHandler; -const Logger = @import("logger.zig"); +const Logger = @import("../logger.zig"); +const Config = @import("../config.zig"); +const utils = @import("../utils.zig"); -const ptrCast = @import("utils.zig").ptrCast; - -const MemoryStorage = @This(); +const Memory = @This(); internal: std.StringHashMap(types.ZType), allocator: std.mem.Allocator, @@ -26,8 +25,8 @@ pub fn init( allocator: std.mem.Allocator, config: Config, persister: *PersistanceHandler, -) MemoryStorage { - return MemoryStorage{ +) Memory { + return Memory{ .internal = std.StringHashMap(types.ZType).init(allocator), .allocator = allocator, .config = config, @@ -37,8 +36,8 @@ pub fn init( }; } -pub fn put(self: *MemoryStorage, key: []const u8, value: types.ZType) !void { - const tracking = ptrCast(TracingAllocator, self.allocator.ptr); +pub fn put(self: *Memory, key: []const u8, value: types.ZType) !void { + const tracking = utils.ptrCast(TracingAllocator, self.allocator.ptr); self.lock.lock(); defer self.lock.unlock(); @@ -58,14 +57,14 @@ pub fn put(self: *MemoryStorage, key: []const u8, value: types.ZType) !void { } } -pub fn get(self: *MemoryStorage, key: []const u8) !types.ZType { +pub fn get(self: *Memory, key: []const u8) !types.ZType { self.lock.lockShared(); defer self.lock.unlock(); return self.internal.get(key) orelse error.NotFound; } -pub fn delete(self: *MemoryStorage, key: []const u8) bool { +pub fn delete(self: *Memory, key: []const u8) bool { self.lock.lock(); defer self.lock.unlock(); @@ -83,7 +82,7 @@ pub fn delete(self: *MemoryStorage, key: []const u8) bool { return true; } -pub fn flush(self: *MemoryStorage) void { +pub fn flush(self: *Memory) void { self.lock.lock(); defer self.lock.unlock(); @@ -99,21 +98,21 @@ pub fn flush(self: *MemoryStorage) void { self.internal.clearRetainingCapacity(); } -pub fn size(self: *MemoryStorage) i64 { +pub fn size(self: *Memory) i64 { self.lock.lockShared(); defer self.lock.unlock(); return self.internal.count(); } -pub fn save(self: *MemoryStorage) !usize { +pub fn save(self: *Memory) !usize { self.lock.lockShared(); defer self.lock.unlock(); return try self.persister.save(self); } -pub fn keys(self: *MemoryStorage) !std.ArrayList(types.ZType) { +pub fn keys(self: *Memory) !std.ArrayList(types.ZType) { self.lock.lockShared(); defer self.lock.unlock(); @@ -128,7 +127,7 @@ pub fn keys(self: *MemoryStorage) !std.ArrayList(types.ZType) { return result; } -pub fn deinit(self: *MemoryStorage) void { +pub fn deinit(self: *Memory) void { var value = .{ .map = self.internal }; types.ztype_free( diff --git a/src/server/persistance.zig b/src/server/storage/persistance.zig similarity index 88% rename from src/server/persistance.zig rename to src/server/storage/persistance.zig index dadf0a4..adcabbf 100644 --- a/src/server/persistance.zig +++ b/src/server/storage/persistance.zig @@ -1,16 +1,16 @@ const std = @import("std"); -const Config = @import("config.zig"); -const MemoryStorage = @import("storage.zig"); +const Config = @import("../config.zig"); +const Memory = @import("memory.zig"); // Context changes -const Serializer = @import("../protocol/deserializer.zig").Deserializer; -const DeserializerT = @import("../protocol/serializer.zig").SerializerT; +const types = @import("../../protocol/types.zig"); +const Serializer = @import("../../protocol/deserializer.zig").Deserializer; +const DeserializerT = @import("../../protocol/serializer.zig").SerializerT; const Deserializer = DeserializerT(std.io.FixedBufferStream([]u8).Reader); -const types = @import("../protocol/types.zig"); -const utils = @import("utils.zig"); -const Logger = @import("logger.zig"); +const utils = @import("../utils.zig"); +const Logger = @import("../logger.zig"); const time = @import("std").time; const DEFAULT_PATH: []const u8 = "./persist/"; @@ -51,7 +51,7 @@ pub fn deinit(self: *PersistanceHandler) void { self.deserializer.deinit(); } -pub fn save(self: *PersistanceHandler, storage: *MemoryStorage) !usize { +pub fn save(self: *PersistanceHandler, memory: *Memory) !usize { var serializer = Serializer.init(self.allocator); defer serializer.deinit(); @@ -61,7 +61,7 @@ pub fn save(self: *PersistanceHandler, storage: *MemoryStorage) !usize { const header = try std.fmt.allocPrint( self.allocator, "zcpf%{d}\r\n", - .{storage.size()}, + .{memory.size()}, ); defer self.allocator.free(header); @@ -90,7 +90,7 @@ pub fn save(self: *PersistanceHandler, storage: *MemoryStorage) !usize { }; defer file.close(); - var iterator = storage.internal.iterator(); + var iterator = memory.internal.iterator(); while (iterator.next()) |item| { const key = try serializer.process(.{ .str = @constCast(item.key_ptr.*) }); try bytes.appendSlice(key); @@ -104,13 +104,13 @@ pub fn save(self: *PersistanceHandler, storage: *MemoryStorage) !usize { defer self.allocator.free(payload); try file.writeAll(payload); - storage.last_save = timestamp; + memory.last_save = timestamp; return payload.len; } // have to load latest file from `self.path` -pub fn load(self: *PersistanceHandler, storage: *MemoryStorage) !void { +pub fn load(self: *PersistanceHandler, memory: *Memory) !void { var dir = try std.fs.cwd().openDir(self.path.?, .{ .no_follow = true, .access_sub_paths = false, @@ -161,7 +161,7 @@ pub fn load(self: *PersistanceHandler, storage: *MemoryStorage) !void { const dot_index: usize = std.mem.indexOf(u8, file_name, ".").?; const str_timestamp: []const u8 = file_name[underscore_index + 1 .. dot_index]; - storage.last_save = try std.fmt.parseInt(i64, str_timestamp, 10); + memory.last_save = try std.fmt.parseInt(i64, str_timestamp, 10); var stream = std.io.fixedBufferStream(buffer[4..buffer.len]); var reader = stream.reader(); @@ -181,7 +181,7 @@ pub fn load(self: *PersistanceHandler, storage: *MemoryStorage) !void { const key = self.deserializer.process(reader) catch return error.InvalidFile; const value = self.deserializer.process(reader) catch return error.InvalidFile; - try storage.put(key.str, value); + try memory.put(key.str, value); } } diff --git a/src/server/utils.zig b/src/server/utils.zig index 04e24b7..a971249 100644 --- a/src/server/utils.zig +++ b/src/server/utils.zig @@ -42,14 +42,6 @@ pub fn timestampf(buff: []u8) usize { return time_len; } -// Checks if the provided network address is present in the given whitelist. -pub fn is_whitelisted(whitelist: std.ArrayList(std.net.Address), addr: std.net.Address) bool { - for (whitelist.items) |whitelisted| { - if (std.meta.eql(whitelisted.any.data[2..].*, addr.any.data[2..].*)) return true; - } - return false; -} - // Converts the provided byte array representing protocol raw data to its string // representation by replacing occurrences of "\r\n" with "\\r\\n". pub fn repr(allocator: std.mem.Allocator, value: []const u8) ![]const u8 { @@ -58,7 +50,3 @@ pub fn repr(allocator: std.mem.Allocator, value: []const u8) ![]const u8 { _ = std.mem.replace(u8, value, "\r\n", "\\r\\n", output); return output; } - -test { - std.testing.refAllDecls(@This()); -} diff --git a/src/test.zig b/src/test.zig index 8fa917c..a85584a 100644 --- a/src/test.zig +++ b/src/test.zig @@ -7,8 +7,8 @@ comptime { _ = @import("tests/protocol/deserializer.zig"); // // server - _ = @import("tests/server/cmd_handler.zig"); - _ = @import("tests/server/err_handler.zig"); + _ = @import("tests/server/commands.zig"); + _ = @import("tests/server/errors.zig"); // // _ = @import("src/server/listener.zig"); _ = @import("tests/server/config.zig"); _ = @import("tests/server/storage.zig"); @@ -17,5 +17,5 @@ comptime { _ = @import("tests/server/logger.zig"); _ = @import("tests/server/utils.zig"); _ = @import("tests/server/persistance.zig"); - _ = @import("tests/server/access_control.zig"); + _ = @import("tests/server/access.zig"); } diff --git a/src/tests/fixtures.zig b/src/tests/fixtures.zig index 065a2a8..cff96dc 100644 --- a/src/tests/fixtures.zig +++ b/src/tests/fixtures.zig @@ -4,8 +4,9 @@ const Logger = @import("../server/logger.zig"); const Config = @import("../server/config.zig"); const TracingAllocator = @import("../server/tracing.zig"); -const PersistanceHandler = @import("../server/persistance.zig").PersistanceHandler; -const MemoryStorage = @import("../server/storage.zig"); + +const PersistanceHandler = @import("../server/storage/persistance.zig"); +const Memory = @import("../server/storage/memory.zig"); pub const ContextFixture = struct { allocator: std.mem.Allocator, @@ -13,7 +14,7 @@ pub const ContextFixture = struct { logger: Logger, config: Config, persistance: ?PersistanceHandler, - memory_storage: ?MemoryStorage, + memory: ?Memory, pub fn init() !ContextFixture { const allocator: std.mem.Allocator = std.testing.allocator; @@ -28,15 +29,15 @@ pub const ContextFixture = struct { .logger = logger, .config = config, .persistance = null, - .memory_storage = null, + .memory = null, }; } - pub fn create_memory_storage(self: *ContextFixture) !void { - if (self.memory_storage != null) self.memory_storage.?.deinit(); + pub fn create_memory(self: *ContextFixture) !void { + if (self.memory != null) self.memory.?.deinit(); if (self.persistance == null) try self.create_persistance(); - self.memory_storage = MemoryStorage.init(self.tracing_allocator.allocator(), self.config, &self.persistance.?); + self.memory = Memory.init(self.tracing_allocator.allocator(), self.config, &self.persistance.?); } pub fn create_persistance(self: *ContextFixture) !void { if (self.persistance != null) self.persistance.?.deinit(); @@ -47,6 +48,6 @@ pub const ContextFixture = struct { pub fn deinit(self: *ContextFixture) void { self.config.deinit(); if (self.persistance != null) self.persistance.?.deinit(); - if (self.memory_storage != null) self.memory_storage.?.deinit(); + if (self.memory != null) self.memory.?.deinit(); } }; diff --git a/src/tests/helper.zig b/src/tests/helper.zig index 92ac586..3db6ab9 100644 --- a/src/tests/helper.zig +++ b/src/tests/helper.zig @@ -1,10 +1,13 @@ const std = @import("std"); -const Config = @import("../server/config.zig"); -const MemoryStorage = @import("../server/storage.zig"); -const PersistanceHandler = @import("../server/persistance.zig").PersistanceHandler; -const CMDHandler = @import("../server/cmd_handler.zig").CMDHandler; +const PersistanceHandler = @import("../server/storage/persistance.zig"); +const Memory = @import("../server/storage/memory.zig"); + +const commands = @import("../server/processing/commands.zig"); + const types = @import("../protocol/types.zig"); + +const Config = @import("../server/config.zig"); const Logger = @import("../server/logger.zig"); const activeTag = std.meta.activeTag; @@ -33,7 +36,7 @@ pub fn setup_map(allocator: std.mem.Allocator) !std.StringHashMap(types.ZType) { return map; } -pub fn setup_storage(storage: *MemoryStorage) !void { +pub fn setup_storage(storage: *Memory) !void { try storage.put("foo", .{ .int = 42 }); try storage.put("foo2", .{ .float = 123.45 }); try storage.put("foo3", .{ .bool = true }); diff --git a/src/tests/server/access_control.zig b/src/tests/server/access.zig similarity index 82% rename from src/tests/server/access_control.zig rename to src/tests/server/access.zig index 0b37d53..577550d 100644 --- a/src/tests/server/access_control.zig +++ b/src/tests/server/access.zig @@ -3,13 +3,13 @@ const std = @import("std"); const fixtures = @import("../fixtures.zig"); const ContextFixture = fixtures.ContextFixture; -const AccessControl = @import("../../server/access_control.zig"); +const AccessMiddleware = @import("../../server/middleware/access.zig"); test "should not return errors" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - const access_control = AccessControl.init(&fixture.config, &fixture.logger); + const access_control = AccessMiddleware.init(&fixture.config, &fixture.logger); const address = std.net.Address.initIp4(.{ 192, 168, 0, 1 }, 1234); const result = access_control.verify(address); try std.testing.expectEqual(result, void{}); @@ -26,7 +26,7 @@ test "should return error.NotPermitted" { fixture.config.whitelist = whitelist; - const access_control = AccessControl.init(&fixture.config, &fixture.logger); + const access_control = AccessMiddleware.init(&fixture.config, &fixture.logger); const address = std.net.Address.initIp4(.{ 192, 168, 0, 1 }, 1234); const result = access_control.verify(address); try std.testing.expectEqual(result, error.NotPermitted); diff --git a/src/tests/server/cmd_handler.zig b/src/tests/server/commands.zig similarity index 69% rename from src/tests/server/cmd_handler.zig rename to src/tests/server/commands.zig index 8d99031..35b9ba9 100644 --- a/src/tests/server/cmd_handler.zig +++ b/src/tests/server/commands.zig @@ -5,14 +5,14 @@ const fixtures = @import("../fixtures.zig"); const ContextFixture = fixtures.ContextFixture; const ZType = @import("../../protocol/types.zig").ZType; -const CMDHandler = @import("../../server/cmd_handler.zig").CMDHandler; +const commands = @import("../../server/processing/commands.zig"); test "should handle SET command" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); - var cmd_handler = CMDHandler.init(fixture.allocator, &fixture.memory_storage.?, &fixture.logger); + var cmd_handler = commands.Handler.init(fixture.allocator, &fixture.memory.?, &fixture.logger); var command_set = std.ArrayList(ZType).init(fixture.allocator); defer command_set.deinit(); @@ -24,15 +24,15 @@ test "should handle SET command" { const result = cmd_handler.process(&command_set); try std.testing.expectEqual(result.ok, ZType{ .sstr = @constCast("OK") }); - try std.testing.expectEqualStrings((try fixture.memory_storage.?.get("key")).str, @constCast("value")); + try std.testing.expectEqualStrings((try fixture.memory.?.get("key")).str, @constCast("value")); } test "should SET return error.InvalidCommand when passed 2 args" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); - var cmd_handler = CMDHandler.init(fixture.allocator, &fixture.memory_storage.?, &fixture.logger); + var cmd_handler = commands.Handler.init(fixture.allocator, &fixture.memory.?, &fixture.logger); var command_set = std.ArrayList(ZType).init(fixture.allocator); defer command_set.deinit(); @@ -48,9 +48,9 @@ test "should SET return error.InvalidCommand when passed 2 args" { test "should SET return error.InvalidCommand when passed 1 args" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); - var cmd_handler = CMDHandler.init(fixture.allocator, &fixture.memory_storage.?, &fixture.logger); + var cmd_handler = commands.Handler.init(fixture.allocator, &fixture.memory.?, &fixture.logger); var command_set = std.ArrayList(ZType).init(fixture.allocator); defer command_set.deinit(); @@ -65,14 +65,14 @@ test "should SET return error.InvalidCommand when passed 1 args" { test "should handle GET command" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); - var cmd_handler = CMDHandler.init(fixture.allocator, &fixture.memory_storage.?, &fixture.logger); + var cmd_handler = commands.Handler.init(fixture.allocator, &fixture.memory.?, &fixture.logger); var command_set = std.ArrayList(ZType).init(fixture.allocator); defer command_set.deinit(); - try fixture.memory_storage.?.put("key", .{ .str = @constCast("value") }); + try fixture.memory.?.put("key", .{ .str = @constCast("value") }); try command_set.append(.{ .str = @constCast("GET") }); try command_set.append(.{ .str = @constCast("key") }); @@ -84,11 +84,11 @@ test "should handle GET command" { test "should SET return error.InvalidCommand when missing key" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); - try fixture.memory_storage.?.put("key", .{ .str = @constCast("value") }); + try fixture.memory.?.put("key", .{ .str = @constCast("value") }); - var cmd_handler = CMDHandler.init(fixture.allocator, &fixture.memory_storage.?, &fixture.logger); + var cmd_handler = commands.Handler.init(fixture.allocator, &fixture.memory.?, &fixture.logger); var command_set = std.ArrayList(ZType).init(fixture.allocator); defer command_set.deinit(); @@ -102,11 +102,11 @@ test "should SET return error.InvalidCommand when missing key" { test "should handle DELETE command" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); - try fixture.memory_storage.?.put("key", .{ .str = @constCast("value") }); + try fixture.memory.?.put("key", .{ .str = @constCast("value") }); - var cmd_handler = CMDHandler.init(fixture.allocator, &fixture.memory_storage.?, &fixture.logger); + var cmd_handler = commands.Handler.init(fixture.allocator, &fixture.memory.?, &fixture.logger); var command_set = std.ArrayList(ZType).init(fixture.allocator); defer command_set.deinit(); @@ -115,16 +115,16 @@ test "should handle DELETE command" { try command_set.append(.{ .str = @constCast("key") }); const result = cmd_handler.process(&command_set); - try std.testing.expectEqual(result, CMDHandler.HandlerResult{ .ok = .{ .sstr = @constCast("OK") } }); - try std.testing.expectEqual(fixture.memory_storage.?.get("key"), error.NotFound); + try std.testing.expectEqual(result, commands.Handler.Result{ .ok = .{ .sstr = @constCast("OK") } }); + try std.testing.expectEqual(fixture.memory.?.get("key"), error.NotFound); } test "should return error.NotFound for non existing during DELETE command" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); - var cmd_handler = CMDHandler.init(fixture.allocator, &fixture.memory_storage.?, &fixture.logger); + var cmd_handler = commands.Handler.init(fixture.allocator, &fixture.memory.?, &fixture.logger); var command_set = std.ArrayList(ZType).init(fixture.allocator); defer command_set.deinit(); @@ -133,17 +133,17 @@ test "should return error.NotFound for non existing during DELETE command" { try command_set.append(.{ .str = @constCast("key") }); const result = cmd_handler.process(&command_set); - try std.testing.expectEqual(result, CMDHandler.HandlerResult{ .err = error.NotFound }); + try std.testing.expectEqual(result, commands.Handler.Result{ .err = error.NotFound }); } test "should DELETE return error.InvalidCommand when missing key" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); - try fixture.memory_storage.?.put("key", .{ .str = @constCast("value") }); + try fixture.memory.?.put("key", .{ .str = @constCast("value") }); - var cmd_handler = CMDHandler.init(fixture.allocator, &fixture.memory_storage.?, &fixture.logger); + var cmd_handler = commands.Handler.init(fixture.allocator, &fixture.memory.?, &fixture.logger); var command_set = std.ArrayList(ZType).init(fixture.allocator); defer command_set.deinit(); @@ -157,11 +157,11 @@ test "should DELETE return error.InvalidCommand when missing key" { test "should handle FLUSH command" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); - try fixture.memory_storage.?.put("key", .{ .str = @constCast("value") }); + try fixture.memory.?.put("key", .{ .str = @constCast("value") }); - var cmd_handler = CMDHandler.init(fixture.allocator, &fixture.memory_storage.?, &fixture.logger); + var cmd_handler = commands.Handler.init(fixture.allocator, &fixture.memory.?, &fixture.logger); var command_set = std.ArrayList(ZType).init(fixture.allocator); defer command_set.deinit(); @@ -170,17 +170,17 @@ test "should handle FLUSH command" { const result = cmd_handler.process(&command_set); try std.testing.expectEqual(result.ok, ZType{ .sstr = @constCast("OK") }); - try std.testing.expectEqual(fixture.memory_storage.?.internal.count(), 0); + try std.testing.expectEqual(fixture.memory.?.internal.count(), 0); } test "should handle PING command" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); - try fixture.memory_storage.?.put("key", .{ .str = @constCast("value") }); + try fixture.memory.?.put("key", .{ .str = @constCast("value") }); - var cmd_handler = CMDHandler.init(fixture.allocator, &fixture.memory_storage.?, &fixture.logger); + var cmd_handler = commands.Handler.init(fixture.allocator, &fixture.memory.?, &fixture.logger); var command_set = std.ArrayList(ZType).init(fixture.allocator); defer command_set.deinit(); @@ -194,11 +194,11 @@ test "should handle PING command" { test "should handle DBSIZE command" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); - try fixture.memory_storage.?.put("key", .{ .str = @constCast("value") }); + try fixture.memory.?.put("key", .{ .str = @constCast("value") }); - var cmd_handler = CMDHandler.init(fixture.allocator, &fixture.memory_storage.?, &fixture.logger); + var cmd_handler = commands.Handler.init(fixture.allocator, &fixture.memory.?, &fixture.logger); var command_set = std.ArrayList(ZType).init(fixture.allocator); defer command_set.deinit(); @@ -212,12 +212,12 @@ test "should handle DBSIZE command" { test "should handle MGET command" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); - try fixture.memory_storage.?.put("key", .{ .str = @constCast("value") }); - try fixture.memory_storage.?.put("key2", .{ .str = @constCast("value2") }); + try fixture.memory.?.put("key", .{ .str = @constCast("value") }); + try fixture.memory.?.put("key2", .{ .str = @constCast("value2") }); - var cmd_handler = CMDHandler.init(fixture.allocator, &fixture.memory_storage.?, &fixture.logger); + var cmd_handler = commands.Handler.init(fixture.allocator, &fixture.memory.?, &fixture.logger); var command_set = std.ArrayList(ZType).init(fixture.allocator); defer command_set.deinit(); @@ -239,9 +239,9 @@ test "should handle MGET command" { test "should handle MSET command" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); - var cmd_handler = CMDHandler.init(fixture.allocator, &fixture.memory_storage.?, &fixture.logger); + var cmd_handler = commands.Handler.init(fixture.allocator, &fixture.memory.?, &fixture.logger); var command_set = std.ArrayList(ZType).init(fixture.allocator); defer command_set.deinit(); @@ -253,15 +253,15 @@ test "should handle MSET command" { const result = cmd_handler.process(&command_set); try std.testing.expectEqual(result.ok, ZType{ .sstr = @constCast("OK") }); - try std.testing.expectEqualStrings((try fixture.memory_storage.?.get("key")).str, command_set.items[2].str); + try std.testing.expectEqualStrings((try fixture.memory.?.get("key")).str, command_set.items[2].str); } test "should handle MSET return InvalidArgs when empty" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); - var cmd_handler = CMDHandler.init(fixture.allocator, &fixture.memory_storage.?, &fixture.logger); + var cmd_handler = commands.Handler.init(fixture.allocator, &fixture.memory.?, &fixture.logger); var command_set = std.ArrayList(ZType).init(fixture.allocator); defer command_set.deinit(); @@ -276,9 +276,9 @@ test "should handle MSET return InvalidArgs when empty" { test "should handle MSET and return InvalidArgs when not even" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); - var cmd_handler = CMDHandler.init(fixture.allocator, &fixture.memory_storage.?, &fixture.logger); + var cmd_handler = commands.Handler.init(fixture.allocator, &fixture.memory.?, &fixture.logger); var command_set = std.ArrayList(ZType).init(fixture.allocator); defer command_set.deinit(); @@ -294,9 +294,9 @@ test "should handle MSET and return InvalidArgs when not even" { test "should handle MSET and return KeyNotString" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); - var cmd_handler = CMDHandler.init(fixture.allocator, &fixture.memory_storage.?, &fixture.logger); + var cmd_handler = commands.Handler.init(fixture.allocator, &fixture.memory.?, &fixture.logger); var command_set = std.ArrayList(ZType).init(fixture.allocator); defer command_set.deinit(); @@ -313,12 +313,12 @@ test "should handle MSET and return KeyNotString" { test "should handle KEYS command" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); - try fixture.memory_storage.?.put("key", .{ .str = @constCast("value") }); - try fixture.memory_storage.?.put("key2", .{ .str = @constCast("value2") }); + try fixture.memory.?.put("key", .{ .str = @constCast("value") }); + try fixture.memory.?.put("key2", .{ .str = @constCast("value2") }); - var cmd_handler = CMDHandler.init(fixture.allocator, &fixture.memory_storage.?, &fixture.logger); + var cmd_handler = commands.Handler.init(fixture.allocator, &fixture.memory.?, &fixture.logger); var command_set = std.ArrayList(ZType).init(fixture.allocator); defer command_set.deinit(); @@ -340,9 +340,9 @@ test "should handle KEYS command" { test "should handle KEYS command no data in storage" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); - var cmd_handler = CMDHandler.init(fixture.allocator, &fixture.memory_storage.?, &fixture.logger); + var cmd_handler = commands.Handler.init(fixture.allocator, &fixture.memory.?, &fixture.logger); var command_set = std.ArrayList(ZType).init(fixture.allocator); defer command_set.deinit(); @@ -362,11 +362,11 @@ test "should handle KEYS command no data in storage" { test "should handle LASTSAVE command" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); - const expected: i64 = fixture.memory_storage.?.last_save; + const expected: i64 = fixture.memory.?.last_save; - var cmd_handler = CMDHandler.init(fixture.allocator, &fixture.memory_storage.?, &fixture.logger); + var cmd_handler = commands.Handler.init(fixture.allocator, &fixture.memory.?, &fixture.logger); var command_set = std.ArrayList(ZType).init(fixture.allocator); defer command_set.deinit(); @@ -380,9 +380,9 @@ test "should handle LASTSAVE command" { test "should SAVE return error.SaveFailure when there is no data" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); - var cmd_handler = CMDHandler.init(fixture.allocator, &fixture.memory_storage.?, &fixture.logger); + var cmd_handler = commands.Handler.init(fixture.allocator, &fixture.memory.?, &fixture.logger); var command_set = std.ArrayList(ZType).init(fixture.allocator); defer command_set.deinit(); diff --git a/src/tests/server/config.zig b/src/tests/server/config.zig index fc8b4f2..66c9a37 100644 --- a/src/tests/server/config.zig +++ b/src/tests/server/config.zig @@ -1,7 +1,7 @@ const std = @import("std"); const Config = @import("../../server/config.zig"); -const DEFAULT_PATH = @import("../../server/config.zig").DEFAULT_PATH; +const DEFAULT_PATH = Config.DEFAULT_PATH; test "config default values ipv4" { var config = try Config.load(std.testing.allocator, null, null); diff --git a/src/tests/server/err_handler.zig b/src/tests/server/errors.zig similarity index 81% rename from src/tests/server/err_handler.zig rename to src/tests/server/errors.zig index 1e65614..a1e172e 100644 --- a/src/tests/server/err_handler.zig +++ b/src/tests/server/errors.zig @@ -4,14 +4,14 @@ const ZType = @import("../../protocol/types.zig").ZType; const BUFF_SIZE: u8 = 150; -const err_handler = @import("../../server/err_handler.zig"); +const errors = @import("../../server/processing/errors.zig"); test "BadRequest" { var buffer: [BUFF_SIZE]u8 = undefined; var stream = std.io.fixedBufferStream(&buffer); var logger = try Logger.init(std.testing.allocator, null, false); - try err_handler.handle(&stream, error.BadRequest, .{}, &logger); + try errors.handle(&stream, error.BadRequest, .{}, &logger); const expected: []u8 = @constCast("-ERR bad request\r\n"); @@ -26,8 +26,8 @@ test "UnknownCommand" { var array = std.ArrayList(ZType).initCapacity(std.testing.allocator, 0) catch { return error.AllocatorError; }; - const args = err_handler.build_args(&array); - try err_handler.handle(&stream, error.UnknownCommand, args, &logger); + const args = errors.build_args(&array); + try errors.handle(&stream, error.UnknownCommand, args, &logger); const expected: []u8 = @constCast("-ERR unknown command\r\n"); @@ -45,8 +45,8 @@ test "UnknownCommand with command name" { try array.append(.{ .str = @constCast("help") }); defer array.deinit(); - const args = err_handler.build_args(&array); - try err_handler.handle(&stream, error.UnknownCommand, args, &logger); + const args = errors.build_args(&array); + try errors.handle(&stream, error.UnknownCommand, args, &logger); try std.testing.expectFmt( stream.getWritten(), @@ -60,7 +60,7 @@ test "unexpected error" { var stream = std.io.fixedBufferStream(&buffer); var logger = try Logger.init(std.testing.allocator, null, false); - try err_handler.handle(&stream, error.Unexpected, .{}, &logger); + try errors.handle(&stream, error.Unexpected, .{}, &logger); const expected: []u8 = @constCast("-ERR unexpected\r\n"); @@ -72,7 +72,7 @@ test "max clients reached" { var stream = std.io.fixedBufferStream(&buffer); var logger = try Logger.init(std.testing.allocator, null, false); - try err_handler.handle(&stream, error.MaxClientsReached, .{}, &logger); + try errors.handle(&stream, error.MaxClientsReached, .{}, &logger); const expected: []u8 = @constCast("-ERR max number of clients reached\r\n"); @@ -91,8 +91,8 @@ test "NotFound with key name" { try array.append(.{ .str = @constCast("user_cache_12345") }); defer array.deinit(); - const args = err_handler.build_args(&array); - try err_handler.handle(&stream, error.NotFound, args, &logger); + const args = errors.build_args(&array); + try errors.handle(&stream, error.NotFound, args, &logger); try std.testing.expectFmt( stream.getWritten(), diff --git a/src/tests/server/persistance.zig b/src/tests/server/persistance.zig index fb3fbd0..1725d7f 100644 --- a/src/tests/server/persistance.zig +++ b/src/tests/server/persistance.zig @@ -9,19 +9,19 @@ test "should load" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); fixture.persistance.?.path = "./tmp/persist/"; - try std.testing.expectEqual(fixture.memory_storage.?.internal.count(), 0); + try std.testing.expectEqual(fixture.memory.?.internal.count(), 0); const file_content = "zcpf%4\r\n$5\r\ntest2\r\n$8\r\ntesttest\r\n$5\r\ntest1\r\n$8\r\ntesttest\r\n$5\r\ntest3\r\n$8\r\ntesttest\r\n$5\r\ntest4\r\n$8\r\ntesttest\r\n"; const file = try std.fs.cwd().createFile("./tmp/persist/dump_123.zcpf", .{}); try file.writeAll(file_content); defer file.close(); - try fixture.persistance.?.load(&fixture.memory_storage.?); + try fixture.persistance.?.load(&fixture.memory.?); - try std.testing.expectEqual(fixture.memory_storage.?.internal.count(), 4); + try std.testing.expectEqual(fixture.memory.?.internal.count(), 4); std.fs.cwd().deleteFile("./tmp/persist/dump_123.zcpf") catch {}; std.fs.cwd().deleteDir("./tmp/persist") catch {}; @@ -32,19 +32,19 @@ test "should not load without header" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); fixture.persistance.?.path = "./tmp/persist/without_header/"; std.fs.cwd().makeDir("./tmp/persist/without_header") catch {}; - try std.testing.expectEqual(fixture.memory_storage.?.internal.count(), 0); + try std.testing.expectEqual(fixture.memory.?.internal.count(), 0); const file_content = "%4\r\n$5\r\ntest2\r\n$8\r\ntesttest\r\n$5\r\ntest1\r\n$8\r\ntesttest\r\n$5\r\ntest3\r\n$8\r\ntesttest\r\n$5\r\ntest4\r\n$8\r\ntesttest"; const file = try std.fs.cwd().createFile("./tmp/persist/without_header/dump_123.zcpf", .{}); try file.writeAll(file_content); defer file.close(); - try std.testing.expectEqual(fixture.persistance.?.load(&fixture.memory_storage.?), error.InvalidFile); + try std.testing.expectEqual(fixture.persistance.?.load(&fixture.memory.?), error.InvalidFile); std.fs.cwd().deleteFile("./tmp/persist/without_header/dump_123.zcpf") catch {}; std.fs.cwd().deleteDir("./tmp/persist") catch {}; @@ -55,19 +55,19 @@ test "should not load invalid ext" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); fixture.persistance.?.path = "./tmp/persist/invalid_ext/"; std.fs.cwd().makeDir("./tmp/persist/invalid_ext") catch {}; - try std.testing.expectEqual(fixture.memory_storage.?.internal.count(), 0); + try std.testing.expectEqual(fixture.memory.?.internal.count(), 0); const file_content = "%4\r\n$5\r\ntest2\r\n$8\r\ntesttest\r\n$5\r\ntest1\r\n$8\r\ntesttest\r\n$5\r\ntest3\r\n$8\r\ntesttest\r\n$5\r\ntest4\r\n$8\r\ntesttest"; const file = try std.fs.cwd().createFile("./tmp/persist/invalid_ext/dump_latest_123.asdf", .{}); try file.writeAll(file_content); defer file.close(); - try std.testing.expectEqual(fixture.persistance.?.load(&fixture.memory_storage.?), error.InvalidFile); + try std.testing.expectEqual(fixture.persistance.?.load(&fixture.memory.?), error.InvalidFile); std.fs.cwd().deleteFile("./tmp/persist/invalid_ext/dump_123.asdf") catch {}; std.fs.cwd().deleteDir("./tmp/persist") catch {}; @@ -78,19 +78,19 @@ test "should not load corrupted file" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); fixture.persistance.?.path = "./tmp/persist/corrupted/"; std.fs.cwd().makeDir("./tmp/persist/corrupted") catch {}; - try std.testing.expectEqual(fixture.memory_storage.?.internal.count(), 0); + try std.testing.expectEqual(fixture.memory.?.internal.count(), 0); const file_content = "%4\r\n$5test2\r\n$4\r\ntesttest\r\n$5\r\ntest1\r\n$8\r\ntesttest\r\n$5\r\ntest3\r\n$8\r\ntesttest\r\n$5\r\ntest4\r\n$8\r\ntesttest"; const file = try std.fs.cwd().createFile("./tmp/persist/corrupted/dump_123.asdf", .{}); try file.writeAll(file_content); defer file.close(); - try std.testing.expectEqual(fixture.persistance.?.load(&fixture.memory_storage.?), error.InvalidFile); + try std.testing.expectEqual(fixture.persistance.?.load(&fixture.memory.?), error.InvalidFile); std.fs.cwd().deleteFile("./tmp/persist/corrupted/dump_123.asdf") catch {}; std.fs.cwd().deleteDir("./tmp/persist") catch {}; @@ -101,14 +101,14 @@ test "should save" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); - try fixture.memory_storage.?.put("test1", .{ .str = @constCast("testtest") }); - try fixture.memory_storage.?.put("test2", .{ .str = @constCast("testtest") }); - try fixture.memory_storage.?.put("test3", .{ .str = @constCast("testtest") }); - try fixture.memory_storage.?.put("test4", .{ .str = @constCast("testtest") }); + try fixture.memory.?.put("test1", .{ .str = @constCast("testtest") }); + try fixture.memory.?.put("test2", .{ .str = @constCast("testtest") }); + try fixture.memory.?.put("test3", .{ .str = @constCast("testtest") }); + try fixture.memory.?.put("test4", .{ .str = @constCast("testtest") }); - const result = try fixture.persistance.?.save(&fixture.memory_storage.?); + const result = try fixture.persistance.?.save(&fixture.memory.?); try std.testing.expectEqual(result, 108); diff --git a/src/tests/server/storage.zig b/src/tests/server/storage.zig index 28567c0..7296564 100644 --- a/src/tests/server/storage.zig +++ b/src/tests/server/storage.zig @@ -9,94 +9,94 @@ const helper = @import("../helper.zig"); test "should get existing and not get non-existing key" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); - try helper.setup_storage(&fixture.memory_storage.?); + try helper.setup_storage(&fixture.memory.?); - try std.testing.expectEqual(fixture.memory_storage.?.get("foo"), types.ZType{ .int = 42 }); - try std.testing.expectEqual(fixture.memory_storage.?.get("foo2"), types.ZType{ .float = 123.45 }); - try std.testing.expectEqual(fixture.memory_storage.?.get("foo3"), types.ZType{ .bool = true }); - try std.testing.expectEqual(fixture.memory_storage.?.get("foo4"), types.ZType{ .null = void{} }); + try std.testing.expectEqual(fixture.memory.?.get("foo"), types.ZType{ .int = 42 }); + try std.testing.expectEqual(fixture.memory.?.get("foo2"), types.ZType{ .float = 123.45 }); + try std.testing.expectEqual(fixture.memory.?.get("foo3"), types.ZType{ .bool = true }); + try std.testing.expectEqual(fixture.memory.?.get("foo4"), types.ZType{ .null = void{} }); // we have to compare values cause it's not same place in memory - try std.testing.expectEqualStrings((try fixture.memory_storage.?.get("foo5")).sstr, helper.SIMPLE_STRING); - try std.testing.expectEqualStrings((try fixture.memory_storage.?.get("bar")).str, helper.STRING); + try std.testing.expectEqualStrings((try fixture.memory.?.get("foo5")).sstr, helper.SIMPLE_STRING); + try std.testing.expectEqualStrings((try fixture.memory.?.get("bar")).str, helper.STRING); // array var array = try helper.setup_array(fixture.allocator); defer array.deinit(); - try fixture.memory_storage.?.put("foo6", .{ .array = array }); + try fixture.memory.?.put("foo6", .{ .array = array }); - const getted = try fixture.memory_storage.?.get("foo6"); + const getted = try fixture.memory.?.get("foo6"); try helper.expectEqualZTypes(getted, .{ .array = array }); // map var map = try helper.setup_map(fixture.allocator); defer map.deinit(); - try fixture.memory_storage.?.put("foo7", .{ .map = map }); + try fixture.memory.?.put("foo7", .{ .map = map }); - const getted_map = try fixture.memory_storage.?.get("foo7"); + const getted_map = try fixture.memory.?.get("foo7"); try helper.expectEqualZTypes(getted_map, .{ .map = map }); - try std.testing.expectEqual(fixture.memory_storage.?.get("baz"), error.NotFound); + try std.testing.expectEqual(fixture.memory.?.get("baz"), error.NotFound); } test "should delete existing key" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); const string = "Die meisten Menschen sind nichts als Bauern auf einem Schachbrett, das von einer unbekannten Hand geführt wird."; const value: types.ZType = .{ .str = @constCast(string) }; - try fixture.memory_storage.?.put("foo", .{ .int = 42 }); - try fixture.memory_storage.?.put("bar", value); + try fixture.memory.?.put("foo", .{ .int = 42 }); + try fixture.memory.?.put("bar", value); - try std.testing.expectEqual(fixture.memory_storage.?.delete("foo"), true); - try std.testing.expectEqual(fixture.memory_storage.?.get("foo"), error.NotFound); - try std.testing.expectEqualStrings((try fixture.memory_storage.?.get("bar")).str, value.str); + try std.testing.expectEqual(fixture.memory.?.delete("foo"), true); + try std.testing.expectEqual(fixture.memory.?.get("foo"), error.NotFound); + try std.testing.expectEqualStrings((try fixture.memory.?.get("bar")).str, value.str); } test "should not delete non-existing key" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); - try std.testing.expectEqual(fixture.memory_storage.?.delete("foo"), false); + try std.testing.expectEqual(fixture.memory.?.delete("foo"), false); } test "should flush storage" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); const string = "Es gibt Momente im Leben, da muss man verstehen, dass die Entscheidungen, die man trifft, nicht nur das eigene Schicksal angehen."; const value: types.ZType = .{ .str = @constCast(string) }; - try fixture.memory_storage.?.put("foo", .{ .int = 42 }); - try fixture.memory_storage.?.put("bar", value); + try fixture.memory.?.put("foo", .{ .int = 42 }); + try fixture.memory.?.put("bar", value); - fixture.memory_storage.?.flush(); + fixture.memory.?.flush(); - try std.testing.expectEqual(fixture.memory_storage.?.get("foo"), error.NotFound); - try std.testing.expectEqual(fixture.memory_storage.?.get("bar"), error.NotFound); + try std.testing.expectEqual(fixture.memory.?.get("foo"), error.NotFound); + try std.testing.expectEqual(fixture.memory.?.get("bar"), error.NotFound); } test "should not store error" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); const err_value = .{ .err = .{ .message = "random error" } }; - try std.testing.expectEqual(fixture.memory_storage.?.put("test", err_value), error.CantInsertError); + try std.testing.expectEqual(fixture.memory.?.put("test", err_value), error.CantInsertError); } test "should return error.MemoryLimitExceeded" { var fixture = try ContextFixture.init(); defer fixture.deinit(); fixture.config.maxmemory = 1048576; - try fixture.create_memory_storage(); + try fixture.create_memory(); var arena = std.heap.ArenaAllocator.init(fixture.allocator); defer arena.deinit(); @@ -105,16 +105,16 @@ test "should return error.MemoryLimitExceeded" { const value: types.ZType = .{ .str = @constCast(string) }; for (0..6554) |i| { const key = try std.fmt.allocPrint(arena.allocator(), "key-{d}", .{i}); - try fixture.memory_storage.?.put(key, value); + try fixture.memory.?.put(key, value); } - try std.testing.expectEqual(fixture.memory_storage.?.put("test key", value), error.MemoryLimitExceeded); + try std.testing.expectEqual(fixture.memory.?.put("test key", value), error.MemoryLimitExceeded); } test "should not return error.MemoryLimitExceed when max but deleted some" { var fixture = try ContextFixture.init(); defer fixture.deinit(); - try fixture.create_memory_storage(); + try fixture.create_memory(); fixture.config.maxmemory = 1048576; @@ -127,10 +127,10 @@ test "should not return error.MemoryLimitExceed when max but deleted some" { const value: types.ZType = .{ .str = @constCast(string) }; for (0..1) |i| { const key = try std.fmt.allocPrint(arena.allocator(), "key-{d}", .{i}); - try fixture.memory_storage.?.put(key, value); + try fixture.memory.?.put(key, value); } - const result = fixture.memory_storage.?.put("test key", value); + const result = fixture.memory.?.put("test key", value); try std.testing.expectEqual(void{}, result); } diff --git a/src/tests/server/utils.zig b/src/tests/server/utils.zig index 23f032f..4919f15 100644 --- a/src/tests/server/utils.zig +++ b/src/tests/server/utils.zig @@ -67,88 +67,6 @@ test "timestampf should format current time correctly" { try std.testing.expectEqualStrings(ex_buffer[0..time_len], actual); } -test "is_whitelisted should return true for whitelisted address ipv4" { - var whitelist = std.ArrayList(std.net.Address).init(std.testing.allocator); - const whitelisted = std.net.Address.initIp4(.{ 127, 0, 0, 1 }, 7556); - defer whitelist.deinit(); - - try whitelist.append(whitelisted); - - const addrToCheck = std.net.Address.initIp4(.{ 127, 0, 0, 1 }, 7556); - - try std.testing.expectEqual(true, utils.is_whitelisted(whitelist, addrToCheck)); -} - -test "is_whitelisted should return true for whitelisted address ipv4 if different port" { - var whitelist = std.ArrayList(std.net.Address).init(std.testing.allocator); - const whitelisted = std.net.Address.initIp4(.{ 127, 0, 0, 1 }, 7556); - defer whitelist.deinit(); - - try whitelist.append(whitelisted); - - const addrToCheck = std.net.Address.initIp4(.{ 127, 0, 0, 1 }, 7558); - - try std.testing.expectEqual(true, utils.is_whitelisted(whitelist, addrToCheck)); -} - -test "is_whitelisted should return false for non whitelisted address ipv4" { - var whitelist = std.ArrayList(std.net.Address).init(std.testing.allocator); - const whitelisted = std.net.Address.initIp4(.{ 127, 0, 0, 5 }, 7556); - defer whitelist.deinit(); - - try whitelist.append(whitelisted); - - const addrToCheck = std.net.Address.initIp4(.{ 127, 0, 0, 1 }, 7556); - - try std.testing.expectEqual(false, utils.is_whitelisted(whitelist, addrToCheck)); -} - -test "is_whitelisted should return true for whitelisted address ipv6" { - const addr = .{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; - - var whitelist = std.ArrayList(std.net.Address).init(std.testing.allocator); - const whitelisted = std.net.Address.initIp6(addr, 1234, 0, 0); - defer whitelist.deinit(); - - try whitelist.append(whitelisted); - - const addrToCheck = std.net.Address.initIp6(addr, 1234, 0, 0); - - try std.testing.expectEqual(true, utils.is_whitelisted(whitelist, addrToCheck)); -} - -test "is_whitelisted should return true for whitelisted address ipv6 if different port" { - const addr = .{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; - - var whitelist = std.ArrayList(std.net.Address).init(std.testing.allocator); - const whitelisted = std.net.Address.initIp6(addr, 1234, 0, 0); - defer whitelist.deinit(); - - try whitelist.append(whitelisted); - - const addrToCheck = std.net.Address.initIp6(addr, 7556, 0, 0); - - try std.testing.expectEqual(true, utils.is_whitelisted(whitelist, addrToCheck)); -} - -test "is_whitelisted should return fallse for non whitelisted address ipv6" { - const addr = .{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; - - var whitelist = std.ArrayList(std.net.Address).init(std.testing.allocator); - const whitelisted = std.net.Address.initIp6( - .{ 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 }, - 1234, - 0, - 0, - ); - defer whitelist.deinit(); - - try whitelist.append(whitelisted); - - const addrToCheck = std.net.Address.initIp6(addr, 1234, 0, 0); - - try std.testing.expectEqual(false, utils.is_whitelisted(whitelist, addrToCheck)); -} test "repr" { const expected: []const u8 = "Hello\\r\\nWorld"; const input: []const u8 = "Hello\r\nWorld";