Coverage for utils/helpers.py: 100%

81 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-03-12 14:47 +0000

1from utils.config import * 

2import subprocess 

3import os 

4from flask import jsonify 

5 

6def compile_simulation(debug=False): 

7 """ 

8 Compiles the C++ simulation executable on startup. 

9  

10 Returns: 

11 bool: True if compilation succeeds, False otherwise 

12 """ 

13 global COMPILE_ERROR 

14 

15 # Clean existing executable 

16 if os.path.exists(SIMULATION_EXECUTABLE): 

17 logger.info(f"Removing existing executable: {SIMULATION_EXECUTABLE}") 

18 os.remove(SIMULATION_EXECUTABLE) 

19 

20 # Verify source file exists 

21 if not os.path.exists("./src/main.cpp"): 

22 COMPILE_ERROR = { 

23 "error": "main.cpp not found", 

24 "details": "Ensure main.cpp is in the correct directory." 

25 } 

26 logger.error(f"Compilation failed: {COMPILE_ERROR['error']} - {COMPILE_ERROR['details']}") 

27 return False 

28 

29 # Run compilation with optimization 

30 logger.info("Compiling simulation...") 

31 compile_result = subprocess.run( 

32 ["g++", "-O3", "-o", SIMULATION_EXECUTABLE, "./src/main.cpp"], 

33 capture_output=True, 

34 text=True 

35 ) 

36 if compile_result.returncode != 0: 

37 COMPILE_ERROR = { 

38 "error": "Compilation failed", 

39 "details": compile_result.stderr 

40 } 

41 logger.error(f"Compilation failed: {COMPILE_ERROR['error']} - {COMPILE_ERROR['details']}") 

42 return False 

43 

44 if debug: COMPILE_ERROR = None 

45 logger.info("File compiled successfully") 

46 return True 

47 

48def validate_simulation_prerequisites(): 

49 """ 

50 Validates compilation status and executable existence. 

51  

52 Returns: 

53 tuple: (is_valid, response) where is_valid is a boolean and  

54 response is an optional error response 

55 """ 

56 # Check if compilation failed during startup 

57 if COMPILE_ERROR: 

58 return False, (jsonify({ 

59 "status": "error", 

60 "message": COMPILE_ERROR["error"], 

61 "error": COMPILE_ERROR["details"] 

62 }), 500) 

63 

64 # Verify executable exists 

65 if not os.path.exists(SIMULATION_EXECUTABLE): 

66 return False, (jsonify({ 

67 "status": "error", 

68 "message": "Simulation executable not found", 

69 "error": "Contact administrator for assistance" 

70 }), 500) 

71 

72 return True, None 

73 

74def parse_simulation_parameters(data): 

75 """ 

76 Parses and validates simulation parameters from request data. 

77  

78 Args: 

79 data (dict): Request JSON data 

80  

81 Returns: 

82 tuple: Either (True, parameters) if valid, or (False, error_response) if invalid 

83 """ 

84 # Extract parameters with default values 

85 algorithm = data.get("algorithm", "FirstFit") 

86 networkType = data.get("networkType", 1) 

87 goalConnections = data.get("goalConnections", 100000) 

88 confidence = data.get("confidence", 0.05) 

89 lambdaParam = data.get("lambdaParam", 1) 

90 mu = data.get("mu", 10) 

91 network = data.get("network", "NSFNet") 

92 bitrate = data.get("bitrate", "fixed-rate") 

93 K = data.get("K", 3) 

94 

95 # Validate data types 

96 if not isinstance(algorithm, str): 

97 return False, (jsonify({ 

98 "status": "error", 

99 "message": "Invalid parameters", 

100 "error": "algorithm must be a string" 

101 }), 400) 

102 if not isinstance(networkType, int): 

103 return False, (jsonify({ 

104 "status": "error", 

105 "message": "Invalid parameters", 

106 "error": "networkType must be an integer" 

107 }), 400) 

108 if not isinstance(goalConnections, int): 

109 return False, (jsonify({ 

110 "status": "error", 

111 "message": "Invalid parameters", 

112 "error": "goalConnections must be an integer" 

113 }), 400) 

114 if not isinstance(confidence, (int, float)): 

115 return False, (jsonify({ 

116 "status": "error", 

117 "message": "Invalid parameters", 

118 "error": "confidence must be a number" 

119 }), 400) 

120 if not isinstance(lambdaParam, (int, float)): 

121 return False, (jsonify({ 

122 "status": "error", 

123 "message": "Invalid parameters", 

124 "error": "lambdaParam must be a number" 

125 }), 400) 

