lupine.api 1.0.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -0
  3. package/admin/admin-about.tsx +16 -0
  4. package/admin/admin-config.tsx +44 -0
  5. package/admin/admin-css.tsx +3 -0
  6. package/admin/admin-db.tsx +74 -0
  7. package/admin/admin-frame-props.tsx +9 -0
  8. package/admin/admin-frame.tsx +466 -0
  9. package/admin/admin-index.tsx +66 -0
  10. package/admin/admin-login.tsx +99 -0
  11. package/admin/admin-menu-edit.tsx +637 -0
  12. package/admin/admin-menu-list.tsx +87 -0
  13. package/admin/admin-page-edit.tsx +564 -0
  14. package/admin/admin-page-list.tsx +83 -0
  15. package/admin/admin-performance.tsx +28 -0
  16. package/admin/admin-release.tsx +320 -0
  17. package/admin/admin-resources.tsx +385 -0
  18. package/admin/admin-shell.tsx +89 -0
  19. package/admin/admin-table-data.tsx +146 -0
  20. package/admin/admin-table-list.tsx +231 -0
  21. package/admin/admin-test-animations.tsx +379 -0
  22. package/admin/admin-test-component.tsx +808 -0
  23. package/admin/admin-test-edit.tsx +319 -0
  24. package/admin/admin-test-themes.tsx +56 -0
  25. package/admin/admin-tokens.tsx +338 -0
  26. package/admin/design/admin-design.tsx +174 -0
  27. package/admin/design/block-grid.tsx +36 -0
  28. package/admin/design/block-grid1.tsx +21 -0
  29. package/admin/design/block-paragraph.tsx +19 -0
  30. package/admin/design/block-title.tsx +19 -0
  31. package/admin/design/design-block-box.tsx +140 -0
  32. package/admin/design/drag-data.tsx +24 -0
  33. package/admin/index.ts +6 -0
  34. package/admin/package.json +15 -0
  35. package/admin/tsconfig.json +127 -0
  36. package/dev/copy-folder.js +32 -0
  37. package/dev/cp-index-html.js +69 -0
  38. package/dev/file-utils.js +12 -0
  39. package/dev/index.js +19 -0
  40. package/dev/package.json +12 -0
  41. package/dev/plugin-gen-versions.js +20 -0
  42. package/dev/plugin-ifelse.js +155 -0
  43. package/dev/plugin-ifelse.test.js +37 -0
  44. package/dev/run-cmd.js +14 -0
  45. package/dev/send-request.js +12 -0
  46. package/package.json +55 -0
  47. package/src/admin-api/admin-api.ts +59 -0
  48. package/src/admin-api/admin-auth.ts +87 -0
  49. package/src/admin-api/admin-config.ts +93 -0
  50. package/src/admin-api/admin-csv.ts +81 -0
  51. package/src/admin-api/admin-db.ts +269 -0
  52. package/src/admin-api/admin-helper.ts +111 -0
  53. package/src/admin-api/admin-menu.ts +135 -0
  54. package/src/admin-api/admin-page.ts +135 -0
  55. package/src/admin-api/admin-performance.ts +128 -0
  56. package/src/admin-api/admin-release.ts +498 -0
  57. package/src/admin-api/admin-resources.ts +318 -0
  58. package/src/admin-api/admin-token-helper.ts +79 -0
  59. package/src/admin-api/admin-tokens.ts +90 -0
  60. package/src/admin-api/index.ts +2 -0
  61. package/src/api/api-cache.ts +103 -0
  62. package/src/api/api-helper.ts +44 -0
  63. package/src/api/api-module.ts +60 -0
  64. package/src/api/api-router.ts +177 -0
  65. package/src/api/api-shared-storage.ts +64 -0
  66. package/src/api/async-storage.ts +5 -0
  67. package/src/api/debug-service.ts +56 -0
  68. package/src/api/encode-html.ts +27 -0
  69. package/src/api/handle-status.ts +71 -0
  70. package/src/api/index.ts +16 -0
  71. package/src/api/mini-web-socket.ts +270 -0
  72. package/src/api/server-content-type.ts +82 -0
  73. package/src/api/server-render.ts +216 -0
  74. package/src/api/shell-service.ts +66 -0
  75. package/src/api/simple-storage.ts +80 -0
  76. package/src/api/static-server.ts +125 -0
  77. package/src/api/to-client-delivery.ts +26 -0
  78. package/src/app/app-cache.ts +55 -0
  79. package/src/app/app-loader.ts +62 -0
  80. package/src/app/app-message.ts +60 -0
  81. package/src/app/app-shared-storage.ts +317 -0
  82. package/src/app/app-start.ts +117 -0
  83. package/src/app/cleanup-exit.ts +12 -0
  84. package/src/app/host-to-path.ts +38 -0
  85. package/src/app/index.ts +11 -0
  86. package/src/app/process-dev-requests.ts +90 -0
  87. package/src/app/web-listener.ts +230 -0
  88. package/src/app/web-processor.ts +42 -0
  89. package/src/app/web-server.ts +86 -0
  90. package/src/common-js/web-env.js +104 -0
  91. package/src/index.ts +7 -0
  92. package/src/lang/api-lang-en.ts +27 -0
  93. package/src/lang/api-lang-zh-cn.ts +28 -0
  94. package/src/lang/index.ts +2 -0
  95. package/src/lang/lang-helper.ts +76 -0
  96. package/src/lang/lang-props.ts +6 -0
  97. package/src/lib/db/db-helper.ts +23 -0
  98. package/src/lib/db/db-mysql.ts +250 -0
  99. package/src/lib/db/db-sqlite.ts +101 -0
  100. package/src/lib/db/db.spec.ts +28 -0
  101. package/src/lib/db/db.ts +304 -0
  102. package/src/lib/db/index.ts +5 -0
  103. package/src/lib/index.ts +3 -0
  104. package/src/lib/logger.spec.ts +214 -0
  105. package/src/lib/logger.ts +274 -0
  106. package/src/lib/runtime-require.ts +37 -0
  107. package/src/lib/utils/cookie-util.ts +34 -0
  108. package/src/lib/utils/crypto.ts +58 -0
  109. package/src/lib/utils/date-utils.ts +317 -0
  110. package/src/lib/utils/deep-merge.ts +37 -0
  111. package/src/lib/utils/delay.ts +12 -0
  112. package/src/lib/utils/file-setting.ts +55 -0
  113. package/src/lib/utils/format-bytes.ts +11 -0
  114. package/src/lib/utils/fs-utils.ts +144 -0
  115. package/src/lib/utils/get-env.ts +27 -0
  116. package/src/lib/utils/index.ts +12 -0
  117. package/src/lib/utils/is-type.ts +48 -0
  118. package/src/lib/utils/load-env.ts +14 -0
  119. package/src/lib/utils/pad.ts +6 -0
  120. package/src/models/api-base.ts +5 -0
  121. package/src/models/api-module-props.ts +11 -0
  122. package/src/models/api-router-props.ts +26 -0
  123. package/src/models/app-cache-props.ts +33 -0
  124. package/src/models/app-data-props.ts +10 -0
  125. package/src/models/app-loader-props.ts +6 -0
  126. package/src/models/app-shared-storage-props.ts +37 -0
  127. package/src/models/app-start-props.ts +18 -0
  128. package/src/models/async-storage-props.ts +13 -0
  129. package/src/models/db-config.ts +30 -0
  130. package/src/models/host-to-path-props.ts +12 -0
  131. package/src/models/index.ts +16 -0
  132. package/src/models/json-object.ts +8 -0
  133. package/src/models/locals-props.ts +36 -0
  134. package/src/models/logger-props.ts +84 -0
  135. package/src/models/simple-storage-props.ts +14 -0
  136. package/src/models/to-client-delivery-props.ts +6 -0
  137. package/tsconfig.json +115 -0
