Coverage for app / backend / src / tests / test_model_constraints.py: 96%

102 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-03-19 14:14 +0000

1import pytest 

2from sqlalchemy.exc import IntegrityError 

3from sqlalchemy.sql import func 

4 

5from couchers.db import session_scope 

6from couchers.models import ( 

7 ActivenessProbe, 

8 ActivenessProbeStatus, 

9 Cluster, 

10 Node, 

11 NodeType, 

12 Page, 

13 PageType, 

14 PageVersion, 

15 Thread, 

16) 

17from couchers.utils import create_polygon_lat_lng, to_multi 

18from tests.fixtures.db import generate_user 

19from tests.test_communities import create_1d_polygon, create_community 

20 

21 

22@pytest.fixture(autouse=True) 

23def _(testconfig): 

24 pass 

25 

26 

27def test_node_constraints(db): 

28 # check we can't have two official clusters for a given node 

29 with pytest.raises(IntegrityError) as e: 

30 with session_scope() as session: 

31 node = Node(geom=to_multi(create_1d_polygon(0, 2)), node_type=NodeType.world) 

32 session.add(node) 

33 session.flush() 

34 cluster1 = Cluster( 

35 name="Testing community, cluster 1", 

36 description="Testing community description", 

37 parent_node_id=node.id, 

38 is_official_cluster=True, 

39 ) 

40 session.add(cluster1) 

41 cluster2 = Cluster( 

42 name="Testing community, cluster 2", 

43 description="Testing community description", 

44 parent_node_id=node.id, 

45 is_official_cluster=True, 

46 ) 

47 session.add(cluster2) 

48 assert "violates unique constraint" in str(e.value) 

49 assert "ix_clusters_owner_parent_node_id_is_official_cluster" in str(e.value) 

50 

51 

52def test_page_constraints(db): 

53 user, token = generate_user() 

54 

55 with session_scope() as session: 

56 c_id = create_community(session, 0, 2, "Root node", [user], [], None).id 

57 

58 # check we can't create a page without an owner 

59 with pytest.raises(IntegrityError) as e: 

60 with session_scope() as session: 

61 thread = Thread() 

62 session.add(thread) 

63 session.flush() 

64 page = Page( 

65 parent_node_id=c_id, 

66 # note no owner 

67 creator_user_id=user.id, 

68 type=PageType.guide, 

69 thread_id=thread.id, 

70 ) 

71 session.add(page) 

72 session.flush() 

73 session.add( 

74 PageVersion( 

75 page_id=page.id, 

76 editor_user_id=user.id, 

77 title="Title", 

78 content="Content", 

79 ) 

80 ) 

81 assert "violates check constraint" in str(e.value) 

82 assert "one_owner" in str(e.value) 

83 

84 with session_scope() as session: 

85 node = Node( 

86 geom=to_multi(create_polygon_lat_lng([[0, 0], [0, 2], [2, 2], [2, 0], [0, 0]])), node_type=NodeType.world 

87 ) 

88 session.add(node) 

89 session.flush() 

90 cluster = Cluster( 

91 name="Testing Community", 

92 description="Description for testing community", 

93 parent_node_id=node.id, 

94 ) 

95 session.add(cluster) 

96 session.flush() 

97 cluster_parent_id = cluster.parent_node_id 

98 cluster_id = cluster.id 

99 

100 # check we can't create a page with two owners 

101 with pytest.raises(IntegrityError) as e: 

102 with session_scope() as session: 

103 thread = Thread() 

104 session.add(thread) 

105 session.flush() 

106 page = Page( 

107 parent_node_id=cluster_parent_id, 

108 creator_user_id=user.id, 

109 owner_cluster_id=cluster_id, 

110 owner_user_id=user.id, 

111 type=PageType.guide, 

112 thread_id=thread.id, 

113 ) 

114 session.add(page) 

115 session.flush() 

116 session.add( 

117 PageVersion( 

118 page_id=page.id, 

119 editor_user_id=user.id, 

120 title="Title", 

121 content="Content", 

122 ) 

123 ) 

124 assert "violates check constraint" in str(e.value) 

125 assert "one_owner" in str(e.value) 

126 

127 # main page must be owned by the right cluster 

128 with pytest.raises(IntegrityError) as e: 

129 with session_scope() as session: 

130 thread = Thread() 

131 session.add(thread) 

132 session.flush() 

133 main_page = Page( 

134 parent_node_id=cluster_parent_id, 

135 # note owner is not cluster 

136 creator_user_id=user.id, 

137 owner_user_id=user.id, 

138 type=PageType.main_page, 

139 thread_id=thread.id, 

140 ) 

141 session.add(main_page) 

142 session.flush() 

143 session.add( 

144 PageVersion( 

145 page_id=main_page.id, 

146 editor_user_id=user.id, 

147 title="Main page for the testing community", 

148 content="Empty.", 

149 ) 

150 ) 

151 assert "violates check constraint" in str(e.value) 

152 assert "main_page_owned_by_cluster" in str(e.value) 

153 

154 # can only have one main page 

155 with pytest.raises(IntegrityError) as e: 

156 with session_scope() as session: 

157 thread1 = Thread() 

158 session.add(thread1) 

159 session.flush() 

160 main_page1 = Page( 

161 parent_node_id=cluster_parent_id, 

162 creator_user_id=user.id, 

163 owner_cluster_id=cluster_id, 

164 type=PageType.main_page, 

165 thread_id=thread1.id, 

166 ) 

167 session.add(main_page1) 

168 session.flush() 

169 session.add( 

170 PageVersion( 

171 page_id=main_page1.id, 

172 editor_user_id=user.id, 

173 title="Main page 1 for the testing community", 

174 content="Empty.", 

175 ) 

176 ) 

177 thread2 = Thread() 

178 session.add(thread2) 

179 session.flush() 

180 main_page2 = Page( 

181 parent_node_id=cluster_parent_id, 

182 creator_user_id=user.id, 

183 owner_cluster_id=cluster_id, 

184 type=PageType.main_page, 

185 thread_id=thread2.id, 

186 ) 

187 session.add(main_page2) 

188 session.flush() 

189 session.add( 

190 PageVersion( 

191 page_id=main_page2.id, 

192 editor_user_id=user.id, 

193 title="Main page 2 for the testing community", 

194 content="Empty.", 

195 ) 

196 ) 

197 assert "violates unique constraint" in str(e.value) 

198 assert "ix_pages_owner_cluster_id_type" in str(e.value) 

199 

200 

201def test_activeness_probes_cant_have_multiple(db): 

202 # can't have two active activeness probes for a given user 

203 user, token = generate_user() 

204 

205 with session_scope() as session: 

206 # we can create one 

207 first_probe = ActivenessProbe(user_id=user.id) 

208 session.add(first_probe) 

209 session.commit() 

210 

211 # change it to expired 

212 first_probe.response = ActivenessProbeStatus.expired 

213 first_probe.responded = func.now() 

214 session.commit() 

215 

216 # can create another one 

217 session.add(ActivenessProbe(user_id=user.id)) 

218 session.commit() 

219 

220 # can't create one more 

221 with pytest.raises(IntegrityError) as e: 

222 with session_scope() as session: 

223 session.add(ActivenessProbe(user_id=user.id)) 

224 assert "violates unique constraint" in str(e.value)