Skip to content

Commit c3a045c

Browse files
committed
chore: Setup emulator testing for Functions integration tests
1 parent 9cdf76a commit c3a045c

File tree

7 files changed

+157
-14
lines changed

7 files changed

+157
-14
lines changed

.github/workflows/ci.yml

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@ jobs:
1212

1313
steps:
1414
- uses: actions/checkout@v4
15+
16+
- name: Set up Python 3.13 for emulator
17+
uses: actions/setup-python@v5
18+
with:
19+
python-version: '3.13'
20+
- name: Setup functions emulator environment
21+
run: |
22+
python -m venv integration/emulators/functions/venv
23+
source integration/emulators/functions/venv/bin/activate
24+
pip install -r integration/emulators/functions/requirements.txt
25+
deactivate
1526
- name: Set up Python ${{ matrix.python }}
1627
uses: actions/setup-python@v5
1728
with:
@@ -26,12 +37,12 @@ jobs:
2637
uses: actions/setup-node@v4
2738
with:
2839
node-version: 20
29-
- name: Run integration tests against emulator
30-
run: |
31-
npm install -g firebase-tools
32-
firebase emulators:exec --only database --project fake-project-id 'pytest integration/test_db.py'
33-
34-
lint:
40+
- name: Install firebase-tools
41+
run: npm install -g firebase-tools
42+
- name: Run Database emulator tests
43+
run: firebase emulators:exec --only database --project fake-project-id 'pytest integration/test_db.py'
44+
- name: Run Functions emulator tests
45+
run: firebase emulators:exec --config integration/emulators/firebase.json --only tasks,functions --project fake-project-id 'CLOUD_TASKS_EMULATOR_HOST=localhost:9499 pytest integration/test_functions.py'
3546
runs-on: ubuntu-latest
3647
steps:
3748
- uses: actions/checkout@v4

integration/emulators/.gitignore

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
firebase-debug.log*
8+
firebase-debug.*.log*
9+
10+
# Firebase cache
11+
.firebase/
12+
13+
# Firebase config
14+
15+
# Uncomment this if you'd like others to create their own Firebase project.
16+
# For a team working on the same Firebase project(s), it is recommended to leave
17+
# it commented so all members can deploy to the same project(s) in .firebaserc.
18+
# .firebaserc
19+
20+
# Runtime data
21+
pids
22+
*.pid
23+
*.seed
24+
*.pid.lock
25+
26+
# Directory for instrumented libs generated by jscoverage/JSCover
27+
lib-cov
28+
29+
# Coverage directory used by tools like istanbul
30+
coverage
31+
32+
# nyc test coverage
33+
.nyc_output
34+
35+
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
36+
.grunt
37+
38+
# Bower dependency directory (https://bower.io/)
39+
bower_components
40+
41+
# node-waf configuration
42+
.lock-wscript
43+
44+
# Compiled binary addons (http://nodejs.org/api/addons.html)
45+
build/Release
46+
47+
# Dependency directories
48+
node_modules/
49+
50+
# Optional npm cache directory
51+
.npm
52+
53+
# Optional eslint cache
54+
.eslintcache
55+
56+
# Optional REPL history
57+
.node_repl_history
58+
59+
# Output of 'npm pack'
60+
*.tgz
61+
62+
# Yarn Integrity file
63+
.yarn-integrity
64+
65+
# dotenv environment variables file
66+
.env
67+
68+
# dataconnect generated files
69+
.dataconnect
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"emulators": {
3+
"tasks": {
4+
"port": 9499
5+
},
6+
"ui": {
7+
"enabled": false
8+
},
9+
"singleProjectMode": true,
10+
"functions": {
11+
"port": 5001
12+
}
13+
},
14+
"functions": [
15+
{
16+
"source": "functions",
17+
"codebase": "default",
18+
"disallowLegacyRuntimeConfig": true,
19+
"ignore": [
20+
"venv",
21+
".git",
22+
"firebase-debug.log",
23+
"firebase-debug.*.log",
24+
"*.local"
25+
],
26+
"runtime": "python313"
27+
}
28+
]
29+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Python bytecode
2+
__pycache__/
3+
4+
# Python virtual environment
5+
venv/
6+
*.local
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from firebase_functions import tasks_fn
2+
3+
@tasks_fn.on_task_dispatched()
4+
def testTaskQueue(req: tasks_fn.CallableRequest) -> None:
5+
"""Handles tasks from the task queue."""
6+
print(f"Received task with data: {req.data}")
7+
return
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
firebase_functions~=0.4.1

integration/test_functions.py

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,35 @@
1414

1515
"""Integration tests for firebase_admin.functions module."""
1616

17+
import os
1718
import pytest
1819

1920
import firebase_admin
2021
from firebase_admin import functions
22+
from firebase_admin import _utils
2123
from integration import conftest
2224

2325

2426
_DEFAULT_DATA = {'data': {'city': 'Seattle'}}
27+
def integration_conf(request):
28+
host_override = os.environ.get('CLOUD_TASKS_EMULATOR_HOST')
29+
if host_override:
30+
return _utils.EmulatorAdminCredentials(), 'fake-project-id'
31+
32+
return conftest.integration_conf(request)
2533

2634
@pytest.fixture(scope='module')
2735
def app(request):
28-
cred, _ = conftest.integration_conf(request)
29-
return firebase_admin.initialize_app(cred, name='integration-functions')
36+
cred, project_id = integration_conf(request)
37+
return firebase_admin.initialize_app(
38+
cred, options={'projectId': project_id}, name='integration-functions')
39+
40+
@pytest.fixture(scope='module', autouse=True)
41+
def default_app(request):
42+
cred, project_id = integration_conf(request)
43+
app = firebase_admin.initialize_app(cred, options={'projectId': project_id})
44+
yield app
45+
firebase_admin.delete_app(app)
3046

3147

3248
class TestFunctions:
@@ -56,17 +72,21 @@ def test_task_queue_app(self, task_queue_params, app):
5672
assert queue is not None
5773
assert callable(queue.enqueue)
5874
assert callable(queue.delete)
59-
60-
def test_task_enqueue(self, app):
61-
queue = functions.task_queue('testTaskQueue', app=app)
75+
76+
def test_task_enqueue(self):
77+
queue = functions.task_queue('testTaskQueue')
6278
task_id = queue.enqueue(_DEFAULT_DATA)
6379
assert task_id is not None
64-
65-
def test_task_delete(self, app):
80+
81+
@pytest.mark.skipif(
82+
os.environ.get('CLOUD_TASKS_EMULATOR_HOST') is not None,
83+
reason="Skipping test_task_delete against emulator due to bug in firebase-tools"
84+
)
85+
def test_task_delete(self):
6686
# Skip this test against the emulator since tasks can't be delayed there to verify deletion
6787
# See: https://github.com/firebase/firebase-tools/issues/8254
6888
task_options = functions.TaskOptions(schedule_delay_seconds=60)
69-
queue = functions.task_queue('testTaskQueue', app=app)
89+
queue = functions.task_queue('testTaskQueue')
7090
task_id = queue.enqueue(_DEFAULT_DATA, task_options)
7191
assert task_id is not None
7292
queue.delete(task_id)

0 commit comments

Comments
 (0)