• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

statuscompliance / status-backend / 14572310690

21 Apr 2025 10:59AM UTC coverage: 39.582% (+3.6%) from 35.962%
14572310690

Pull #123

github

web-flow
Merge f2fd7f63a into 1b90d53e5
Pull Request #123: test (endpoint): added middleware

252 of 731 branches covered (34.47%)

Branch coverage included in aggregate %.

80 of 84 new or added lines in 1 file covered. (95.24%)

4 existing lines in 1 file now uncovered.

696 of 1664 relevant lines covered (41.83%)

4.18 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.2
/src/middleware/endpoint.js
1
import { models } from '../models/models.js';
2

3
class CacheLoadError extends Error {
4
  constructor(message, originalError) {
5
    super(message);
4✔
6
    this.name = 'CacheLoadError';
4✔
7
    this.originalError = originalError;
4✔
8
  }
9
}
10

11
class ConfigurationNotFoundError extends Error {
12
  constructor(message) {
13
    super(message);
2✔
14
    this.name = 'ConfigurationNotFoundError';
2✔
15
  }
16
}
17

18
class AssistantFetchError extends Error {
19
  constructor(message, originalError) {
20
    super(message);
3✔
21
    this.name = 'AssistantFetchError';
3✔
22
    this.originalError = originalError;
3✔
23
  }
24
}
25

26
const ASSISTANT_ENDPOINT = '/api/assistant';
15✔
27
const ERROR_MESSAGE_GENERIC = 'Internal server error.';
15✔
28

29
let configurationsCache = null;
15✔
30

31
export const setConfigurationCache = (newCache) => {
15✔
32
  configurationsCache = newCache;
29✔
33
};
34

35
export const getConfigurationsCache = () => configurationsCache;
15✔
36

37
export async function updateConfigurationsCache() {
38
  try {
2✔
39
    configurationsCache = await models.Configuration.findAll();
2✔
40
  } catch (err) {
41
    console.error(err);
2✔
42
  }
43
}
44

45
async function fetchAllConfigurations() {
46
  try {
7✔
47
    return await models.Configuration.findAll();
7✔
48
  } catch (err) {
49
    console.error('Error fetching configurations from DB:', err);
3✔
50
    throw new CacheLoadError('Failed to fetch configurations from database', err);
3✔
51
  }
52
}
53

54
export async function ensureConfigurationsLoaded() {
55
  if (!configurationsCache) {
21✔
56
    try {
7✔
57
      configurationsCache = await fetchAllConfigurations();
7✔
58
      if (!configurationsCache) {
4✔
59
        // This case might happen if findAll returns null/undefined unexpectedly
60
        // Although less likely for findAll, adding a check is safer.
61
        console.error('fetchAllConfigurations returned null or undefined.');
1✔
62
        throw new CacheLoadError('Configurations cache is still empty after fetching.');
1✔
63
      }
64
      console.log('Configurations cache loaded successfully.');
3✔
65
    } catch (error) {
66
      // Re-throw the custom error caught from fetchAllConfigurations
67
      console.error(error);
4✔
68
      throw error;
4✔
69
    }
70
  }
71
}
72

73
function findMatchingConfiguration(endpoint, cache) {
74
  const matchingConfig = cache.find(
6✔
75
    (config) => config.endpoint === endpoint
5✔
76
  );
77

78
  if (matchingConfig && typeof matchingConfig.available !== 'undefined') {
5✔
79
    return matchingConfig;
3✔
80
  }
81

82
  return null;
2✔
83
}
84

