@@ -37,3 +37,64 @@ def test_plotusers_loads_local_plotly(client):
3737 with patch ('google.cloud.ndb.Key' , return_value = mock_key_instance ):
3838 response = client .get ('/plotusers' )
3939 assert b'plotlyVP7.min.js' in response .data
40+
41+
42+ def test_update_user_count_no_cron_header (client ):
43+ """Returns 403 when X-Appengine-Cron header is absent."""
44+ response = client .get ('/admin/update-user-count' )
45+ assert response .status_code == 403
46+
47+
48+ def test_update_user_count_appends_new_point (client ):
49+ """Appends a new data point to existing history and returns 200."""
50+ existing = {
51+ 'updated' : '2026-04-01' ,
52+ 'points' : [{'month' : '2012-09' , 'count' : 320 }],
53+ }
54+
55+ stat_mock = MagicMock ()
56+ stat_mock .count = 314925
57+
58+ setting_mock = MagicMock ()
59+ setting_mock .value = json .dumps (existing )
60+
61+ def key_factory (* args , ** kwargs ):
62+ m = MagicMock ()
63+ if args and args [0 ] == '__Stat_Kind__' :
64+ m .get .return_value = stat_mock
65+ else :
66+ m .get .return_value = setting_mock
67+ return m
68+
69+ with patch ('google.cloud.ndb.Key' , side_effect = key_factory ):
70+ response = client .get ('/admin/update-user-count' ,
71+ headers = {'X-Appengine-Cron' : 'true' })
72+
73+ assert response .status_code == 200
74+ updated_history = json .loads (setting_mock .value )
75+ assert len (updated_history ['points' ]) == 2
76+ assert updated_history ['points' ][- 1 ]['count' ] == 314925
77+ setting_mock .put .assert_called_once ()
78+
79+
80+ def test_update_user_count_creates_setting_when_missing (client ):
81+ """Creates a new Setting entity when none exists."""
82+ stat_mock = MagicMock ()
83+ stat_mock .count = 100
84+
85+ def key_factory (* args , ** kwargs ):
86+ m = MagicMock ()
87+ if args and args [0 ] == '__Stat_Kind__' :
88+ m .get .return_value = stat_mock
89+ else :
90+ m .get .return_value = None
91+ return m
92+
93+ with patch ('google.cloud.ndb.Key' , side_effect = key_factory ), \
94+ patch ('ide.routes.Setting' ) as mock_setting_class :
95+ response = client .get ('/admin/update-user-count' ,
96+ headers = {'X-Appengine-Cron' : 'true' })
97+
98+ assert response .status_code == 200
99+ mock_setting_class .assert_called_once_with (id = 'user_count_history' )
100+ mock_setting_class .return_value .put .assert_called_once ()
0 commit comments