Skip to content
Merged
97 changes: 97 additions & 0 deletions web/src/__tests__/components/Lineage.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright 2018-2023 contributors to the Marquez project
// SPDX-License-Identifier: Apache-2.0

import * as React from 'react'
import { shallow } from 'enzyme'
import Lineage from '../../components/lineage/Lineage'

const mockGraphWithCycle = [
{
id: 'job_foo',
type: 'JOB',
inEdges: [
{
origin: 'dataset_foo',
destination: 'job_foo'
}
],
outEdges: [
{
origin: 'job_foo',
destination: 'dataset_bar'
}
]
},
{
id: 'dataset_bar',
type: 'DATASET',
inEdges: [
{
origin: 'job_foo',
destination: 'dataset_bar'
}
],
outEdges: [
{
origin: 'dataset_bar',
destination: 'job_bar'
}
]
},
{
id: 'job_bar',
type: 'JOB',
inEdges: [
{
origin: 'dataset_bar',
destination: 'job_bar'
}
],
outEdges: [
{
origin: 'job_bar',
destination: 'dataset_foo'
}
]
},
{
id: 'dataset_foo',
type: 'DATASET',
inEdges: [
{
origin: 'job_bar',
destination: 'dataset_foo'
}
],
outEdges: [
{
origin: 'dataset_foo',
destination: 'job_foo'
}
]
}
]

describe('Lineage Component', () => {
const mockProps = {
setLineage: str => null
// TODO: do we really need to stub all of these?
}

it("doesn't follow cycles in the lineage graph", () => {
const wrapper = shallow(
<Lineage
{...mockProps}
// TODO: fix type errors, probably needs a stub interface?
lineage={mockGraphWithCycle}
selectedNode={mockGraphWithCycle[0].id}
/>
)

const instance = wrapper.instance()
// TODO: fix type errors, the above stub interface will probably fix this
const paths = instance.getSelectedPaths()
Comment thread
jlukenoff marked this conversation as resolved.

// TODO: validate that we never have duplicate paths
})
})
12 changes: 12 additions & 0 deletions web/src/components/lineage/Lineage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,16 @@ class Lineage extends React.Component<LineageProps, LineageState> {
getSelectedPaths = () => {
const paths = [] as Array<[string, string]>

// Sets used to detect cycles and break out of the recursive loop

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBD: How would this work if we had a really large cycle with many nodes/paths involved? Perhaps we still run the risk of blowing the stack with this as well.

const visitedNodes = {
successors: new Set(),
predecessors: new Set()
}

const getSuccessors = (node: string) => {
if (visitedNodes.successors.has(node)) return
visitedNodes.successors.add(node)

Comment thread
jlukenoff marked this conversation as resolved.
const successors = g?.successors(node)
if (successors?.length) {
for (let i = 0; i < node.length - 1; i++) {
Expand All @@ -156,6 +165,9 @@ class Lineage extends React.Component<LineageProps, LineageState> {
}

const getPredecessors = (node: string) => {
if (visitedNodes.predecessors.has(node)) return
visitedNodes.predecessors.add(node)

const predecessors = g?.predecessors(node)
if (predecessors?.length) {
for (let i = 0; i < node.length - 1; i++) {
Expand Down