@@ -0,0 +1,304 @@
1
+ import { Logger } from '../logger';
2
+ import { DbConfig } from '../../models/db-config';
3
+
4
+ // Instead, Boolean values are stored as integers 0 (false) and 1 (true).
5
+ export type DbFieldValue = { [key: string]: string | number };
6
+
7
+ const logger = new Logger('db');
8
+ export class Db {
9
+ type: string;
10
+ tablePrefix: string;
11
+
12
+ constructor(option: DbConfig) {
13
+ console.log(
14
+ `init Db, type: ${option.type}, host: ${option.host}:${option.port}, user: ${option.user}, database: ${option.database}, filename: ${option.filename}`
15
+ );
16
+
17
+ this.type = option.type;
18
+ this.tablePrefix = option.tablePrefix || 'tbl_';
19
+ }
20
+
21
+ public close() {
22
+ throw new Error('Method not implemented');
23
+ }
24
+
25
+ public connect() {
26
+ throw new Error('Method not implemented');
27
+ }
28
+
29
+ // public async createTable(table: string, fields: string[]): Promise<any> {
30
+ // throw new Error('Method not implemented');
31
+ // }
32
+
33
+ public async getAllTables(addCount = false): Promise<any> {
34
+ throw new Error('Method not implemented');
35
+ }
36
+
37
+ public async getAllTableNames(): Promise<string[]> {
38
+ const result = await this.getAllTables(false);
39
+ return result.map((item: any) => item.name);
40
+ }
41
+
42
+ public async getTableInfo(table: string): Promise<any> {
43
+ throw new Error('Method not implemented');
44
+ }
45
+
46
+ // can be used like this: order by ${db.getRandomOrder()}
47
+ // MySQL / MariaDB: RAND()
48
+ // PostgreSQL, SQLite: RANDOM()
49
+ // SQL Server: NEWID()
50
+ public getRandomOrder(): string {
51
+ if (this.type === 'mysql' || this.type === 'mariadb') {
52
+ return 'RAND()';
53
+ }
54
+ if (this.type === 'postgres' || this.type === 'sqlite') {
55
+ return 'RANDOM()';
56
+ }
57
+ if (this.type === 'sqlserver') {
58
+ return 'NEWID()';
59
+ }
60
+ throw new Error(`Unsupported database type: ${this.type}`);
61
+ }
62
+
63
+ protected nativeQuery(sql: string, params?: any, isSelect?: boolean): Promise<any> {
64
+ throw new Error('Method not implemented');
65
+ }
66
+
67
+ public async truncateTable(tableName: string): Promise<any> {
68
+ throw new Error('Method not implemented');
69
+ }
70
+
71
+ public async select(sql: string, params?: any) {
72
+ const fixedSql = this.replacePrefix(sql);
73
+ return await this.nativeQuery(fixedSql, params, true);
74
+ }
75
+ public async execute(sql: string, params?: any) {
76
+ const fixedSql = this.replacePrefix(sql);
77
+ return await this.nativeQuery(fixedSql, params, false);
78
+ }
79
+ // public async query(sql: string, params?: any, addReturning?: boolean) {
80
+ // try {
81
+ // const fixedSql = this.replacePrefix(sql);
82
+ // return await this.nativeQuery(fixedSql, params, addReturning);
83
+ // } catch (err) {
84
+ // console.log(err);
85
+ // throw err;
86
+ // }
87
+ // }
88
+
89
+ // public replacePrefixXX(tableName: string, fromPrefix?: string) {
90
+ // if (!fromPrefix) {
91
+ // fromPrefix = '$__';
92
+ // }
93
+
94
+ // if (tableName.startsWith(fromPrefix)) {
95
+ // return this.tablePrefix + tableName.substring(fromPrefix.length);
96
+ // }
97
+ // return tableName;
98
+ // }
99
+
100
+ public replacePrefix(sql: string, fromPrefix?: string) {
101
+ if (!fromPrefix || typeof fromPrefix === 'undefined') {
102
+ fromPrefix = '$__';
103
+ }
104
+
105
+ var escaped = false;
106
+ var quoteChar = '';
107
+ sql = sql.trim();
108
+ var n = sql.length;
109
+
110
+ var startPos = 0;
111
+ var literal = '';
112
+ while (startPos < n) {
113
+ var ip = sql.indexOf(fromPrefix, startPos);
114
+ if (ip < 0) {
115
+ break;
116
+ }
117
+
118
+ var j = sql.indexOf("'", startPos);
119
+ var k = sql.indexOf('"', startPos);
120
+ if (k >= 0 && (k < j || j < 0)) {
121
+ quoteChar = '"';
122
+ j = k;
123
+ } else {
124
+ quoteChar = "'";
125
+ }
126
+
127
+ if (j < 0) {
128
+ j = n;
129
+ }
130
+ //literal += sql.substring(startPos, j).replace(prefix, this.tableprefix);
131
+ literal += sql.substring(startPos, j).split(fromPrefix).join(this.tablePrefix);
132
+ startPos = j;
133
+
134
+ j = startPos + 1;
135
+
136
+ if (j >= n) {
137
+ break;
138
+ }
139
+
140
+ // quote comes first, find end of quote
141
+ while (true) {
142
+ k = sql.indexOf(quoteChar, j);
143
+ escaped = false;
144
+ if (k < 0) {
145
+ break;
146
+ }
147
+ let l = k - 1;
148
+ while (l >= 0 && sql.substring(l, l + 1) == '\\') {
149
+ l--;
150
+ escaped = !escaped;
151
+ }
152
+ if (escaped) {
153
+ j = k + 1;
154
+ continue;
155
+ }
156
+ break;
157
+ }
158
+ if (k < 0) {
159
+ // error in the query - no end quote; ignore it
160
+ break;
161
+ }
162
+ literal += sql.substring(startPos, k + 1);
163
+ startPos = k + 1;
164
+ }
165
+ if (startPos < n) {
166
+ literal += sql.substring(startPos, n);
167
+ }
168
+ return literal;
169
+ }
170
+
171
+ // public escapeId(field) {
172
+ // return field;
173
+ // }
174
+
175
+ // public escape(field) {
176
+ // return field;
177
+ // }
178
+
179
+ private selectBaseSql(table: string, fields?: string[], whereFieldValues?: DbFieldValue, orderSql?: string) {
180
+ table = this.replacePrefix(table);
181
+ let sql = 'SELECT ';
182
+ if (fields && fields.length > 0) {
183
+ sql += fields.join(',');
184
+ } else {
185
+ sql += '*';
186
+ }
187
+
188
+ sql += ' FROM ' + table;
189
+ let params: any[] = [];
190
+ if (whereFieldValues && Object.keys(whereFieldValues).length > 0) {
191
+ sql +=
192
+ ' WHERE ' +
193
+ Object.keys(whereFieldValues)
194
+ .map((item) => `${item}=?`)
195
+ .join(' AND ');
196
+ params = Object.values(whereFieldValues);
197
+ }
198
+ if (orderSql) {
199
+ sql += ' ORDER BY ' + orderSql;
200
+ }
201
+ return { sql, params };
202
+ }
203
+
204
+ public async selectObject(
205
+ table: string,
206
+ fields?: string[],
207
+ whereFieldValues?: DbFieldValue,
208
+ orderSql?: string,
209
+ limit?: number,
210
+ offset?: number
211
+ ) {
212
+ const base = this.selectBaseSql(table, fields, whereFieldValues, orderSql);
213
+ if (limit && limit > 0) {
214
+ base.sql += ' LIMIT ' + limit;
215
+ }
216
+ if (typeof offset === 'number' && !isNaN(offset)) {
217
+ base.sql += ' OFFSET ' + offset;
218
+ }
219
+ return await this.select(base.sql, base.params);
220
+ }
221
+
222
+ public async selectOneRow(
223
+ table: string,
224
+ fields?: string[],
225
+ whereFieldValues?: DbFieldValue,
226
+ orderSql?: string,
227
+ offset?: number
228
+ ) {
229
+ const result = await this.selectObject(table, fields, whereFieldValues, orderSql, 1, offset);
230
+ if (result && Array.isArray(result)) {
231
+ return result[0];
232
+ }
233
+ return undefined;
234
+ }
235
+
236
+ public async selectOneResult(table: string, field: string, whereFieldValues?: DbFieldValue) {
237
+ const base = this.selectBaseSql(table, [field], whereFieldValues);
238
+ const result = await this.select(base.sql, base.params);
239
+ if (result && Array.isArray(result)) {
240
+ return result[0][Object.keys(result[0])[0]];
241
+ }
242
+ return undefined;
243
+ }
244
+
245
+ // return ids
246
+ public async insertObject(table: string, fieldValues: DbFieldValue) {
247
+ table = this.replacePrefix(table);
248
+ const fields = Object.keys(fieldValues);
249
+ const values = Array(fields.length).fill('?').join(',');
250
+ let sql = 'INSERT INTO ' + table + ' (' + fields.join(',') + ') VALUES (' + values + ')';
251
+ const params = Object.values(fieldValues);
252
+ return await this.execute(sql, params);
253
+ }
254
+
255
+ public async updateObject(table: string, updateFieldValues: DbFieldValue, whereFieldValues: DbFieldValue) {
256
+ table = this.replacePrefix(table);
257
+ const fields = Object.keys(updateFieldValues);
258
+ let sql = 'UPDATE ' + table + ' SET ' + fields.map((item) => `${item}=?`).join(',');
259
+ const params = Object.values(updateFieldValues);
260
+
261
+ if (whereFieldValues && Object.keys(whereFieldValues).length > 0) {
262
+ sql +=
263
+ ' WHERE ' +
264
+ Object.keys(whereFieldValues)
265
+ .map((item) => `${item}=?`)
266
+ .join(' AND ');
267
+ params.push(...Object.values(whereFieldValues));
268
+ }
269
+ return await this.execute(sql, params);
270
+ }
271
+
272
+ public async deleteObject(table: string, whereFieldValues: DbFieldValue) {
273
+ table = this.replacePrefix(table);
274
+ let sql =
275
+ 'DELETE FROM ' +
276
+ table +
277
+ ' WHERE ' +
278
+ Object.keys(whereFieldValues)
279
+ .map((item) => `${item}=?`)
280
+ .join(' AND ');
281
+ const params = Object.values(whereFieldValues);
282
+
283
+ return await this.execute(sql, params);
284
+ }
285
+
286
+ // public async hasTable(table: string): Promise<boolean> {
287
+ // table = this.replacePrefix(table);
288
+ // return await this.knex.schema.hasTable(table);
289
+ // }
290
+
291
+ // public async createTable(table: string, funCallback: (tableBuilder: Knex.CreateTableBuilder) => any) {
292
+ // table = this.replacePrefix(table);
293
+ // return await this.knex.schema.createTable(table, funCallback);
294
+ // }
295
+
296
+ // public async dropTable(table: string) {
297
+ // table = this.replacePrefix(table);
298
+ // return await this.knex.schema.dropTableIfExists(table);
299
+ // }
300
+
301
+ public async testConnection() {
302
+ return await this.select('select 1+1 as result');
303
+ }
304
+ }
@@ -0,0 +1,5 @@
1
+ export * from './db';
2
+ export * from '../../models/db-config';
3
+ export * from './db-helper';
4
+ // export * from './db-mysql';
5
+ export * from './db-sqlite';
@@ -0,0 +1,3 @@
1
+ export * from './db';
2
+ export * from './utils';
3
+ export * from './logger';
@@ -0,0 +1,214 @@
1
+ import { Logger, LogLevels } from './logger';
2
+ const cluster = require('cluster');
3
+ const vm = require('vm');
4
+
5
+ const fs = require('fs');
6
+ jest.mock('fs');
7
+ jest.mock('cluster');
8
+
9
+ describe('Test logger', () => {
10
+ beforeEach(() => {
11
+ jest.resetAllMocks();
12
+ });
13
+
14
+ it('test init without recreating a file', async () => {
15
+ fs.existsSync.mockReturnValue(false);
16
+ fs.openSync.mockReturnValue(1);
17
+ fs.fstatSync.mockReturnValue({ size: 1 });
18
+
19
+ const logger = new Logger('test1');
20
+ logger.init({
21
+ folder: './log',
22
+ filename: 'log%index%.log',
23
+ maxSize: 1024,
24
+ maxCount: 5,
25
+ outToFile: true,
26
+ outToConsole: true,
27
+ level: LogLevels.debug,
28
+ });
29
+
30
+ expect(fs.existsSync).toHaveBeenCalled();
31
+ expect(fs.openSync).toHaveBeenCalled();
32
+ expect(fs.fstatSync).toHaveBeenCalled();
33
+ expect(fs.existsSync.mock.calls[0][0]).toBe('./log');
34
+ expect(fs.mkdirSync.mock.calls[0][0]).toBe('./log');
35
+ expect(fs.openSync.mock.calls[0][0]).toBe('log/log0.log');
36
+ });
37
+
38
+ it('test init, with recreating log file', async () => {
39
+ fs.existsSync.mockReturnValue(true);
40
+ fs.openSync.mockReturnValue(1);
41
+ fs.fstatSync.mockReturnValue({ size: 1025 });
42
+
43
+ const logger = new Logger('test2');
44
+ logger.init({
45
+ folder: './log',
46
+ filename: 'log%index%.log',
47
+ maxSize: 10,
48
+ maxCount: 5,
49
+ outToFile: true,
50
+ outToConsole: true,
51
+ level: LogLevels.debug,
52
+ });
53
+
54
+ logger.debug('a'.repeat(11));
55
+
56
+ expect(fs.closeSync).toHaveBeenCalled();
57
+ expect(fs.openSync).toHaveBeenCalled();
58
+ expect(fs.fstatSync).toHaveBeenCalled();
59
+ expect(fs.closeSync.mock.calls[0][0]).toBe(1);
60
+
61
+ expect(fs.renameSync.mock.calls[0][0]).toBe('log/log3.log');
62
+ expect(fs.renameSync.mock.calls[3][0]).toBe('log/log0.log');
63
+
64
+ expect(fs.openSync.mock.calls[0][0]).toBe('log/log0.log');
65
+ expect(fs.openSync.mock.calls[1][0]).toBe('log/log0.log');
66
+ });
67
+
68
+ it('test init, with recreating log file after logs', async () => {
69
+ fs.existsSync.mockReturnValue(true);
70
+ fs.openSync.mockReturnValue(1);
71
+ fs.fstatSync.mockReturnValue({ size: 9 });
72
+
73
+ const logger = new Logger('test2');
74
+ logger.init({
75
+ folder: './log',
76
+ filename: 'log%index%.log',
77
+ maxSize: 10,
78
+ maxCount: 5,
79
+ outToFile: true,
80
+ outToConsole: true,
81
+ level: LogLevels.debug,
82
+ });
83
+
84
+ logger.debug('a'.repeat(9));
85
+
86
+ expect(fs.openSync).toHaveBeenCalled();
87
+ expect(fs.fstatSync).toHaveBeenCalled();
88
+
89
+ fs.fstatSync.mockReturnValue({ size: 11 });
90
+ logger.debug('a'.repeat(2));
91
+
92
+ expect(fs.closeSync).toHaveBeenCalled();
93
+ expect(fs.closeSync.mock.calls[1][0]).toBe(1);
94
+ expect(fs.renameSync.mock.calls[0][0]).toBe('log/log3.log');
95
+ expect(fs.renameSync.mock.calls[3][0]).toBe('log/log0.log');
96
+
97
+ expect(fs.openSync.mock.calls[0][0]).toBe('log/log0.log');
98
+ expect(fs.openSync.mock.calls[1][0]).toBe('log/log0.log');
99
+ });
100
+
101
+ it('test log format', async () => {
102
+ fs.existsSync.mockReturnValue(true);
103
+ fs.openSync.mockReturnValue(1);
104
+ fs.fstatSync.mockReturnValue({ size: 9 });
105
+
106
+ const logger = new Logger('test2');
107
+ logger.init({
108
+ folder: './log',
109
+ filename: 'log%index%.log',
110
+ maxSize: 1024,
111
+ maxCount: 5,
112
+ outToFile: true,
113
+ outToConsole: true,
114
+ level: LogLevels.debug,
115
+ });
116
+
117
+ logger.debug(
118
+ 'log test. numer: %d, string: %s, json: %j, [%%], Pretty-print: %O',
119
+ 123,
120
+ 's456',
121
+ { k: 'key', v: 789 },
122
+ { k2: 'key2', v2: 901 }
123
+ );
124
+ console.log('test writing log: [' + fs.writeFileSync.mock.calls[0][1].toString() + ']');
125
+ expect(
126
+ fs.writeFileSync.mock.calls[0][1]
127
+ .toString()
128
+ .endsWith(
129
+ `test2: log test. numer: 123, string: s456, json: {"k":"key","v":789}, [%], Pretty-print: { k2: 'key2', v2: 901 }\r\n`
130
+ )
131
+ ).toBe(true);
132
+ });
133
+
134
+ it('test different log level', async () => {
135
+ fs.existsSync.mockReturnValue(true);
136
+ fs.openSync.mockReturnValue(1);
137
+ fs.fstatSync.mockReturnValue({ size: 9 });
138
+
139
+ const logger = new Logger('test2');
140
+ logger.init({
141
+ folder: './log',
142
+ filename: 'log%index%.log',
143
+ maxSize: 1024,
144
+ maxCount: 5,
145
+ outToFile: true,
146
+ outToConsole: true,
147
+ level: LogLevels.info,
148
+ });
149
+
150
+ logger.debug('a'.repeat(10));
151
+ logger.info('b'.repeat(10));
152
+ logger.warn('c'.repeat(10));
153
+ logger.error('d'.repeat(10));
154
+ logger.fatal('e'.repeat(10));
155
+ console.log('test writing log: [' + fs.writeFileSync.mock.calls[0][1].toString() + ']');
156
+ expect(fs.writeFileSync.mock.calls[0][1].toString().endsWith('test2: bbbbbbbbbb\r\n')).toBe(true);
157
+ expect(fs.writeFileSync.mock.calls[3][1].toString().endsWith('test2: eeeeeeeeee\r\n')).toBe(true);
158
+ });
159
+
160
+ it('test logs in cluster, messages should be sent to Master', async () => {
161
+ fs.existsSync.mockReturnValue(true);
162
+ fs.openSync.mockReturnValue(1);
163
+ fs.fstatSync.mockReturnValue({ size: 1 });
164
+
165
+ const process = require('process');
166
+ const mockSend = jest.spyOn(process, 'send').mockImplementation(() => {});
167
+
168
+ const logger = new Logger('test2');
169
+ logger.init({
170
+ folder: './log',
171
+ filename: 'log%index%.log',
172
+ maxSize: 1024,
173
+ maxCount: 5,
174
+ outToFile: true,
175
+ outToConsole: true,
176
+ level: LogLevels.debug,
177
+ });
178
+
179
+ // change isPrimary to false, so Logger will send message to Master
180
+ cluster.isPrimary = false;
181
+ logger.debug('isPrimary, %d, %s', 1, '2');
182
+ cluster.isPrimary = true;
183
+
184
+ expect(mockSend).toHaveBeenCalledWith({
185
+ color: 204,
186
+ id: 'LogWriter',
187
+ level: 'DEBUG',
188
+ messageList: ['isPrimary, %d, %s', 1, '2'],
189
+ namespace: 'test2',
190
+ pid: process.pid,
191
+ });
192
+ });
193
+
194
+ it('test no file output', async () => {
195
+ fs.existsSync.mockReturnValue(true);
196
+ fs.openSync.mockReturnValue(1);
197
+ fs.fstatSync.mockReturnValue({ size: 1 });
198
+
199
+ const logger = new Logger('test2');
200
+ logger.init({
201
+ folder: './log',
202
+ filename: 'log%index%.log',
203
+ maxSize: 1024,
204
+ maxCount: 5,
205
+ outToFile: false,
206
+ outToConsole: true,
207
+ level: LogLevels.debug,
208
+ });
209
+
210
+ logger.debug('debug');
211
+
212
+ expect(fs.writeFileSync).not.toHaveBeenCalled();
213
+ });
214
+ });