85
export async function endpointAvailable(req, res, next) {
86
  try {
7✔
87
    await ensureConfigurationsLoaded();
7✔
88
    
89
    if (!configurationsCache) {
6!
NEW
UNCOV
90
      console.error('Configurations cache is unexpectedly empty.');
×
NEW
UNCOV
91
      throw new CacheLoadError('Configurations cache is unavailable.');
×
92
    }
93

94

95
    const endpoint = req.url;
6✔
96
    const matchingConfig = findMatchingConfiguration(endpoint, configurationsCache);
6✔
97

98
    if (!matchingConfig) {
5✔
99
      return res.status(404).json({ message: 'Endpoint not found' });
2✔
100
    }
101

102
    if (matchingConfig.available) {
3✔
103
      next();
2✔
104
    } else {
105
      res.status(404).send('Endpoint not available');
1✔
106
    }
107

108
  } catch (error) {
109
    if (error instanceof CacheLoadError) {
2✔
110
      console.error('Endpoint Availability Middleware Error:', error);
1✔
111
      return res.status(500).send('Error loading configurations.');
1✔
112
    } else {
113
      console.error('Unhandled error in endpointAvailable middleware:', error);
1✔
114
      return res.status(500).send(ERROR_MESSAGE_GENERIC);
1✔
115
    }
116
  }
117
}
118

119
async function loadAssistantConfiguration(endpoint = ASSISTANT_ENDPOINT) {
9✔
120
  try {
9✔
121

122
    const config = await models.Configuration.findOne({ where: { endpoint } });
9✔
123

124
    if (!config || typeof config.limit === 'undefined') {
7✔
125
      console.warn(`Configuration for ${endpoint} not found or limit not defined.`);
2✔
126
      throw new ConfigurationNotFoundError(`Endpoint configuration for ${endpoint} not found or limit not defined.`);
2✔
127
    }
128

129
    return config.limit;
5✔
130

131
  } catch (error) {
132

133
    if (!(error instanceof ConfigurationNotFoundError)) {
4✔
134
      console.error(`Error fetching assistant configuration for ${endpoint}:`, error);
2✔
135
    }
136
    throw error;
4✔
137
  }
138
}
139

140
async function getAssistantCount() {
141
  try {
5✔
142
    const assistants = await models.Assistant.findAll();
5✔
143
    if (Array.isArray(assistants)) {
4✔
144
      return assistants.length;
3✔
145
    } else {
146
      console.error('models.Assistant.findAll did not return an array.');
1✔
147
      throw new AssistantFetchError('Failed to get assistant count: unexpected database response.');
1✔
148
    }
149
  } catch (error) {
150
    console.error('Error fetching assistants from DB:', error);
2✔
151
    throw new AssistantFetchError('Failed to fetch assistants from database', error);
2✔
152
  }
153
}
154

155
export async function assistantlimitReached(req, res, next) {
156
  try {
10✔
157
    await ensureConfigurationsLoaded();
10✔
158

159
    if (!configurationsCache) {
9!
160

NEW
UNCOV
161
      console.error('Configurations cache is unexpectedly empty.');
×
NEW
UNCOV
162
      throw new CacheLoadError('Configurations cache is unavailable.');
×
163
    }
164

165
    const limit = await loadAssistantConfiguration();
9✔
166
    const assistantCount = await getAssistantCount();
5✔
167

168
    if (limit <= assistantCount) {
3✔
169
      return res.status(429).send('Assistant limit reached.');
1✔
170
    }
171

172
    next();
2✔
173

174
  } catch (error) {
175

176
    if (error instanceof CacheLoadError) {
7✔
177
      console.error('Assistant Limit Middleware Error (Cache):', error);
1✔
178
      return res.status(500).send('Error loading configurations.');
1✔
179
    } else if (error instanceof ConfigurationNotFoundError) {
6✔
180
      console.warn('Assistant Limit Middleware Error (Config Not Found):', error.message);
2✔
181
      return res.status(404).json({ message: error.message });
2✔
182
    } else if (error instanceof AssistantFetchError) {
4✔
183
      console.error('Assistant Limit Middleware Error (Fetch):', error);
2✔
184
      return res.status(500).send('Error checking assistant limits.');
2✔
185
    } else {
186
      console.error('Unhandled error in assistantlimitReached middleware:', error);
2✔
187
      return res.status(500).send(ERROR_MESSAGE_GENERIC);
2✔
188
    }
189
  }
190
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc