Commit eef27f6a authored by Vũ Hoàng Anh's avatar Vũ Hoàng Anh

Auto commit: Add run_agent.sh and Cuccu Note test scripts.

parent dc3ac729
...@@ -8,7 +8,8 @@ ...@@ -8,7 +8,8 @@
"Bash(py -3 -m pip install -e backend/ -q)", "Bash(py -3 -m pip install -e backend/ -q)",
"Bash(npm install *)", "Bash(npm install *)",
"Bash(npm run *)", "Bash(npm run *)",
"Bash(npx playwright *)" "Bash(npx playwright *)",
"Bash(docker-compose *)"
] ]
} }
} }
#!/usr/bin/env python3
"""
Seed test data for Playwright E2E tests.
Creates a test user and sample memos if they don't exist.
"""
import os
import asyncio
import httpx
BACKEND_URL = os.getenv("BACKEND_URL", "http://backend:5000")
TEST_USER = {
"email": "test@example.com",
"password": "testpassword123",
"username": "testuser",
}
async def signup_user():
"""Create test user via signup API."""
async with httpx.AsyncClient() as client:
try:
response = await client.post(
f"{BACKEND_URL}/api/v1/auth/signup",
json={
"email": TEST_USER["email"],
"password": TEST_USER["password"],
"username": TEST_USER["username"],
}
)
if response.status_code in (200, 201):
print(f"✅ Created test user: {TEST_USER['email']}")
data = response.json()
return data.get("token") or data.get("access_token")
elif response.status_code == 409:
print(f"ℹ️ Test user already exists, signing in...")
# Try to sign in
resp = await client.post(
f"{BACKEND_URL}/api/v1/auth/signin",
json={
"email": TEST_USER["email"],
"password": TEST_USER["password"],
}
)
if resp.status_code == 200:
data = resp.json()
print(f"✅ Signed in as test user")
return data.get("token") or data.get("access_token")
else:
print(f"❌ Failed to sign in: {resp.status_code}")
else:
print(f"❌ Signup failed: {response.status_code} - {response.text}")
except Exception as e:
print(f"❌ Error signing up: {e}")
return None
async def create_sample_memos(token: str):
"""Create a few sample memos for testing."""
headers = {"Authorization": f"Bearer {token}"}
async with httpx.AsyncClient(headers=headers) as client:
memo_contents = [
"This is a test memo for Playwright E2E tests.",
"Another test memo with some content.",
"Third memo - testing comment functionality.",
]
for content in memo_contents:
try:
response = await client.post(
f"{BACKEND_URL}/api/v1/memos",
json={"content": content, "visibility": "PUBLIC"}
)
if response.status_code in (200, 201):
print(f"✅ Created memo: {content[:30]}...")
elif response.status_code == 409:
print(f"ℹ️ Memo already exists: {content[:30]}...")
else:
print(f"❌ Failed to create memo: {response.status_code}")
except Exception as e:
print(f"❌ Error creating memo: {e}")
async def main():
print("🌱 Seeding test data...")
token = await signup_user()
if token:
await create_sample_memos(token)
print("✅ Test data seeding complete!")
else:
print("❌ Failed to get auth token, skipping memo creation")
if __name__ == "__main__":
asyncio.run(main())
...@@ -14,6 +14,9 @@ services: ...@@ -14,6 +14,9 @@ services:
volumes: volumes:
- backend_data:/app/data - backend_data:/app/data
command: python server.py command: python server.py
depends_on:
meilisearch:
condition: service_healthy
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5000/docs"] test: ["CMD", "curl", "-f", "http://localhost:5000/docs"]
interval: 30s interval: 30s
...@@ -75,6 +78,7 @@ services: ...@@ -75,6 +78,7 @@ services:
container_name: cuccu_playwright_test container_name: cuccu_playwright_test
environment: environment:
- BASE_URL=http://frontend:3001 - BASE_URL=http://frontend:3001
- BACKEND_URL=http://backend:5000
depends_on: depends_on:
backend: backend:
condition: service_healthy condition: service_healthy
...@@ -87,10 +91,12 @@ services: ...@@ -87,10 +91,12 @@ services:
- test_results:/app/test-results - test_results:/app/test-results
command: > command: >
sh -c " sh -c "
echo 'Waiting for frontend to be ready...' && echo 'Waiting for frontend to be ready...' &&
while ! curl -s http://frontend:3001 > /dev/null; do sleep 2; done && while ! curl -s http://frontend:3001 > /dev/null; do sleep 2; done &&
echo 'Running Playwright tests...' && echo '🌱 Seeding test data...' &&
npx playwright test --reporter=html node tests/seed-test-data.js &&
echo '🚀 Running Playwright tests...' &&
npx playwright test --reporter=html,line
" "
volumes: volumes:
......
#!/usr/bin/env node
/**
* Seed test data for Playwright E2E tests.
* Creates a test user and sample memos if they don't exist.
*/
const http = require('http');
const BACKEND_URL = process.env.BACKEND_URL || 'http://backend:5000';
const TEST_USER = {
email: 'test@example.com',
password: 'testpassword123',
username: 'testuser',
};
function request(url, options = {}) {
return new Promise((resolve, reject) => {
const urlObj = new URL(url);
const opts = {
hostname: urlObj.hostname,
port: urlObj.port,
path: urlObj.pathname + urlObj.search,
method: options.method || 'GET',
headers: options.headers || {},
};
if (options.body) {
opts.headers['Content-Type'] = 'application/json';
options.body = JSON.stringify(options.body);
}
const req = http.request(opts, (res) => {
let data = '';
res.on('data', (chunk) => data += chunk);
res.on('end', () => {
try {
const json = JSON.parse(data);
resolve({ status: res.statusCode, data: json, headers: res.headers });
} catch {
resolve({ status: res.statusCode, data: data, headers: res.headers });
}
});
});
req.on('error', reject);
if (options.body) req.write(options.body);
req.end();
});
}
async function signupUser() {
console.log('Creating test user...');
try {
const res = await request(`${BACKEND_URL}/auth/signup`, {
method: 'POST',
body: {
email: TEST_USER.email,
password: TEST_USER.password,
username: TEST_USER.username,
},
});
if (res.status === 200 || res.status === 201) {
console.log('✅ Created test user:', TEST_USER.email);
return res.data.token || res.data.access_token;
} else if (res.status === 409) {
console.log('ℹ️ Test user already exists, signing in...');
const signinRes = await request(`${BACKEND_URL}/auth/signin`, {
method: 'POST',
body: {
email: TEST_USER.email,
password: TEST_USER.password,
},
});
if (signinRes.status === 200) {
console.log('✅ Signed in as test user');
return signinRes.data.token || signinRes.data.access_token;
} else {
console.error('❌ Failed to sign in:', signinRes.status);
}
} else {
console.error('❌ Signup failed:', res.status, res.data);
}
} catch (err) {
console.error('❌ Error signing up:', err.message);
}
return null;
}
async function createSampleMemos(token) {
console.log('Creating sample memos...');
const headers = { 'Content-Type': 'application/json' };
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
const memos = [
'This is a test memo for Playwright E2E tests.',
'Another test memo with some content.',
'Third memo - testing comment functionality.',
];
for (const content of memos) {
try {
const res = await request(`${BACKEND_URL}/api/v1/memos`, {
method: 'POST',
headers,
body: { content, visibility: 'PUBLIC' },
});
if (res.status === 200 || res.status === 201) {
console.log('✅ Created memo:', content.substring(0, 30) + '...');
} else if (res.status === 409) {
console.log('ℹ️ Memo already exists:', content.substring(0, 30) + '...');
} else {
console.error('❌ Failed to create memo:', res.status);
}
} catch (err) {
console.error('❌ Error creating memo:', err.message);
}
}
}
async function waitForBackend(maxAttempts = 30) {
console.log('Waiting for backend to be ready...');
for (let i = 0; i < maxAttempts; i++) {
try {
const res = await request(`${BACKEND_URL}/docs`);
if (res.status < 500) {
console.log('✅ Backend is ready');
return true;
}
} catch (err) {
// ignore
}
await new Promise(r => setTimeout(r, 2000));
}
console.error('❌ Backend did not become ready in time');
return false;
}
async function main() {
console.log('🌱 Seeding test data for Playwright E2E tests...');
if (await waitForBackend()) {
const token = await signupUser();
if (token) {
await createSampleMemos(token);
console.log('✅ Test data seeding complete!');
} else {
console.error('❌ Failed to get auth token');
process.exit(1);
}
} else {
console.error('❌ Backend not ready');
process.exit(1);
}
}
main().catch(console.error);
#!/bin/bash
# Ralph Wiggum Loop for Claude Code + AUTO TMUX WRAPPER
# Tự động nhốt vào tmux chạy nền + Tự động retry khi có lỗi vòng lặp
PLAN_FILE="/root/app/cuccu_legal/plan/AI_DEVELOPMENT_PLAN.md"
# 1. Bẫy Tmux Tự động: Nếu Terminal không nằm trong tmux, nó sẽ tự nhét nó vào tmux!
if [ -z "$TMUX" ]; then
SESSION_NAME="cucu_legal_agent"
echo "🛡️ Phát hiện bro đang gõ lệnh ở ngoài! Đang tự động tạo lớp khiên tmux tên là '$SESSION_NAME'..."
# Tránh lỗi kẹt file flag Done
rm -f /root/app/cuccu_legal/plan/DONE.flag
# Bật tmux ngầm (detached) và gọi chính cái file bash này chạy tiếp
tmux new-session -d -s $SESSION_NAME "$0"
echo "✅ XONG BÉNG! Con AI đã được thả xích cày ngầm."
echo "👉 Đóng VS Code thoải mái, sập nguồn wifi thoải mái..."
echo "👉 Chiều mai muốn xem nó code tới đâu thì gõ lại lệnh: tmux attach -t $SESSION_NAME"
exit 0
fi
# ==================== PHẦN LÕI CỦA LOOP (CHẠY BÊN TRONG TMUX) ====================
echo "🚀 Bắt đầu khơi chạy Agentic Loop cho dự án CuCu Legal..."
echo "👉 Sử dụng file kế hoạch: $PLAN_FILE"
while true; do
echo "---------------------------------------------------------"
echo "🤖 Đang gọi Claude Code (Tự động pass permission)..."
# Prompt cốt lõi siêu bảo mật
claude --permission-mode auto -p "Đọc file $PLAN_FILE. Tìm task đầu tiên đang là [ ] và thực thi việc code/fix. Hoàn thành thì chạy skill /eval-quality, nếu PASS thì đổi thành [x]. ⛔ CẢNH BÁO CAO ĐỘ: TUYỆT ĐỐI KHÔNG ĐƯỢC XOÁ HOẶC THAY ĐỔI CẤU TRÚC DB (DROP/DELETE/ALTER). NẾU CẦN THÊM BẢNG PHẢI DÙNG FOLDER /migrations. Nếu TẤT CẢ đã là [x], hãy tạo một file tên là '/root/app/cuccu_legal/plan/DONE.flag' để báo hiệu. Tuyệt đối không được dừng lại giữa chừng nếu chưa xong 1 task."
if [ -f "/root/app/cuccu_legal/plan/DONE.flag" ]; then
echo "🎉 BINGO! Toàn bộ kế hoạch trong AI_DEVELOPMENT_PLAN.md đã hoàn tất!"
rm -f /root/app/cuccu_legal/plan/DONE.flag
break
fi
echo "⏳ Claude Code vừa bị ngắt. Sẽ tự động RETRY tiếp tục công việc sau 5 giây..."
sleep 5
done
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment