При создании приложения вы можете ограничить доступ к базе данных 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 состоят из двух частей:
- Инструкция
match, которая идентифицирует документы в базе данных. - Выражение
allow, которое управляет доступом к этим документам.
Firebase Authentication проверяет учетные данные пользователей и обеспечивает основу для систем доступа на основе пользователей и ролей.
Каждый запрос к базе данных из клиентской библиотеки правил для мобильных устройств или веб-клиентов оценивается на соответствие правилам безопасности перед чтением или записью любых данных. Если правила запрещают доступ к любому из указанных путей к документам, весь запрос завершается ошибкой.
Подробнее Cloud Firestore Security Rules рассказывается в статье Начало работы с Cloud Firestore Security Rules.
Установите эмулятор
Чтобы установить эмулятор Cloud Firestore, используйте интерфейс командной строки Firebase и выполните команду ниже.
firebase setup:emulators:firestore
Запустите эмулятор
Сначала инициализируйте проект Firebase в рабочем каталоге. Это распространенный первый шаг при использовании интерфейса командной строки Firebase.
firebase init
Запустите эмулятор с помощью следующей команды. Эмулятор будет работать, пока вы не остановите процесс:
firebase emulators:start --only firestore
Во многих случаях вам нужно запустить эмулятор, запустить набор тестов, а затем выключить эмулятор после запуска тестов. Это можно сделать с помощью команды emulators:exec:
firebase emulators:exec --only firestore "./my-test-script.sh"
При запуске эмулятор попытается использовать порт по умолчанию (8080). Чтобы изменить порт эмулятора, отредактируйте раздел "emulators" в файле firebase.json:
{
// ...
"emulators": {
"firestore": {
"port": "YOUR_PORT"
}
}
}Перед запуском эмулятора
Прежде чем начать работу с эмулятором, обратите внимание на следующее:
- Эмулятор сначала загрузит правила, указанные в поле
firestore.rulesфайлаfirebase.json. Она ожидает название локального файла, содержащего ваш Cloud Firestore Security Rules, и применяет эти правила ко всем проектам. Если вы не укажете путь к локальному файлу или не воспользуетесь методомloadFirestoreRules, как описано ниже, эмулятор будет считать, что правила открыты для всех проектов. - Хотя большинство Firebase SDK работают с эмуляторами напрямую, только библиотека
@firebase/rules-unit-testingподдерживает имитациюauthв правилах безопасности, что значительно упрощает модульное тестирование. Кроме того, библиотека поддерживает несколько функций, характерных для эмулятора, например очистку всех данных, как указано ниже. - Эмуляторы также принимают рабочие токены Firebase Auth, предоставляемые клиентскими SDK, и оценивают правила соответствующим образом, что позволяет подключать приложение непосредственно к эмуляторам при интеграции и ручном тестировании.
Запустите локальные модульные тесты
Как запустить локальное модульное тестирование с помощью JavaScript SDK версии 9
Firebase распространяет библиотеку модульного тестирования правил безопасности вместе с JavaScript SDK версий 8 и 9. API библиотек значительно различаются. Мы рекомендуем использовать библиотеку тестирования версии 9, которая более оптимизирована и требует меньше настроек для подключения к эмуляторам, что позволяет безопасно избежать случайного использования рабочих ресурсов. Для обеспечения обратной совместимости мы по-прежнему предоставляем библиотеку тестирования v8.
- Распространенные методы тестирования и служебные функции в SDK версии 9
- Методы тестирования в эмуляторе в SDK версии 9
Для взаимодействия с эмулятором, который работает локально, используйте модуль @firebase/rules-unit-testing. Если вы получаете ошибки ECONNREFUSED или ошибки, связанные с превышением времени ожидания, убедитесь, что эмулятор действительно запущен.
Мы настоятельно рекомендуем использовать последнюю версию Node.js, чтобы вы могли использовать нотацию async/await. Почти все действия, которые вы захотите протестировать, включают асинхронные функции, а модуль тестирования предназначен для работы с кодом на основе Promise.
Библиотека модульного тестирования правил v9 всегда знает об эмуляторах и никогда не касается ваших производственных ресурсов.
Вы импортируете библиотеку, используя операторы модульного импорта версии 9. Пример:
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.
Общие методы и служебные функции
Также ознакомьтесь с методами тестирования, предназначенными для эмулятора, в SDK версии 9.
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. Контекст будет удален, как только объект Promise будет распознан или отклонен.
RulesTestEnvironment.cleanup()
Этот метод удаляет все объекты RulesTestContexts, созданные в тестовой среде, и очищает базовые ресурсы, позволяя выполнить чистый выход.
Этот метод никак не влияет на состояние эмуляторов. Чтобы сбросить данные между тестами, используйте метод очистки данных, предназначенный для эмулятора приложения.
assertSucceeds(pr: Promise<any>)) => Promise<any>
Это служебная функция отчета о тестировании.
Функция утверждает, что предоставленный объект Promise, который содержит операцию эмулятора, будет разрешен без нарушений правил безопасности.
await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });assertFails(pr: Promise<any>)) => Promise<any>
Это служебная функция отчета о тестировании.
Функция утверждает, что предоставленный Promise, который оборачивает операцию эмулятора, будет отклонен из-за нарушения правил безопасности.
await assertFails(setDoc(alice.firestore(), '/users/bob'), { ... });Методы, относящиеся к эмулятору
Также ознакомьтесь с распространенными методами тестирования и служебными функциями в SDK версии 9.
RulesTestEnvironment.clearFirestore() => Promise<void>
Этот метод очищает данные в базе данных Firestore, которая принадлежит projectId, настроенному для эмулятора Firestore.
RulesTestContext.firestore(settings?: Firestore.FirestoreSettings) => Firestore;
Этот метод получает экземпляр Firestore для этого контекста тестирования. Возвращенный экземпляр Firebase JS Client SDK можно использовать с API клиентского SDK (модульным или совместимым v9).
Визуализация оценок правил
Эмулятор Cloud Firestore позволяет визуализировать запросы клиентов в интерфейсе Emulator Suite, включая трассировку оценки для правил безопасности Firebase.
Откройте вкладку Firestore > Requests (Firestore > Запросы), чтобы посмотреть подробную последовательность оценки для каждого запроса.
Создание отчетов о тестировании
После запуска набора тестов вы можете получить доступ к отчетам о покрытии тестами, в которых показано, как оценивалось каждое из ваших правил безопасности.
Чтобы получить отчеты, отправьте запрос к конечной точке эмулятора, пока он работает. Чтобы открыть версию для браузера, перейдите по следующему URL:
http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage.html
Правила будут разбиты на выражения и подвыражения. Наведите указатель мыши на выражение, чтобы увидеть дополнительную информацию, в том числе количество вычислений и возвращенные значения. Чтобы получить необработанные данные в формате JSON, добавьте в запрос следующий URL:
http://localhost:8080/emulator/v1/projects/<project_id>:ruleCoverage
Различия между эмулятором и рабочей средой
- Вам не нужно создавать проект Cloud Firestore. Эмулятор автоматически создает любой экземпляр, к которому осуществляется доступ.
- Эмулятор Cloud Firestore не работает с обычным процессом Firebase Authentication.
Вместо этого в Firebase Test SDK мы добавили метод
initializeTestApp()в библиотекуrules-unit-testing, который принимает полеauth. Дескриптор Firebase, созданный с помощью этого метода, будет вести себя так, как будто он успешно прошел аутентификацию в качестве любого указанного вами объекта. Если вы передадитеnull, он будет вести себя как неаутентифицированный пользователь (например, правилаauth != nullне будут выполняться).
Устранение известных неполадок
При использовании эмулятора Cloud Firestore могут возникать следующие известные проблемы. Ниже приведены инструкции по устранению неполадок. Эти примечания написаны с учетом библиотеки модульного тестирования правил безопасности, но общие подходы применимы к любому Firebase SDK.
Нестабильное поведение теста
Если тесты иногда проходят, а иногда нет, даже если вы не вносили в них никаких изменений, возможно, вам нужно проверить, правильно ли они упорядочены.
Большинство взаимодействий с эмулятором асинхронны, поэтому убедитесь, что весь асинхронный код выполняется в правильной последовательности. Чтобы исправить последовательность, можно связать промисы или использовать нотацию 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 разрешает или запрещает доступ в разных случаях.