آزمایش کردن «قوانین امنیتی Cloud Firestore»

هنگام ساختن برنامه‌تان، ممکن است بخواهید دسترسی به پایگاه داده Cloud Firestore را قفل کنید. بااین‌حال، قبل‌از راه‌اندازی، به Cloud Firestore Security Rules دقیق‌تری نیاز دارید. با شبیه‌ساز Cloud Firestore، علاوه‌بر نمونه‌سازی اولیه و آزمایش ویژگی‌ها و رفتار کلی برنامه‌تان، می‌توانید آزمایش‌های واحدی بنویسید که رفتار Cloud Firestore Security Rules شما را بررسی می‌کند.

راه‌اندازی سریع

برای چند چارچوب تست پایه با قوانین ساده، نمونه شروع سریع را امتحان کنید.

درک Cloud Firestore Security Rules

وقتی از کتابخانه‌های کارخواه وب و تلفن همراه استفاده می‌کنید، Firebase Authentication و Cloud Firestore Security Rules را برای اصالت‌سنجی، صدور مجوز، و اعتبارسنجی داده بدون سرور پیاده‌سازی کنید.

Cloud Firestore Security Rules شامل دو بخش است:

  1. عبارت match که اسناد را در پایگاه داده شما شناسایی می‌کند.
  2. عبارت allow که دسترسی به آن اسناد را کنترل می‌کند.

Firebase Authentication اعتبارنامه کاربران را درستی‌سنجی می‌کند و پایه‌ای برای سیستم‌های دسترسی کاربرمحور و نقش‌محور فراهم می‌کند.

هر درخواست پایگاه داده از کتابخانه کارخواه وب/تلفن همراه Rules قبل‌از خواندن یا نوشتن هر داده‌ای، براساس قوانین امنیتی شما ارزیابی می‌شود. اگر قوانین دسترسی به هرکدام از مسیرهای سند مشخص‌شده را رد کند، کل درخواست ناموفق می‌شود.

در شروع به کار با Cloud Firestore Security Rules، درباره Cloud Firestore Security Rules بیشتر بدانید.

نصب شبیه‌ساز

برای نصب شبیه‌ساز Cloud Firestore، از میانای خط فرمان Firebase استفاده کنید و فرمان زیر را اجرا کنید:

firebase setup:emulators:firestore

اجرای شبیه‌ساز

با مقداردهی اولیه پروژه Firebase در دایرکتوری کاری‌تان شروع کنید. این یک گام اول رایج هنگام استفاده از Firebase CLI است.

firebase init

شبیه‌ساز را بااستفاده از فرمان زیر راه‌اندازی کنید. شبیه‌ساز تا زمانی که فرایند را متوقف کنید اجرا خواهد شد:

firebase emulators:start --only firestore

در بسیاری از موارد، می‌خواهید شبیه‌ساز را راه‌اندازی کنید، مجموعه آزمون را اجرا کنید، و سپس شبیه‌ساز را پس‌از اجرای آزمایش‌ها خاموش کنید. می‌توانید این کار را به‌راحتی بااستفاده از فرمان emulators:exec انجام دهید:

firebase emulators:exec --only firestore "./my-test-script.sh"

وقتی شبیه‌ساز شروع می‌شود، تلاش می‌کند روی درگاه پیش‌فرض (۸۰۸۰) اجرا شود. می‌توانید درگاه شبیه‌ساز را با اصلاح بخش "emulators" در فایل firebase.json تغییر دهید:

{
  // ...
  "emulators": {
    "firestore": {
      "port": "YOUR_PORT"
    }
  }
}

قبل‌از اجرای شبیه‌ساز

قبل‌از شروع استفاده از شبیه‌ساز، موارد زیر را درنظر داشته باشید:

  • شبیه‌ساز در ابتدا قوانینی را که در فیلد firestore.rules فایل firebase.json شما مشخص شده است بار می‌کند. این گزینه نام فایل محلی حاوی Cloud Firestore Security Rules شما را می‌خواهد و آن قوانین را برای همه پروژه‌ها اعمال می‌کند. اگر مسیر فایل محلی را ارائه نکنید یا از روش loadFirestoreRules طبق شرح زیر استفاده نکنید، شبیه‌ساز همه پروژه‌ها را دارای قوانین باز درنظر می‌گیرد.
  • درحالی‌که اکثر کیت‌های توسعه نرم‌افزار Firebase مستقیماً با شبیه‌سازها کار می‌کنند، فقط کتابخانه @firebase/rules-unit-testing از شبیه‌سازی auth در «قوانین امنیتی» پشتیبانی می‌کند که آزمایش‌های واحد را بسیار آسان‌تر می‌کند. علاوه‌براین، کتابخانه از چند ویژگی خاص شبیه‌ساز مانند پاک کردن همه داده‌ها پشتیبانی می‌کند، همان‌طور که در زیر فهرست شده است.
  • شبیه‌سازها همچنین توکن‌های Firebase Auth تولیدی را که ازطریق کیت‌های توسعه نرم‌افزار کارخواه ارائه می‌شوند می‌پذیرند و قوانین را براساس آن ارزیابی می‌کنند، که امکان اتصال مستقیم برنامه شما به شبیه‌سازها را در آزمایش‌های دستی و یکپارچه‌سازی فراهم می‌کند.

اجرای آزمایش‌های واحد محلی

اجرای آزمایش‌های واحد محلی با کیت توسعه نرم‌افزار جاوا اسکریپت نسخه ۹

Firebase یک کتابخانه آزمایش واحد «قوانین امنیتی» را با هر دو نسخه 9 کیت توسعه نرم‌افزار جاوا اسکریپت و نسخه 8 کیت توسعه نرم‌افزار خود توزیع می‌کند. میاناهای برنامه‌سازی کاربردی کتابخانه تفاوت قابل‌توجهی دارند. کتابخانه آزمایشی v9 را توصیه می‌کنیم که ساده‌تر است و برای اتصال به شبیه‌سازها به راه‌اندازی کمتری نیاز دارد و بنابراین به‌طور ایمن از استفاده تصادفی از منابع تولید جلوگیری می‌کند. برای سازگاری با نسخه‌های قدیمی، همچنان کتابخانه آزمایشی v8 را دردسترس قرار می‌دهیم.

از پیمانه @firebase/rules-unit-testing برای تعامل با شبیه‌سازی که به‌صورت محلی اجرا می‌شود استفاده کنید. اگر با خطای اتمام مهلت یا خطای ECONNREFUSED مواجه شدید، دوباره بررسی کنید که شبیه‌ساز واقعاً درحال اجرا باشد.

توصیه می‌کنیم از نسخه جدید Node.js استفاده کنید تا بتوانید از نماد async/await استفاده کنید. تقریباً همه رفتارهایی که ممکن است بخواهید آزمایش کنید شامل توابع ناهمگام است و واحد آزمایشی برای کار با کد مبتنی بر Promise طراحی شده است.

کتابخانه v9 Rules Unit Testing همیشه از شبیه‌سازها آگاه است و هرگز به منابع تولید شما دست نمی‌زند.

کتابخانه را بااستفاده از دستورات وارد کردن مدولار نسخه ۹ وارد می‌کنید. برای مثال:

import {
  assertFails,
  assertSucceeds,
  initializeTestEnvironment
} from "@firebase/rules-unit-testing"

// Use `const { … } = require("@firebase/rules-unit-testing")` if imports are not supported
// Or we suggest `const testing = require("@firebase/rules-unit-testing")` if necessary.

پس‌از وارد کردن، پیاده‌سازی آزمون‌های واحد شامل موارد زیر می‌شود:

  • درحال ایجاد و پیکربندی RulesTestEnvironment با تماس با initializeTestEnvironment.
  • راه‌اندازی داده‌های آزمایشی بدون فعال کردن «قوانین»، بااستفاده از روشی راحت که به شما امکان می‌دهد موقتاً آن‌ها را دور بزنید، RulesTestEnvironment.withSecurityRulesDisabled.
  • راه‌اندازی مجموعه آزمون و قلاب‌های قبل/بعداز هر آزمون با تماس‌هایی برای پاک‌سازی داده‌ها و محیط آزمون، مثل RulesTestEnvironment.cleanup() یا RulesTestEnvironment.clearFirestore().
  • پیاده‌سازی چارچوب‌های تستی که وضعیت‌های اصالت‌سنجی را بااستفاده از RulesTestEnvironment.authenticatedContext و RulesTestEnvironment.unauthenticatedContext شبیه‌سازی می‌کنند.