126 if not isinstance(mu, (int, float)): 

127 return False, (jsonify({ 

128 "status": "error", 

129 "message": "Invalid parameters", 

130 "error": "mu must be a number" 

131 }), 400) 

132 if not isinstance(network, str): 

133 return False, (jsonify({ 

134 "status": "error", 

135 "message": "Invalid parameters", 

136 "error": "network must be a string" 

137 }), 400) 

138 if not isinstance(bitrate, str): 

139 return False, (jsonify({ 

140 "status": "error", 

141 "message": "Invalid parameters", 

142 "error": "bitrate must be a string" 

143 }), 400) 

144 if not isinstance(K, int): 

145 return False, (jsonify({ 

146 "status": "error", 

147 "message": "Invalid parameters", 

148 "error": "K must be an integer" 

149 }), 400) 

150 

151 # Validate networkType 

152 if networkType != 1: 

153 return False, (jsonify({ 

154 "status": "error", 

155 "message": "Invalid parameters", 

156 "error": "At the moment only networkType 1 is supported" 

157 }), 400) 

158 

159 # Validate goalConnections 

160 if goalConnections > 10000000: 

161 return False, (jsonify({ 

162 "status": "error", 

163 "message": "Invalid parameters", 

164 "error": "goalConnections must be less than 10,000,000" 

165 }), 400) 

166 elif goalConnections < 1: 

167 return False, (jsonify({ 

168 "status": "error", 

169 "message": "Invalid parameters", 

170 "error": "goalConnections must be greater than 0" 

171 }), 400) 

172 

173 # Validate K 

174 if K > 6: 

175 return False, (jsonify({ 

176 "status": "error", 

177 "message": "Invalid parameters", 

178 "error": "Max K is 6" 

179 }), 400) 

180 elif K < 1: 

181 return False, (jsonify({ 

182 "status": "error", 

183 "message": "Invalid parameters", 

184 "error": "Min K is 1" 

185 }), 400) 

186 

187 # Validate confidence 

188 if confidence >= 1 or confidence <= 0: 

189 return False, (jsonify({ 

190 "status": "error", 

191 "message": "Invalid parameters", 

192 "error": "confidence must be between 0 and 1" 

193 }), 400) 

194 

195 # Validate lambda 

196 if lambdaParam <= 0: 

197 return False, (jsonify({ 

198 "status": "error", 

199 "message": "Invalid parameters", 

200 "error": "lambdaParam must be greater than 0" 

201 }), 400) 

202 

203 # Validate mu 

204 if mu <= 0: 

205 return False, (jsonify({ 

206 "status": "error", 

207 "message": "Invalid parameters", 

208 "error": "mu must be greater than 0" 

209 }), 400) 

210 

211 # Validate algorithm 

212 if algorithm not in ["FirstFit", "BestFit"]: 

213 return False, (jsonify({ 

214 "status": "error", 

215 "message": "Invalid parameters", 

216 "error": "algorithm must be FirstFit or BestFit" 

217 }), 400) 

218 

219 # Validate network 

220 if network not in valid_networks: 

221 return False, (jsonify({ 

222 "status": "error", 

223 "message": "Invalid parameters", 

224 "error": f"network must be one of: {', '.join(valid_networks)}" 

225 }), 400) 

226 

227 # Validate bitrate 

228 if bitrate not in valid_bitrates: 

229 return False, (jsonify({ 

230 "status": "error", 

231 "message": "Invalid parameters", 

232 "error": f"bitrate must be one of: {', '.join(valid_bitrates)}" 

233 }), 400) 

234 

235 # All parameters are valid, return the parameter tuple 

236 return True, (algorithm, networkType, goalConnections, confidence, 

237 lambdaParam, mu, network, bitrate, K) 

238 

239def build_simulation_command(params): 

240 """ 

241 Builds command for simulation process. 

242  

243 Args: 

244 params (tuple): Simulation parameters 

245  

246 Returns: 

247 list: Command list for subprocess 

248 """ 

249 algorithm, networkType, goalConnections, confidence, lambdaParam, mu, network, bitrate, K = params 

250 

251 return [ 

252 f"./{SIMULATION_EXECUTABLE}", 

253 str(algorithm), 

254 str(networkType), 

255 str(goalConnections), 

256 str(confidence), 

257 str(lambdaParam), 

258 str(mu), 

259 str(network), 

260 str(bitrate), 

261 str(K) 

262 ]