当前位置: 首页 > news >正文

【4. 搭建基础设施】:创建目录结构、数据库初始化脚本、配置管理模块、.gitignore,安装测试框架 gtest,实现日志封装、数据库连接池

目录

1. 创建项目目录结构

2. 创建数据库初始化脚本

3. 创建配置管理模块

3.1 yaml

4. 测试框架 gtest

4.1 认识“单元测试”

4.2 安装 gtest

4.3 生成单元测试

5. 配置 .gitignore

6. 日志封装

7. 数据库连接池实现


1. 创建项目目录结构

@SPEC.md 请按照文档中 "Phase 1" 描述,先进行 "项目目录结构搭建" 操作。具体的目录结构请 按照 "6 项目目录结构" 的描述来构建。此处只是创建目录结构和空文件,暂时不编写文件的具体 内容。

此时,opencode 就会按照SPEC.md 中描述的目录结构,进行创建。

  • 通过mkdir 创建一系列的目录
  • 通过touch 创建一系列的空文件

当opencode 完成创建后,还会自主使用ls 命令检查当前的目录结构是否正确。

完成之后,和之前一样,记得提交一个git版本并推送。

每完成一个Phase,都可以提示AI修改SPEC.md,把对应的任务标记成完成。

2. 创建数据库初始化脚本

@SPEC.md 请按照文档中 Phase 1 中的描述,进行完成 "MySQL 数据库初始化脚本" 工作。具体需要创建的表结构,参考 "## 4. 数据库 Schema " 章节。

AI根据提示词,先编写init.sql 脚本