روش‌های رایج و توابع سودمندی

همچنین، روش‌های آزمایش مختص شبیه‌ساز در کیت توسعه نرم‌افزار نسخه ۹ را ببینید.

initializeTestEnvironment() => RulesTestEnvironment

این تابع محیط آزمایشی را برای آزمایش واحد قوانین مقداردهی اولیه می‌کند. ابتدا این تابع را برای راه‌اندازی آزمایش فراخوانی کنید. برای اجرای موفقیت‌آمیز، شبیه‌سازها باید درحال اجرا باشند.

این تابع شیء اختیاری‌ای را می‌پذیرد که TestEnvironmentConfig را تعریف می‌کند، که می‌تواند شامل شناسه پروژه و تنظیمات پیکربندی شبیه‌ساز باشد.

let testEnv = await initializeTestEnvironment({
  projectId: "demo-project-1234",
  firestore: {
    rules: fs.readFileSync("firestore.rules", "utf8"),
  },
});

RulesTestEnvironment.authenticatedContext({ user_id: string, tokenOptions?: TokenOptions }) => RulesTestContext

این روش یک RulesTestContext ایجاد می‌کند که مانند یک کاربر اصالت‌سنجی‌شده رفتار می‌کند. درخواست‌های ایجادشده ازطریق بافت برگردانده‌شده دارای یک نشان اصالت‌سنجی ساختگی خواهند بود. درصورت تمایل، شیئی را ارسال کنید که ادعاهای سفارشی یا جایگزینی‌های بار داده‌های کد اصالت‌سنجی را تعریف می‌کند.

از شیء زمینه آزمایشی برگردانده‌شده در آزمایش‌هایتان برای دسترسی به هر نمونه شبیه‌ساز پیکربندی‌شده، ازجمله نمونه‌های پیکربندی‌شده با initializeTestEnvironment، استفاده کنید.

// Assuming a Firestore app and the Firestore emulator for this example
import { setDoc } from "firebase/firestore";

const alice = testEnv.authenticatedContext("alice", { … });
// Use the Firestore instance associated with this context
await assertSucceeds(setDoc(alice.firestore().doc('/users/alice'), { ... });

RulesTestEnvironment.unauthenticatedContext() => RulesTestContext

این روش یک RulesTestContext ایجاد می‌کند که مانند یک مشتری رفتار می‌کند که ازطریق اصالت‌سنجی وارد سیستم نشده است. درخواست‌های ایجادشده ازطریق زمینه برگردانده‌شده نشان Firebase Auth پیوست‌شده نخواهند داشت.

از شیء زمینه آزمایشی برگردانده‌شده در آزمایش‌هایتان برای دسترسی به هر نمونه شبیه‌ساز پیکربندی‌شده، ازجمله نمونه‌های پیکربندی‌شده با initializeTestEnvironment، استفاده کنید.

// Assuming a Cloud Storage app and the Storage emulator for this example
import { getStorage, ref, deleteObject } from "firebase/storage";

const alice = testEnv.unauthenticatedContext();

// Use the Cloud Storage instance associated with this context
const desertRef = ref(alice.storage(), 'images/desert.jpg');
await assertSucceeds(deleteObject(desertRef));

RulesTestEnvironment.withSecurityRulesDisabled()

تابع راه‌اندازی آزمایشی را با زمینه‌ای اجرا کنید که طوری رفتار می‌کند که گویی «قوانین امنیتی» غیرفعال شده‌اند.

این روش یک تابع بازخوانی می‌گیرد که بافت دور زدن قوانین امنیتی را می‌گیرد و یک وعده برمی‌گرداند. وقتی promise حل‌وفصل / رد شود، بافت ازبین می‌رود.

RulesTestEnvironment.cleanup()

این روش همه RulesTestContexts ایجادشده در محیط آزمایشی را ازبین می‌برد و منابع زیربنایی را پاک‌سازی می‌کند تا خروج تمیزی انجام شود.

این روش به هیچ وجه وضعیت شبیه‌سازها را تغییر نمی‌دهد. برای بازنشانی داده‌ها بین آزمایش‌ها، از روش پاک کردن داده‌های مختص شبیه‌ساز برنامه استفاده کنید.

assertSucceeds(pr: Promise<any>)) => Promise<any>

This is a test case utility function.

این تابع ادعا می‌کند که Promise ارائه‌شده که عملیات شبیه‌ساز را دربرمی‌گیرد بدون هیچ‌گونه نقض «قوانین امنیتی» حل‌وفصل خواهد شد.

await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });

assertFails(pr: Promise<any>)) => Promise<any>

This is a test case utility function.

این تابع تأیید می‌کند که Promise ارائه‌شده که عملیات شبیه‌ساز را دربرمی‌گیرد به‌دلیل نقض «قوانین امنیتی» رد خواهد شد.

await assertFails(setDoc(alice.firestore(), '/users/bob'), { ... });

روش‌های مختص شبیه‌ساز

همچنین روش‌های آزمایش رایج و توابع سودمندی در کیت توسعه نرم‌افزار v9 را ببینید.

RulesTestEnvironment.clearFirestore() => Promise<void>

این روش داده‌های موجود در پایگاه داده Firestore را که متعلق به projectId پیکربندی‌شده برای شبیه‌ساز Firestore است پاک می‌کند.

RulesTestContext.firestore(settings?: Firestore.FirestoreSettings) => Firestore;

این روش یک نمونه Firestore برای این زمینه آزمایشی دریافت می‌کند. نمونه «کیت توسعه نرم‌افزار کارخواه Firebase JS» برگردانده‌شده را می‌توان با میاناهای برنامه‌سازی کاربردی کیت توسعه نرم‌افزار کارخواه (v9 modular یا v9 compat) استفاده کرد.

تجسم ارزیابی‌های قوانین

شبیه‌ساز Cloud Firestore به شما امکان می‌دهد درخواست‌های مشتری را در رابط کاربری «مجموعه شبیه‌ساز» تجسم کنید، ازجمله ردیابی ارزیابی برای «قوانین امنیتی Firebase».

برگه Firestore > درخواست‌ها را باز کنید تا توالی ارزیابی دقیق را برای هر درخواست مشاهده کنید.

«پایشگر درخواست‌های شبیه‌ساز Firestore» که ارزیابی‌های «قوانین امنیتی» را نشان می‌دهد

تولید گزارش‌های آزمایش

پس‌از اجرای مجموعه‌ای از آزمایش‌ها، می‌توانید به گزارش‌های پوشش آزمایش دسترسی پیدا کنید که نشان می‌دهد هریک از قوانین امنیتی شما چگونه ارزیابی شده است.

برای دریافت گزارش‌ها، نقطه پایانی را که در شبیه‌ساز درحال اجرا نمایش داده شده است پُرسمان کنید. برای نسخه سازگار با مرورگر، از نشانی وب زیر استفاده کنید:

http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage.html

این کار قوانین شما را به عبارت‌ها و زیرعبارت‌هایی تقسیم می‌کند که می‌توانید برای اطلاعات بیشتر، ازجمله تعداد ارزیابی‌ها و مقادیر برگردانده‌شده، موشواره را روی آن‌ها نگه دارید. برای نسخه JSON خام این داده‌ها، نشانی وب زیر را در پرسمانتان اضافه کنید:

http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage

تفاوت‌های بین شبیه‌ساز و تولید

  1. لازم نیست صریحاً پروژه Cloud Firestore ایجاد کنید. شبیه‌ساز به‌طور خودکار هر نمونه‌ای را که به آن دسترسی پیدا شود ایجاد می‌کند.
  2. شبیه‌ساز Cloud Firestore با جریان عادی Firebase Authentication کار نمی‌کند. درعوض، در Firebase Test SDK، روش initializeTestApp() را در کتابخانه rules-unit-testing ارائه کرده‌ایم که فیلد auth را می‌گیرد. دستگیره Firebase ایجادشده بااستفاده از این روش طوری رفتار خواهد کرد که گویی با موفقیت به‌عنوان هر نهادی که ارائه می‌دهید اصالت‌سنجی شده است. اگر null را وارد کنید، به‌عنوان کاربر تأییدنشده رفتار خواهد کرد (برای مثال، قوانین auth != null ناموفق خواهد بود).

