Skip to content

Commit 9e2fa5c

Browse files
@jotadevelopersergiohgz
authored andcommitted
feat: add limit feature
1 parent 62ba603 commit 9e2fa5c

File tree

5 files changed

+134
-45
lines changed

5 files changed

+134
-45
lines changed

plugins/memory/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ Complete configuration example:
1919
```yaml
2020
store:
2121
memory:
22-
cache: true
23-
```
22+
limit: 1000
23+
```
2424
2525
in `config.yaml`
2626

@@ -33,7 +33,7 @@ auth:
3333
file: ./htpasswd
3434
store:
3535
memory:
36-
cache: true
36+
limit: 1000
3737
```
3838

3939
## Disclaimer

plugins/memory/src/local-memory.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,33 @@ import MemoryHandler from './memory-handler';
44
import type { LocalStorage, Logger, Config } from '@verdaccio/types';
55
import type { ILocalData } from '@verdaccio/local-storage';
66

7+
export type ConfigMemory = Config & { limit?: number };
8+
9+
const DEFAULT_LIMIT: number = 1000;
710
class LocalMemory implements ILocalData {
811
path: string;
12+
limit: number;
913
logger: Logger;
1014
data: LocalStorage;
1115
config: Config;
1216
locked: boolean;
1317

14-
constructor(config: Config, logger: Logger) {
18+
constructor(config: ConfigMemory, logger: Logger) {
1519
this.config = config;
20+
this.limit = config.limit || DEFAULT_LIMIT;
1621
this.logger = logger;
1722
this.data = this._createEmtpyDatabase();
1823
this.data.secret = config.checkSecretKey(this.data.secret);
1924
}
2025

2126
add(name: string) {
22-
if (this.data.list.indexOf(name) === -1) {
23-
this.data.list.push(name);
27+
if (this.data.list.length < this.limit) {
28+
if (this.data.list.indexOf(name) === -1) {
29+
this.data.list.push(name);
30+
}
31+
} else {
32+
this.logger.info({ limit: this.limit }, 'Storage memory has reached limit of @{limit} packages');
33+
return new Error('Storage memory has reached limit of limit packages');
2434
}
2535
}
2636

@@ -40,8 +50,7 @@ class LocalMemory implements ILocalData {
4050
}
4151

4252
getPackageStorage(packageInfo: string) {
43-
// $FlowFixMe
44-
return new MemoryHandler(packageInfo, this.data.files, this.logger);
53+
return new MemoryHandler(packageInfo, this.logger);
4554
}
4655

4756
_createEmtpyDatabase(): LocalStorage {

plugins/memory/src/memory-handler.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,23 @@ class MemoryHandler implements ILocalPackageManager {
4242
}
4343

4444
updatePackage(pkgFileName: string, updateHandler: Callback, onWrite: Callback, transformPackage: Function, onEnd: Callback): void {
45-
const json = this._getStorage(pkgFileName);
45+
let json = this._getStorage(pkgFileName);
46+
47+
try {
48+
json = JSON.parse(json);
49+
} catch (err) {
50+
return onEnd(err);
51+
}
4652

4753
updateHandler(json, err => {
4854
if (err) {
4955
return onEnd(err);
5056
}
51-
onWrite(pkgFileName, transformPackage(json), onEnd);
57+
try {
58+
onWrite(pkgFileName, transformPackage(json), onEnd);
59+
} catch (err) {
60+
return onEnd(fSError('error on parse', 500));
61+
}
5262
});
5363
}
5464

@@ -81,7 +91,6 @@ class MemoryHandler implements ILocalPackageManager {
8191
const json = this._getStorage(name);
8292

8393
try {
84-
// $FlowFixMe
8594
cb(typeof json === 'undefined' ? noPackageFoundError() : null, JSON.parse(json));
8695
} catch (err) {
8796
cb(fSError('package not found', 404));

plugins/memory/test/memory.spec.js

Lines changed: 103 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
// @flow
22

33
import LocalMemory from '../src/index';
4-
import type { Logger } from '@verdaccio/types';
5-
import type { ILocalData, IPackageStorage } from '@verdaccio/local-storage';
64
import config from './partials/config';
75
import pkgExample from './partials/pkg';
6+
import MemoryHandler from '../src/memory-handler';
7+
8+
import type { Logger } from '@verdaccio/types';
9+
import type { ILocalData, IPackageStorage } from '@verdaccio/local-storage';
810

911
const logger: Logger = {
1012
error: e => console.warn(e),
@@ -17,47 +19,116 @@ const logger: Logger = {
1719
};
1820

1921
describe('memory unit test .', () => {
20-
test('should create an instance', () => {
21-
const localMemory: ILocalData = new LocalMemory(config, logger);
22+
describe('LocalMemory', () => {
23+
test('should create an LocalMemory instance', () => {
24+
const localMemory: ILocalData = new LocalMemory(config, logger);
2225

23-
expect(localMemory).toBeDefined();
24-
});
26+
expect(localMemory).toBeDefined();
27+
});
2528

26-
test('should save a package', done => {
27-
const localMemory: ILocalData = new LocalMemory(config, logger);
29+
test('should create add a package', () => {
30+
const localMemory: ILocalData = new LocalMemory(config, logger);
31+
localMemory.add('test');
2832

29-
const handler = localMemory.getPackageStorage('test');
30-
expect(handler).toBeDefined();
33+
expect(localMemory.get()).toHaveLength(1);
34+
});
3135

32-
if (handler) {
33-
handler.savePackage('test', pkgExample, err => {
34-
expect(err).toBeNull();
35-
handler.readPackage('test', (err, data) => {
36-
expect(err).toBeNull();
37-
expect(data).toEqual(pkgExample);
38-
done();
39-
});
40-
});
41-
}
36+
test('should reach max limit', () => {
37+
config.limit = 2;
38+
const localMemory: ILocalData = new LocalMemory(config, logger);
39+
expect(localMemory.add('test1')).toBeUndefined();
40+
expect(localMemory.add('test2')).toBeUndefined();
41+
expect(localMemory.add('test3')).not.toBeNull();
42+
});
43+
44+
test('should remove a package', () => {
45+
const localMemory: ILocalData = new LocalMemory(config, logger);
46+
localMemory.add('test');
47+
localMemory.remove('test');
48+
49+
expect(localMemory.get()).toHaveLength(0);
50+
});
4251
});
4352

44-
test('should delete a package', done => {
45-
const localMemory: ILocalData = new LocalMemory(config, logger);
53+
describe('MemoryHandler', () => {
54+
test('should create an MemoryHandler instance', () => {
55+
const memoryHandler: ILocalPackageManager = new MemoryHandler('test', pkgExample, logger);
56+
57+
expect(memoryHandler).toBeDefined();
58+
});
59+
60+
test('should save a package', done => {
61+
const localMemory: ILocalData = new LocalMemory(config, logger);
4662

47-
const handler: IPackageStorage = localMemory.getPackageStorage('test2');
48-
expect(handler).toBeDefined();
49-
if (handler) {
50-
handler.createPackage('test2', pkgExample, err => {
51-
expect(err).toBeNull();
52-
handler.deletePackage('test2', (err, data) => {
63+
const handler = localMemory.getPackageStorage('test');
64+
expect(handler).toBeDefined();
65+
66+
if (handler) {
67+
handler.savePackage('test', pkgExample, err => {
5368
expect(err).toBeNull();
5469
handler.readPackage('test', (err, data) => {
55-
expect(err).not.toBeNull();
56-
expect(err.message).toMatch(/package not found/);
70+
expect(err).toBeNull();
71+
expect(data).toEqual(pkgExample);
5772
done();
5873
});
5974
});
60-
});
61-
}
75+
}
76+
});
77+
78+
test('should update a package', done => {
79+
const localMemory: ILocalData = new LocalMemory(config, logger);
80+
81+
const handler = localMemory.getPackageStorage('test');
82+
expect(handler).toBeDefined();
83+
const onEnd = jest.fn();
84+
85+
if (handler) {
86+
handler.savePackage('test', pkgExample, err => {
87+
expect(err).toBeNull();
88+
89+
handler.updatePackage(
90+
'test',
91+
(json, callback) => {
92+
expect(json).toBeDefined();
93+
expect(json.name).toBe(pkgExample.name);
94+
expect(callback).toBeDefined();
95+
callback();
96+
},
97+
(name, data, onEnd) => {
98+
expect(name).toBe('test');
99+
expect(data.name).toBe(pkgExample.name);
100+
onEnd();
101+
expect(onEnd).toBeCalled();
102+
done();
103+
},
104+
data => {
105+
expect(data).toBeDefined();
106+
return data;
107+
},
108+
onEnd
109+
);
110+
});
111+
}
112+
});
113+
114+
test('should delete a package', done => {
115+
const localMemory: ILocalData = new LocalMemory(config, logger);
116+
117+
const handler: IPackageStorage = localMemory.getPackageStorage('test2');
118+
expect(handler).toBeDefined();
119+
if (handler) {
120+
handler.createPackage('test2', pkgExample, err => {
121+
expect(err).toBeNull();
122+
handler.deletePackage('test2', (err, data) => {
123+
expect(err).toBeNull();
124+
handler.readPackage('test', (err, data) => {
125+
expect(err).not.toBeNull();
126+
expect(err.message).toMatch(/package not found/);
127+
done();
128+
});
129+
});
130+
});
131+
}
132+
});
62133
});
63134
});

plugins/memory/test/partials/config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// @flow
22

3-
import type { Config } from '@verdaccio/types';
3+
import type { ConfigMemory } from '../../src/local-memory';
44

5-
const config: Config = {
5+
const config: ConfigMemory = {
66
user_agent: 'string',
77
server_id: 1234,
88
storage: './home',

0 commit comments

Comments
 (0)