UNPKG

@treecg/curation

Version:

This library implements a class (Curator) with methods to curate an announcement LDES in LDP.

505 lines (504 loc) 28.4 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); var fs_1 = require("fs"); var path_1 = __importDefault(require("path")); var ldes_announcements_1 = require("@treecg/ldes-announcements"); var ldes_orchestrator_1 = require("@treecg/ldes-orchestrator"); var Login_1 = require("@treecg/ldes-orchestrator/dist/src/Login"); var Curator_1 = require("../src/Curator"); var Conversion_1 = require("../src/util/Conversion"); var Vocabularies_1 = require("../src/util/Vocabularies"); var solidHelper_1 = require("./solidHelper"); describe('Integration test for LDESinSolid and Orchestrating functionalities', function () { var base = (0, solidHelper_1.solidUrl)(); var session; var announcement; var solidPodPath = path_1.default.join(__dirname, 'solidPod'); beforeAll(function () { return __awaiter(void 0, void 0, void 0, function () { var viewString, viewStore, announcementConfig; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, (0, Login_1.getSession)()]; case 1: // create session session = _a.sent(); viewString = '<https://test/output/root.ttl> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/tree#Node>.'; return [4 /*yield*/, (0, Conversion_1.turtleStringToStore)(viewString)]; case 2: viewStore = _a.sent(); announcementConfig = { bucketizer: 'substring', creatorName: 'woutslabbinck', creatorURL: "https://github.com/woutslabbinck", originalLDESURL: 'https://smartdata.dev-vlaanderen.be/base/gemeente', pageSize: '100', propertyPath: '<http://www.w3.org/2000/01/rdf-schema#label>', viewId: 'https://test/output/root.ttl' }; return [4 /*yield*/, (0, ldes_announcements_1.createViewAnnouncement)(viewStore, announcementConfig)]; case 3: announcement = _a.sent(); return [2 /*return*/]; } }); }); }); describe('General tests', function () { it('server online', function () { return __awaiter(void 0, void 0, void 0, function () { var getRequest; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, fetch(base)]; case 1: getRequest = _a.sent(); expect(getRequest.status).toBe(200); return [2 /*return*/]; } }); }); }); it('is logged in', function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) { expect(session.info.isLoggedIn).toBe(true); return [2 /*return*/]; }); }); }); }); describe('Curation', function () { var curationDirectory = 'curationTest'; var ldesName = 'ldes'; var curatedName = 'curated'; var synchronizedName = 'synchronized'; var curationbaseUrl = "".concat(base + curationDirectory, "/"); var ldesBaseUrl = "".concat(curationbaseUrl + ldesName, "/"); var curatedIRI = "".concat(curationbaseUrl + curatedName, "/"); var synchronizedIRI = "".concat(curationbaseUrl + synchronizedName, "/"); var curationConfig = { ldesIRI: ldesBaseUrl, curatedIRI: curatedIRI, synchronizedIRI: synchronizedIRI }; // path to the synchronized directory var synchronizedPath = path_1.default.join(solidPodPath, curationDirectory, synchronizedName); /** * Very specific function to get the relation store of a synced collection node * @returns {Promise<Store<Quad, Quad, Quad, Quad>>} */ function getSyncedRelationStore() { return __awaiter(this, void 0, void 0, function () { var rootStore, relationUrl, relationName; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, (0, solidHelper_1.fileAsStore)(path_1.default.join(synchronizedPath, 'root.ttl'))]; case 1: rootStore = _a.sent(); relationUrl = rootStore.getQuads(null, Vocabularies_1.TREE.node, null, null)[0].object.id; relationName = relationUrl.split('/').slice(-1)[0]; return [4 /*yield*/, (0, solidHelper_1.fileAsStore)(path_1.default.join(synchronizedPath, "".concat(relationName, "$.ttl")))]; case 2: return [2 /*return*/, _a.sent()]; } }); }); } beforeEach(function () { return __awaiter(void 0, void 0, void 0, function () { var ldesConfig, aclConfig, ldes; return __generator(this, function (_a) { switch (_a.label) { case 0: ldesConfig = { base: ldesBaseUrl, treePath: Vocabularies_1.DCT.modified, shape: 'https://tree.linkeddatafragments.org/announcements/shape', relationType: Vocabularies_1.TREE.GreaterThanOrEqualToRelation }; if (!session.info.webId) throw Error("Should be present"); aclConfig = { agent: session.info.webId }; ldes = new ldes_orchestrator_1.LDESinSolid(ldesConfig, aclConfig, session, 1); return [4 /*yield*/, ldes.createLDESinLDP()]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }); afterEach(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) { (0, fs_1.rmdirSync)(path_1.default.join(solidPodPath, curationDirectory), { recursive: true }); return [2 /*return*/]; }); }); }); it('Synchronizing', function () { return __awaiter(void 0, void 0, void 0, function () { var response, announcementURI, curator, files, relationStore; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, (0, ldes_announcements_1.postAnnouncement)(announcement, ldesBaseUrl)]; case 1: response = _a.sent(); announcementURI = response.headers.get('location'); curator = new Curator_1.Curator(curationConfig, session); return [4 /*yield*/, curator.synchronize()]; case 2: _a.sent(); files = (0, fs_1.readdirSync)(synchronizedPath); expect(files.includes('root.ttl')).toBe(true); expect(files.length).toBe(2); return [4 /*yield*/, getSyncedRelationStore()]; case 3: relationStore = _a.sent(); // time object of the announcement should exist expect(relationStore.getQuads(announcementURI, null, null, null).length).toBe(1); return [2 /*return*/]; } }); }); }); it('Multiple synchronizing: Orchestrator was executed', function () { return __awaiter(void 0, void 0, void 0, function () { var ldesConfig, ldes, orchestrator, curator, files; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, ldes_orchestrator_1.LDESinSolid.getConfig(ldesBaseUrl, session)]; case 1: ldesConfig = _a.sent(); ldes = new ldes_orchestrator_1.LDESinSolid(ldesConfig.ldesConfig, ldesConfig.aclConfig, session, 1); orchestrator = new ldes_orchestrator_1.Orchestrator(session); curator = new Curator_1.Curator(curationConfig, session); // add one announcement return [4 /*yield*/, (0, ldes_announcements_1.postAnnouncement)(announcement, ldesBaseUrl)]; case 2: // add one announcement _a.sent(); // synchronize once return [4 /*yield*/, curator.synchronize()]; case 3: // synchronize once _a.sent(); // orchestrate once orchestrator.orchestrateLDES(ldes, .1); return [4 /*yield*/, (0, solidHelper_1.sleep)(1000)]; case 4: _a.sent(); // make sure there was some orchestration orchestrator.stopOrchestrating(); // add another announcement return [4 /*yield*/, (0, ldes_announcements_1.postAnnouncement)(announcement, ldesBaseUrl)]; case 5: // add another announcement _a.sent(); // synchronize again return [4 /*yield*/, curator.synchronize()]; case 6: // synchronize again _a.sent(); files = (0, fs_1.readdirSync)(synchronizedPath); expect(files.length).toBe(3); return [2 /*return*/]; } }); }); }); it('Multiple synchronizing: new member was added', function () { return __awaiter(void 0, void 0, void 0, function () { var curator, responseAnnouncement1, responseAnnouncement2, relationStore, announcementPresent1, announcementPresent2; return __generator(this, function (_a) { switch (_a.label) { case 0: curator = new Curator_1.Curator(curationConfig, session); return [4 /*yield*/, (0, ldes_announcements_1.postAnnouncement)(announcement, ldesBaseUrl)]; case 1: responseAnnouncement1 = _a.sent(); // synchronize once return [4 /*yield*/, curator.synchronize()]; case 2: // synchronize once _a.sent(); return [4 /*yield*/, (0, solidHelper_1.sleep)(1000)]; case 3: _a.sent(); return [4 /*yield*/, (0, ldes_announcements_1.postAnnouncement)(announcement, ldesBaseUrl)]; case 4: responseAnnouncement2 = _a.sent(); return [4 /*yield*/, curator.synchronize()]; case 5: _a.sent(); return [4 /*yield*/, getSyncedRelationStore()]; case 6: relationStore = _a.sent(); announcementPresent1 = relationStore.getQuads(responseAnnouncement1.headers.get('location'), null, null, null); announcementPresent2 = relationStore.getQuads(responseAnnouncement2.headers.get('location'), null, null, null); expect(announcementPresent1.length).toBe(1); expect(announcementPresent2.length).toBe(1); return [2 /*return*/]; } }); }); }); it('Retrieve empty list when memberUris are not synchronized', function () { return __awaiter(void 0, void 0, void 0, function () { var curator, members; return __generator(this, function (_a) { switch (_a.label) { case 0: curator = new Curator_1.Curator(curationConfig, session); return [4 /*yield*/, (0, ldes_announcements_1.postAnnouncement)(announcement, ldesBaseUrl)]; case 1: _a.sent(); return [4 /*yield*/, curator.getRecentMembers(1)]; case 2: members = _a.sent(); expect(members.length).toBe(0); return [2 /*return*/]; } }); }); }); it('Retrieve list of memberUris of synchronized list', function () { return __awaiter(void 0, void 0, void 0, function () { var curator, response, members; return __generator(this, function (_a) { switch (_a.label) { case 0: curator = new Curator_1.Curator(curationConfig, session); return [4 /*yield*/, (0, ldes_announcements_1.postAnnouncement)(announcement, ldesBaseUrl)]; case 1: response = _a.sent(); return [4 /*yield*/, curator.synchronize()]; case 2: _a.sent(); return [4 /*yield*/, curator.getRecentMembers(1)]; case 3: members = _a.sent(); expect(members.length).toBe(1); expect(members[0].memberIRI).toBe(response.headers.get('location')); return [2 /*return*/]; } }); }); }); it('Extracting one member', function () { return __awaiter(void 0, void 0, void 0, function () { var curator, response, members, member; return __generator(this, function (_a) { switch (_a.label) { case 0: curator = new Curator_1.Curator(curationConfig, session); return [4 /*yield*/, (0, ldes_announcements_1.postAnnouncement)(announcement, ldesBaseUrl)]; case 1: response = _a.sent(); return [4 /*yield*/, curator.synchronize()]; case 2: _a.sent(); return [4 /*yield*/, curator.getRecentMembers(1)]; case 3: members = _a.sent(); return [4 /*yield*/, curator.extractMember(members[0].memberIRI)]; case 4: member = _a.sent(); expect(member.type).toBe(Vocabularies_1.TREE.Node); expect(member.value["@id"]).toBe("".concat(response.headers.get('location'), "#view")); return [2 /*return*/]; } }); }); }); it('Initiating the curated ldes', function () { return __awaiter(void 0, void 0, void 0, function () { var curator, curatedLdesPath, curatedFiles, curatedRoot, view; return __generator(this, function (_a) { switch (_a.label) { case 0: curator = new Curator_1.Curator(curationConfig, session); return [4 /*yield*/, curator.init()]; case 1: _a.sent(); curatedLdesPath = path_1.default.join(solidPodPath, curationDirectory, curatedName); curatedFiles = (0, fs_1.readdirSync)(curatedLdesPath); expect(curatedFiles.includes('root.ttl')).toBe(true); // files expected are: the root, the directory of the relation of the root, the acl file of the ldes and the .meta file expect(curatedFiles.length).toBe(4); return [4 /*yield*/, (0, solidHelper_1.fileAsStore)(path_1.default.join(curatedLdesPath, 'root.ttl'))]; case 2: curatedRoot = _a.sent(); view = curatedRoot.getQuads("".concat(curatedIRI, "root.ttl"), Vocabularies_1.RDF.type, null, null)[0]; expect(view.object.id).toBe(Vocabularies_1.TREE.Node); return [2 /*return*/]; } }); }); }); it('Rejecting one member (giving the timestamp)', function () { return __awaiter(void 0, void 0, void 0, function () { var curator, members, membersLeft; return __generator(this, function (_a) { switch (_a.label) { case 0: curator = new Curator_1.Curator(curationConfig, session); return [4 /*yield*/, (0, ldes_announcements_1.postAnnouncement)(announcement, ldesBaseUrl)]; case 1: _a.sent(); return [4 /*yield*/, curator.synchronize()]; case 2: _a.sent(); return [4 /*yield*/, curator.getRecentMembers(1)]; case 3: members = _a.sent(); return [4 /*yield*/, curator.reject(members[0].memberIRI, members[0].timestamp)]; case 4: _a.sent(); return [4 /*yield*/, curator.getRecentMembers(1)]; case 5: membersLeft = _a.sent(); expect(membersLeft.length).toBe(0); return [2 /*return*/]; } }); }); }); it('Rejecting one member (not giving the timestamp)', function () { return __awaiter(void 0, void 0, void 0, function () { var curator, response, membersLeft; return __generator(this, function (_a) { switch (_a.label) { case 0: curator = new Curator_1.Curator(curationConfig, session); return [4 /*yield*/, (0, ldes_announcements_1.postAnnouncement)(announcement, ldesBaseUrl)]; case 1: response = _a.sent(); return [4 /*yield*/, curator.synchronize()]; case 2: _a.sent(); return [4 /*yield*/, curator.reject(response.headers.get('location'))]; case 3: _a.sent(); return [4 /*yield*/, curator.reject(response.headers.get('location'))]; case 4: _a.sent(); return [4 /*yield*/, curator.getRecentMembers(1)]; case 5: membersLeft = _a.sent(); expect(membersLeft.length).toBe(0); return [2 /*return*/]; } }); }); }); it('Accepting without initialising should throw error', function () { return __awaiter(void 0, void 0, void 0, function () { var curator, e_1, err; return __generator(this, function (_a) { switch (_a.label) { case 0: expect.assertions(2); curator = new Curator_1.Curator(curationConfig, session); _a.label = 1; case 1: _a.trys.push([1, 3, , 4]); return [4 /*yield*/, curator.accept('iri')]; case 2: _a.sent(); return [3 /*break*/, 4]; case 3: e_1 = _a.sent(); err = e_1; expect(err.name).toBe("Error"); expect(err.message).toBe("First execute function init() as the curated LDES was not initialised yet"); return [3 /*break*/, 4]; case 4: return [2 /*return*/]; } }); }); }); it('Accepting one member (giving all information)', function () { return __awaiter(void 0, void 0, void 0, function () { var curator, members, member, curatedLdesPath, directoryInCuratedLdes, relationPath, curatedMemberFileName, curatedRoot, view; return __generator(this, function (_a) { switch (_a.label) { case 0: curator = new Curator_1.Curator(curationConfig, session); return [4 /*yield*/, (0, ldes_announcements_1.postAnnouncement)(announcement, ldesBaseUrl)]; case 1: _a.sent(); return [4 /*yield*/, curator.synchronize()]; case 2: _a.sent(); return [4 /*yield*/, curator.init()]; case 3: _a.sent(); return [4 /*yield*/, curator.getRecentMembers(1)]; case 4: members = _a.sent(); return [4 /*yield*/, curator.extractMember(members[0].memberIRI)]; case 5: member = _a.sent(); return [4 /*yield*/, curator.accept(members[0].memberIRI, member.value, members[0].timestamp)]; case 6: _a.sent(); curatedLdesPath = path_1.default.join(solidPodPath, curationDirectory, curatedName); directoryInCuratedLdes = (0, fs_1.readdirSync)(curatedLdesPath, { withFileTypes: true }) .filter(function (dirent) { return dirent.isDirectory(); }).map(function (dirent) { return dirent.name; }); relationPath = path_1.default.join(solidPodPath, curationDirectory, curatedName, directoryInCuratedLdes[0]); curatedMemberFileName = (0, fs_1.readdirSync)(relationPath).filter(function (name) { return !name.includes('acl'); })[0]; return [4 /*yield*/, (0, solidHelper_1.fileAsStore)(path_1.default.join(relationPath, curatedMemberFileName))]; case 7: curatedRoot = _a.sent(); view = curatedRoot.getQuads("".concat(member.iri, "#view"), Vocabularies_1.RDF.type, null, null)[0]; expect(view.object.id).toBe(Vocabularies_1.TREE.Node); return [2 /*return*/]; } }); }); }); it('Accepting one member (giving only the memberIRI)', function () { return __awaiter(void 0, void 0, void 0, function () { var curator, response, memberIri, curatedLdesPath, directoryInCuratedLdes, relationPath, curatedMemberFileName, curatedMemberPath, curatedRoot, view; return __generator(this, function (_a) { switch (_a.label) { case 0: curator = new Curator_1.Curator(curationConfig, session); return [4 /*yield*/, (0, ldes_announcements_1.postAnnouncement)(announcement, ldesBaseUrl)]; case 1: response = _a.sent(); return [4 /*yield*/, curator.synchronize()]; case 2: _a.sent(); return [4 /*yield*/, curator.init()]; case 3: _a.sent(); memberIri = response.headers.get('location'); return [4 /*yield*/, curator.accept(memberIri)]; case 4: _a.sent(); curatedLdesPath = path_1.default.join(solidPodPath, curationDirectory, curatedName); directoryInCuratedLdes = (0, fs_1.readdirSync)(curatedLdesPath, { withFileTypes: true }) .filter(function (dirent) { return dirent.isDirectory(); }).map(function (dirent) { return dirent.name; }); relationPath = path_1.default.join(solidPodPath, curationDirectory, curatedName, directoryInCuratedLdes[0]); curatedMemberFileName = (0, fs_1.readdirSync)(relationPath).filter(function (name) { return !name.includes('acl'); })[0]; curatedMemberPath = path_1.default.join(relationPath, curatedMemberFileName); return [4 /*yield*/, (0, solidHelper_1.fileAsStore)(curatedMemberPath)]; case 5: curatedRoot = _a.sent(); view = curatedRoot.getQuads("".concat(memberIri, "#view"), Vocabularies_1.RDF.type, null, null)[0]; expect(view.object.id).toBe(Vocabularies_1.TREE.Node); return [2 /*return*/]; } }); }); }); }); });