Best Python code snippet using yandex-tank
job-manager.test.js
Source:job-manager.test.js
1// Switch these lines once there are useful utils2// const testUtils = require('./utils');3require('./utils');4const assert = require('assert');5const path = require('path');6const sinon = require('sinon');7const delay = require('delay');8const FakeTimers = require('@sinonjs/fake-timers');9const logging = require('@tryghost/logging');10const JobManager = require('../index');11const sandbox = sinon.createSandbox();12const jobModelInstance = {13 id: 'unique',14 get: (field) => {15 if (field === 'status') {16 return 'finished';17 }18 }19};20describe('Job Manager', function () {21 beforeEach(function () {22 sandbox.stub(logging, 'info');23 sandbox.stub(logging, 'warn');24 sandbox.stub(logging, 'error');25 });26 afterEach(function () {27 sandbox.restore();28 });29 it('public interface', function () {30 const jobManager = new JobManager({});31 should.exist(jobManager.addJob);32 should.exist(jobManager.hasExecutedSuccessfully);33 should.exist(jobManager.awaitCompletion);34 });35 describe('Add a job', function () {36 describe('Inline jobs', function () {37 it('adds a job to a queue', async function () {38 const spy = sinon.spy();39 const jobManager = new JobManager({40 JobModel: sinon.stub().resolves()41 });42 jobManager.addJob({43 job: spy,44 data: 'test data',45 offloaded: false46 });47 should(jobManager.queue.idle()).be.false();48 // give time to execute the job49 await delay(1);50 should(jobManager.queue.idle()).be.true();51 should(spy.called).be.true();52 should(spy.args[0][0]).equal('test data');53 });54 it('handles failed job gracefully', async function () {55 const spy = sinon.stub().throws();56 const jobManager = new JobManager({});57 jobManager.addJob({58 job: spy,59 data: 'test data',60 offloaded: false61 });62 should(jobManager.queue.idle()).be.false();63 // give time to execute the job64 await delay(1);65 should(jobManager.queue.idle()).be.true();66 should(spy.called).be.true();67 should(spy.args[0][0]).equal('test data');68 should(logging.error.called).be.true();69 });70 });71 describe('Offloaded jobs', function () {72 it('fails to schedule for invalid scheduling expression', function () {73 const jobManager = new JobManager({});74 try {75 jobManager.addJob({76 at: 'invalid expression',77 name: 'jobName'78 });79 } catch (err) {80 err.message.should.equal('Invalid schedule format');81 }82 });83 it('fails to schedule for no job name', function () {84 const jobManager = new JobManager({});85 try {86 jobManager.addJob({87 at: 'invalid expression',88 job: () => {}89 });90 } catch (err) {91 err.message.should.equal('Name parameter should be present if job is a function');92 }93 });94 it('schedules a job using date format', async function () {95 const jobManager = new JobManager({});96 const timeInTenSeconds = new Date(Date.now() + 10);97 const jobPath = path.resolve(__dirname, './jobs/simple.js');98 const clock = FakeTimers.install({now: Date.now()});99 jobManager.addJob({100 at: timeInTenSeconds,101 job: jobPath,102 name: 'job-in-ten'103 });104 should(jobManager.bree.timeouts['job-in-ten']).type('object');105 should(jobManager.bree.workers['job-in-ten']).type('undefined');106 // allow to run the job and start the worker107 await clock.nextAsync();108 should(jobManager.bree.workers['job-in-ten']).type('object');109 const promise = new Promise((resolve, reject) => {110 jobManager.bree.workers['job-in-ten'].on('error', reject);111 jobManager.bree.workers['job-in-ten'].on('exit', (code) => {112 should(code).equal(0);113 resolve();114 });115 });116 // allow job to finish execution and exit117 clock.next();118 await promise;119 should(jobManager.bree.workers['job-in-ten']).type('undefined');120 clock.uninstall();121 });122 it('schedules a job to run immediately', async function () {123 const jobManager = new JobManager({});124 const clock = FakeTimers.install({now: Date.now()});125 const jobPath = path.resolve(__dirname, './jobs/simple.js');126 jobManager.addJob({127 job: jobPath,128 name: 'job-now'129 });130 should(jobManager.bree.timeouts['job-now']).type('object');131 // allow scheduler to pick up the job132 clock.tick(1);133 should(jobManager.bree.workers['job-now']).type('object');134 const promise = new Promise((resolve, reject) => {135 jobManager.bree.workers['job-now'].on('error', reject);136 jobManager.bree.workers['job-now'].on('exit', (code) => {137 should(code).equal(0);138 resolve();139 });140 });141 await promise;142 should(jobManager.bree.workers['job-now']).type('undefined');143 clock.uninstall();144 });145 it('fails to schedule a job with the same name to run immediately one after another', async function () {146 const jobManager = new JobManager({});147 const clock = FakeTimers.install({now: Date.now()});148 const jobPath = path.resolve(__dirname, './jobs/simple.js');149 jobManager.addJob({150 job: jobPath,151 name: 'job-now'152 });153 should(jobManager.bree.timeouts['job-now']).type('object');154 // allow scheduler to pick up the job155 clock.tick(1);156 should(jobManager.bree.workers['job-now']).type('object');157 const promise = new Promise((resolve, reject) => {158 jobManager.bree.workers['job-now'].on('error', reject);159 jobManager.bree.workers['job-now'].on('exit', (code) => {160 should(code).equal(0);161 resolve();162 });163 });164 await promise;165 should(jobManager.bree.workers['job-now']).type('undefined');166 (() => {167 jobManager.addJob({168 job: jobPath,169 name: 'job-now'170 });171 }).should.throw('Job #1 has a duplicate job name of job-now');172 clock.uninstall();173 });174 it('uses custom error handler when job fails', async function (){175 let job = function namedJob() {176 throw new Error('job error');177 };178 const spyHandler = sinon.spy();179 const jobManager = new JobManager({errorHandler: spyHandler});180 jobManager.addJob({181 job,182 name: 'will-fail'183 });184 // give time to execute the job185 // has to be this long because in Node v10 the communication is186 // done through processes, which takes longer comparing to worker_threads187 // can be reduced to 100 when Node v10 support is dropped188 await delay(600);189 should(spyHandler.called).be.true();190 should(spyHandler.args[0][0].message).equal('job error');191 should(spyHandler.args[0][1].name).equal('will-fail');192 });193 it('uses worker message handler when job sends a message', async function (){194 const workerMessageHandlerSpy = sinon.spy();195 const jobManager = new JobManager({workerMessageHandler: workerMessageHandlerSpy});196 jobManager.addJob({197 job: path.resolve(__dirname, './jobs/message.js'),198 name: 'will-send-msg'199 });200 jobManager.bree.run('will-send-msg');201 jobManager.bree.workers['will-send-msg'].postMessage('hello from Ghost!');202 // Give time for worker (worker thread) <-> parent process (job manager) communication203 await delay(100);204 should(workerMessageHandlerSpy.called).be.true();205 should(workerMessageHandlerSpy.args[0][0].name).equal('will-send-msg');206 should(workerMessageHandlerSpy.args[0][0].message).equal('Worker received: hello from Ghost!');207 });208 });209 });210 describe('Add one off job', function () {211 it('throws if name parameter is not provided', async function () {212 const jobManager = new JobManager({});213 try {214 await jobManager.addOneOffJob({215 job: () => {}216 });217 throw new Error('should have thrown');218 } catch (err) {219 should.equal(err.message, 'The name parameter is required for a one off job.');220 }221 });222 describe('Inline jobs', function () {223 it('adds job to the queue when it is a unique one', async function () {224 const spy = sinon.spy();225 const JobModel = {226 findOne: sinon.stub().resolves(undefined),227 add: sinon.stub().resolves()228 };229 const jobManager = new JobManager({JobModel});230 await jobManager.addOneOffJob({231 job: spy,232 name: 'unique name',233 data: 'test data',234 offloaded: false235 });236 assert.equal(JobModel.add.called, true);237 });238 it('does not add a job to the queue when it already exists', async function () {239 const spy = sinon.spy();240 const JobModel = {241 findOne: sinon.stub().resolves(jobModelInstance),242 add: sinon.stub().throws('should not be called')243 };244 const jobManager = new JobManager({JobModel});245 try {246 await jobManager.addOneOffJob({247 job: spy,248 name: 'I am the only one',249 data: 'test data',250 offloaded: false251 });252 throw new Error('should not reach this point');253 } catch (error) {254 assert.equal(error.message, 'A "I am the only one" one off job has already been executed.');255 }256 });257 it('sets a finished state on an inline job', async function () {258 const JobModel = {259 findOne: sinon.stub()260 .onCall(0)261 .resolves(null)262 .resolves({id: 'unique', name: 'successful-oneoff'}),263 add: sinon.stub().resolves({name: 'successful-oneoff'}),264 edit: sinon.stub().resolves({name: 'successful-oneoff'})265 };266 const jobManager = new JobManager({JobModel});267 jobManager.addOneOffJob({268 job: async () => {269 return await delay(10);270 },271 name: 'successful-oneoff',272 offloaded: false273 });274 // allow job to get picked up and executed275 await delay(20);276 // tracks the job queued277 should(JobModel.add.args[0][0].status).equal('queued');278 should(JobModel.add.args[0][0].name).equal('successful-oneoff');279 // tracks the job started280 should(JobModel.edit.args[0][0].status).equal('started');281 should(JobModel.edit.args[0][0].started_at).not.equal(undefined);282 should(JobModel.edit.args[0][1].id).equal('unique');283 // tracks the job finish284 should(JobModel.edit.args[1][0].status).equal('finished');285 should(JobModel.edit.args[1][0].finished_at).not.equal(undefined);286 should(JobModel.edit.args[1][1].id).equal('unique');287 });288 it('sets a failed state on a job', async function () {289 const JobModel = {290 findOne: sinon.stub()291 .onCall(0)292 .resolves(null)293 .resolves({id: 'unique', name: 'failed-oneoff'}),294 add: sinon.stub().resolves({name: 'failed-oneoff'}),295 edit: sinon.stub().resolves({name: 'failed-oneoff'})296 };297 let job = function namedJob() {298 throw new Error('job error');299 };300 const spyHandler = sinon.spy();301 const jobManager = new JobManager({errorHandler: spyHandler, JobModel});302 await jobManager.addOneOffJob({303 job,304 name: 'failed-oneoff',305 offloaded: false306 });307 // give time to execute the job308 await delay(50);309 // tracks the job start310 should(JobModel.edit.args[0][0].status).equal('started');311 should(JobModel.edit.args[0][0].started_at).not.equal(undefined);312 should(JobModel.edit.args[0][1].id).equal('unique');313 // tracks the job failure314 should(JobModel.edit.args[1][0].status).equal('failed');315 should(JobModel.edit.args[1][1].id).equal('unique');316 });317 it('adds job to the queue after failing', async function () {318 const JobModel = {319 findOne: sinon.stub()320 .onCall(0)321 .resolves(null)322 .onCall(1)323 .resolves({id: 'unique'})324 .resolves({325 id: 'unique',326 get: (field) => {327 if (field === 'status') {328 return 'failed';329 }330 }331 }),332 add: sinon.stub().resolves({}),333 edit: sinon.stub().resolves()334 };335 let job = function namedJob() {336 throw new Error('job error');337 };338 const spyHandler = sinon.spy();339 const jobManager = new JobManager({errorHandler: spyHandler, JobModel});340 await jobManager.addOneOffJob({341 job,342 name: 'failed-oneoff',343 offloaded: false344 });345 // give time to execute the job and fail346 await delay(50);347 should(JobModel.edit.args[1][0].status).equal('failed');348 // simulate process restart and "fresh" slate to add the job349 jobManager.removeJob('failed-oneoff');350 await jobManager.addOneOffJob({351 job,352 name: 'failed-oneoff',353 offloaded: false354 });355 // give time to execute the job and fail AGAIN356 await delay(50);357 should(JobModel.edit.args[3][0].status).equal('started');358 should(JobModel.edit.args[4][0].status).equal('failed');359 });360 });361 describe('Offloaded jobs', function () {362 it('adds job to the queue when it is a unique one', async function () {363 const spy = sinon.spy();364 const JobModel = {365 findOne: sinon.stub().resolves(undefined),366 add: sinon.stub().resolves()367 };368 const jobManager = new JobManager({JobModel});369 await jobManager.addOneOffJob({370 job: spy,371 name: 'unique name',372 data: 'test data'373 });374 assert.equal(JobModel.add.called, true);375 });376 it('does not add a job to the queue when it already exists', async function () {377 const spy = sinon.spy();378 const JobModel = {379 findOne: sinon.stub().resolves(jobModelInstance),380 add: sinon.stub().throws('should not be called')381 };382 const jobManager = new JobManager({JobModel});383 try {384 await jobManager.addOneOffJob({385 job: spy,386 name: 'I am the only one',387 data: 'test data'388 });389 throw new Error('should not reach this point');390 } catch (error) {391 assert.equal(error.message, 'A "I am the only one" one off job has already been executed.');392 }393 });394 it('sets a finished state on a job', async function () {395 const JobModel = {396 findOne: sinon.stub()397 .onCall(0)398 .resolves(null)399 .resolves({id: 'unique', name: 'successful-oneoff'}),400 add: sinon.stub().resolves({name: 'successful-oneoff'}),401 edit: sinon.stub().resolves({name: 'successful-oneoff'})402 };403 const jobManager = new JobManager({JobModel});404 await jobManager.addOneOffJob({405 job: path.resolve(__dirname, './jobs/message.js'),406 name: 'successful-oneoff'407 });408 // allow job to get picked up and executed409 await delay(50);410 jobManager.bree.workers['successful-oneoff'].postMessage('be done!');411 // allow the message to be passed around412 await delay(50);413 // tracks the job start414 should(JobModel.edit.args[0][0].status).equal('started');415 should(JobModel.edit.args[0][0].started_at).not.equal(undefined);416 should(JobModel.edit.args[0][1].id).equal('unique');417 // tracks the job finish418 should(JobModel.edit.args[1][0].status).equal('finished');419 should(JobModel.edit.args[1][0].finished_at).not.equal(undefined);420 should(JobModel.edit.args[1][1].id).equal('unique');421 });422 it('handles a failed job', async function () {423 const JobModel = {424 findOne: sinon.stub()425 .onCall(0)426 .resolves(null)427 .resolves(jobModelInstance),428 add: sinon.stub().resolves({name: 'failed-oneoff'}),429 edit: sinon.stub().resolves({name: 'failed-oneoff'})430 };431 let job = function namedJob() {432 throw new Error('job error');433 };434 const spyHandler = sinon.spy();435 const jobManager = new JobManager({errorHandler: spyHandler, JobModel});436 await jobManager.addOneOffJob({437 job,438 name: 'failed-oneoff'439 });440 // give time to execute the job441 // has to be this long because in Node v10 the communication is442 // done through processes, which takes longer comparing to worker_threads443 // can be reduced to 100 when Node v10 support is dropped444 await delay(100);445 // still calls the original error handler446 should(spyHandler.called).be.true();447 should(spyHandler.args[0][0].message).equal('job error');448 should(spyHandler.args[0][1].name).equal('failed-oneoff');449 // tracks the job start450 should(JobModel.edit.args[0][0].status).equal('started');451 should(JobModel.edit.args[0][0].started_at).not.equal(undefined);452 should(JobModel.edit.args[0][1].id).equal('unique');453 // tracks the job failure454 should(JobModel.edit.args[1][0].status).equal('failed');455 should(JobModel.edit.args[1][1].id).equal('unique');456 });457 });458 });459 describe('Job execution progress', function () {460 it('checks if job has ever been executed', async function () {461 const JobModel = {462 findOne: sinon.stub()463 .withArgs('solovei')464 .onCall(0)465 .resolves(null)466 .onCall(1)467 .resolves({468 id: 'unique',469 get: (field) => {470 if (field === 'status') {471 return 'finished';472 }473 }474 })475 .onCall(2)476 .resolves({477 id: 'unique',478 get: (field) => {479 if (field === 'status') {480 return 'failed';481 }482 }483 })484 };485 const jobManager = new JobManager({JobModel});486 let executed = await jobManager.hasExecutedSuccessfully('solovei');487 should.equal(executed, false);488 executed = await jobManager.hasExecutedSuccessfully('solovei');489 should.equal(executed, true);490 executed = await jobManager.hasExecutedSuccessfully('solovei');491 should.equal(executed, false);492 });493 it('can wait for job completion', async function () {494 const spy = sinon.spy();495 let status = 'queued';496 const jobWithDelay = async () => {497 await delay(80);498 status = 'finished';499 spy();500 };501 const JobModel = {502 findOne: sinon.stub()503 // first call when adding a job504 .withArgs('solovei')505 .onCall(0)506 // first call when adding a job507 .resolves(null)508 .onCall(1)509 .resolves(null)510 .resolves({511 id: 'unique',512 get: () => status513 }),514 add: sinon.stub().resolves()515 };516 const jobManager = new JobManager({JobModel});517 await jobManager.addOneOffJob({518 job: jobWithDelay,519 name: 'solovei',520 offloaded: false521 });522 should.equal(spy.called, false);523 await jobManager.awaitCompletion('solovei');524 should.equal(spy.called, true);525 });526 });527 describe('Remove a job', function () {528 it('removes a scheduled job from the queue', async function () {529 const jobManager = new JobManager({});530 const timeInTenSeconds = new Date(Date.now() + 10);531 const jobPath = path.resolve(__dirname, './jobs/simple.js');532 jobManager.addJob({533 at: timeInTenSeconds,534 job: jobPath,535 name: 'job-in-ten'536 });537 jobManager.bree.config.jobs[0].name.should.equal('job-in-ten');538 await jobManager.removeJob('job-in-ten');539 should(jobManager.bree.config.jobs[0]).be.undefined;540 });541 });542 describe('Shutdown', function () {543 it('gracefully shuts down an inline jobs', async function () {544 const jobManager = new JobManager({});545 jobManager.addJob({546 job: require('./jobs/timed-job'),547 data: 200,548 offloaded: false549 });550 should(jobManager.queue.idle()).be.false();551 await jobManager.shutdown();552 should(jobManager.queue.idle()).be.true();553 });554 it('gracefully shuts down an interval job', async function () {555 const jobManager = new JobManager({});556 jobManager.addJob({557 at: 'every 5 seconds',558 job: path.resolve(__dirname, './jobs/graceful.js')559 });560 await delay(1); // let the job execution kick in561 should(Object.keys(jobManager.bree.workers).length).equal(0);562 should(Object.keys(jobManager.bree.timeouts).length).equal(0);563 should(Object.keys(jobManager.bree.intervals).length).equal(1);564 await jobManager.shutdown();565 should(Object.keys(jobManager.bree.intervals).length).equal(0);566 });567 });...
recruitment.sagas.js
Source:recruitment.sagas.js
1import {2 all,3 call,4 put,5 select,6 takeLatest,7 takeEvery,8} from "redux-saga/effects";9import { path, pathOr, prop, propOr } from "ramda";10import { toast } from "react-toastify";11import en from "../lang/en";12import {13 getDecisionFromClient,14 STATUS_NO_GO,15 DECISION_NO_GO,16} from "../utils/kanban";17import {18 GET_RECRUITMENT,19 updateClientCorporationsIds,20 updateClientCorporations,21 getJobOrders as getJobOrdersAction,22 updateJobOrders,23 getJobSubmissions as getJobSubmissionsAction,24 updateJobSubmissions,25 GET_RECRUITMENT_JOB_SUBMISSIONS,26 GET_RECRUITMENT_JOB_ORDERS,27 updateHrs,28 UPDATE_RECRUITMENT_JOB_SUBMISSION,29 setJobOrders,30 setJobSubmissions,31 CREATE_RECRUITMENT_JOB_SUBMISSION,32 DELETE_RECRUITMENT_JOB_SUBMISSION,33 removeJobSubmission,34} from "./recruitment.actions";35import {36 getTalentAcquisitionManagers,37 getJobSubmissions as getJobSubmissionsService,38 updateJobSubmission as updateJobSubmissionService,39 getCandidate,40 updateCandidateDecision,41 getClientCorporation,42} from "./recruitment.service";43import {44 getJobOrders as getJobOrdersService,45 createJobSubmission as createJobSubmissionService,46 getJobSubmission,47 deleteJobSubmission as deleteJobSubmissionService,48} from "../kanban/kanban.service";49import {50 getStateJobSubmissions as getStateJobSubmissionsKanban,51 deleteJobSubmission as deleteJobSubmissionKanban,52} from "../kanban/kanban.sagas";53export const getStateClientCorporation = (state, ccId) =>54 pathOr({}, ["recruitment", "clientCorporations", ccId], state);55export const getStateJobSubmissions = (state) =>56 pathOr({}, ["recruitment", "jobSubmissions"], state);57export const getStateJobSubmission = (state, joId) =>58 pathOr({}, ["recruitment", "jobSubmissions", joId], state);59export const getStateJobOrders = (state) =>60 pathOr({}, ["recruitment", "jobOrders"], state);61export const getStateJobOrder = (state, jobOrderId) =>62 pathOr({}, ["recruitment", "jobOrders", jobOrderId], state);63export function* getRecruitment() {64 yield call(getTams);65}66export function* getTams(start = 0) {67 try {68 const tamsResponse = yield call(getTalentAcquisitionManagers, start);69 const tamList = yield call(propOr, [], "data", tamsResponse);70 yield all(tamList.map((tam) => put(getJobOrdersAction(prop("id", tam)))));71 if (propOr(0, "count", tamsResponse) > 0)72 yield call(73 getTalentAcquisitionManagers,74 propOr(0, "start", tamsResponse) + propOr(0, "count", tamsResponse)75 );76 } catch (e) {77 //78 }79}80export function* getClientCorporations(tamId, jobOrders) {81 const ccList = [];82 const clientCorporations = yield all(83 jobOrders.reduce((acc, jo) => {84 const cc = prop("clientCorporation", jo);85 ccList.push(prop("id", cc));86 const jos = pathOr([], [prop("id", cc), "jobOrders"], acc).concat(87 prop("id", jo)88 );89 acc[prop("id", cc)] = {90 ...cc,91 jobOrders: jos,92 };93 return acc;94 }, {})95 );96 for (let ccId of ccList) {97 const ccResponse = yield call(getClientCorporation, ccId);98 const clientCorporation = propOr({}, "data", ccResponse);99 clientCorporations[ccId] = {100 ...clientCorporations[ccId],101 ...clientCorporation,102 };103 }104 yield put(updateClientCorporations(clientCorporations));105 yield put(updateClientCorporationsIds(ccList));106}107export function* getJobOrders(action, start = 0) {108 const tamId = prop("payload", action);109 try {110 const jobOrdersResponse = yield call(getJobOrdersService, tamId, start);111 const jobOrderList = yield call(propOr, [], "data", jobOrdersResponse);112 yield call(getClientCorporations, tamId, jobOrderList);113 const jobOrders = yield all(114 jobOrderList.reduce((acc, jo) => {115 acc[prop("id", jo)] = { ...jo, jobSubmissions: {} };116 return acc;117 }, {})118 );119 yield put(updateJobOrders(jobOrders));120 yield all(121 jobOrderList.map((jobOrder) =>122 put(123 getJobSubmissionsAction(124 prop("id", jobOrder),125 path(["clientCorporation", "id"], jobOrder)126 )127 )128 )129 );130 const newStart =131 propOr(0, "start", jobOrdersResponse) +132 propOr(0, "count", jobOrdersResponse);133 if (newStart < propOr(0, "total", jobOrdersResponse))134 yield call(getJobOrders, action, newStart);135 } catch (e) {136 //137 }138}139export function* getJobSubmissions(action, start = 0) {140 const { joId, ccId } = prop("payload", action);141 try {142 const jobSubmissionsResponse = yield call(143 getJobSubmissionsService,144 joId,145 start146 );147 const jsList = propOr([], "data", jobSubmissionsResponse);148 const jobOrders = {};149 const hrs = [];150 const jobSubmissions = yield all(151 jsList.reduce((acc, js) => {152 acc[prop("id", js)] = {153 ...js,154 clientCorporationId: ccId,155 };156 const joId = path(["jobOrder", "id"], js);157 const jojss = pathOr(158 [],159 [joId, "jobSubmissions", js.status],160 jobOrders161 ).concat([js.id]);162 jobOrders[joId] = {163 jobSubmissions: {164 ...pathOr({}, [joId, "jobSubmissions"], jobOrders),165 [js.status]: jojss,166 },167 };168 return acc;169 }, {})170 );171 for (let js of jsList) {172 const candidateResponse = yield call(173 getCandidate,174 path(["candidate", "id"], js)175 );176 const candidate = propOr({}, "data", candidateResponse);177 jobSubmissions[prop("id", js)].candidate = candidate;178 const hr = prop("owner", candidate);179 if (hr) hrs.push(hr);180 }181 yield put(updateJobSubmissions(jobSubmissions));182 yield put(updateJobOrders(jobOrders));183 yield put(updateHrs(hrs));184 } catch (e) {185 //186 }187}188export function* getDecision(jobOrderId, status) {189 const jo = yield select(getStateJobOrder, jobOrderId);190 const cc = yield select(191 getStateClientCorporation,192 path(["clientCorporation", "id"], jo)193 );194 if (status === STATUS_NO_GO) return DECISION_NO_GO;195 else return yield call(getDecisionFromClient, propOr("", "name", cc));196}197export function* updateJobSubmission(action) {198 const {199 payload: {200 prevStatus,201 jobSubmissionId,202 prevJobOrderId,203 jobOrderId,204 status,205 },206 } = action;207 const jobSubmission = yield select(getStateJobSubmission, jobSubmissionId);208 try {209 const decision = yield call(getDecision, jobOrderId, status);210 yield call(updateStateJobSubmission, {211 ...action,212 payload: {213 ...action.payload,214 decision,215 dateLastModified: new Date().getTime(),216 },217 });218 yield call(updateJobSubmissionService, jobSubmissionId, status, jobOrderId);219 yield call(toast.success, en.UPDATE_STATUS_SUCCESS);220 } catch (e) {221 const decision = yield call(getDecision, prevJobOrderId, prevStatus);222 yield call(updateStateJobSubmission, {223 ...action,224 payload: {225 ...action.payload,226 status: prevStatus,227 prevStatus: status,228 jobOrderId: prevJobOrderId,229 prevJobOrderId: jobOrderId,230 decision,231 dateLastModified: prop("dateLastModified", jobSubmission),232 },233 });234 yield call(toast.error, en.UPDATE_STATUS_ERROR);235 }236}237export function* updateStateJobSubmission(action) {238 const {239 payload: {240 prevJobOrderId,241 jobOrderId,242 prevStatus,243 jobSubmissionId,244 status,245 decision,246 dateLastModified,247 },248 } = action;249 const stateJobSubmissions = yield select(getStateJobSubmissions);250 const jobSubmission = stateJobSubmissions[jobSubmissionId];251 const stateNewJobOrder = yield select(getStateJobOrder, jobOrderId);252 const jobSubmissions = {253 ...stateJobSubmissions,254 [jobSubmissionId]: {255 ...jobSubmission,256 status,257 jobOrder: {258 id: prop("id", stateNewJobOrder),259 title: prop("title", stateNewJobOrder),260 },261 candidate: {262 ...jobSubmission.candidate,263 middleName: decision,264 },265 dateLastModified,266 },267 };268 yield put(setJobSubmissions(jobSubmissions));269 const statePrevJobOrder = yield select(getStateJobOrder, prevJobOrderId);270 const prevJojss = {271 ...prop("jobSubmissions", statePrevJobOrder),272 [prevStatus]: pathOr(273 [],274 ["jobSubmissions", prevStatus],275 statePrevJobOrder276 ).filter((jsId) => jsId !== jobSubmissionId),277 };278 const prevJobOrder = {279 [prevJobOrderId]: {280 ...statePrevJobOrder,281 jobSubmissions: prevJojss,282 },283 };284 const stateJobOrders1 = yield select(getStateJobOrders);285 yield put(setJobOrders({ ...stateJobOrders1, ...prevJobOrder }));286 const stateJobOrder = yield select(getStateJobOrder, jobOrderId);287 const jojss = {288 ...prop("jobSubmissions", stateJobOrder),289 [status]: pathOr([], ["jobSubmissions", status], stateJobOrder).concat([290 jobSubmissionId,291 ]),292 };293 const jobOrder = {294 [jobOrderId]: {295 ...stateJobOrder,296 jobSubmissions: jojss,297 },298 };299 const stateJobOrders2 = yield select(getStateJobOrders);300 yield put(setJobOrders({ ...stateJobOrders2, ...jobOrder }));301}302export function* createJobSubmission(action) {303 const {304 payload: { jobOrder, jobSubmission, status },305 } = action;306 try {307 const js = {308 candidate: { id: path(["candidate", "id"], jobSubmission) },309 jobOrder: { id: prop("id", jobOrder) },310 status,311 };312 const putJobSubmissionResponse = yield call(createJobSubmissionService, js);313 const createdId = prop("changedEntityId", putJobSubmissionResponse);314 const jobSubmissionResponse = yield call(getJobSubmission, createdId);315 const candidateResponse = yield call(316 getCandidate,317 path(["candidate", "id"], jobSubmission)318 );319 const decision = yield call(getDecision, prop("id", jobOrder), status);320 const newJobSubmission = {321 ...propOr({}, "data", jobSubmissionResponse),322 bmId: prop("bmId", jobOrder),323 clientCorporationId: path(["clientCorporation", "id"], jobOrder),324 jobOrderId: prop("id", jobOrder),325 candidate: prop("data", candidateResponse),326 };327 yield call(addJobSubmission, newJobSubmission);328 yield call(toast.success, en.CREATE_CANDIDATE_SUCCESS);329 yield call(330 updateCandidateDecision,331 path(["candidate", "id"], jobSubmission),332 decision333 );334 } catch (e) {335 yield call(toast.error, en.CREATE_CANDIDATE_ERROR);336 }337}338export function* addJobSubmission(jobSubmission) {339 const jobSubmissionId = propOr("", "id", jobSubmission);340 const stateJobSubmissions = yield select(getStateJobSubmissions);341 var jobSubmissions = {342 ...stateJobSubmissions,343 [jobSubmissionId]: jobSubmission,344 };345 yield put(setJobSubmissions(jobSubmissions));346 const jobOrderId = path(["jobOrder", "id"], jobSubmission);347 const stateJobOrder = yield select(getStateJobOrder, jobOrderId);348 const status = prop("status", jobSubmission);349 const jojss = {350 ...prop("jobSubmissions", stateJobOrder),351 [status]: pathOr([], ["jobSubmissions", status], stateJobOrder).concat([352 jobSubmissionId,353 ]),354 };355 const jobOrder = {356 [jobOrderId]: {357 ...stateJobOrder,358 jobSubmissions: jojss,359 },360 };361 const stateJobOrders = yield select(getStateJobOrders);362 yield put(setJobOrders({ ...stateJobOrders, ...jobOrder }));363}364export function* deleteJobSubmissions(action) {365 const jobSubmission = prop("payload", action);366 const stateJobSubmissions = yield select(getStateJobSubmissions);367 const jobSubmissionsToDelete = Object.keys(stateJobSubmissions).filter(368 (jsId) =>369 path([jsId, "candidate", "id"], stateJobSubmissions) ===370 path(["candidate", "id"], jobSubmission)371 );372 for (let jsId of jobSubmissionsToDelete) {373 yield call(deleteJobSubmission, {374 payload: prop(jsId, stateJobSubmissions),375 });376 }377 const stateKanbanJobSubmissions = yield select(getStateJobSubmissionsKanban);378 const jobSubmissionsToDeleteInKanban = Object.keys(379 stateKanbanJobSubmissions380 ).filter(381 (jsId) =>382 path([jsId, "candidate", "id"], stateKanbanJobSubmissions) ===383 path(["candidate", "id"], jobSubmission)384 );385 for (let jsId of jobSubmissionsToDeleteInKanban) {386 yield call(deleteJobSubmissionKanban, {387 payload: prop(jsId, stateKanbanJobSubmissions),388 });389 }390}391export function* deleteJobSubmission(action) {392 const jobSubmission = prop("payload", action);393 const jobSubmissionId = prop("id", jobSubmission);394 const jobOrderId = path(["jobOrder", "id"], jobSubmission);395 const status = prop("status", jobSubmission);396 try {397 yield call(deleteJobSubmissionService, jobSubmissionId);398 yield put(removeJobSubmission(jobSubmissionId));399 const stateJobOrder = yield select(getStateJobOrder, jobOrderId);400 const jojss = {401 ...prop("jobSubmissions", stateJobOrder),402 [status]: pathOr([], ["jobSubmissions", status], stateJobOrder).filter(403 (jsId) => jsId !== jobSubmissionId404 ),405 };406 const jobOrder = {407 [jobOrderId]: {408 ...stateJobOrder,409 jobSubmissions: jojss,410 },411 };412 const stateJobOrders = yield select(getStateJobOrders);413 yield put(setJobOrders({ ...stateJobOrders, ...jobOrder }));414 yield call(toast.success, en.DELETE_JS_SUCCESS);415 } catch (e) {416 yield call(toast.error, en.DELETE_JS_ERROR);417 }418}419export default function kanbanSagas() {420 return [421 takeLatest(GET_RECRUITMENT, getRecruitment),422 takeEvery(GET_RECRUITMENT_JOB_ORDERS, getJobOrders),423 takeEvery(GET_RECRUITMENT_JOB_SUBMISSIONS, getJobSubmissions),424 takeEvery(UPDATE_RECRUITMENT_JOB_SUBMISSION, updateJobSubmission),425 takeEvery(CREATE_RECRUITMENT_JOB_SUBMISSION, createJobSubmission),426 takeEvery(DELETE_RECRUITMENT_JOB_SUBMISSION, deleteJobSubmissions),427 ];...
kanban.sagas.js
Source:kanban.sagas.js
1import { all, call, put, select, takeEvery, takeLatest } from "redux-saga/effects"2import { ascend, dissoc, path, pathOr, prop, propOr, sortWith } from "ramda"3import { toast } from "react-toastify"4import {5 GET_KANBAN,6 GET_JOB_ORDERS,7 GET_JOB_SUBMISSIONS,8 UPDATE_JOB_SUBMISSION,9 CREATE_JOB_SUBMISSION,10 DELETE_JOB_SUBMISSION,11 updateBms,12 updateClientCorporations,13 getJobOrders as getJobOrdersAction,14 setJobOrders,15 updateJobOrders,16 getJobSubmissions as getJobSubmissionsAction,17 setJobSubmissions,18 updateJobSubmissions,19 setBms,20 removeJobSubmission,21} from "./kanban.actions"22import {23 getBusinessManagers,24 getJobOrders as getJobOrdersService,25 getJobSubmissions as getJobSubmissionsService,26 updateJobSubmissionStatus as updateJobSubmissionStatusService,27 createJobSubmission as createJobSubmissionService,28 getJobSubmission,29 deleteJobSubmission as deleteJobSubmissionService,30} from "./kanban.service"31import en from "../lang/en"32import { filterJobOrdersPerPriority, getStateFilter } from "../priorityFilter/priorityFilter.sagas"33export const getStateBms = (state) => pathOr([], ["kanban", "bmList"], state)34export const getStateJobOrder = (state, joId) => pathOr({}, ["kanban", "jobOrders", joId], state)35export const getStateJobOrders = (state) => pathOr([], ["kanban", "jobOrders"], state)36export const getStateJobSubmissions = (state) => pathOr([], ["kanban", "jobSubmissions"], state)37export function* getKanbanBoard() {38 yield call(getBms)39}40export function* getBms(start = 0) {41 try {42 const bmsResponse = yield call(getBusinessManagers, start)43 const bmList = yield call(propOr, [], "data", bmsResponse)44 const bms = yield all(bmList.reduce((acc, bm) => ({ ...acc, [bm.id]: { ...bm, clientCorporations: [] } }), {}))45 yield put(updateBms(bms))46 yield all(bmList.map((bm) => put(getJobOrdersAction(prop("id", bm)))))47 const bmIds = yield all(bmList.map((bm) => prop("id", bm)))48 const stateBms = yield select(getStateBms)49 yield put(setBms(stateBms.concat(bmIds)))50 if (propOr(0, "count", bmsResponse) > 0)51 yield call(getBms, propOr(0, "start", bmsResponse) + propOr(0, "count", bmsResponse))52 } catch (e) {53 //54 }55}56export function* getClientCorporations(bmId, jobOrders) {57 const bms = {}58 const joClientCorporations = yield all(jobOrders.map((jo) => prop("clientCorporation", jo)))59 const clientCorporations = yield all(60 joClientCorporations.reduce((acc, jocc) => {61 const joccId = prop("id", jocc)62 if (!pathOr([], [bmId, "clientCorporations"], bms).find((ccId) => ccId === joccId)) {63 const bmcc = pathOr([], [bmId, "clientCorporations"], bms).concat([joccId])64 bms[bmId] = { clientCorporations: bmcc }65 }66 const clientCorporation = prop(joccId, acc)67 if (!clientCorporation) {68 acc[joccId] = { ...jocc, bmIds: { [bmId]: { jobOrders: [] } } }69 }70 return acc71 }, {})72 )73 yield put(updateClientCorporations(clientCorporations))74 yield put(updateBms(bms))75}76export function* getJobOrders(action, start = 0) {77 const bmId = action.payload78 try {79 const jobOrdersResponse = yield call(getJobOrdersService, bmId, start)80 const jobOrderList = yield call(propOr, [], "data", jobOrdersResponse)81 yield call(getClientCorporations, bmId, jobOrderList)82 const clientCorporations = {}83 const stateFilter = yield select(getStateFilter)84 const jobOrders = yield all(85 jobOrderList.reduce((acc, jobOrder) => {86 const ccId = path(["clientCorporation", "id"], jobOrder)87 const ccjos = pathOr([], [ccId, "bmIds", bmId, "jobOrders"], clientCorporations).concat([88 { id: jobOrder.id, employmentType: jobOrder.employmentType },89 ])90 const sortedCcjos = sortWith([ascend(prop("employmentType"))], ccjos)91 clientCorporations[ccId] = {92 bmIds: {93 [bmId]: {94 jobOrders: sortedCcjos,95 filteredJobOrders: filterJobOrdersPerPriority(sortedCcjos, stateFilter),96 },97 },98 }99 acc[jobOrder.id] = {100 ...jobOrder,101 bmId,102 clientCorporationId: ccId,103 jobSubmissions: {},104 }105 return acc106 }, {})107 )108 yield put(updateJobOrders(jobOrders))109 yield put(updateClientCorporations(clientCorporations))110 yield all(111 jobOrderList.map((jobOrder) =>112 put(getJobSubmissionsAction(bmId, path(["clientCorporation", "id"], jobOrder), prop("id", jobOrder)))113 )114 )115 const newStart = propOr(0, "start", jobOrdersResponse) + propOr(0, "count", jobOrdersResponse)116 if (newStart < propOr(0, "total", jobOrdersResponse)) yield call(getJobOrders, action, newStart)117 } catch (e) {118 //119 }120}121export function* getJobSubmissions(action, start = 0) {122 const {123 payload: { bmId, clientCorporationId, jobOrderId },124 } = action125 try {126 const jobOrders = {}127 const jobSubmissionsResponse = yield call(getJobSubmissionsService, jobOrderId, start)128 const jsList = propOr([], "data", jobSubmissionsResponse)129 const jobSubmissions = yield all(130 jsList.reduce((acc, js) => {131 const jojss = pathOr([], [jobOrderId, "jobSubmissions", js.status], jobOrders).concat([js.id])132 jobOrders[jobOrderId] = {133 jobSubmissions: {134 ...pathOr({}, [jobOrderId, "jobSubmissions"], jobOrders),135 [js.status]: jojss,136 },137 }138 acc[js.id] = {139 ...js,140 bmId,141 clientCorporationId,142 jobOrderId,143 }144 return acc145 }, {})146 )147 yield put(updateJobSubmissions(jobSubmissions))148 yield put(updateJobOrders(jobOrders))149 const newStart = propOr(0, "start", jobSubmissionsResponse) + propOr(0, "count", jobSubmissionsResponse)150 if (newStart < propOr(0, "total", jobSubmissionsResponse)) yield call(getJobSubmissions, action, newStart)151 } catch (e) {152 //153 }154}155export function* updateJobSubmission(action) {156 const {157 payload: { prevStatus, jobSubmissionId, status },158 } = action159 try {160 yield call(updateJobSubmissionStatus, action)161 yield call(updateJobSubmissionStatusService, jobSubmissionId, status)162 yield call(toast.success, en.UPDATE_STATUS_SUCCESS)163 } catch (e) {164 yield call(updateJobSubmissionStatus, {165 ...action,166 payload: { ...action.payload, status: prevStatus, prevStatus: status },167 })168 yield call(toast.error, en.UPDATE_STATUS_ERROR)169 }170}171export function* updateJobSubmissionStatus(action) {172 const {173 payload: { jobOrderId, prevStatus, jobSubmissionId, status },174 } = action175 const stateJobSubmissions = yield select(getStateJobSubmissions)176 const jobSubmission = stateJobSubmissions[jobSubmissionId]177 const jobSubmissions = {178 ...stateJobSubmissions,179 [jobSubmissionId]: {180 ...jobSubmission,181 status,182 dateLastModified: new Date().getTime(),183 },184 }185 yield put(setJobSubmissions(jobSubmissions))186 const stateJobOrder = yield select(getStateJobOrder, jobOrderId)187 const jojss = {188 ...prop("jobSubmissions", stateJobOrder),189 [prevStatus]: pathOr([], ["jobSubmissions", prevStatus], stateJobOrder).filter((jsId) => jsId !== jobSubmissionId),190 [status]: pathOr([], ["jobSubmissions", status], stateJobOrder).concat([jobSubmissionId]),191 }192 const jobOrder = {193 [jobOrderId]: {194 ...stateJobOrder,195 jobSubmissions: jojss,196 },197 }198 const stateJobOrders = yield select(getStateJobOrders)199 yield put(setJobOrders({ ...stateJobOrders, ...jobOrder }))200}201export const createTempId = (jobOrder, jobSubmission) =>202 `temp${prop("id", jobOrder)}${path(["candidate", "id"], jobSubmission)}`203export function* createJobSubmission(action) {204 const {205 payload: { jobOrder, jobSubmission, status },206 } = action207 const tempJs = {208 id: createTempId(jobOrder, jobSubmission),209 candidate: prop("candidate", jobSubmission),210 jobOrder,211 sendingUser: { id: prop("bmId", jobOrder) },212 status,213 bmId: prop("bmId", jobOrder),214 clientCorporationId: prop("clientCorporationId", jobOrder),215 jobOrderId: prop("id", jobOrder),216 }217 try {218 yield call(addJobSubmission, tempJs)219 const js = {220 candidate: { id: path(["candidate", "id"], jobSubmission) },221 jobOrder: { id: prop("id", jobOrder) },222 sendingUser: { id: prop("bmId", jobOrder) },223 status,224 }225 const putJobSubmissionResponse = yield call(createJobSubmissionService, js)226 const createdId = prop("changedEntityId", putJobSubmissionResponse)227 const jobSubmissionResponse = yield call(getJobSubmission, createdId)228 const newJobSubmission = {229 ...propOr({}, "data", jobSubmissionResponse),230 bmId: prop("bmId", jobOrder),231 clientCorporationId: prop("clientCorporationId", jobOrder),232 jobOrderId: prop("id", jobOrder),233 }234 yield call(addJobSubmission, newJobSubmission)235 yield call(toast.success, en.CREATE_CANDIDATE_SUCCESS)236 } catch (e) {237 yield call(removeTempJobSubmission, prop("id", tempJs))238 yield call(toast.error, en.CREATE_CANDIDATE_ERROR)239 }240}241export function* addJobSubmission(jobSubmission) {242 const jobSubmissionId = propOr("", "id", jobSubmission)243 const tempId = createTempId(prop("jobOrder", jobSubmission), jobSubmission)244 const stateJobSubmissions = yield select(getStateJobSubmissions)245 var jobSubmissions = {246 ...stateJobSubmissions,247 [jobSubmissionId]: jobSubmission,248 }249 if (!jobSubmissionId.toString().includes("temp")) jobSubmissions = dissoc(tempId, jobSubmissions)250 yield put(setJobSubmissions(jobSubmissions))251 const jobOrderId = path(["jobOrder", "id"], jobSubmission)252 const stateJobOrder = yield select(getStateJobOrder, jobOrderId)253 const status = prop("status", jobSubmission)254 const jojss = {255 ...prop("jobSubmissions", stateJobOrder),256 [status]: pathOr([], ["jobSubmissions", status], stateJobOrder)257 .filter((joId) => joId !== tempId)258 .concat([jobSubmissionId]),259 }260 const jobOrder = {261 [jobOrderId]: {262 ...stateJobOrder,263 jobSubmissions: jojss,264 },265 }266 const stateJobOrders = yield select(getStateJobOrders)267 yield put(setJobOrders({ ...stateJobOrders, ...jobOrder }))268}269export function* removeTempJobSubmission(jobSubmission) {270 const jobSubmissionId = prop("id", jobSubmission)271 const stateJobSubmissions = yield select(getStateJobSubmissions)272 const jobSubmissions = dissoc(jobSubmissionId, stateJobSubmissions)273 yield put(setJobSubmissions(jobSubmissions))274 const jobOrderId = path(["jobOrder", "id"], jobSubmission)275 const stateJobOrder = yield select(getStateJobOrder, jobOrderId)276 const status = prop("status", jobSubmission)277 const jojss = {278 ...prop("jobSubmissions", stateJobOrder),279 [status]: pathOr([], ["jobSubmissions", status], stateJobOrder).filter((jsId) => jsId !== jobSubmissionId),280 }281 const jobOrder = {282 [jobOrderId]: {283 ...stateJobOrder,284 jobSubmissions: jojss,285 },286 }287 const stateJobOrders = yield select(getStateJobOrders)288 yield put(setJobOrders({ ...stateJobOrders, ...jobOrder }))289}290export function* deleteJobSubmission(action) {291 const jobSubmission = prop("payload", action)292 const jobSubmissionId = prop("id", jobSubmission)293 const jobOrderId = path(["jobOrder", "id"], jobSubmission)294 const status = prop("status", jobSubmission)295 try {296 yield call(deleteJobSubmissionService, jobSubmissionId)297 yield put(removeJobSubmission(jobSubmissionId))298 const stateJobOrder = yield select(getStateJobOrder, jobOrderId)299 const jojss = {300 ...prop("jobSubmissions", stateJobOrder),301 [status]: pathOr([], ["jobSubmissions", status], stateJobOrder).filter((jsId) => jsId !== jobSubmissionId),302 }303 const jobOrder = {304 [jobOrderId]: {305 ...stateJobOrder,306 jobSubmissions: jojss,307 },308 }309 const stateJobOrders = yield select(getStateJobOrders)310 yield put(setJobOrders({ ...stateJobOrders, ...jobOrder }))311 yield call(toast.success, en.DELETE_JS_SUCCESS)312 } catch (e) {313 yield call(toast.error, en.DELETE_JS_ERROR)314 }315}316export default function kanbanSagas() {317 return [318 takeLatest(GET_KANBAN, getKanbanBoard),319 takeEvery(GET_JOB_ORDERS, getJobOrders),320 takeEvery(GET_JOB_SUBMISSIONS, getJobSubmissions),321 takeEvery(UPDATE_JOB_SUBMISSION, updateJobSubmission),322 takeEvery(CREATE_JOB_SUBMISSION, createJobSubmission),323 takeEvery(DELETE_JOB_SUBMISSION, deleteJobSubmission),324 ]...
JobDAG.py
Source:JobDAG.py
1#* This file is part of the MOOSE framework2#* https://www.mooseframework.org3#*4#* All rights reserved, see COPYRIGHT for full restrictions5#* https://github.com/idaholab/moose/blob/master/COPYRIGHT6#*7#* Licensed under LGPL 2.1, please see LICENSE for details8#* https://www.gnu.org/licenses/lgpl-2.1.html9from schedulers.Job import Job10from contrib import dag11class JobDAG(object):12 """ Class which builds a Job DAG for use by the Scheduler """13 def __init__(self, options):14 self.__job_dag = dag.DAG()15 self.options = options16 def createJobs(self, testers):17 """ Return a usable Job DAG based on supplied list of tester objects """18 # for each tester, instance a job and create a DAG node for that job19 self.__name_to_job = {}20 for tester in testers:21 job = Job(tester, self.__job_dag, self.options)22 name = job.getUniqueIdentifier()23 if name not in self.__name_to_job:24 self.__name_to_job[name] = job25 else:26 job.addCaveats('duplicate test')27 job.setStatus(job.skip)28 self.__job_dag.add_node(job)29 return self._checkDAG()30 def getDAG(self):31 """ return the running DAG object """32 return self.__job_dag33 def getJobs(self):34 """ return current job group """35 return self.__job_dag.ind_nodes()36 def getJobsAndAdvance(self):37 """38 return finished jobs, and remove them from the DAG, thus39 advancing to the next set of jobs when called again.40 """41 # handle any skipped dependencies42 self._doSkippedDependencies()43 # delete finished jobs44 next_jobs = set([])45 for job in list(self.__job_dag.ind_nodes()):46 if job.isFinished():47 next_jobs.add(job)48 self.__job_dag.delete_node(job)49 next_jobs.update(self.getJobs())50 return next_jobs51 def removeAllDependencies(self):52 """ Flatten current DAG so that it no longer contains any dependency information """53 if self.__name_to_job and self.__job_dag.size():54 tmp_job_dag = dag.DAG()55 for job in self.__job_dag.topological_sort():56 tmp_job_dag.add_node(job)57 self.__job_dag = tmp_job_dag58 return self.__job_dag59 def _checkDAG(self):60 """ perform some sanity checks on the current DAG """61 if self.__job_dag.size():62 self._doMakeDependencies()63 self._doSkippedDependencies()64 # If there are race conditions, then there may be more skipped jobs65 if self._doRaceConditions():66 self._doSkippedDependencies()67 return self.__job_dag68 def _doMakeDependencies(self):69 """ Setup dependencies within the current Job DAG """70 for job in self.__job_dag.ind_nodes():71 prereq_jobs = job.getUniquePrereqs()72 for prereq_job in prereq_jobs:73 try:74 self.__name_to_job[prereq_job]75 self.__job_dag.add_edge(self.__name_to_job[prereq_job], job)76 # Cyclic errors77 except dag.DAGValidationError:78 err_output = self._printDownstreams(job)79 err_output += ' %s <--> %s' % (job.getTestName().split('.')[1],80 self.__name_to_job[prereq_job].getTestName().split('.')[1])81 job.setOutput('Cyclic dependency error!\n\t' + err_output)82 job.setStatus(job.error, 'Cyclic or Invalid Dependency Detected!')83 # test file has invalid prereq set84 except KeyError:85 job.setStatus(job.error, 'unknown dependency')86 def _doSkippedDependencies(self):87 """ Determine which jobs in the DAG should be skipped """88 for job in list(self.__job_dag.topological_sort()):89 tester = job.getTester()90 dep_jobs = set([])91 if not job.getRunnable() or self._haltDescent(job):92 job.setStatus(job.skip)93 dep_jobs.update(self.__job_dag.all_downstreams(job))94 # Remove parent dependency so it can launch individually95 for p_job in self.__job_dag.predecessors(job):96 self.__job_dag.delete_edge_if_exists(p_job, job)97 for d_job in dep_jobs:98 d_tester = d_job.getTester()99 if tester.isSilent() and not d_job.getRunnable():100 d_tester.setStatus(d_tester.silent)101 elif not self._skipPrereqs():102 d_job.setStatus(d_job.skip)103 d_job.addCaveats('skipped dependency')104 self.__job_dag.delete_edge_if_exists(job, d_job)105 def _doRaceConditions(self):106 """ Check for race condition errors within in the DAG"""107 # Build output_file in relation to job dictionary108 output_to_job = {}109 for job in self.__job_dag.topological_sort():110 if job.getRunnable() and not job.isFinished():111 for output_file in job.getOutputFiles():112 output_to_job[output_file] = output_to_job.get(output_file, [])113 output_to_job[output_file].append(job)114 # Remove jobs which have accurate dependencies115 for outfile, job_list in output_to_job.iteritems():116 for job in list(job_list):117 for match_job in self.__job_dag.all_downstreams(job):118 if match_job in job_list:119 job_list.remove(match_job)120 # Left over multiple items in job_list are problematic121 for outfile, job_list in output_to_job.iteritems():122 # Same test has duplicate output files123 if len(job_list) > 1 and len(set(job_list)) == 1:124 job_list[0].setOutput('Duplicate output files:\n\t%s\n' % (outfile))125 job_list[0].setStatus(job.error, 'DUPLICATE OUTFILES')126 # Multiple tests will clobber eachothers output file127 elif len(job_list) > 1:128 for job in job_list:129 job.setOutput('Output file will over write pre-existing output file:\n\t%s\n' % (outfile))130 job.setStatus(job.error, 'OUTFILE RACE CONDITION')131 def _haltDescent(self, job):132 """ return boolean if this job should not allow its children to run """133 tester = job.getTester()134 if (job.isFail()135 or job.isSkip()136 or tester.isFail()137 or tester.isSkip()138 or tester.isSilent()139 or tester.isDeleted()):140 return True141 def _skipPrereqs(self):142 """143 Method to return boolean to skip dependency prerequisites checks.144 """145 if (self.options.ignored_caveats146 and ('all' in self.options.ignored_caveats147 or 'prereq' in self.options.ignored_caveats)):148 return True149 def _printDownstreams(self, job):150 """151 create a printable dependency chart of for supplied job152 # TODO: It would be super cool to print the entire DAG153 in this fashion.154 """155 downstreams = self.__job_dag.all_downstreams(job)156 cyclic_path = []157 for d_job in downstreams:158 cyclic_path.append('%s -->'% (d_job.getTestNameShort()))...
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!