Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
171202e4
Commit
171202e4
authored
Aug 11, 2021
by
Sarah Groff Hennigh-Palermo
Committed by
Andrew Fontaine
Aug 11, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Pipeline Graph: Stop calling parseData twice
parent
6c24fa0b
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
260 additions
and
277 deletions
+260
-277
app/assets/javascripts/pipelines/components/graph/graph_component.vue
...avascripts/pipelines/components/graph/graph_component.vue
+11
-4
app/assets/javascripts/pipelines/components/graph/graph_component_wrapper.vue
...ts/pipelines/components/graph/graph_component_wrapper.vue
+11
-7
app/assets/javascripts/pipelines/components/graph/linked_pipelines_column.vue
...ts/pipelines/components/graph/linked_pipelines_column.vue
+7
-3
app/assets/javascripts/pipelines/components/graph/perf_utils.js
...sets/javascripts/pipelines/components/graph/perf_utils.js
+50
-0
app/assets/javascripts/pipelines/components/graph/utils.js
app/assets/javascripts/pipelines/components/graph/utils.js
+26
-0
app/assets/javascripts/pipelines/components/graph_shared/drawing_utils.js
...cripts/pipelines/components/graph_shared/drawing_utils.js
+1
-1
app/assets/javascripts/pipelines/components/graph_shared/links_inner.vue
...scripts/pipelines/components/graph_shared/links_inner.vue
+5
-5
app/assets/javascripts/pipelines/components/graph_shared/links_layer.vue
...scripts/pipelines/components/graph_shared/links_layer.vue
+18
-99
app/assets/javascripts/pipelines/components/parsing_utils.js
app/assets/javascripts/pipelines/components/parsing_utils.js
+7
-1
locale/gitlab.pot
locale/gitlab.pot
+0
-6
spec/frontend/pipelines/graph/graph_component_spec.js
spec/frontend/pipelines/graph/graph_component_spec.js
+2
-2
spec/frontend/pipelines/graph/graph_component_wrapper_spec.js
.../frontend/pipelines/graph/graph_component_wrapper_spec.js
+118
-0
spec/frontend/pipelines/graph_shared/links_inner_spec.js
spec/frontend/pipelines/graph_shared/links_inner_spec.js
+1
-1
spec/frontend/pipelines/graph_shared/links_layer_spec.js
spec/frontend/pipelines/graph_shared/links_layer_spec.js
+0
-145
spec/frontend/pipelines/parsing_utils_spec.js
spec/frontend/pipelines/parsing_utils_spec.js
+3
-3
No files found.
app/assets/javascripts/pipelines/components/graph/graph_component.vue
View file @
171202e4
...
...
@@ -39,10 +39,10 @@ export default {
required
:
false
,
default
:
false
,
},
pipelineLayers
:
{
type
:
Array
,
computedPipelineInfo
:
{
type
:
Object
,
required
:
false
,
default
:
()
=>
[]
,
default
:
()
=>
({})
,
},
type
:
{
type
:
String
,
...
...
@@ -81,7 +81,10 @@ export default {
layout
()
{
return
this
.
isStageView
?
this
.
pipeline
.
stages
:
generateColumnsFromLayersListMemoized
(
this
.
pipeline
,
this
.
pipelineLayers
);
:
generateColumnsFromLayersListMemoized
(
this
.
pipeline
,
this
.
computedPipelineInfo
.
pipelineLayers
,
);
},
hasDownstreamPipelines
()
{
return
Boolean
(
this
.
pipeline
?.
downstream
?.
length
>
0
);
...
...
@@ -92,6 +95,9 @@ export default {
isStageView
()
{
return
this
.
viewType
===
STAGE_VIEW
;
},
linksData
()
{
return
this
.
computedPipelineInfo
?.
linksData
??
null
;
},
metricsConfig
()
{
return
{
path
:
this
.
configPaths
.
metricsPath
,
...
...
@@ -188,6 +194,7 @@ export default {
:container-id=
"containerId"
:container-measurements=
"measurements"
:highlighted-job=
"hoveredJobName"
:links-data=
"linksData"
:metrics-config=
"metricsConfig"
:show-links=
"showJobLinks"
:view-type=
"viewType"
...
...
app/assets/javascripts/pipelines/components/graph/graph_component_wrapper.vue
View file @
171202e4
...
...
@@ -9,11 +9,11 @@ import { DEFAULT, DRAW_FAILURE, LOAD_FAILURE } from '../../constants';
import
DismissPipelineGraphCallout
from
'
../../graphql/mutations/dismiss_pipeline_notification.graphql
'
;
import
getPipelineQuery
from
'
../../graphql/queries/get_pipeline_header_data.query.graphql
'
;
import
{
reportToSentry
,
reportMessageToSentry
}
from
'
../../utils
'
;
import
{
listByLayers
}
from
'
../parsing_utils
'
;
import
{
IID_FAILURE
,
LAYER_VIEW
,
STAGE_VIEW
,
VIEW_TYPE_KEY
}
from
'
./constants
'
;
import
PipelineGraph
from
'
./graph_component.vue
'
;
import
GraphViewSelector
from
'
./graph_view_selector.vue
'
;
import
{
calculatePipelineLayersInfo
,
getQueryHeaders
,
serializeLoadErrors
,
toggleQueryPollingByVisibility
,
...
...
@@ -51,10 +51,10 @@ export default {
return
{
alertType
:
null
,
callouts
:
[],
computedPipelineInfo
:
null
,
currentViewType
:
STAGE_VIEW
,
canRefetchHeaderPipeline
:
false
,
pipeline
:
null
,
pipelineLayers
:
null
,
showAlert
:
false
,
showLinks
:
false
,
};
...
...
@@ -214,12 +214,16 @@ export default {
reportToSentry
(
this
.
$options
.
name
,
`error:
${
err
}
, info:
${
info
}
`
);
},
methods
:
{
getPipelineLayers
()
{
if
(
this
.
currentViewType
===
LAYER_VIEW
&&
!
this
.
pipelineLayers
)
{
this
.
pipelineLayers
=
listByLayers
(
this
.
pipeline
);
getPipelineInfo
()
{
if
(
this
.
currentViewType
===
LAYER_VIEW
&&
!
this
.
computedPipelineInfo
)
{
this
.
computedPipelineInfo
=
calculatePipelineLayersInfo
(
this
.
pipeline
,
this
.
$options
.
name
,
this
.
metricsPath
,
);
}
return
this
.
pipelineLayers
;
return
this
.
computedPipelineInfo
;
},
handleTipDismissal
()
{
try
{
...
...
@@ -288,7 +292,7 @@ export default {
v-if=
"pipeline"
:config-paths=
"configPaths"
:pipeline=
"pipeline"
:
pipeline-layers=
"getPipelineLayers
()"
:
computed-pipeline-info=
"getPipelineInfo
()"
:show-links=
"showLinks"
:view-type=
"graphViewType"
@
error=
"reportFailure"
...
...
app/assets/javascripts/pipelines/components/graph/linked_pipelines_column.vue
View file @
171202e4
...
...
@@ -2,10 +2,10 @@
import
getPipelineDetails
from
'
shared_queries/pipelines/get_pipeline_details.query.graphql
'
;
import
{
LOAD_FAILURE
}
from
'
../../constants
'
;
import
{
reportToSentry
}
from
'
../../utils
'
;
import
{
listByLayers
}
from
'
../parsing_utils
'
;
import
{
ONE_COL_WIDTH
,
UPSTREAM
,
LAYER_VIEW
,
STAGE_VIEW
}
from
'
./constants
'
;
import
LinkedPipeline
from
'
./linked_pipeline.vue
'
;
import
{
calculatePipelineLayersInfo
,
getQueryHeaders
,
serializeLoadErrors
,
toggleQueryPollingByVisibility
,
...
...
@@ -138,7 +138,11 @@ export default {
},
getPipelineLayers
(
id
)
{
if
(
this
.
viewType
===
LAYER_VIEW
&&
!
this
.
pipelineLayers
[
id
])
{
this
.
pipelineLayers
[
id
]
=
listByLayers
(
this
.
currentPipeline
);
this
.
pipelineLayers
[
id
]
=
calculatePipelineLayersInfo
(
this
.
currentPipeline
,
this
.
$options
.
name
,
this
.
configPaths
.
metricsPath
,
);
}
return
this
.
pipelineLayers
[
id
];
...
...
@@ -223,7 +227,7 @@ export default {
class=
"d-inline-block gl-mt-n2"
:config-paths=
"configPaths"
:pipeline=
"currentPipeline"
:
pipeline-layers
=
"getPipelineLayers(pipeline.id)"
:
computed-pipeline-info
=
"getPipelineLayers(pipeline.id)"
:show-links=
"showLinks"
:is-linked-pipeline=
"true"
:view-type=
"graphViewType"
...
...
app/assets/javascripts/pipelines/components/graph/perf_utils.js
0 → 100644
View file @
171202e4
import
{
PIPELINES_DETAIL_LINKS_MARK_CALCULATE_START
,
PIPELINES_DETAIL_LINKS_MARK_CALCULATE_END
,
PIPELINES_DETAIL_LINKS_MEASURE_CALCULATION
,
PIPELINES_DETAIL_LINK_DURATION
,
PIPELINES_DETAIL_LINKS_TOTAL
,
PIPELINES_DETAIL_LINKS_JOB_RATIO
,
}
from
'
~/performance/constants
'
;
import
{
performanceMarkAndMeasure
}
from
'
~/performance/utils
'
;
import
{
reportPerformance
}
from
'
../graph_shared/api
'
;
export
const
beginPerfMeasure
=
()
=>
{
performanceMarkAndMeasure
({
mark
:
PIPELINES_DETAIL_LINKS_MARK_CALCULATE_START
});
};
export
const
finishPerfMeasureAndSend
=
(
numLinks
,
numGroups
,
metricsPath
)
=>
{
performanceMarkAndMeasure
({
mark
:
PIPELINES_DETAIL_LINKS_MARK_CALCULATE_END
,
measures
:
[
{
name
:
PIPELINES_DETAIL_LINKS_MEASURE_CALCULATION
,
start
:
PIPELINES_DETAIL_LINKS_MARK_CALCULATE_START
,
},
],
});
window
.
requestAnimationFrame
(()
=>
{
const
duration
=
window
.
performance
.
getEntriesByName
(
PIPELINES_DETAIL_LINKS_MEASURE_CALCULATION
,
)[
0
]?.
duration
;
if
(
!
duration
)
{
return
;
}
const
data
=
{
histograms
:
[
{
name
:
PIPELINES_DETAIL_LINK_DURATION
,
value
:
duration
/
1000
},
{
name
:
PIPELINES_DETAIL_LINKS_TOTAL
,
value
:
numLinks
},
{
name
:
PIPELINES_DETAIL_LINKS_JOB_RATIO
,
value
:
numLinks
/
numGroups
,
},
],
};
reportPerformance
(
metricsPath
,
data
);
});
};
app/assets/javascripts/pipelines/components/graph/utils.js
View file @
171202e4
import
{
isEmpty
}
from
'
lodash
'
;
import
Visibility
from
'
visibilityjs
'
;
import
{
getIdFromGraphQLId
}
from
'
~/graphql_shared/utils
'
;
import
{
reportToSentry
}
from
'
../../utils
'
;
import
{
listByLayers
}
from
'
../parsing_utils
'
;
import
{
unwrapStagesWithNeedsAndLookup
}
from
'
../unwrapping_utils
'
;
import
{
beginPerfMeasure
,
finishPerfMeasureAndSend
}
from
'
./perf_utils
'
;
const
addMulti
=
(
mainPipelineProjectPath
,
linkedPipeline
)
=>
{
return
{
...
...
@@ -10,6 +13,28 @@ const addMulti = (mainPipelineProjectPath, linkedPipeline) => {
};
};
const
calculatePipelineLayersInfo
=
(
pipeline
,
componentName
,
metricsPath
)
=>
{
const
shouldCollectMetrics
=
Boolean
(
metricsPath
.
length
);
if
(
shouldCollectMetrics
)
{
beginPerfMeasure
();
}
let
layers
=
null
;
try
{
layers
=
listByLayers
(
pipeline
);
if
(
shouldCollectMetrics
)
{
finishPerfMeasureAndSend
(
layers
.
linksData
.
length
,
layers
.
numGroups
,
metricsPath
);
}
}
catch
(
err
)
{
reportToSentry
(
componentName
,
err
);
}
return
layers
;
};
/* eslint-disable @gitlab/require-i18n-strings */
const
getQueryHeaders
=
(
etagResource
)
=>
{
return
{
...
...
@@ -106,6 +131,7 @@ const unwrapPipelineData = (mainPipelineProjectPath, data) => {
const
validateConfigPaths
=
(
value
)
=>
value
.
graphqlResourceEtag
?.
length
>
0
;
export
{
calculatePipelineLayersInfo
,
getQueryHeaders
,
serializeGqlErr
,
serializeLoadErrors
,
...
...
app/assets/javascripts/pipelines/components/graph_shared/drawing_utils.js
View file @
171202e4
...
...
@@ -13,7 +13,7 @@ export const createUniqueLinkId = (stageName, jobName) => `${stageName}-${jobNam
* @returns {Array} Links that contain all the information about them
*/
export
const
generateLinksData
=
(
{
links
}
,
containerID
,
modifier
=
''
)
=>
{
export
const
generateLinksData
=
(
links
,
containerID
,
modifier
=
''
)
=>
{
const
containerEl
=
document
.
getElementById
(
containerID
);
return
links
.
map
((
link
)
=>
{
...
...
app/assets/javascripts/pipelines/components/graph_shared/links_inner.vue
View file @
171202e4
...
...
@@ -17,8 +17,8 @@ export default {
type
:
Object
,
required
:
true
,
},
parsed
Data
:
{
type
:
Object
,
links
Data
:
{
type
:
Array
,
required
:
true
,
},
pipelineId
:
{
...
...
@@ -95,7 +95,7 @@ export default {
highlightedJobs
(
jobs
)
{
this
.
$emit
(
'
highlightedJobsChange
'
,
jobs
);
},
parsed
Data
()
{
links
Data
()
{
this
.
calculateLinkData
();
},
viewType
()
{
...
...
@@ -112,7 +112,7 @@ export default {
reportToSentry
(
this
.
$options
.
name
,
`error:
${
err
}
, info:
${
info
}
`
);
},
mounted
()
{
if
(
!
isEmpty
(
this
.
parsed
Data
))
{
if
(
!
isEmpty
(
this
.
links
Data
))
{
this
.
calculateLinkData
();
}
},
...
...
@@ -122,7 +122,7 @@ export default {
},
calculateLinkData
()
{
try
{
this
.
links
=
generateLinksData
(
this
.
parsed
Data
,
this
.
containerId
,
`-
${
this
.
pipelineId
}
`
);
this
.
links
=
generateLinksData
(
this
.
links
Data
,
this
.
containerId
,
`-
${
this
.
pipelineId
}
`
);
}
catch
(
err
)
{
this
.
$emit
(
'
error
'
,
{
type
:
DRAW_FAILURE
,
reportToSentry
:
false
});
reportToSentry
(
this
.
$options
.
name
,
err
);
...
...
app/assets/javascripts/pipelines/components/graph_shared/links_layer.vue
View file @
171202e4
<
script
>
import
{
isEmpty
}
from
'
lodash
'
;
import
{
__
}
from
'
~/locale
'
;
import
{
PIPELINES_DETAIL_LINKS_MARK_CALCULATE_START
,
PIPELINES_DETAIL_LINKS_MARK_CALCULATE_END
,
PIPELINES_DETAIL_LINKS_MEASURE_CALCULATION
,
PIPELINES_DETAIL_LINK_DURATION
,
PIPELINES_DETAIL_LINKS_TOTAL
,
PIPELINES_DETAIL_LINKS_JOB_RATIO
,
}
from
'
~/performance/constants
'
;
import
{
performanceMarkAndMeasure
}
from
'
~/performance/utils
'
;
import
{
memoize
}
from
'
lodash
'
;
import
{
reportToSentry
}
from
'
../../utils
'
;
import
{
parseData
}
from
'
../parsing_utils
'
;
import
{
reportPerformance
}
from
'
./api
'
;
import
LinksInner
from
'
./links_inner.vue
'
;
const
parseForLinksBare
=
(
pipeline
)
=>
{
const
arrayOfJobs
=
pipeline
.
flatMap
(({
groups
})
=>
groups
);
return
parseData
(
arrayOfJobs
).
links
;
};
const
parseForLinks
=
memoize
(
parseForLinksBare
);
export
default
{
name
:
'
LinksLayer
'
,
components
:
{
...
...
@@ -29,10 +25,10 @@ export default {
type
:
Array
,
required
:
true
,
},
metricsConfig
:
{
type
:
Object
,
linksData
:
{
type
:
Array
,
required
:
false
,
default
:
()
=>
({})
,
default
:
()
=>
[]
,
},
showLinks
:
{
type
:
Boolean
,
...
...
@@ -40,30 +36,16 @@ export default {
default
:
true
,
},
},
data
()
{
return
{
alertDismissed
:
false
,
parsedData
:
{},
showLinksOverride
:
false
,
};
},
i18n
:
{
showLinksAnyways
:
__
(
'
Show links anyways
'
),
tooManyJobs
:
__
(
'
This graph has a large number of jobs and showing the links between them may have performance implications.
'
,
),
},
computed
:
{
containerZero
()
{
return
!
this
.
containerMeasurements
.
width
||
!
this
.
containerMeasurements
.
height
;
},
numGroups
()
{
return
this
.
pipelineData
.
reduce
((
acc
,
{
groups
})
=>
{
return
acc
+
Number
(
groups
.
length
);
},
0
);
},
shouldCollectMetrics
()
{
return
this
.
metricsConfig
.
collectMetrics
&&
this
.
metricsConfig
.
path
;
getLinksData
()
{
if
(
this
.
linksData
.
length
>
0
)
{
return
this
.
linksData
;
}
return
parseForLinks
(
this
.
pipelineData
);
},
showLinkedLayers
()
{
return
this
.
showLinks
&&
!
this
.
containerZero
;
...
...
@@ -72,77 +54,14 @@ export default {
errorCaptured
(
err
,
_vm
,
info
)
{
reportToSentry
(
this
.
$options
.
name
,
`error:
${
err
}
, info:
${
info
}
`
);
},
mounted
()
{
if
(
!
isEmpty
(
this
.
pipelineData
))
{
window
.
requestAnimationFrame
(()
=>
{
this
.
prepareLinkData
();
});
}
},
methods
:
{
beginPerfMeasure
()
{
if
(
this
.
shouldCollectMetrics
)
{
performanceMarkAndMeasure
({
mark
:
PIPELINES_DETAIL_LINKS_MARK_CALCULATE_START
});
}
},
finishPerfMeasureAndSend
(
numLinks
)
{
if
(
this
.
shouldCollectMetrics
)
{
performanceMarkAndMeasure
({
mark
:
PIPELINES_DETAIL_LINKS_MARK_CALCULATE_END
,
measures
:
[
{
name
:
PIPELINES_DETAIL_LINKS_MEASURE_CALCULATION
,
start
:
PIPELINES_DETAIL_LINKS_MARK_CALCULATE_START
,
},
],
});
}
window
.
requestAnimationFrame
(()
=>
{
const
duration
=
window
.
performance
.
getEntriesByName
(
PIPELINES_DETAIL_LINKS_MEASURE_CALCULATION
,
)[
0
]?.
duration
;
if
(
!
duration
)
{
return
;
}
const
data
=
{
histograms
:
[
{
name
:
PIPELINES_DETAIL_LINK_DURATION
,
value
:
duration
/
1000
},
{
name
:
PIPELINES_DETAIL_LINKS_TOTAL
,
value
:
numLinks
},
{
name
:
PIPELINES_DETAIL_LINKS_JOB_RATIO
,
value
:
numLinks
/
this
.
numGroups
,
},
],
};
reportPerformance
(
this
.
metricsConfig
.
path
,
data
);
});
},
prepareLinkData
()
{
this
.
beginPerfMeasure
();
let
numLinks
;
try
{
const
arrayOfJobs
=
this
.
pipelineData
.
flatMap
(({
groups
})
=>
groups
);
this
.
parsedData
=
parseData
(
arrayOfJobs
);
numLinks
=
this
.
parsedData
.
links
.
length
;
}
catch
(
err
)
{
reportToSentry
(
this
.
$options
.
name
,
err
);
}
this
.
finishPerfMeasureAndSend
(
numLinks
);
},
},
};
</
script
>
<
template
>
<links-inner
v-if=
"showLinkedLayers"
:container-measurements=
"containerMeasurements"
:
parsed-data=
"parsed
Data"
:
links-data=
"getLinks
Data"
:pipeline-data=
"pipelineData"
:total-groups=
"numGroups"
v-bind=
"$attrs"
v-on=
"$listeners"
>
...
...
app/assets/javascripts/pipelines/components/parsing_utils.js
View file @
171202e4
...
...
@@ -175,7 +175,7 @@ export const listByLayers = ({ stages }) => {
const
parsedData
=
parseData
(
arrayOfJobs
);
const
dataWithLayers
=
createSankey
()(
parsedData
);
return
dataWithLayers
.
nodes
.
reduce
((
acc
,
{
layer
,
name
})
=>
{
const
pipelineLayers
=
dataWithLayers
.
nodes
.
reduce
((
acc
,
{
layer
,
name
})
=>
{
/* sort groups by layer */
if
(
!
acc
[
layer
])
{
...
...
@@ -186,6 +186,12 @@ export const listByLayers = ({ stages }) => {
return
acc
;
},
[]);
return
{
linksData
:
parsedData
.
links
,
numGroups
:
arrayOfJobs
.
length
,
pipelineLayers
,
};
};
export
const
generateColumnsFromLayersListBare
=
({
stages
,
stagesLookup
},
pipelineLayers
)
=>
{
...
...
locale/gitlab.pot
View file @
171202e4
...
...
@@ -30537,9 +30537,6 @@ msgstr ""
msgid "Show latest version"
msgstr ""
msgid "Show links anyways"
msgstr ""
msgid "Show list"
msgstr ""
...
...
@@ -33877,9 +33874,6 @@ msgstr ""
msgid "This field is required."
msgstr ""
msgid "This graph has a large number of jobs and showing the links between them may have performance implications."
msgstr ""
msgid "This group"
msgstr ""
...
...
spec/frontend/pipelines/graph/graph_component_spec.js
View file @
171202e4
...
...
@@ -4,8 +4,8 @@ import PipelineGraph from '~/pipelines/components/graph/graph_component.vue';
import
JobItem
from
'
~/pipelines/components/graph/job_item.vue
'
;
import
LinkedPipelinesColumn
from
'
~/pipelines/components/graph/linked_pipelines_column.vue
'
;
import
StageColumnComponent
from
'
~/pipelines/components/graph/stage_column_component.vue
'
;
import
{
calculatePipelineLayersInfo
}
from
'
~/pipelines/components/graph/utils
'
;
import
LinksLayer
from
'
~/pipelines/components/graph_shared/links_layer.vue
'
;
import
{
listByLayers
}
from
'
~/pipelines/components/parsing_utils
'
;
import
{
generateResponse
,
mockPipelineResponse
,
...
...
@@ -150,7 +150,7 @@ describe('graph component', () => {
},
props
:
{
viewType
:
LAYER_VIEW
,
pipelineLayers
:
listByLayers
(
defaultProps
.
pipeline
),
computedPipelineInfo
:
calculatePipelineLayersInfo
(
defaultProps
.
pipeline
,
'
layer
'
,
''
),
},
});
});
...
...
spec/frontend/pipelines/graph/graph_component_wrapper_spec.js
View file @
171202e4
import
{
GlAlert
,
GlLoadingIcon
}
from
'
@gitlab/ui
'
;
import
{
mount
,
shallowMount
}
from
'
@vue/test-utils
'
;
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
Vue
from
'
vue
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
{
useLocalStorageSpy
}
from
'
helpers/local_storage_helper
'
;
import
createMockApollo
from
'
helpers/mock_apollo_helper
'
;
import
getPipelineDetails
from
'
shared_queries/pipelines/get_pipeline_details.query.graphql
'
;
import
getUserCallouts
from
'
~/graphql_shared/queries/get_user_callouts.query.graphql
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
{
PIPELINES_DETAIL_LINK_DURATION
,
PIPELINES_DETAIL_LINKS_TOTAL
,
PIPELINES_DETAIL_LINKS_JOB_RATIO
,
}
from
'
~/performance/constants
'
;
import
*
as
perfUtils
from
'
~/performance/utils
'
;
import
{
IID_FAILURE
,
LAYER_VIEW
,
...
...
@@ -16,9 +24,11 @@ import PipelineGraph from '~/pipelines/components/graph/graph_component.vue';
import
PipelineGraphWrapper
from
'
~/pipelines/components/graph/graph_component_wrapper.vue
'
;
import
GraphViewSelector
from
'
~/pipelines/components/graph/graph_view_selector.vue
'
;
import
StageColumnComponent
from
'
~/pipelines/components/graph/stage_column_component.vue
'
;
import
*
as
Api
from
'
~/pipelines/components/graph_shared/api
'
;
import
LinksLayer
from
'
~/pipelines/components/graph_shared/links_layer.vue
'
;
import
*
as
parsingUtils
from
'
~/pipelines/components/parsing_utils
'
;
import
getPipelineHeaderData
from
'
~/pipelines/graphql/queries/get_pipeline_header_data.query.graphql
'
;
import
*
as
sentryUtils
from
'
~/pipelines/utils
'
;
import
{
mockRunningPipelineHeaderData
}
from
'
../mock_data
'
;
import
{
mapCallouts
,
mockCalloutsResponse
,
mockPipelineResponse
}
from
'
./mock_data
'
;
...
...
@@ -480,4 +490,112 @@ describe('Pipeline graph wrapper', () => {
});
});
});
describe
(
'
performance metrics
'
,
()
=>
{
const
metricsPath
=
'
/root/project/-/ci/prometheus_metrics/histograms.json
'
;
let
markAndMeasure
;
let
reportToSentry
;
let
reportPerformance
;
let
mock
;
beforeEach
(()
=>
{
jest
.
spyOn
(
window
,
'
requestAnimationFrame
'
).
mockImplementation
((
cb
)
=>
cb
());
markAndMeasure
=
jest
.
spyOn
(
perfUtils
,
'
performanceMarkAndMeasure
'
);
reportToSentry
=
jest
.
spyOn
(
sentryUtils
,
'
reportToSentry
'
);
reportPerformance
=
jest
.
spyOn
(
Api
,
'
reportPerformance
'
);
});
describe
(
'
with no metrics path
'
,
()
=>
{
beforeEach
(
async
()
=>
{
createComponentWithApollo
();
jest
.
runOnlyPendingTimers
();
await
wrapper
.
vm
.
$nextTick
();
});
it
(
'
is not called
'
,
()
=>
{
expect
(
markAndMeasure
).
not
.
toHaveBeenCalled
();
expect
(
reportToSentry
).
not
.
toHaveBeenCalled
();
expect
(
reportPerformance
).
not
.
toHaveBeenCalled
();
});
});
describe
(
'
with metrics path
'
,
()
=>
{
const
duration
=
875
;
const
numLinks
=
7
;
const
totalGroups
=
8
;
const
metricsData
=
{
histograms
:
[
{
name
:
PIPELINES_DETAIL_LINK_DURATION
,
value
:
duration
/
1000
},
{
name
:
PIPELINES_DETAIL_LINKS_TOTAL
,
value
:
numLinks
},
{
name
:
PIPELINES_DETAIL_LINKS_JOB_RATIO
,
value
:
numLinks
/
totalGroups
,
},
],
};
describe
(
'
when no duration is obtained
'
,
()
=>
{
beforeEach
(
async
()
=>
{
jest
.
spyOn
(
window
.
performance
,
'
getEntriesByName
'
).
mockImplementation
(()
=>
{
return
[];
});
createComponentWithApollo
({
provide
:
{
metricsPath
,
glFeatures
:
{
pipelineGraphLayersView
:
true
,
},
},
data
:
{
currentViewType
:
LAYER_VIEW
,
},
});
jest
.
runOnlyPendingTimers
();
await
wrapper
.
vm
.
$nextTick
();
});
it
(
'
attempts to collect metrics
'
,
()
=>
{
expect
(
markAndMeasure
).
toHaveBeenCalled
();
expect
(
reportPerformance
).
not
.
toHaveBeenCalled
();
expect
(
reportToSentry
).
not
.
toHaveBeenCalled
();
});
});
describe
(
'
with duration and no error
'
,
()
=>
{
beforeEach
(()
=>
{
mock
=
new
MockAdapter
(
axios
);
mock
.
onPost
(
metricsPath
).
reply
(
200
,
{});
jest
.
spyOn
(
window
.
performance
,
'
getEntriesByName
'
).
mockImplementation
(()
=>
{
return
[{
duration
}];
});
createComponentWithApollo
({
provide
:
{
metricsPath
,
glFeatures
:
{
pipelineGraphLayersView
:
true
,
},
},
data
:
{
currentViewType
:
LAYER_VIEW
,
},
});
});
afterEach
(()
=>
{
mock
.
restore
();
});
it
(
'
it calls reportPerformance with expected arguments
'
,
()
=>
{
expect
(
markAndMeasure
).
toHaveBeenCalled
();
expect
(
reportPerformance
).
toHaveBeenCalled
();
expect
(
reportPerformance
).
toHaveBeenCalledWith
(
metricsPath
,
metricsData
);
expect
(
reportToSentry
).
not
.
toHaveBeenCalled
();
});
});
});
});
});
spec/frontend/pipelines/graph_shared/links_inner_spec.js
View file @
171202e4
...
...
@@ -31,7 +31,7 @@ describe('Links Inner component', () => {
propsData
:
{
...
defaultProps
,
...
props
,
parsedData
:
parseData
(
currentPipelineData
.
flatMap
(({
groups
})
=>
groups
))
,
linksData
:
parseData
(
currentPipelineData
.
flatMap
(({
groups
})
=>
groups
)).
links
,
},
});
};
...
...
spec/frontend/pipelines/graph_shared/links_layer_spec.js
View file @
171202e4
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
{
PIPELINES_DETAIL_LINK_DURATION
,
PIPELINES_DETAIL_LINKS_TOTAL
,
PIPELINES_DETAIL_LINKS_JOB_RATIO
,
}
from
'
~/performance/constants
'
;
import
*
as
perfUtils
from
'
~/performance/utils
'
;
import
*
as
Api
from
'
~/pipelines/components/graph_shared/api
'
;
import
LinksInner
from
'
~/pipelines/components/graph_shared/links_inner.vue
'
;
import
LinksLayer
from
'
~/pipelines/components/graph_shared/links_layer.vue
'
;
import
*
as
sentryUtils
from
'
~/pipelines/utils
'
;
import
{
generateResponse
,
mockPipelineResponse
}
from
'
../graph/mock_data
'
;
describe
(
'
links layer component
'
,
()
=>
{
...
...
@@ -94,139 +84,4 @@ describe('links layer component', () => {
expect
(
findLinksInner
().
exists
()).
toBe
(
false
);
});
});
describe
(
'
performance metrics
'
,
()
=>
{
const
metricsPath
=
'
/root/project/-/ci/prometheus_metrics/histograms.json
'
;
let
markAndMeasure
;
let
reportToSentry
;
let
reportPerformance
;
let
mock
;
beforeEach
(()
=>
{
jest
.
spyOn
(
window
,
'
requestAnimationFrame
'
).
mockImplementation
((
cb
)
=>
cb
());
markAndMeasure
=
jest
.
spyOn
(
perfUtils
,
'
performanceMarkAndMeasure
'
);
reportToSentry
=
jest
.
spyOn
(
sentryUtils
,
'
reportToSentry
'
);
reportPerformance
=
jest
.
spyOn
(
Api
,
'
reportPerformance
'
);
});
describe
(
'
with no metrics config object
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
();
});
it
(
'
is not called
'
,
()
=>
{
expect
(
markAndMeasure
).
not
.
toHaveBeenCalled
();
expect
(
reportToSentry
).
not
.
toHaveBeenCalled
();
expect
(
reportPerformance
).
not
.
toHaveBeenCalled
();
});
});
describe
(
'
with metrics config set to false
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
props
:
{
metricsConfig
:
{
collectMetrics
:
false
,
metricsPath
:
'
/path/to/metrics
'
,
},
},
});
});
it
(
'
is not called
'
,
()
=>
{
expect
(
markAndMeasure
).
not
.
toHaveBeenCalled
();
expect
(
reportToSentry
).
not
.
toHaveBeenCalled
();
expect
(
reportPerformance
).
not
.
toHaveBeenCalled
();
});
});
describe
(
'
with no metrics path
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
props
:
{
metricsConfig
:
{
collectMetrics
:
true
,
metricsPath
:
''
,
},
},
});
});
it
(
'
is not called
'
,
()
=>
{
expect
(
markAndMeasure
).
not
.
toHaveBeenCalled
();
expect
(
reportToSentry
).
not
.
toHaveBeenCalled
();
expect
(
reportPerformance
).
not
.
toHaveBeenCalled
();
});
});
describe
(
'
with metrics path and collect set to true
'
,
()
=>
{
const
duration
=
875
;
const
numLinks
=
7
;
const
totalGroups
=
8
;
const
metricsData
=
{
histograms
:
[
{
name
:
PIPELINES_DETAIL_LINK_DURATION
,
value
:
duration
/
1000
},
{
name
:
PIPELINES_DETAIL_LINKS_TOTAL
,
value
:
numLinks
},
{
name
:
PIPELINES_DETAIL_LINKS_JOB_RATIO
,
value
:
numLinks
/
totalGroups
,
},
],
};
describe
(
'
when no duration is obtained
'
,
()
=>
{
beforeEach
(()
=>
{
jest
.
spyOn
(
window
.
performance
,
'
getEntriesByName
'
).
mockImplementation
(()
=>
{
return
[];
});
createComponent
({
props
:
{
metricsConfig
:
{
collectMetrics
:
true
,
path
:
metricsPath
,
},
},
});
});
it
(
'
attempts to collect metrics
'
,
()
=>
{
expect
(
markAndMeasure
).
toHaveBeenCalled
();
expect
(
reportPerformance
).
not
.
toHaveBeenCalled
();
expect
(
reportToSentry
).
not
.
toHaveBeenCalled
();
});
});
describe
(
'
with duration and no error
'
,
()
=>
{
beforeEach
(()
=>
{
mock
=
new
MockAdapter
(
axios
);
mock
.
onPost
(
metricsPath
).
reply
(
200
,
{});
jest
.
spyOn
(
window
.
performance
,
'
getEntriesByName
'
).
mockImplementation
(()
=>
{
return
[{
duration
}];
});
createComponent
({
props
:
{
metricsConfig
:
{
collectMetrics
:
true
,
path
:
metricsPath
,
},
},
});
});
afterEach
(()
=>
{
mock
.
restore
();
});
it
(
'
it calls reportPerformance with expected arguments
'
,
()
=>
{
expect
(
markAndMeasure
).
toHaveBeenCalled
();
expect
(
reportPerformance
).
toHaveBeenCalled
();
expect
(
reportPerformance
).
toHaveBeenCalledWith
(
metricsPath
,
metricsData
);
expect
(
reportToSentry
).
not
.
toHaveBeenCalled
();
});
});
});
});
});
spec/frontend/pipelines/parsing_utils_spec.js
View file @
171202e4
...
...
@@ -120,8 +120,8 @@ describe('DAG visualization parsing utilities', () => {
describe
(
'
generateColumnsFromLayersList
'
,
()
=>
{
const
pipeline
=
generateResponse
(
mockPipelineResponse
,
'
root/fungi-xoxo
'
);
const
layers
=
listByLayers
(
pipeline
);
const
columns
=
generateColumnsFromLayersListBare
(
pipeline
,
l
ayers
);
const
{
pipelineLayers
}
=
listByLayers
(
pipeline
);
const
columns
=
generateColumnsFromLayersListBare
(
pipeline
,
pipelineL
ayers
);
it
(
'
returns stage-like objects with default name, id, and status
'
,
()
=>
{
columns
.
forEach
((
col
,
idx
)
=>
{
...
...
@@ -136,7 +136,7 @@ describe('DAG visualization parsing utilities', () => {
it
(
'
creates groups that match the list created in listByLayers
'
,
()
=>
{
columns
.
forEach
((
col
,
idx
)
=>
{
const
groupNames
=
col
.
groups
.
map
(({
name
})
=>
name
);
expect
(
groupNames
).
toEqual
(
l
ayers
[
idx
]);
expect
(
groupNames
).
toEqual
(
pipelineL
ayers
[
idx
]);
});
});
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment