Update packages version
Add first test Add design pattern builder + Youtube builder
This commit is contained in:
		
							
								
								
									
										778
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										778
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -16,14 +16,15 @@
 | 
				
			|||||||
    "discord.js": "^12.0.1",
 | 
					    "discord.js": "^12.0.1",
 | 
				
			||||||
    "fs-extra": "^9.0.0",
 | 
					    "fs-extra": "^9.0.0",
 | 
				
			||||||
    "jsonfile": "^6.0.1",
 | 
					    "jsonfile": "^6.0.1",
 | 
				
			||||||
    "lodash": "^4.17.15",
 | 
					    "lodash": "^4.17.20",
 | 
				
			||||||
    "pm2": "^4.2.3",
 | 
					    "pm2": "^4.5.1",
 | 
				
			||||||
    "rss-parser": "^3.7.5"
 | 
					    "rss-parser": "^3.7.5"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "chai": "^4.2.0",
 | 
					    "chai": "^4.2.0",
 | 
				
			||||||
    "mocha": "^8.2.1",
 | 
					    "mocha": "^8.2.1",
 | 
				
			||||||
    "proxyquire": "^2.1.3",
 | 
					    "proxyquire": "^2.1.3",
 | 
				
			||||||
    "sinon": "^9.2.2"
 | 
					    "sinon": "^9.2.2",
 | 
				
			||||||
 | 
					    "sinon-chai": "^3.5.0"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										47
									
								
								src/Models/Builders/AbstractListenerRSSBuilder.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/Models/Builders/AbstractListenerRSSBuilder.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					const ListenerRSS = require('../listener-rss');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AbstractListnerRSSBuilder {
 | 
				
			||||||
 | 
					    _listenerRSS = undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor() {
 | 
				
			||||||
 | 
					        if(this.constructor === AbstractListnerRSSBuilder)
 | 
				
			||||||
 | 
					            throw new Error('The Abstract class "AbstractListnerRSSBuilder" cannot be instantiated');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @brief first function to call after constructor. It's building the listener
 | 
				
			||||||
 | 
					     * @param infos Must to be an object ListenerRSSInfos
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    constructListener(infos) {
 | 
				
			||||||
 | 
					        this._listenerRSS = new ListenerRSS();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.setInfos(infos);
 | 
				
			||||||
 | 
					        this.setSpecificInfos();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @brief give the listener just build
 | 
				
			||||||
 | 
					     * @return ListenerRSS with all the setups datas
 | 
				
			||||||
 | 
					     * @exception if the listener isn't construct
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    get listenerRSS() {
 | 
				
			||||||
 | 
					        if(this._listenerRSS === undefined)
 | 
				
			||||||
 | 
					            throw new Error('the listener is not yet build');
 | 
				
			||||||
 | 
					        return this._listenerRSS;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setInfos(infos) { // Nominal Infos (like name, addresse, and other)
 | 
				
			||||||
 | 
					        this._listenerRSS.name = infos._name;
 | 
				
			||||||
 | 
					        this._listenerRSS.address = infos._address;
 | 
				
			||||||
 | 
					        this._listenerRSS.timeloop = infos._timeloop;
 | 
				
			||||||
 | 
					        this._listenerRSS.name = infos._name;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setSpecificInfos() { // More generic infos who's depend of platforms
 | 
				
			||||||
 | 
					        throw new Error('This function is not implemented');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = AbstractListnerRSSBuilder
 | 
				
			||||||
							
								
								
									
										16
									
								
								src/Models/Builders/YoutubeListenerRSSBuilder.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/Models/Builders/YoutubeListenerRSSBuilder.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					const AbstractListenerRSSBuilder = require('AbstractListenerRSSBuilder')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class YoutubeListenerRSSBuilder extends AbstractListenerRSSBuilder {
 | 
				
			||||||
 | 
					    constructor() {
 | 
				
			||||||
 | 
					        super();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setSpecificInfos() {
 | 
				
			||||||
 | 
					        this.listenerRSS._customfields = [
 | 
				
			||||||
 | 
					            ['description', ['media:group', 'media:description']],
 | 
				
			||||||
 | 
					            ['icon', ['media:group', 'media:thumbnail']]
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = YoutubeListenerRSSBuilder
 | 
				
			||||||
							
								
								
									
										42
									
								
								src/Models/listenerRSSInfos.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/Models/listenerRSSInfos.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
				
			|||||||
 | 
					class ListenerRSSInfos {
 | 
				
			||||||
 | 
					    _name = undefined; // name of the listener
 | 
				
			||||||
 | 
					    _address = undefined; // feed's address
 | 
				
			||||||
 | 
					    _timeloop = 1 * 60; // update time RSS feed
 | 
				
			||||||
 | 
					    _customfields = [] // rss fields custom
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    set name(value) {
 | 
				
			||||||
 | 
					        this._name = value;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    set address(value) {
 | 
				
			||||||
 | 
					        this._address = value;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    set timeloop(value) {
 | 
				
			||||||
 | 
					        this._timeloop = value;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    set customfields(value) {
 | 
				
			||||||
 | 
					        this._customfields = value;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get name() {
 | 
				
			||||||
 | 
					        return this._name;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get address() {
 | 
				
			||||||
 | 
					        return this._address;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get timeloop() {
 | 
				
			||||||
 | 
					        return this._timeloop;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get customfields() {
 | 
				
			||||||
 | 
					        return this._customfields;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = ListenerRSSInfos
 | 
				
			||||||
							
								
								
									
										22
									
								
								src/listener-director.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/listener-director.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					const YoutubeListenerRSSBuilder = require('./Models/YoutubeListenerRSSBuilder');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ListenerBuildDirector {
 | 
				
			||||||
 | 
					    _builder = undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(builder) {
 | 
				
			||||||
 | 
					        this._builder = builder;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    getListener() {
 | 
				
			||||||
 | 
					        return this._builder.listenerRSS();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    build(infos) {
 | 
				
			||||||
 | 
					        if(infos === undefined)
 | 
				
			||||||
 | 
					            throw new Error('infos must be initialized');
 | 
				
			||||||
 | 
					        this._builder.constructListener(infos);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = ListenerBuildDirector
 | 
				
			||||||
							
								
								
									
										61
									
								
								src/listener-rss.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/listener-rss.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,61 @@
 | 
				
			|||||||
 | 
					const jsonFile = require('jsonfile');
 | 
				
			||||||
 | 
					const Parser = require('rss-parser');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ListenerRss {
 | 
				
			||||||
 | 
					    name = undefined;
 | 
				
			||||||
 | 
					    address = undefined;
 | 
				
			||||||
 | 
					    timeloop = 5 * 60; // time in seconds
 | 
				
			||||||
 | 
					    customfields = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // private fields
 | 
				
			||||||
 | 
					    parser = null;
 | 
				
			||||||
 | 
					    obj = null;
 | 
				
			||||||
 | 
					    loopRunning = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(info) {
 | 
				
			||||||
 | 
					        // set parser
 | 
				
			||||||
 | 
					        this.parser = new Parser({
 | 
				
			||||||
 | 
					            customFields : {
 | 
				
			||||||
 | 
					                item: info._customfields.map((elt) => {
 | 
				
			||||||
 | 
					                    return Array.isArray(elt[1]) ? elt[1][0] : elt[1];
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Set data
 | 
				
			||||||
 | 
					        this.name = info._name === undefined ? info._address : info._name; // if name is undefined let's take the address
 | 
				
			||||||
 | 
					        this.address = info._address;
 | 
				
			||||||
 | 
					        this.timeloop = info._timeloop;
 | 
				
			||||||
 | 
					        this.customfields = info._customfields;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fetchRSS() {
 | 
				
			||||||
 | 
					        return this.parser.parseURL(this.address)
 | 
				
			||||||
 | 
					            .catch((err) => { throw new Error('bad address or no access : ' + err);});
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @brief call the callback function each looptime
 | 
				
			||||||
 | 
					     * @param callback function who's going to be called with the latest get
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    start(callback) {
 | 
				
			||||||
 | 
					        this.loopRunning = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        (async () => {
 | 
				
			||||||
 | 
					            while(this.loopRunning === true) {
 | 
				
			||||||
 | 
					                callback(await this.fetchRSS());
 | 
				
			||||||
 | 
					                await new Promise(res => setTimeout(res, this.timeloop * 1000));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        })();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @brief stop the async function
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    stop() {
 | 
				
			||||||
 | 
					        this.loopRunning = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = ListenerRss
 | 
				
			||||||
@@ -1,59 +1,100 @@
 | 
				
			|||||||
const chai = require("chai");
 | 
					const chai = require("chai");
 | 
				
			||||||
const sinon = require("sinon");
 | 
					const sinon = require("sinon");
 | 
				
			||||||
const proxyquire = require("proxyquire");
 | 
					const sinon_chai = require("sinon-chai");
 | 
				
			||||||
 | 
					chai.use(sinon_chai);
 | 
				
			||||||
const Parser = require("rss-parser");
 | 
					const Parser = require("rss-parser");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Listeners = require('../src/listener-rss')
 | 
				
			||||||
 | 
					const ListenerRRSInfo = require('../src/Models/listenerRSSInfos')
 | 
				
			||||||
 | 
					const YtbBuilder = require('../src/Models/YoutubeListenerRSSBuilder')
 | 
				
			||||||
 | 
					const YtbDirector = require('../src/listener-director')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const expect = chai.expect;
 | 
					const expect = chai.expect;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe("RSS Youtube", function () {
 | 
					describe("test class RSS: jsonfile", function () {
 | 
				
			||||||
  let rssYoutubeService;
 | 
					    let myListener = undefined;
 | 
				
			||||||
  let timecode;
 | 
					
 | 
				
			||||||
  let routage;
 | 
					    let infosListener = new ListenerRRSInfo();
 | 
				
			||||||
  let parseUrlStub;
 | 
					    infosListener.name = 'my-test-service';
 | 
				
			||||||
  let mockedInput = {
 | 
					    infosListener.address = 'fake.rss.service';
 | 
				
			||||||
 | 
					    infosListener.timeloop = 15;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // parseURL tests
 | 
				
			||||||
 | 
					    let stubParser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const mockedRSSOutput = {
 | 
				
			||||||
        items: [
 | 
					        items: [
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
        id: "::account",
 | 
					                'title': 'my title 00',
 | 
				
			||||||
        url:
 | 
					                'media:group': {
 | 
				
			||||||
        isoDate: Date.now().toISOString(),
 | 
					                    'media:description': 'my description 00',
 | 
				
			||||||
        "media:group": {
 | 
					                    'media:thumbnail': [{$: {height: 360, width: 420, url: 'my_image00.jpg'}}],
 | 
				
			||||||
          "media:description": [
 | 
					                },
 | 
				
			||||||
            "my description"
 | 
					                'link': 'my_url_00.com',
 | 
				
			||||||
          ]
 | 
					                'pubDate': 'myDate00'
 | 
				
			||||||
        }
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                'title': 'my title 01',
 | 
				
			||||||
 | 
					                'media:group' : {
 | 
				
			||||||
 | 
					                    'media:description': 'my description 01',
 | 
				
			||||||
 | 
					                    'media:thumbnail': [{$: { height: 360, width: 420, url: 'my_image01.jpg'}}],
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                'link': 'my_url_01.com',
 | 
				
			||||||
 | 
					                'pubDate': 'myDate01'
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                'title': 'my title 02',
 | 
				
			||||||
 | 
					                'media:group' : {
 | 
				
			||||||
 | 
					                    'media:description': 'my description 02',
 | 
				
			||||||
 | 
					                    'media:thumbnail': [{$: { height: 360, width: 420, url: 'my_image02.jpg'}}],
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                'link': 'my_url_02.com',
 | 
				
			||||||
 | 
					                'pubDate': 'myDate02'
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    beforeEach(function () {
 | 
					    beforeEach(function () {
 | 
				
			||||||
    timecode = {
 | 
					        // stubs
 | 
				
			||||||
      "lastCheck": "2020-11-12T17:44:11.713Z",
 | 
					        stubParser = sinon.stub(Parser.prototype, 'parseURL')
 | 
				
			||||||
      "MyUser": "2020-11-12T17:44:11.713Z"
 | 
					            .withArgs(listenerInfo.address)
 | 
				
			||||||
    };
 | 
					            .resolves(mockedRSSOutput);
 | 
				
			||||||
    routage = {
 | 
					 | 
				
			||||||
      log: sinon.stub(),
 | 
					 | 
				
			||||||
      send: sinon.stub()
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    parseUrlStub = sinon.stub(Parser.prototype, "parseURL")
 | 
					        // constructor
 | 
				
			||||||
      .callsFake((_, callback) => callback(null, "data"));
 | 
					        myListener = new Listeners();
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
    rssYoutubeService = proxyquire("../services/rss-youtube", {
 | 
					 | 
				
			||||||
      "../modules/routage": () => routage,
 | 
					 | 
				
			||||||
      "../db/rss-youtube.json": {
 | 
					 | 
				
			||||||
        config: {
 | 
					 | 
				
			||||||
          timeLoop: 5,
 | 
					 | 
				
			||||||
          urlFeeds: "https://www.youtube.com/feeds/videos.xml?channel_id=",
 | 
					 | 
				
			||||||
          sliceDescription: 142
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        feeds: {
 | 
					 | 
				
			||||||
          MyUser: "Some channel"
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        timecode
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    afterEach(function () {
 | 
					    afterEach(function () {
 | 
				
			||||||
    Parser.prototype.parseURL.reset();
 | 
					        // restore stubs
 | 
				
			||||||
 | 
					        Parser.prototype.parseURL.restore();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    describe("Building Ytb listener", function () {
 | 
				
			||||||
 | 
					        it("The build without problems", function () {
 | 
				
			||||||
 | 
					            let builder = new YtbBuilder();
 | 
				
			||||||
 | 
					            let director = new YtbDirector(builder);
 | 
				
			||||||
 | 
					            director.build(infosListener);
 | 
				
			||||||
 | 
					            myListener = director.getListener();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // assertions
 | 
				
			||||||
 | 
					            expect(stubParser).to.have.been.calledOnce;
 | 
				
			||||||
 | 
					            expect(stubParser).to.have.been.calledWith(infosListener._address);
 | 
				
			||||||
 | 
					            expect(myListener.customFields).to.eql([
 | 
				
			||||||
 | 
					                ['description', ['media:group', 'media:description']],
 | 
				
			||||||
 | 
					                ['icon', ['media:group', 'media:thumbnail']]
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					            //TODO test les infos dans "myListener"
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //Todo
 | 
				
			||||||
 | 
					    describe.skip("start", function () {
 | 
				
			||||||
 | 
					        it("Let's start the timer", function () {
 | 
				
			||||||
 | 
					            myListener.setDatas(listenerInfo);
 | 
				
			||||||
 | 
					            myListener.start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user