-- 创建数据库 CREATE DATABASE IF NOT EXISTS oj_system DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE oj_system; -- 用户表:存储用户账号、密码哈希、角色 CREATE TABLE IF NOT EXISTS users ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, password_hash VARCHAR(255) NOT NULL, role ENUM('user', 'admin') NOT NULL DEFAULT 'user', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, INDEX idx_username (username) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 题目表:存储题目基本信息、难度、资源限制 CREATE TABLE IF NOT EXISTS problems ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, title VARCHAR(200) NOT NULL, description TEXT NOT NULL, difficulty ENUM('easy', 'medium', 'hard') NOT NULL DEFAULT 'medium', time_limit_ms INT UNSIGNED NOT NULL DEFAULT 1000, memory_limit_mb INT UNSIGNED NOT NULL DEFAULT 256, created_by BIGINT UNSIGNED NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, INDEX idx_created_by (created_by), FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 测试用例表:存储题目输入输出、是否示例 CREATE TABLE IF NOT EXISTS testcases ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, problem_id BIGINT UNSIGNED NOT NULL, input TEXT NOT NULL, expected_output TEXT NOT NULL, is_sample BOOLEAN NOT NULL DEFAULT FALSE, INDEX idx_problem_id (problem_id), FOREIGN KEY (problem_id) REFERENCES problems(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 提交记录表:存储代码提交、判题状态、执行资源消耗 CREATE TABLE IF NOT EXISTS submissions ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, user_id BIGINT UNSIGNED NOT NULL, problem_id BIGINT UNSIGNED NOT NULL, code TEXT NOT NULL, language VARCHAR(20) NOT NULL, status ENUM('pending', 'compiling', 'running', 'accepted', 'wrong_answer', 'time_limit_exceeded', 'memory_limit_exceeded', 'runtime_error', 'compile_error') NOT NULL DEFAULT 'pending', error_msg TEXT, execution_time_ms INT UNSIGNED, execution_memory_kb INT UNSIGNED, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, INDEX idx_user_id (user_id), INDEX idx_problem_id (problem_id), INDEX idx_status (status), FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, FOREIGN KEY (problem_id) REFERENCES problems(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

注意,此时仅仅是生成了数据库脚本,并没有真正执行,此时的数据库也是空的数据库。我们可以另外起一个终端,登陆到数据库上检查。接下来,可以直接让opencode 来执行这个数据库初始化脚本。

这个过程中,opencode 执行的多个操作,均因为没有 root 权限而失败。
我们可以通过 root 用户运行 opencode 权限,或者把当前用户添加到 sudoers 中解决这个问题,但是这样做并不合适。LLM 返回的结果可能是“有幻觉”的。万一返回了一些危险命令(比如 rm -rf / ),并直接执行了,在 root 用户下造成的后果会非常严重。

完成上述配置后,我们可以让opencode 总结下数据库访问方式,以备后续开发中使用。

把当前数据库的访问方式(用户名密码) 总结写入到 @SPEC.md 中

## 3. 数据库配置 **连接方式**: ```bash mysql -u wsj -p'' ``` **数据库信息**: - 用户名:`wsj` - 密码:(空) - Socket:`/var/run/mysqld/mysqld.sock` - 数据库名:`oj_system` ---

3. 创建配置管理模块

@SPEC.md 请开发 Phase 1 这里的“配置管理”功能。相关的代码编写在 @src/utils/config.cc 中

此时 opencode 就会按照要求,完成下列工作:

  • 在 config.h 和 config.cc 中编写代码进行实现。
  • 修改 CMakeLists.txt,增加编译相关配置
  • 生成 config.yaml 作为配置模板。

生成的代码核心是 ConfigManager 单例类,以单例模式的方式进行配置的解析管理。

# OJ 系统配置文件 # 数据库配置 database: host: "localhost" username: "wsj" password: "" name: "oj_system" socket: "/var/run/mysqld/mysqld.sock" # 服务器配置 server: host: "0.0.0.0" port: 8080 # 判题配置 judger: # 代码存放目录 work_dir: "/tmp/oj-judger" # 默认时间限制(毫秒) default_time_limit_ms: 2000 # 默认内存限制(MB) default_memory_limit_mb: 256 # 日志配置 logger: # 日志级别: trace, debug, info, warn, error, critical level: "info" # 日志输出目录 dir: "logs" # 控制台输出 console: true

3.1 yaml

yaml 是当前一种流行的配置文件组织格式,格式以“缩进”方式来组织处一个“树形结构”,每一级缩进都相当于一个“子树”,每个树的节点都是一个“键值对”,形如下列形式:

server: host: 0.0.0.0 port: 8080 thread_pool_size: 4 database: host: localhost port: 3306 username: wsj password: database: oj_system max_connections: 10

4. 测试框架 gtest

当然,光靠肉眼来观察代码,不足以验证代码的正确性。我们还可以通过“单元测试”的方式,来对代码进行进一步验证。

4.1 认识“单元测试”

一个项目整体的“正确”,意味着项目中的每个模块,每个部分都是正确的。
与其等待整个项目开发完,再验证正确,不如每开发一个模块,都先验证下这个模块是否正确。
这个针对模块验证的过程,就是“单元测试”。这是在开发中一种常见的测试方式。


在 C++ 中,编写单元测试不必从头开始。google 提供了 google test(简称 gtest)框架,可以让我们更方便的完成单元测试。

4.2 安装 gtest

sudo apt install libgtest-dev

4.3 生成单元测试

针对上述配置管理功能的开发,基于 gtest 设计单元测试用例。相关代码存放在 @tests/unit/ 目录中。

此时,opencode 会进行下列操作:

  • 编写单元测试代码
  • 修改 CMakeLists.txt,添加针对单元测试程序的编译选项。
  • 编译,并修改编译报错。
  • 运行,并修改失败的用例。

AI虽然功能很强,但是也不是无所不能。我们仍然要对AI生成的结果进行检查验证,对于不符合要求的地方,要能够给出及时的提示和修正。

5. 配置 .gitignore

这一次进行提交 git 版本时,我们发现,要提交的内容突然变很多。

仔细观察发现,这些文件,都是 cmake 构建过程中,生成的临时文件。这些临时文件原则上是不需要提交到 git 中。

只要有 CMakeLists.txt 这一个配置文件,都是随时可以生成出上述临时文件的。

如何避免提交这些临时文件呢?可以通过 git 内置的功能,.gitignore 来实现。

.gitignore 是一个纯文本文件。我们可以在项目的根目录中创建出这个文件

文件的内容按行组织,每一行描述了要忽略一类文件,针对上述的临时文件来说,他们都是处于“build”目录下的,因此直接在 .gitignore 中编写

build/

此时,这些临时文件就不会被加入到 git 仓库中了。使用 .gitignore 是开发中的一个良好习惯。确保只提交项目真正关键的代码/配置文件即可。

6. 日志封装

日志是一个系统中的重要环节,是程序员定位问题的重要手段,相比于“断点调试”来说,日志的普适性是更强的,断点一旦把程序“断住”,其实影响到了程序原有的执行逻辑。在一个已经改变的逻辑上定位问题,本身已经未必“靠谱”了,相比之下,日志对于程序的侵入性更小,能更好的还原出现问题的线索。

提示词:

@SPEC.md 请按照“Phase 1”中“日志封装”这样的部分,来进行开发。代码放到 @backend/logger/logger.cpp 中。

AI 按照提示词,很快完成开发。封装好的日志会支持日志级别(ERROR、WARNING、INFO、DEBUG 等)。和前面类似,同样可以针对日志生成测试用例,进行验证。

此时,opencode 会按照要求,设计测试用例,编译,调试测试用例通过。

根据上述编写的代码,基于 gtest 设计测试用例。测试用例代码放到 @tests/unit/ 目录中。

7. 数据库连接池实现

opencode 会按照要求,开始进行开发,开发出来的连接池:

  • 对 mysql 原生 API 进行了封装,简化了使用
  • 提前创建好多个连接,后续代码需要使用数据库连接时直接从池子中获取
  • 考虑到了线程安全,在合理位置进行加锁

@SPEC.md 根据文档描述,完成“Phase1”中的“数据库连接池实现”,实现的代码放到 @backend/repository/db_pool.cpp 中。

开发完毕之后,和前面一样,让 opencode 编写单元测试。

对上述的数据库连接池,设计单元测试用例,基于 gtest 实现。代码放在 @tests/unit/ 中

http://www.cnnetsun.cn/news/3781991.html

相关文章:

  • TSB技能编辑器实战:可视化设计游戏角色技能与优化
  • 5款零代码AI工具推荐:非技术人员也能快速搭建智能助手
  • 如何与头部连锁商超高效对接?供应商须打通从订单到结算的数据链路
  • 嵌入式视觉AI模块AT指令开发指南:从串口通信到人脸识别实战
  • XGP游戏存档提取器:免费实现Xbox Game Pass存档跨平台迁移的完整指南
  • C++ vector迭代器失效全解析:从内存模型到安全编程实践
  • Hackintool:黑苹果配置的终极工具箱,快速解决硬件兼容性问题
  • 云市场加速试点:如何用模板+AI助手把试点周期从3个月压到6周
  • Python OCR实战:pytesseract安装配置、图像预处理与参数调优全攻略
  • WorkBuddy 第一次配置执行模式,为什么先选 Plan 而不是 Craft?
  • 从盲目输出到数据驱动:GBFR Logs如何让你的《碧蓝幻想:Relink》战斗水平翻倍
  • 如何为Photoshop添加完整的WebP格式支持:WebPShop插件终极指南
  • Hackintosh黑苹果网络驱动实战:从硬件适配到系统级优化的完整解决方案
  • 5分钟打造精简Windows 11:tiny11builder完全配置指南
  • 抖音直播实战:6大技巧破解直播间流量密码
  • Windows任务栏美化终极指南:用TranslucentTB轻松打造透明桌面效果
  • Visual C++ Redistributable AIO:3分钟解决Windows应用程序启动失败的终极方案
  • 硬件盲盒的 遗憾
  • AI模型上线即故障?B端后台必须预埋的7类模型生命周期监控断点
  • 2.基于 ABAP 面向对象与 BAPI 接口的采购订单批量审批系统设计与性能优化
  • SEM代运营服务商哪家靠谱?
  • 网盘直链下载助手终极指南:免费解决9大网盘下载限速问题
  • SEO优化核心策略:技术提升与内容匹配
  • arXiv论文提交全流程详解:从账号认证到LaTeX格式处理
  • Python dominate库:用代码优雅生成HTML的完整指南
  • 企业全光网络架构选型技术白皮书:从物理层到运维层的全链路分析
  • 华为eNSP模拟器FTP服务器配置与文件传输实战指南
  • 无人机实名登记新规落地 无人机维修行业迎来合规新要求
  • 如何快速配置Foobar2000逐字歌词同步:新手零基础教程
  • AI框架升级紧急响应清单:当ONNX Runtime v1.16触发推理结果漂移,如何30分钟内定位并回滚?