QA 13: Terminal, Git, Docker va Loglar — QA'ning muhandislik asboblari
🧪 QA Engineer — Zero to Hero
QA 13: Terminal, Git, Docker va Loglar — QA'ning muhandislik asboblari
Holat: 2026-yil oktabr. Terminal va Git misollari macOS 26 (zsh) va Git 2.53 da ishga tushirib tekshirilgan —
git bisect,grep,curlvajqchiqishlari haqiqiy. Docker Compose buyruqlari Docker'ning rasmiy hujjatlari asosida keltirilgan.
Bu darsdan keyin siz: dasturchi bilan bir tilda gaplashadigan "texnik QA"ga aylanasiz.
- terminalda fayl, log va API bilan tez ishlaysiz (
grep,tail -f,curl,jq); - feature branch'ni lokal ishga tushirib test qilasiz va PR'ni QA ko'zi bilan o'qiysiz;
git bisectbilan regressiyani keltirib chiqargan commit'ni bir necha qadamda topasiz;- Docker Compose bilan lokal muhitni ko'tarasiz, loglarini o'qiysiz va tozalaysiz;
- log, request ID va stack trace'dan bug report uchun dalil yig'asiz.
Mundarija
- Nega QA'ga terminal kerak
- Terminal asoslari: navigatsiya va fayllar
- grep, pipe va yo'naltirish: loglarda qidirish
- curl va jq: API bilan terminaldan ishlash
- O'zgaruvchilar va skriptlar: mini smoke test
- Git QA uchun: branch, log, diff, blame, stash
- git bisect: regressiyani topish
- Muhitlar, feature flag'lar va .env
- Docker va Docker Compose: lokal muhit
- Loglar: darajalar, structured log, request ID
- Stack trace va mobil loglar
- Amaliy mashqlar
- Xulosa
- Manbalar
1. Nega QA'ga terminal kerak {#nega-terminal}
Ko'p yangi QA'lar terminaldan qo'rqadi: qora ekran, hech qanday tugma yo'q. Lekin amalda u — eng tez "pult". Bir qator buyruq bilan 10 000 qatorlik logdan kerakli xatoni topasiz, API'ni brauzersiz chaqirasiz yoki dasturchining branch'ini o'z kompyuteringizda ishga tushirasiz.
| Vaziyat | Terminalsiz | Terminal bilan |
|---|---|---|
| Server logida bitta so'rov izini topish | Faylni ochib, ko'z bilan qidirish | grep "req-7f3a" api.log |
| API javob beryaptimi | Postman ochish, so'rov yasash | curl -s -o /dev/null -w "%{http_code}" URL |
| Dasturchi "fix qildim" dedi — lekin qaysi branch'da? | Kutish, so'rash | git switch feature/... yoki gh pr checkout 123 |
| "Qachondan buzildi?" | Taxmin | git bisect bilan aniq commit |
| Lokal muhitni noldan ko'tarish | Ko'rsatma bo'yicha soatlab sozlash | docker compose up -d |
Bu dars dasturchi bo'lishni talab qilmaydi. Maqsad — QA ishida eng ko'p uchraydigan 20–30 ta buyruqni ishonch bilan ishlatish.
🎯 Intervyuda: "Log fayldan ma'lum foydalanuvchi so'rovlarini qanday topasiz?" —
grepbilan request ID yoki user ID bo'yicha qidiraman (grep -n "req-7f3a" api.log), kontekst uchun-C 2, real vaqtda kuzatish uchuntail -f api.log | grep ERROR. Structured (JSON) log bo'lsa —jq 'select(.requestId == "req-7f3a")'.
2. Terminal asoslari: navigatsiya va fayllar {#terminal-asoslari}
Qayerda ishlaymiz:
| OS | Terminal | Shell |
|---|---|---|
| macOS | Terminal.app yoki iTerm2 | zsh (macOS 10.15 dan beri default; undan oldin bash) |
| Linux | Istalgan terminal | Ko'pincha bash |
| Windows | Windows Terminal | PowerShell; Linux buyruqlari uchun WSL tavsiya etiladi |
Bu darsdagi buyruqlar macOS, Linux va WSL'da ishlaydi. Windows PowerShell'da sintaksis farq qiladi.
Eng kerakli buyruqlar
| Buyruq | Nima qiladi | Misol |
|---|---|---|
pwd | Hozir qaysi papkadaman | pwd |
ls -la | Papka ichidagilar (yashirin fayllar bilan) | ls -la logs/ |
cd | Papkaga o'tish | cd ~/projects/demobozor, cd .. |
mkdir -p | Papka yaratish (ichma-ich ham) | mkdir -p evidence/BUG-1234 |
cp, mv | Nusxa olish, ko'chirish/qayta nomlash | cp api.log api.backup.log |
cat | Faylni to'liq chiqarish | cat version.json |
less | Katta faylni varaqlab o'qish (/ qidirish, q chiqish) | less api.log |
head -n, tail -n | Boshidan / oxiridan N qator | tail -n 50 api.log |
tail -f | Faylga yozilayotganlarni real vaqtda kuzatish (Ctrl+C to'xtatadi) | tail -f api.log |
wc -l | Qatorlar soni | wc -l api.log |
find | Fayl qidirish | find . -name "*.log" -mtime -1 (oxirgi 1 kunda o'zgargan) |
Vaqtni tejaydigan odatlar: Tab — nomni avtomatik to'ldiradi; ↑ — oldingi buyruq; Ctrl+R — tarixdan qidirish; Ctrl+C — ishlayotgan buyruqni to'xtatish; clear — ekranni tozalash.
⚠️ Diqqat:
rmfaylni Savatga emas, butunlay o'chiradi,rm -rf papkaesa butun papkani so'roqsiz yo'q qiladi. Buyruqni boshqa joydan ko'chirib olganda,rmbilan boshlansa — Enter bosishdan oldin ikki marta o'qing.
3. grep, pipe va yo'naltirish: loglarda qidirish {#grep-pipe}
Mashq uchun DemoBozor API'ning (xayoliy) log fayli. Quyidagi buyruq faylni yaratadi — <<'EOF' dan EOF gacha bo'lgan matn faylga yoziladi:
cat > api.log <<'EOF'
2026-10-08T16:25:01.112Z INFO [req-5a1c] POST /api/v1/orders user=9 status=201 ms=184
2026-10-08T16:25:03.540Z INFO [req-5a1d] GET /api/v1/products?query=choynak status=200 ms=42
2026-10-08T16:26:00.020Z WARN [req-7f3a] POST /api/v1/payments order=11 provider=UZCARD retry=1
2026-10-08T16:26:00.871Z ERROR [req-7f3a] POST /api/v1/payments order=11 status=502 ms=850 msg="provider timeout"
2026-10-08T16:26:05.300Z INFO [req-5a1e] GET /api/v1/cart user=3 status=200 ms=37
2026-10-08T16:28:30.004Z INFO [req-7f3b] POST /api/v1/payments order=11 provider=UZCARD status=201 ms=410
2026-10-08T16:28:30.010Z ERROR [req-7f3b] amount mismatch order=11 expected=135000 paid=130000
2026-10-08T16:30:12.777Z INFO [req-5a1f] GET /api/v1/orders/11 user=9 status=200 ms=29
2026-10-08T16:31:40.101Z WARN [req-5a20] POST /api/v1/auth/verify phone=+99890***4567 attempts=3 status=429
2026-10-08T16:31:41.500Z INFO [req-5a21] GET /api/v1/products?query=gilam status=200 ms=51
EOF
grep — matn bo'yicha qidirish
$ grep -n "ERROR" api.log
4:2026-10-08T16:26:00.871Z ERROR [req-7f3a] POST /api/v1/payments order=11 status=502 ms=850 msg="provider timeout"
7:2026-10-08T16:28:30.010Z ERROR [req-7f3b] amount mismatch order=11 expected=135000 paid=130000
$ grep -c "ERROR" api.log
2
$ grep "req-7f3a" api.log
2026-10-08T16:26:00.020Z WARN [req-7f3a] POST /api/v1/payments order=11 provider=UZCARD retry=1
2026-10-08T16:26:00.871Z ERROR [req-7f3a] POST /api/v1/payments order=11 status=502 ms=850 msg="provider timeout"
$ grep -E "status=5[0-9]{2}" api.log
2026-10-08T16:26:00.871Z ERROR [req-7f3a] POST /api/v1/payments order=11 status=502 ms=850 msg="provider timeout"
| Flag | Ma'nosi | Qachon kerak |
|---|---|---|
-n | Qator raqamini ko'rsatadi | Bug report'da aniq joyga ishora qilish |
-c | Faqat sonini chiqaradi | "Nechta xato bor?" |
-i | Katta-kichik harfni farqlamaydi | error, Error, ERROR hammasi |
-v | Teskari: mos kelmagan qatorlar | grep -v INFO — shovqinni olib tashlash |
-E | Kengaytirilgan regex | status=5[0-9]{2} — barcha 5xx |
-o | Faqat mos kelgan qismni chiqaradi | Statistika yig'ish |
-C 2, -A, -B | Atrofdagi qatorlar (context, after, before) | Xatodan oldin nima bo'ldi? |
-r | Papka ichida rekursiv | grep -rn "FREE_DELIVERY" src/ |
-w | Butun so'z | -w 200 — 2001 ga mos kelmaydi |
Pipe (|) — buyruqlarni zanjir qilish
Pipe bir buyruq chiqishini keyingisiga kirish qilib beradi. Status kodlar statistikasi bir qatorda:
$ grep -o "status=[0-9]*" api.log | sort | uniq -c | sort -rn
4 status=200
2 status=201
1 status=502
1 status=429
$ grep -v "INFO" api.log | wc -l
4
O'qish tartibi: status'larni ajratib ol → saralab qo'y → bir xillarini sanab chiqar → sanoq bo'yicha kamayish tartibida sarala.
Yo'naltirish: dalilni faylga saqlash
grep "req-7f3a" api.log > evidence-BUG-1234.txt # > — fayl yaratadi yoki USTIDAN yozadi
grep "req-7f3b" api.log >> evidence-BUG-1234.txt # >> — oxiriga qo'shadi
some-command 2>&1 | tee run.log # xatolarni ham ushlab, ekranga va faylga
⚠️ Diqqat:
>mavjud faylni so'roqsiz qayta yozadi. Muhim logni>bilan "ustidan" yozib yubormang — qo'shish uchun>>.
Real vaqtda kuzatish
tail -f api.log | grep --line-buffered "ERROR"
Ilovada amal bajarasiz — terminalda xato darhol paydo bo'ladi. Ctrl+C bilan to'xtatiladi. Bu "qaysi bosish qaysi xatoni keltirib chiqardi" degan savolga eng tez javob.
macOS (BSD) va Linux (GNU) farqlari
macOS'dagi ko'p buyruqlar BSD versiyasi, Linux'da esa GNU. Internetdagi misollar ko'pincha GNU uchun yozilgan:
| Vazifa | Linux (GNU) | macOS (BSD) |
|---|---|---|
| Perl regex | grep -P "\d+" | /usr/bin/grep -P'ni qo'llamaydi → grep -E "[0-9]+" |
| Faylni joyida tahrirlash | sed -i 's/a/b/' f.txt | sed -i '' 's/a/b/' f.txt |
| Kechagi sana | date -d yesterday +%F | date -v-1d +%F |
| Versiyani ko'rish | sed --version | Ko'p BSD vositalarida --version yo'q |
Biror buyruq macOS'da "illegal option" desa — birinchi gumon shu farq.
4. curl va jq: API bilan terminaldan ishlash {#curl-jq}
curl — HTTP so'rov yuboradi, jq — JSON javobni filtrlaydi va chiroyli ko'rsatadi. jq odatda alohida o'rnatiladi: macOS'da brew install jq, Debian/Ubuntu'da sudo apt-get install jq, Windows'da winget install jqlang.jq.
$ curl -s https://jsonplaceholder.typicode.com/todos/1 | jq .
{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
}
$ curl -s -o /dev/null -w "%{http_code}\n" https://restful-booker.herokuapp.com/ping
201
$ curl -s -X POST https://restful-booker.herokuapp.com/auth \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"password123"}' | jq -r .token
e8dcaccbe7170f4
$ curl -s https://jsonplaceholder.typicode.com/users | jq -r '.[] | "\(.id)\t\(.email)"' | head -3
1 Sincere@april.biz
2 Shanna@melissa.tv
3 Nathan@yesenia.net
Token har safar boshqacha bo'ladi — sizdagi qiymat farq qiladi.
curl flag | Ma'nosi |
|---|---|
-s | Jim rejim (progress chiqmaydi) |
-i | Javob header'larini ham ko'rsatadi |
-X POST | HTTP metod |
-H "..." | Header qo'shish |
-d '...' | So'rov tanasi (body) |
-o /dev/null -w "%{http_code}" | Tanani tashlab, faqat status kodni chiqarish |
--max-time 10 | 10 soniyadan oshsa to'xtatish |
jq ifoda | Ma'nosi |
|---|---|
. | Butun JSON, chiroyli formatda |
.title, .data.id | Maydon qiymati |
-r | Qo'shtirnoqsiz "xom" matn |
length | Massiv uzunligi / obyekt maydonlari soni |
.[] | Massiv elementlari bo'ylab |
select(.level == "error") | Shartga mos elementlar |
QA topilmasi: "200 OK" ichidagi xato
$ curl -s -o /dev/null -w "%{http_code}\n" -X POST https://restful-booker.herokuapp.com/auth \
-H "Content-Type: application/json" -d '{"username":"admin","password":"xato"}'
200
$ curl -s -X POST https://restful-booker.herokuapp.com/auth \
-H "Content-Type: application/json" -d '{"username":"admin","password":"xato"}'
{"reason":"Bad credentials"}
Noto'g'ri parol — lekin status 200. REST odatlariga ko'ra bu 401 Unauthorized bo'lishi kerak edi. Faqat status kodga qaraydigan avtotest bu holatni "muvaffaqiyatli login" deb o'tkazib yuboradi. Restful-booker o'quv maqsadida atayin "xato" qilingan API — real loyihada bu bug report bo'lardi (QA 11).
💡 Maslahat: Chrome DevTools'dagi va Proxyman'dagi Copy as cURL funksiyasi brauzer yoki mobil ilova yuborgan so'rovni aynan terminal buyrug'i ko'rinishida beradi (QA 9, QA 15). Uni bug report'ga qo'shsangiz, dasturchi muammoni bir buyruq bilan takrorlaydi. Faqat ichidagi token va shaxsiy ma'lumotlarni yashirishni unutmang.
5. O'zgaruvchilar va skriptlar: mini smoke test {#skriptlar}
Environment variable — buyruqlar va dasturlar o'qiydigan nomlangan qiymat:
export BASE_URL=https://staging.demobozor.example # joriy terminal sessiyasi uchun
echo $BASE_URL
env | grep BASE_URL
BASE_URL=http://localhost:3001 ./smoke.sh # faqat shu bitta buyruq uchun
Endi takrorlanadigan tekshiruvni skriptga aylantiramiz. smoke.sh — muhim endpoint'lar kutilgan status kodni qaytarayotganini tekshiradi:
#!/usr/bin/env bash
# smoke.sh — muhim endpoint'lar javob beryaptimi? (QA uchun mini smoke)
set -u
BASE_URL="${BASE_URL:-https://restful-booker.herokuapp.com}"
failed=0
check() {
local path="$1" expected="$2"
local code
code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$BASE_URL$path")
if [ "$code" = "$expected" ]; then
echo "✅ $path → $code"
else
echo "❌ $path → $code (kutilgan: $expected)"
failed=$((failed + 1))
fi
}
check "/ping" 201
check "/booking" 200
check "/booking/0" 404
if [ "$failed" -gt 0 ]; then
echo "Smoke FAILED: $failed ta tekshiruv yiqildi"
exit 1
fi
echo "Smoke PASSED"
$ chmod +x smoke.sh
$ ./smoke.sh
✅ /ping → 201
✅ /booking → 200
✅ /booking/0 → 404
Smoke PASSED
$ echo $?
0
$ BASE_URL=https://jsonplaceholder.typicode.com ./smoke.sh
❌ /ping → 404 (kutilgan: 201)
❌ /booking → 404 (kutilgan: 200)
✅ /booking/0 → 404
Smoke FAILED: 2 ta tekshiruv yiqildi
$ echo $?
1
Muhim tafsilotlar:
#!/usr/bin/env bash(shebang) — faylni qaysi dastur bajarishini aytadi;chmod +xuni ishga tushiriladigan qiladi.${BASE_URL:-...}— o'zgaruvchi berilmasa, default qiymat.- Exit code:
0— muvaffaqiyat,0dan boshqasi — xato.$?oxirgi buyruqning exit code'ini ko'rsatadi. CI tizimlari aynan shunga qarab pipeline'ni "qizil" yoki "yashil" qiladi (QA 21).
6. Git QA uchun: branch, log, diff, blame, stash {#git}
Git — kod tarixini saqlaydigan tizim. QA uchun u "vaqt mashinasi": istalgan versiyani ishga tushirish, nima o'zgarganini ko'rish, xato qachon paydo bo'lganini topish. To'liq asoslar: Git for iOS Developers va Git buyruqlari cheat sheet.
| Tushuncha | QA uchun ma'nosi |
|---|---|
| Repository (repo) | Loyiha va uning butun tarixi |
| Commit | Bitta saqlangan o'zgarish (hash, muallif, sana, xabar) |
| Branch | Parallel ish chizig'i: main, feature/promo-code-v2 |
| Pull Request (PR) / Merge Request | "Mening branch'imni main'ga qo'shing" degan so'rov + review |
| Tag | Reliz belgisi: v1.2, v1.3 |
Dasturchining branch'ini test qilish
git clone https://github.com/<org>/demobozor.git # bir marta
cd demobozor
git fetch origin # yangi branch'larni olib kelish
git switch feature/promo-code-v2 # branch'ga o'tish
git pull # eng so'nggi commit'lar
gh pr checkout 123 # GitHub CLI: PR raqami bo'yicha (gh o'rnatilgan bo'lsa)
Nima o'zgardi? Reliz orasidagi farq
Regression testing ko'lamini tanlashning eng aniq usuli — ikki reliz orasidagi commit'lar va fayllarga qarash. Quyidagi chiqishlar 7-bo'limdagi mashq repo'sidan:
$ git log --oneline v1.2..v1.3
d0634b0 versiya 1.3.0
5532ddd README yangilandi
1257f6b magic number'lar konstantaga chiqarildi
4bfe1f8 viloyatlar uchun yetkazish muddati
$ git diff --stat v1.2 v1.3
README.md | 1 +
delivery.mjs | 9 ++++++++-
version.json | 1 +
3 files changed, 10 insertions(+), 1 deletion(-)
delivery.mjs o'zgargan — demak yetkazish narxi va muddati regression ro'yxatida birinchi o'rinda. "Refactor" so'zi aldamasin: "faqat kodni chiroyli qildim" degan commit'lar ham xatti-harakatni o'zgartirib yuborishi mumkin.
Kim, qachon, nima uchun: blame va pickaxe
$ git blame -L 4,7 delivery.mjs
^6aa5588 (QA Demo 2026-10-09 22:14:44 +0500 4) export function deliveryFee(subtotal, isPremium = false) {
^6aa5588 (QA Demo 2026-10-09 22:14:44 +0500 5) if (isPremium) return 0;
1257f6b2 (QA Demo 2026-10-09 22:14:44 +0500 6) return subtotal > FREE_DELIVERY_THRESHOLD ? 0 : DELIVERY_FEE;
^6aa5588 (QA Demo 2026-10-09 22:14:44 +0500 7) }
$ git log -S "FREE_DELIVERY_THRESHOLD" --oneline
1257f6b magic number'lar konstantaga chiqarildi
git blame har bir qatorni oxirgi o'zgartirgan commit'ni ko'rsatadi. git log -S "matn" esa shu matn qo'shilgan yoki olib tashlangan commit'larni topadi. Maqsad aybdor qidirish emas — kontekst: o'sha commit'ning PR'i va tiketini o'qib, o'zgarish sababini bilib olasiz.
Yarim ishni vaqtincha chetga qo'yish: stash
$ git stash -u # o'zgarishlar (yangi fayllar bilan) vaqtincha saqlanadi
Saved working directory and index state WIP on feature/qa-test: 0cd74b8 versiya 1.3.0
$ git stash list
stash@{0}: WIP on feature/qa-test: 0cd74b8 versiya 1.3.0
$ git switch main # toza holatda boshqa branch'ga o'tasiz
$ git stash pop # qaytib kelib, saqlanganini tiklaysiz
PR'ni QA ko'zi bilan o'qish
| Nimaga qarash | Nega |
|---|---|
| Bog'langan tiket va qabul mezonlari | Nimani test qilish kerakligi shu yerda |
| O'zgargan fayllar ro'yxati | Risk zonalari va regression ko'lami |
| Testlar qo'shilganmi / o'zgarganmi | Avtomat qamrov bormi |
| Migratsiyalar (DB sxema) | Ma'lumotga ta'sir, rollback xavfi |
| Konfiguratsiya, feature flag'lar | Ikkala holatni ham test qilish kerak |
| CI natijasi | Qizil CI bilan qo'lda test boshlamang |
| Skrinshot / video | UI o'zgarishini kutilgan dizayn bilan solishtirish |
⚠️ Diqqat:
git reset --hard,git clean -fd,git checkout -- .saqlanmagan o'zgarishlarni qaytarib bo'lmas tarzda o'chiradi. QA sifatida ular deyarli kerak bo'lmaydi; ishlatishdan oldingit statusbilan nima yo'qolishini ko'ring yokigit stashqiling.
7. git bisect: regressiyani topish {#git-bisect}
Ssenariy. DemoBozor v1.2 da 300 000 so'mlik buyurtmaga yetkazish bepul edi. v1.3 da xaridorlar 20 000 so'm to'layapti. Ikki reliz orasida o'nlab commit bo'lishi mumkin — qaysi biri buzdi?
git bisect binary search qiladi: "yaxshi" va "yomon" commit orasini har safar teng ikkiga bo'ladi. 1000 ta commit orasidan aybdorni taxminan 10 ta tekshiruvda topadi.
Git oqimi va QA nuqtalari: branch, PR, CI, staging, merge, reliz va bisect
Mashq repo'sini yaratish
Quyidagi skript 6 ta commit'li kichik repo yaratadi (sizdagi commit hash'lari boshqacha bo'ladi — bu normal):
#!/usr/bin/env bash
# bisect-demo.sh — git bisect mashqi uchun kichik repo yaratadi
set -euo pipefail
mkdir delivery-demo && cd delivery-demo
git init -q -b main
git config user.name "QA Demo"
git config user.email "qa-demo@example.com"
fee_v1='export function deliveryFee(subtotal, isPremium = false) {
if (isPremium) return 0;
return subtotal >= 300000 ? 0 : 20000;
}'
fee_v2='const FREE_DELIVERY_THRESHOLD = 300000;
const DELIVERY_FEE = 20000;
export function deliveryFee(subtotal, isPremium = false) {
if (isPremium) return 0;
return subtotal > FREE_DELIVERY_THRESHOLD ? 0 : DELIVERY_FEE;
}'
days='export function deliveryDays(region) {
return region === "Toshkent" ? 1 : 4;
}'
commit() { git add -A && git commit -q -m "$1"; }
echo "$fee_v1" > delivery.mjs; commit "premium mijozlar uchun bepul yetkazish"
echo "# DemoBozor delivery" > README.md; commit "README qo'shildi"; git tag v1.2
printf '%s\n\n%s\n' "$fee_v1" "$days" > delivery.mjs; commit "viloyatlar uchun yetkazish muddati"
printf '%s\n\n%s\n' "$fee_v2" "$days" > delivery.mjs; commit "magic number'lar konstantaga chiqarildi"
echo "Narxlar so'mda." >> README.md; commit "README yangilandi"
echo '{ "version": "1.3.0" }' > version.json; commit "versiya 1.3.0"; git tag v1.3
git log --oneline --decorate
Va QA tekshiruvi — repo'dan tashqarida turadigan qa-check.mjs (Node.js kerak):
// QA tekshiruvi: 300 000 so'mlik buyurtmada yetkazish bepul bo'lishi kerak
import { pathToFileURL } from "node:url";
const { deliveryFee } = await import(
pathToFileURL(`${process.cwd()}/delivery.mjs`).href
);
const fee = deliveryFee(300000);
console.log(`deliveryFee(300000) = ${fee}`);
process.exit(fee === 0 ? 0 : 1); // 0 = good, 1 = bad
bash bisect-demo.sh # repo yaratiladi
cd delivery-demo
Qo'lda bisect
$ git bisect start
status: waiting for both good and bad commits
$ git bisect bad # hozirgi HEAD (v1.3) — buzuq
status: waiting for good commit(s), bad commit known
$ git bisect good v1.2 # v1.2 — ishlagan
Bisecting: 1 revision left to test after this (roughly 1 step)
[1257f6b2802163502533eb65a89c3a40712cf956] magic number'lar konstantaga chiqarildi
$ node ../qa-check.mjs
deliveryFee(300000) = 20000
$ git bisect bad
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[4bfe1f8f9989f70abf85a147ddd6afddb727bb6c] viloyatlar uchun yetkazish muddati
$ node ../qa-check.mjs
deliveryFee(300000) = 0
$ git bisect good
1257f6b2802163502533eb65a89c3a40712cf956 is the first bad commit
commit 1257f6b2802163502533eb65a89c3a40712cf956
Author: QA Demo <qa-demo@example.com>
magic number'lar konstantaga chiqarildi
delivery.mjs | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
$ git bisect reset # bisect tugadi, main'ga qaytamiz
Har qadamda git sizga bitta commit'ni "checkout" qiladi; siz test qilib good yoki bad deysiz. Real loyihada "test" — ilovani ishga tushirib, qo'lda tekshirish ham bo'lishi mumkin.
Avtomatik bisect: git bisect run
Tekshiruv skript bo'lsa, butun jarayonni git'ning o'zi bajaradi:
$ git bisect start v1.3 v1.2 # avval "bad", keyin "good"
$ git bisect run node ../qa-check.mjs
running 'node' '../qa-check.mjs'
deliveryFee(300000) = 20000
Bisecting: 0 revisions left to test after this (roughly 0 steps)
running 'node' '../qa-check.mjs'
deliveryFee(300000) = 0
1257f6b2802163502533eb65a89c3a40712cf956 is the first bad commit
...
bisect found first bad commit
$ git bisect reset
Skriptning exit code'i git uchun hukm:
| Exit code | Ma'nosi |
|---|---|
0 | good — bu commit'da xato yo'q |
1–127 (125 dan tashqari) | bad — xato bor |
125 | bu commit'ni test qilib bo'lmaydi (masalan, build bo'lmaydi) — o'tkazib yuboriladi |
| boshqalar | bisect to'xtatiladi |
Aybdor commit'ning diff'i hamma narsani aytadi:
- return subtotal >= 300000 ? 0 : 20000;
+ return subtotal > FREE_DELIVERY_THRESHOLD ? 0 : DELIVERY_FEE;
"Faqat magic number'larni konstantaga chiqarish" vaqtida >= jimgina > ga aylangan. Bug report'ga "Regression v1.3: 1257f6b commit'da kiritilgan, deliveryFee ichida >= → >" deb yozsangiz, dasturchi tuzatishni minutlarda qiladi. Shu xato SQL darsida ma'lumotlar bazasida ham ko'ringan edi (QA 12) — 4-buyurtma.
🎯 Intervyuda: "Regressiya qaysi commit'da paydo bo'lganini qanday topasiz?" — Ishlagan versiya (masalan, oldingi reliz tag'i) va buzilgan versiyani aniqlab,
git bisectbilan binary search qilaman; tekshiruvni skriptga aylantira olsam —git bisect run. Natijada aybdor commit, uning PR'i va tiketini bug report'ga qo'shaman.
8. Muhitlar, feature flag'lar va .env {#muhitlar}
Bitta ilova bir nechta muhitda (environment) yashaydi:
| Muhit | Kim ishlatadi | Ma'lumot | QA nima qiladi |
|---|---|---|---|
| Local | Dasturchi, QA o'z kompyuterida | Sun'iy, istalgancha buzish mumkin | Feature branch'ni tekshirish, eksperiment |
| Dev | Jamoa, har merge'dan keyin | Sun'iy | Tez tekshiruv, integratsiya |
| Staging / QA | QA jamoasi | Prod'ga yaqin, anonimlashtirilgan | Asosiy testlash, regression |
| Pre-prod / UAT | Biznes, mijoz | Prod nusxasi | Qabul testlari (acceptance) |
| Production | Haqiqiy foydalanuvchilar | Haqiqiy | Smoke, monitoring, faqat o'qish |
Feature flag'lar
Feature flag — funksiyani kodni qayta deploy qilmasdan yoqib-o'chirish imkoniyati. Masalan, promo_v2_enabled. QA uchun qoida: flag bilan yopilgan funksiyani ikkala holatda ham test qiling — yoqilganda ishlashi va o'chirilganda eski oqim buzilmagani. Bir nechta flag bo'lsa, ularning kombinatsiyalari ham risk.
Konfiguratsiya va .env
Ilova sozlamalarini (API manzili, kalitlar, log darajasi) koddan tashqarida, environment variable'larda saqlash — keng tarqalgan amaliyot ("The Twelve-Factor App" metodologiyasi). Lokal ishlab chiqishda ular odatda .env faylda turadi:
# .env.example — repo'da saqlanadi, haqiqiy qiymatlarsiz
BASE_URL=http://localhost:3001
API_BASE_URL=http://localhost:3001/api/v1
LOG_LEVEL=debug
SMS_PROVIDER=mock
PAYMENT_PROVIDER_KEY=
⚠️ Diqqat: Haqiqiy
.env(parollar, token'lar, API kalitlar) hech qachon Git'ga commit qilinmaydi — u.gitignore'da bo'lishi kerak. Repo'da faqat bo'sh qiymatli.env.exampleturadi. PR'da.envyoki kalit ko'rinib qolsa — bu darhol xabar qilinadigan xavfsizlik muammosi.
9. Docker va Docker Compose: lokal muhit {#docker}
"Mening kompyuterimda ishlaydi" muammosining yechimi — Docker: ilova va uning bog'liqliklari (baza, kesh, navbat) bir xil "konteyner"larda ishlaydi.
| Tushuncha | Ma'nosi |
|---|---|
| Image | Ilovaning tayyor "qolipi" (masalan, postgres:17) |
| Container | Image'dan ishga tushirilgan nusxa |
| Volume | Konteyner o'chirilsa ham saqlanadigan ma'lumot (masalan, baza fayllari) |
| Docker Compose | Bir nechta konteynerni bitta fayl bilan boshqarish |
Docker'ni o'zingiz o'rnatasiz: macOS va Windows uchun Docker Desktop, Linux uchun Docker Engine (rasmiy hujjatga qarang). Compose faylining tavsiya etilgan nomi — compose.yaml (eski docker-compose.yml ham qo'llab-quvvatlanadi).
DemoBozor'ning lokal muhiti uchun o'quv misoli:
# compose.yaml — DemoBozor lokal muhiti (o'quv misoli)
services:
db:
image: postgres:17
environment:
POSTGRES_USER: demobozor
POSTGRES_PASSWORD: local_only_password # faqat lokal uchun!
POSTGRES_DB: demobozor
ports:
- "5432:5432"
volumes:
- db-data:/var/lib/postgresql/data
api:
build: ./api # API'ning Dockerfile'i shu papkada
environment:
DATABASE_URL: postgres://demobozor:local_only_password@db:5432/demobozor
SMS_PROVIDER: mock # haqiqiy SMS yubormaslik uchun
LOG_LEVEL: debug
ports:
- "3001:3001"
depends_on:
- db
volumes:
db-data:
QA'ning kundalik Compose buyruqlari
docker compose up -d # hamma servislarni fonda ishga tushirish
docker compose up -d --build # kod o'zgargan bo'lsa — image'ni qayta yig'ib
docker compose ps # qaysi servis ishlayapti
docker compose logs -f api # api loglarini real vaqtda kuzatish
docker compose logs --since 10m api # oxirgi 10 daqiqa
docker compose logs -n 50 api # oxirgi 50 qator
docker compose exec db psql -U demobozor -d demobozor -c "SELECT COUNT(*) FROM orders;"
docker compose restart api # bitta servisni qayta ishga tushirish
docker compose down # konteynerlarni to'xtatib o'chirish (volume qoladi)
Test ma'lumotni noldan boshlash kerak bo'lsa:
docker compose down -v # ⚠️ volume'lar ham o'chadi — bazadagi HAMMA ma'lumot ketadi
docker compose up -d
⚠️ Diqqat:
down -vlokal test bazasi uchun qulay "reset" tugmasi, lekin u nomlangan volume'larni butunlay o'chiradi. Saqlab qolish kerak bo'lgan ma'lumot bo'lsa — avval eksport qiling. Umumiy serverlarda bu buyruqni hech qachon "sinab ko'rish" uchun ishlatmang.
Testcontainers — avtotestlar ichidan haqiqiy baza yoki brokerni konteynerda ko'tarib, test tugagach o'chiradigan kutubxonalar oilasi (Java, Go, .NET, Node.js, Python va boshqalar). Integratsiya testlarini "mock" o'rniga haqiqiy PostgreSQL bilan ishlatish uchun qulay — bunda Docker'ga tayanadi.
10. Loglar: darajalar, structured log, request ID {#loglar}
Log — tizim o'zi haqida yozib boradigan kundalik. QA uchun u eng kuchli dalil manbai: foydalanuvchi ko'rmagan narsani log ko'radi.
Log darajalari
| Daraja | Qachon yoziladi | DemoBozor misoli |
|---|---|---|
TRACE / DEBUG | Batafsil texnik tafsilotlar (odatda faqat dev/staging'da) | "Promo KUZ2026 qoidasi tekshirilyapti" |
INFO | Oddiy biznes hodisalari | "Buyurtma 11 yaratildi" |
WARN | G'alati, lekin tizim ishlashda davom etyapti | "To'lov provayderi javob bermadi, qayta urinish" |
ERROR | Amal bajarilmadi | "Payment 502: provider timeout" |
FATAL | Servis ishlay olmaydi | "Bazaga ulanib bo'lmadi, to'xtayapman" |
QA uchun signal: foydalanuvchi "hech narsa bo'lmadi" desa, lekin logda WARN/ERROR bo'lsa — bu bug. Aksincha, oddiy holatda ERROR yozilsa — bu ham bug (shovqin haqiqiy xatolarni yashiradi).
Structured log (JSON) va jq
Zamonaviy servislar logni JSON qatorlar sifatida yozadi — mashina o'qishi oson:
cat > app.jsonl <<'EOF'
{"time":"2026-10-08T16:25:01.112Z","level":"info","requestId":"req-5a1c","method":"POST","path":"/api/v1/orders","status":201,"ms":184,"userId":9}
{"time":"2026-10-08T16:26:00.020Z","level":"warn","requestId":"req-7f3a","method":"POST","path":"/api/v1/payments","orderId":11,"msg":"retrying provider call"}
{"time":"2026-10-08T16:26:00.871Z","level":"error","requestId":"req-7f3a","method":"POST","path":"/api/v1/payments","status":502,"ms":850,"orderId":11,"msg":"provider timeout"}
{"time":"2026-10-08T16:28:30.004Z","level":"info","requestId":"req-7f3b","method":"POST","path":"/api/v1/payments","status":201,"ms":410,"orderId":11}
{"time":"2026-10-08T16:28:30.010Z","level":"error","requestId":"req-7f3b","orderId":11,"msg":"amount mismatch","expected":135000,"paid":130000}
{"time":"2026-10-08T16:31:40.101Z","level":"warn","requestId":"req-5a20","method":"POST","path":"/api/v1/auth/verify","status":429,"msg":"too many attempts"}
EOF
$ jq -c 'select(.level == "error")' app.jsonl
{"time":"2026-10-08T16:26:00.871Z","level":"error","requestId":"req-7f3a","method":"POST","path":"/api/v1/payments","status":502,"ms":850,"orderId":11,"msg":"provider timeout"}
{"time":"2026-10-08T16:28:30.010Z","level":"error","requestId":"req-7f3b","orderId":11,"msg":"amount mismatch","expected":135000,"paid":130000}
$ jq -r 'select(.requestId == "req-7f3a") | [.time, .level, .msg] | @tsv' app.jsonl
2026-10-08T16:26:00.020Z warn retrying provider call
2026-10-08T16:26:00.871Z error provider timeout
$ jq -s -c 'group_by(.level) | map({level: .[0].level, count: length})' app.jsonl
[{"level":"error","count":2},{"level":"info","count":2},{"level":"warn","count":2}]
$ jq -c 'select(.ms != null and .ms > 300) | {requestId, path, ms}' app.jsonl
{"requestId":"req-7f3a","path":"/api/v1/payments","ms":850}
{"requestId":"req-7f3b","path":"/api/v1/payments","ms":410}
Request ID — bitta so'rovning "pasporti"
Har bir kiruvchi so'rovga noyob ID beriladi va u shu so'rov o'tgan barcha servislar loglariga yoziladi. Ko'p loyihalarda u javob header'ida ham qaytadi (masalan, X-Request-ID — keng tarqalgan odat; taqsimlangan tizimlarda W3C standarti bo'lgan traceparent header'i ishlatiladi).
QA uchun oltin usul:
- DevTools Network yoki Proxyman'da muammoli so'rovni topasiz.
- Javob header'idan request ID'ni olasiz (masalan,
req-7f3a). - Shu ID bo'yicha loglardan butun "hikoya"ni chiqarasiz: retry, timeout, xato.
- Bug report'ga request ID, vaqt (UTC) va log parchasini qo'shasiz.
Dasturchi sizdan "qachon, qaysi foydalanuvchi, qaysi qurilma?" deb so'ramaydi — ID hammasini bog'laydi.
Markazlashgan log va xato tizimlari
Production'da loglar fayllarda emas, maxsus tizimlarda yig'iladi. QA odatda ularga brauzer orqali kiradi:
| Vosita | Nima uchun | QA'ning odatiy so'rovi | |
|---|---|---|---|
| Grafana Loki | Loglarni yig'ish va LogQL bilan qidirish | `{job="demobozor-api"} \ | = "req-7f3a"` |
| Kibana (Elastic) | Loglar ustida qidiruv va dashboard'lar | requestId : "req-7f3a" (KQL) | |
| Sentry | Xatolar: stack trace, breadcrumb'lar, qaysi relizda boshlangani | Issue havolasi va event ID'ni bug report'ga qo'shish | |
| Firebase Crashlytics | Mobil ilova crash'lari | Crash-free foydalanuvchilar, crash stack trace |
LogQL'da JSON loglarni maydon bo'yicha filtrlash: {job="demobozor-api"} | json | level="error". Monitoring va alerting chuqurroq — DevOps: observability.
⚠️ Diqqat: Logda parol, to'liq karta raqami, SMS kod yoki access token ko'rsangiz — bu xavfsizlik bug'i. Yuqoridagi logda telefon
+99890***4567ko'rinishida yashirilgan — to'g'ri amaliyot. Batafsil — QA 24.
11. Stack trace va mobil loglar {#stack-trace}
Stack trace — dastur yiqilgan paytdagi funksiyalar chaqiruvlari zanjiri. Qo'rqinchli ko'rinadi, lekin o'qish qoidasi oddiy.
Node.js'dagi haqiqiy misol — savatchasi hali yaratilmagan yangi foydalanuvchi checkout qilganda:
file:///app/src/cart.mjs:2
return cart.items.reduce((sum, item) => sum + item.price * item.quantity, 0);
^
TypeError: Cannot read properties of undefined (reading 'items')
at cartTotal (file:///app/src/cart.mjs:2:15)
at checkout (file:///app/src/checkout.mjs:4:17)
at file:///app/server.mjs:5:1
at ModuleJob.run (node:internal/modules/esm/module_job:430:25)
at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:661:26)
at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5)
Node.js v24.14.1
Qanday o'qiladi:
- Xato turi va xabari —
TypeError: Cannot read properties of undefined (reading 'items'):undefinedqiymatdan.itemso'qilmoqchi bo'lingan. - Birinchi kadr (frame) — xato aynan qayerda:
cart.mjs, 2-qator, 15-ustun,cartTotalfunksiyasi. - Kim chaqirgan — pastga qarab:
checkout→server.mjs.node:internal/...kadrlari Node.js'ning ichki qismi, ularni odatda o'tkazib yuborasiz. - Xulosa —
user.cartundefinedbo'lgan holat ko'zda tutilmagan. Test g'oyasi: "savatchasi bo'sh/yo'q foydalanuvchi checkout'ni bosadi".
Java'da (masalan, Spring backend) stack trace shunday ko'rinadi — bu namuna, tuzilishi muhim:
java.lang.NullPointerException: Cannot invoke "String.toUpperCase()" because the return value of "uz.demobozor.order.OrderRequest.getPromoCode()" is null
at uz.demobozor.promo.PromoService.apply(PromoService.java:42)
at uz.demobozor.order.OrderService.create(OrderService.java:87)
at uz.demobozor.order.OrderController.createOrder(OrderController.java:35)
...
Bu yerda ham birinchi qator xato turi va sababini aytadi (promo-kod null, ya'ni promo-kodsiz buyurtma), keyingi qatorlar — loyiha paketidagi (uz.demobozor...) birinchi kadr. Java'da Caused by: bilan boshlangan qism ham bo'lishi mumkin — eng pastdagi Caused by odatda asl sababni ko'rsatadi.
💡 Maslahat: Bug report'ga stack trace'ni skrinshot emas, matn sifatida qo'shing (kod bloki ichida). Matnni qidirish, nusxalash va dublikatlarni topish mumkin; skrinshotni — yo'q.
Mobil loglar
| Platforma | Qayerdan olinadi | Buyruq / yo'l |
|---|---|---|
| iOS Simulator | macOS log vositasi simulyator ichida | xcrun simctl spawn booted log stream --level debug --predicate 'process == "DemoBozor"' |
| iOS qurilma | Xcode Console yoki macOS Console ilovasi (qurilma ulangan holda) | Console.app → qurilmani tanlash → jarayon nomi bilan filtrlash |
| iOS crash'lar | Xcode Organizer, TestFlight, Crashlytics | Crash log'ni bug report'ga ilova qilish |
| Android | adb logcat (emulator yoki USB orqali qurilma) | adb logcat "*:E" — faqat xatolar; adb logcat -d > logcat.txt — joriy logni faylga |
adb logcat filtri tag:daraja ko'rinishida: V (verbose), D (debug), I (info), W (warning), E (error), F (fatal), S (silent). zsh'da * belgisi maxsus ma'noga ega, shuning uchun filtrni qo'shtirnoqqa oling: adb logcat "DemoBozor:D *:S". Mobil testlash bo'yicha to'liq — QA 14.
12. Amaliy mashqlar {#mashqlar}
Mashqlar uchun 3- va 10-bo'limlardagi api.log va app.jsonl fayllarini yarating.
Mashq 1: Bitta to'lovning hikoyasi 🟢
api.log dan 11-buyurtma (order=11) bilan bog'liq barcha qatorlarni qator raqami bilan chiqaring. Nechta qator bor va ulardan nechtasi ERROR?
<details> <summary>💡 Javobni ko'rish</summary>
$ grep -n "order=11" api.log
3:2026-10-08T16:26:00.020Z WARN [req-7f3a] POST /api/v1/payments order=11 provider=UZCARD retry=1
4:2026-10-08T16:26:00.871Z ERROR [req-7f3a] POST /api/v1/payments order=11 status=502 ms=850 msg="provider timeout"
6:2026-10-08T16:28:30.004Z INFO [req-7f3b] POST /api/v1/payments order=11 provider=UZCARD status=201 ms=410
7:2026-10-08T16:28:30.010Z ERROR [req-7f3b] amount mismatch order=11 expected=135000 paid=130000
$ grep "order=11" api.log | grep -c "ERROR"
2
4 ta qator, 2 tasi ERROR. E'tibor bering: order=11 qidiruvi GET /api/v1/orders/11 qatorini ushlamadi — u yerda format boshqa. Logda bir obyekt turli ko'rinishda yozilishi mumkin, shuning uchun bir nechta qidiruv bilan tekshiring.
</details>
Mashq 2: Eng sekin so'rovlar 🟡
api.log dagi ms= qiymatlari bo'yicha eng sekin 3 ta qatorni chiqaring.
<details> <summary>💡 Javobni ko'rish</summary>
$ grep -o "\[req-[a-z0-9]*\].*ms=[0-9]*" api.log | awk -F'ms=' '{print $2, $0}' | sort -rn | head -3 | cut -d' ' -f2-
[req-7f3a] POST /api/v1/payments order=11 status=502 ms=850
[req-7f3b] POST /api/v1/payments order=11 provider=UZCARD status=201 ms=410
[req-5a1c] POST /api/v1/orders user=9 status=201 ms=184
awk har qatorning boshiga ms qiymatini qo'yadi, sort -rn shu son bo'yicha kamayish tartibida saralaydi, cut esa yordamchi sonni olib tashlaydi. Bu ishlaydi, lekin o'qish qiyin. Structured log bo'lsa, xuddi shu vazifa ancha sodda:
$ jq -s -c 'map(select(.ms != null)) | sort_by(-.ms) | .[:3] | map({requestId, path, ms})' app.jsonl
[{"requestId":"req-7f3a","path":"/api/v1/payments","ms":850},{"requestId":"req-7f3b","path":"/api/v1/payments","ms":410},{"requestId":"req-5a1c","path":"/api/v1/orders","ms":184}]
Saboq: matnli logni tahlil qilish mumkin, lekin JSON log va jq bilan ish ancha ishonchli. Loyihangiz hali matnli log yozsa — structured log'ga o'tishni taklif qilish ham QA'ning foydali hissasi.
</details>
Mashq 3: curl + jq 🟢
JSONPlaceholder'dan 1-foydalanuvchining postlari sonini va uning bajarilgan (completed: true) vazifalari sonini aniqlang.
<details> <summary>💡 Javobni ko'rish</summary>
$ curl -s "https://jsonplaceholder.typicode.com/posts?userId=1" | jq length
10
$ curl -s "https://jsonplaceholder.typicode.com/todos?userId=1&completed=true" | jq length
11
Query parametrlari bo'lgan URL'ni qo'shtirnoqqa oling: aks holda & belgisini shell "buyruqni fonda ishga tushir" deb tushunadi, ? esa zsh'da fayl nomi shabloni sifatida talqin qilinishi mumkin.
</details>
Mashq 4: Smoke skriptni kengaytirish 🟡
smoke.sh ga restful-booker'ning POST /auth endpoint'i to'g'ri login bilan token qaytarishini tekshiradigan qadam qo'shing.
<details> <summary>💡 Javobni ko'rish</summary>
token=$(curl -s -X POST "$BASE_URL/auth" \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"password123"}' | jq -r '.token // empty')
if [ -n "$token" ]; then
echo "✅ /auth → token olindi"
else
echo "❌ /auth → token yo'q"
failed=$((failed + 1))
fi
// empty — jq'da "maydon yo'q bo'lsa, bo'sh qaytar" degani; aks holda jq -r null so'zini chiqarib, tekshiruv aldanib qolardi. Bu qadamni if [ "$failed" -gt 0 ] dan oldin qo'ying.
</details>
Mashq 5: Reliz farqi va regression ko'lami 🟡
Dasturchi "v1.3 da faqat README va versiya o'zgardi, regression shart emas" demoqda. 7-bo'limdagi repo'da buni qanday tekshirasiz?
<details> <summary>💡 Javobni ko'rish</summary>
git log --oneline v1.2..v1.3 # qaysi commit'lar kirgan
git diff --stat v1.2 v1.3 # qaysi fayllar o'zgargan
git diff v1.2 v1.3 -- delivery.mjs
git diff --stat delivery.mjs faylida 9 qator qo'shilganini ko'rsatadi. Demak yetkazish narxi va muddati — regression ro'yxatida majburiy. Gap bilan emas, dalil bilan gaplashing: diff'ni ko'rsatib, aniq test ssenariylarini taklif qiling.
</details>
Mashq 6: Build bo'lmaydigan commit'lar 🔴
Katta loyihada bisect paytida ba'zi oraliq commit'lar umuman build bo'lmaydi. git bisect run uchun skriptni qanday yozasiz, toki bunday commit'lar "bad" deb belgilanmasin?
<details> <summary>💡 Javobni ko'rish</summary>
Build xatosida skript 125 bilan chiqishi kerak — git bu commit'ni o'tkazib yuboradi (git bisect skip kabi):
#!/usr/bin/env bash
# bisect-check.sh
npm ci --silent || exit 125 # bog'liqliklar o'rnatilmadi → test qilib bo'lmaydi
npm run build --silent || exit 125 # build bo'lmadi → o'tkazib yuboramiz
node ../qa-check.mjs # 0 = good, 1 = bad
Agar build xatosida exit 1 qilinsa, git bu commit'ni "bad" deb hisoblaydi va noto'g'ri commit'ni aybdor qilib ko'rsatishi mumkin.
</details>
Mashq 7: Lokal bazani noldan boshlash 🟡
Docker Compose'dagi DemoBozor muhitida test ma'lumotlar aralashib ketdi. Bazani butunlay tozalab, qayta ko'taring va API'ning oxirgi 50 qator logini ko'ring. Qaysi buyruq xavfli va nega?
<details> <summary>💡 Javobni ko'rish</summary>
docker compose down -v # konteynerlar + nomlangan volume'lar (baza fayllari) o'chadi
docker compose up -d
docker compose logs -n 50 api
Xavfli qadam — down -v: u db-data volume'ini o'chiradi, bazadagi barcha ma'lumot qaytarib bo'lmas tarzda yo'qoladi. Lokal o'quv bazasi uchun bu aynan maqsad, lekin umumiy muhitlarda bunday buyruq faqat jamoa kelishuvi bilan ishlatiladi.
</details>
Mashq 8: Stack trace'dan test g'oyasigacha 🟡
11-bo'limdagi Java namunasini o'qing. Xato qaysi faylning qaysi qatorida, qaysi foydalanuvchi harakati uni keltirib chiqargan bo'lishi mumkin va qanday test case yozasiz?
<details> <summary>💡 Javobni ko'rish</summary>
- Joy:
PromoService.java, 42-qator,applymetodi (loyiha paketidagi birinchi kadr). - Sabab:
getPromoCode()nullqaytargan, kod esa ungatoUpperCase()chaqirgan — promo-kodsiz buyurtma holati ko'zda tutilmagan. - Harakat: foydalanuvchi promo-kod maydonini bo'sh qoldirib buyurtma bergan (yoki mobil ilova maydonni umuman yubormagan).
- Test case'lar: promo-kodsiz buyurtma (maydon yo'q), bo'sh satr
"", faqat probellar" ", kichik harflikuz2026— hammasida buyurtma muvaffaqiyatli yaratilishi yoki tushunarli validatsiya xabari chiqishi kerak, 500 emas.
</details>
O'zingizni tekshiring {#checklist}
- [ ]
grep -n,-c,-i,-v,-E,-Cflaglarini va pipe'ni ishlata olaman - [ ]
>va>>farqini bilaman, dalilni faylga saqlay olaman - [ ]
curlbilan status kod va JSON javob olaman,jqbilan filtrlayman - [ ] Exit code nima ekanini va CI uchun nega muhimligini tushuntira olaman
- [ ] Feature branch'ga o'tib test qila olaman,
git log v1..v2bilan regression ko'lamini aniqlayman - [ ]
git bisect(qo'lda varunbilan) yordamida aybdor commit'ni topa olaman - [ ] Docker Compose bilan muhitni ko'tarib, loglarini o'qiyman;
down -vxavfini bilaman - [ ] Request ID bo'yicha logdan dalil yig'ib, stack trace'ni bug report'ga matn sifatida qo'shaman
Xulosa {#xulosa}
- Terminal — QA'ning eng tez asbobi:
grep, pipe,tail -f,curlvajqbilan log va API'ni sekundlarda tahlil qilasiz. - Exit code (
0= muvaffaqiyat) skriptlar, CI vagit bisect run'ning umumiy tili. - Git QA uchun — vaqt mashinasi: branch'ni test qilish, reliz farqini ko'rish (
git log v1.2..v1.3),blamevalog -Sbilan kontekst topish. git bisectregressiyani keltirib chiqargan commit'ni binary search bilan topadi; tekshiruv skript bo'lsa — to'liq avtomatik.- Muhitlar, feature flag'lar va
.envkonfiguratsiyasini tushunish "nega staging'da ishlaydi-yu, prod'da yo'q?" savoliga javob beradi. Sirlar Git'ga tushmaydi. - Docker Compose lokal muhitni bir buyruq bilan ko'taradi;
down -v— kuchli, lekin qaytarib bo'lmas "reset". - Loglar va request ID — bug report'ning eng kuchli dalili; stack trace'ni matn sifatida qo'shing, logda sirlar ko'rinsa — bu alohida bug.
- Keyingi dars: QA 14: Mobil ilovalarni testlash — iOS va Android farqlari, Simulator, ADB, TestFlight va checklist
Manbalar {#manbalar}
- Apple — Use zsh as the default shell on your Mac
- Microsoft — Install WSL
- grep(1) — Linux manual page
- tail(1) — Linux manual page
- curl — man page
- jq — Manual va jq — Download
- Git — git-bisect documentation
- Git — git-switch, git-blame, git-stash
- GitHub CLI — gh pr checkout
- The Twelve-Factor App — Config
- Docker — Compose application model (compose.yaml)
- Docker — docker compose logs va docker compose down
- Docker Desktop
- Testcontainers
- W3C — Trace Context
- Grafana Loki — Log queries (LogQL)
- Elastic — KQL
- Sentry — Issues
- Firebase Crashlytics
- Android Developers — Logcat
- Apple — Console User Guide