hit-counter
This commit is contained in:
@@ -17,6 +17,7 @@ config['rss']['endpoint'] = '/rsstest';
|
||||
config['rss']['length'] = 2;
|
||||
config['home']['error'] = testError;
|
||||
config['article']['template'] = testTemplate;
|
||||
config['modules']['hit_counter'] = false;
|
||||
|
||||
const app = require('../src/app')(config);
|
||||
|
||||
@@ -28,6 +29,7 @@ beforeEach((done, fail) => {
|
||||
config['error_log'] = '';
|
||||
config['modules']['rss'] = true;
|
||||
config['modules']['webhook'] = true;
|
||||
config['modules']['hit_counter'] = false;
|
||||
|
||||
utils.deleteFolderSync(dataDir);
|
||||
fs.mkdirSync(dataDir);
|
||||
@@ -195,6 +197,22 @@ describe('Test root path', () => {
|
||||
});
|
||||
}, fail);
|
||||
});
|
||||
test('404 index no stats', (done) => {
|
||||
request(app).get('/stats')
|
||||
.then((response) => {
|
||||
expect(response.statusCode).toBe(404);
|
||||
done();
|
||||
});
|
||||
});
|
||||
test('200 index stats', (done) => {
|
||||
config['modules']['hit_counter'] = true;
|
||||
request(app).get('/stats')
|
||||
.then((response) => {
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(response.body).toEqual({ hits: 0, visitors: 0 });
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test RSS feed', () => {
|
||||
@@ -433,6 +451,38 @@ describe('Test articles rendering', () => {
|
||||
});
|
||||
}, fail);
|
||||
});
|
||||
|
||||
test('404 article no stats', (done) => {
|
||||
utils.createEmptyDirs([ path.join(dataDir, '2019', '05', '05') ]);
|
||||
utils.createEmptyFiles([
|
||||
path.join(dataDir, '2019', '05', '05', 'index.md'),
|
||||
path.join(dataDir, testTemplate),
|
||||
]);
|
||||
app.reload(() => {
|
||||
request(app).get('/2019/05/05/hello/stats')
|
||||
.then((response) => {
|
||||
expect(response.statusCode).toBe(404);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('200 index stats', (done) => {
|
||||
config['modules']['hit_counter'] = true;
|
||||
utils.createEmptyDirs([ path.join(dataDir, '2019', '05', '05') ]);
|
||||
utils.createEmptyFiles([
|
||||
path.join(dataDir, '2019', '05', '05', 'index.md'),
|
||||
path.join(dataDir, testTemplate),
|
||||
]);
|
||||
app.reload(() => {
|
||||
request(app).get('/2019/05/05/anything/stats')
|
||||
.then((response) => {
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(response.body).toEqual({ hits: 0, visitors: 0 });
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
const mockClient = {
|
||||
options: {},
|
||||
connected: true,
|
||||
on: () => { /* ignore */ },
|
||||
};
|
||||
|
||||
jest.mock('redis', () => {
|
||||
return {
|
||||
createClient: (options) => {
|
||||
mockClient.options = options;
|
||||
return mockClient;
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const config = {
|
||||
test: true,
|
||||
modules: {
|
||||
hit_counter: true,
|
||||
},
|
||||
redis: {
|
||||
host: 'test-host',
|
||||
port: 'test-port',
|
||||
},
|
||||
hit_counter: {
|
||||
unique_visitor_timeout: -1,
|
||||
},
|
||||
};
|
||||
|
||||
const hc = require('../src/hit_counter')(config, () => { /* ignore */ }, () => { /* ignore */ });
|
||||
|
||||
afterAll(() => {
|
||||
jest.resetModules();
|
||||
});
|
||||
|
||||
test('options passed to redis', () => {
|
||||
expect(mockClient.options).toEqual(config['redis']);
|
||||
});
|
||||
|
||||
describe('read()', () => {
|
||||
beforeEach(() => {
|
||||
mockClient.hgetall = (_, cb) => {
|
||||
cb();
|
||||
};
|
||||
});
|
||||
|
||||
test('read path', (done) => {
|
||||
mockClient.hgetall = (path, cb) => {
|
||||
expect(path).toBe('/test/path/');
|
||||
cb(undefined, { h: 12, v: 34 });
|
||||
};
|
||||
hc.read('/test/path/', (data) => {
|
||||
expect(data).toBeDefined();
|
||||
expect(data.hits).toBe(12);
|
||||
expect(data.visitors).toBe(34);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('read path with error', (done) => {
|
||||
mockClient.hgetall = (path, cb) => {
|
||||
expect(path).toBe('/test/path/');
|
||||
cb('error', undefined);
|
||||
};
|
||||
hc.read('/test/path/', (data) => {
|
||||
expect(data).toBeDefined();
|
||||
expect(data.hits).toBe(0);
|
||||
expect(data.visitors).toBe(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('read path with error 2', (done) => {
|
||||
mockClient.hgetall = (path, cb) => {
|
||||
expect(path).toBe('/test/path/');
|
||||
cb(undefined, {});
|
||||
};
|
||||
hc.read('/test/path/', (data) => {
|
||||
expect(data).toBeDefined();
|
||||
expect(data.hits).toBe(0);
|
||||
expect(data.visitors).toBe(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('count()', () => {
|
||||
beforeEach(() => {
|
||||
mockClient.multi = () => mockClient;
|
||||
mockClient.hincrby = () => mockClient;
|
||||
mockClient.exec = (cb) => {
|
||||
cb();
|
||||
};
|
||||
});
|
||||
|
||||
test('simple visit', (done) => {
|
||||
let multiCalled = false;
|
||||
let execCalled = false;
|
||||
let hincrbyCalls = [];
|
||||
mockClient.multi = () => {
|
||||
multiCalled = true;
|
||||
return mockClient;
|
||||
};
|
||||
mockClient.hincrby = (hash, key, value) => {
|
||||
hincrbyCalls.push([
|
||||
hash,
|
||||
key,
|
||||
value,
|
||||
]);
|
||||
return mockClient;
|
||||
};
|
||||
mockClient.exec = (cb) => {
|
||||
execCalled = true;
|
||||
cb();
|
||||
};
|
||||
hc.count({
|
||||
headers: {},
|
||||
connection: { remoteAddress: 'test1' },
|
||||
}, '/test/path/1', () => {
|
||||
expect(multiCalled).toBeTruthy();
|
||||
expect(hincrbyCalls).toEqual([
|
||||
[
|
||||
'/test/path/1',
|
||||
'h',
|
||||
1,
|
||||
],
|
||||
[
|
||||
'/test/path/1',
|
||||
'v',
|
||||
1,
|
||||
],
|
||||
]);
|
||||
expect(execCalled).toBeTruthy();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('count()', () => {
|
||||
beforeEach(() => {
|
||||
mockClient.multi = () => mockClient;
|
||||
mockClient.hincrby = () => mockClient;
|
||||
mockClient.exec = (cb) => {
|
||||
cb();
|
||||
};
|
||||
config['hit_counter']['unique_visitor_timeout'] = -1;
|
||||
});
|
||||
|
||||
test('simple visit', (done) => {
|
||||
let multiCalled = false;
|
||||
let execCalled = false;
|
||||
let hincrbyCalls = [];
|
||||
mockClient.multi = () => {
|
||||
multiCalled = true;
|
||||
return mockClient;
|
||||
};
|
||||
mockClient.hincrby = (hash, key, value) => {
|
||||
hincrbyCalls.push([
|
||||
hash,
|
||||
key,
|
||||
value,
|
||||
]);
|
||||
return mockClient;
|
||||
};
|
||||
mockClient.exec = (cb) => {
|
||||
execCalled = true;
|
||||
cb();
|
||||
};
|
||||
hc.count({
|
||||
headers: {},
|
||||
connection: { remoteAddress: 'test1' },
|
||||
}, '/test/path/1', () => {
|
||||
expect(multiCalled).toBeTruthy();
|
||||
expect(hincrbyCalls).toEqual([
|
||||
[
|
||||
'/test/path/1',
|
||||
'h',
|
||||
1,
|
||||
],
|
||||
[
|
||||
'/test/path/1',
|
||||
'v',
|
||||
1,
|
||||
],
|
||||
]);
|
||||
expect(execCalled).toBeTruthy();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('re-visit after long time', (done) => {
|
||||
let hincrbyCalls = [];
|
||||
mockClient.hincrby = (hash, key, value) => {
|
||||
hincrbyCalls.push([
|
||||
hash,
|
||||
key,
|
||||
value,
|
||||
]);
|
||||
return mockClient;
|
||||
};
|
||||
hc.count({
|
||||
headers: {},
|
||||
connection: { remoteAddress: 'test2' },
|
||||
}, '/test/path/2', () => {
|
||||
hc.count({
|
||||
headers: {},
|
||||
connection: { remoteAddress: 'test2' },
|
||||
}, '/test/path/2', () => {
|
||||
expect(hincrbyCalls).toEqual([
|
||||
[
|
||||
'/test/path/2',
|
||||
'h',
|
||||
1,
|
||||
],
|
||||
[
|
||||
'/test/path/2',
|
||||
'v',
|
||||
1,
|
||||
],
|
||||
[
|
||||
'/test/path/2',
|
||||
'h',
|
||||
1,
|
||||
],
|
||||
[
|
||||
'/test/path/2',
|
||||
'v',
|
||||
1,
|
||||
],
|
||||
]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('re-visit after short time', (done) => {
|
||||
config['hit_counter']['unique_visitor_timeout'] = 10000;
|
||||
let hincrbyCalls = [];
|
||||
mockClient.hincrby = (hash, key, value) => {
|
||||
hincrbyCalls.push([
|
||||
hash,
|
||||
key,
|
||||
value,
|
||||
]);
|
||||
return mockClient;
|
||||
};
|
||||
hc.count({
|
||||
headers: {},
|
||||
connection: { remoteAddress: 'test3' },
|
||||
}, '/test/path/3', () => {
|
||||
hc.count({
|
||||
headers: {},
|
||||
connection: { remoteAddress: 'test3' },
|
||||
}, '/test/path/3', () => {
|
||||
expect(hincrbyCalls).toEqual([
|
||||
[
|
||||
'/test/path/3',
|
||||
'h',
|
||||
1,
|
||||
],
|
||||
[
|
||||
'/test/path/3',
|
||||
'v',
|
||||
1,
|
||||
],
|
||||
[
|
||||
'/test/path/3',
|
||||
'h',
|
||||
1,
|
||||
],
|
||||
[
|
||||
'/test/path/3',
|
||||
'v',
|
||||
0,
|
||||
],
|
||||
]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user