عیب‌یابی کردن مشکلات شناخته‌شده

هنگام استفاده از شبیه‌ساز Cloud Firestore، ممکن است با مشکلات شناخته‌شده زیر مواجه شوید. برای عیب‌یابی هرگونه رفتار نامنظمی که تجربه می‌کنید، راهنمایی‌های زیر را دنبال کنید. این یادداشت‌ها با درنظر گرفتن کتابخانه آزمایش واحد «قوانین امنیتی» نوشته شده‌اند، اما رویکردهای کلی برای هر «کیت توسعه نرم‌افزار Firebase» قابل‌اعمال است.

رفتار آزمایشی ناسازگار است

اگر آزمایش‌هایتان گاهی موفق و گاهی ناموفق است، حتی بدون هیچ تغییری در خود آزمایش‌ها، ممکن است لازم باشد بررسی کنید که به‌درستی توالی‌بندی شده باشند. اکثر تعامل‌ها با شبیه‌ساز ناهمگام هستند، بنابراین دوباره‌سنجی کنید که همه کدهای ناهمگام به‌درستی توالی‌بندی شده باشند. می‌توانید توالی را با زنجیره‌ای کردن وعده‌ها یا استفاده آزادانه از نماد await اصلاح کنید.

به‌ویژه، عملیات ناهمگام زیر را مرور کنید:

  • تنظیم قوانین امنیتی، برای مثال، با initializeTestEnvironment.
  • خواندن و نوشتن داده‌ها، برای مثال، با db.collection("users").doc("alice").get().
  • ادعاهای عملیاتی، ازجمله assertSucceeds و assertFails.

آزمایش‌ها فقط اولین باری که شبیه‌ساز را بار می‌کنید قبول می‌شوند

شبیه‌ساز حالت‌دار است. این دیسک همه داده‌های نوشته‌شده در آن را در حافظه ذخیره می‌کند، بنابراین هرگاه شبیه‌ساز خاموش شود، همه داده‌ها ازبین می‌رود. اگر چند آزمایش را برای یک شناسه پروژه اجرا می‌کنید، هر آزمایش می‌تواند داده‌هایی تولید کند که ممکن است بر آزمایش‌های بعدی تأثیر بگذارد. می‌توانید از هریک از روش‌های زیر برای دور زدن این رفتار استفاده کنید:

  • برای هر آزمایش از شناسه‌های پروژه یکتا استفاده کنید. توجه داشته باشید که اگر این کار را انتخاب کنید، باید initializeTestEnvironment را به‌عنوان بخشی از هر آزمایش فراخوانی کنید؛ قوانین فقط به‌طور خودکار برای شناسه پروژه پیش‌فرض بار می‌شود.
  • آزمایش‌هایتان را بازسازی کنید تا با داده‌های قبلاً نوشته‌شده تعامل نداشته باشند (برای مثال، برای هر آزمایش از مجموعه متفاوتی استفاده کنید).
  • همه داده‌های نوشته‌شده درطول آزمایش را حذف کنید.

راه‌اندازی آزمایش بسیار پیچیده است

هنگام راه‌اندازی آزمایش، ممکن است بخواهید داده‌ها را به‌گونه‌ای تغییر دهید که Cloud Firestore Security Rules درواقع اجازه نمی‌دهد. اگر قوانین شما راه‌اندازی آزمایشی را پیچیده می‌کند، از RulesTestEnvironment.withSecurityRulesDisabled در مراحل راه‌اندازی استفاده کنید تا خواندن و نوشتن خطاهای PERMISSION_DENIED را راه‌اندازی نکند.

پس‌از آن، آزمون شما می‌تواند عملیات را به‌عنوان کاربر اصالت‌سنجی‌شده یا اصالت‌سنجی‌نشده به‌ترتیب بااستفاده از RulesTestEnvironment.authenticatedContext و unauthenticatedContext انجام دهد. این کار به شما امکان می‌دهد اعتبار سنجی کنید که Cloud Firestore Security Rules شما موارد مختلف را به‌درستی مجاز می‌کند / رد می‌کند.