github.com/getgauge/gauge@v1.6.9/execution/merge.go (about)

     1  /*----------------------------------------------------------------
     2   *  Copyright (c) ThoughtWorks, Inc.
     3   *  Licensed under the Apache License, Version 2.0
     4   *  See LICENSE in the project root for license information.
     5   *----------------------------------------------------------------*/
     6  
     7  package execution
     8  
     9  import (
    10  	"time"
    11  
    12  	"strings"
    13  
    14  	m "github.com/getgauge/gauge-proto/go/gauge_messages"
    15  	"github.com/getgauge/gauge/execution/result"
    16  )
    17  
    18  func mergeDataTableSpecResults(sResult *result.SuiteResult) *result.SuiteResult {
    19  	suiteRes := result.NewSuiteResult(sResult.Tags, time.Now())
    20  	suiteRes.IsFailed = sResult.IsFailed
    21  	suiteRes.ExecutionTime = sResult.ExecutionTime
    22  	suiteRes.PostSuite = sResult.PostSuite
    23  	suiteRes.PreSuite = sResult.PreSuite
    24  	suiteRes.UnhandledErrors = sResult.UnhandledErrors
    25  	suiteRes.Timestamp = sResult.Timestamp
    26  	suiteRes.ProjectName = sResult.ProjectName
    27  	suiteRes.Environment = sResult.Environment
    28  	suiteRes.Tags = sResult.Tags
    29  	suiteRes.PreHookMessages = append(suiteRes.PreHookMessages, sResult.PreHookMessages...)
    30  	suiteRes.PostHookMessages = append(suiteRes.PostHookMessages, sResult.PostHookMessages...)
    31  	suiteRes.PreHookScreenshotFiles = append(suiteRes.PreHookScreenshotFiles, sResult.PreHookScreenshotFiles...)
    32  	suiteRes.PostHookScreenshotFiles = append(suiteRes.PostHookScreenshotFiles, sResult.PostHookScreenshotFiles...)
    33  	suiteRes.PreHookScreenshots = append(suiteRes.PreHookScreenshots, sResult.PreHookScreenshots...)
    34  	suiteRes.PostHookScreenshots = append(suiteRes.PostHookScreenshots, sResult.PostHookScreenshots...)
    35  	combinedResults := make(map[string][]*result.SpecResult)
    36  	for _, res := range sResult.SpecResults {
    37  		fileName := res.ProtoSpec.GetFileName()
    38  		combinedResults[fileName] = append(combinedResults[fileName], res)
    39  	}
    40  	for _, res := range combinedResults {
    41  		mergedRes := res[0]
    42  		if len(res) > 1 {
    43  			mergedRes = mergeResults(res)
    44  		}
    45  		if mergedRes.GetFailed() {
    46  			suiteRes.SpecsFailedCount++
    47  		} else if mergedRes.Skipped {
    48  			suiteRes.SpecsSkippedCount++
    49  		}
    50  		suiteRes.SpecResults = append(suiteRes.SpecResults, mergedRes)
    51  	}
    52  	return suiteRes
    53  }
    54  
    55  func hasTableDrivenSpec(results []*result.SpecResult) bool {
    56  	for _, r := range results {
    57  		if r.ProtoSpec.GetIsTableDriven() {
    58  			return true
    59  		}
    60  	}
    61  	return false
    62  }
    63  
    64  func mergeResults(results []*result.SpecResult) *result.SpecResult {
    65  	specResult := &result.SpecResult{ProtoSpec: &m.ProtoSpec{
    66  		IsTableDriven:    hasTableDrivenSpec(results),
    67  		PreHookMessages:  results[0].ProtoSpec.PreHookMessages,
    68  		PostHookMessages: results[len(results)-1].ProtoSpec.PostHookMessages,
    69  	}}
    70  	var scnResults []*m.ProtoItem
    71  	table := &m.ProtoTable{}
    72  	dataTableScnResults := make(map[string][]*m.ProtoTableDrivenScenario)
    73  	includedTableRowIndexMap := make(map[int32]bool)
    74  	max := results[0].ExecutionTime
    75  	for _, res := range results {
    76  		specResult.ExecutionTime += res.ExecutionTime
    77  		specResult.Errors = res.Errors
    78  		if res.ExecutionTime > max {
    79  			max = res.ExecutionTime
    80  		}
    81  		if res.GetFailed() {
    82  			specResult.IsFailed = true
    83  		}
    84  
    85  		var tableRows []*m.ProtoTableRow // nolint
    86  
    87  		for _, item := range res.ProtoSpec.Items {
    88  			switch item.ItemType {
    89  			case m.ProtoItem_Scenario:
    90  				scnResults = append(scnResults, item)
    91  				modifySpecStats(item.Scenario, specResult)
    92  			case m.ProtoItem_TableDrivenScenario:
    93  				tableRowIndex := item.TableDrivenScenario.TableRowIndex
    94  				if _, ok := includedTableRowIndexMap[tableRowIndex]; !ok {
    95  					table.Rows = append(table.Rows, tableRows...)
    96  					includedTableRowIndexMap[tableRowIndex] = true
    97  				}
    98  				item.TableDrivenScenario.TableRowIndex = int32(len(table.Rows) - 1)
    99  				scnResults = append(scnResults, item)
   100  				heading := item.TableDrivenScenario.Scenario.ScenarioHeading
   101  				dataTableScnResults[heading] = append(dataTableScnResults[heading], item.TableDrivenScenario)
   102  			case m.ProtoItem_Table:
   103  				table.Headers = item.Table.Headers
   104  				tableRows = item.Table.GetRows()
   105  				if len(res.GetPreHook()) > 0 {
   106  					table.Rows = append(table.Rows, tableRows...)
   107  				}
   108  			}
   109  		}
   110  		addHookFailure(table, res.GetPreHook(), specResult.AddPreHook)
   111  		addHookFailure(table, res.GetPostHook(), specResult.AddPostHook)
   112  	}
   113  	if InParallel {
   114  		specResult.ExecutionTime = max
   115  	}
   116  	aggregateDataTableScnStats(dataTableScnResults, specResult)
   117  	specResult.ProtoSpec.FileName = results[0].ProtoSpec.FileName
   118  	specResult.ProtoSpec.Tags = results[0].ProtoSpec.Tags
   119  	specResult.ProtoSpec.SpecHeading = results[0].ProtoSpec.SpecHeading
   120  	specResult.ProtoSpec.Items = getItems(table, scnResults, results)
   121  	return specResult
   122  }
   123  
   124  func addHookFailure(table *m.ProtoTable, f []*m.ProtoHookFailure, add func(...*m.ProtoHookFailure)) {
   125  	for _, h := range f {
   126  		h.TableRowIndex = int32(len(table.Rows) - 1)
   127  	}
   128  	add(f...)
   129  }
   130  
   131  func getItems(table *m.ProtoTable, scnResults []*m.ProtoItem, results []*result.SpecResult) (items []*m.ProtoItem) {
   132  	index := 0
   133  	for _, item := range results[0].ProtoSpec.Items {
   134  		switch item.ItemType {
   135  		case m.ProtoItem_Scenario, m.ProtoItem_TableDrivenScenario:
   136  			items = append(items, scnResults[index])
   137  			index++
   138  		case m.ProtoItem_Table:
   139  			items = append(items, &m.ProtoItem{ItemType: m.ProtoItem_Table, Table: table})
   140  		default:
   141  			items = append(items, item)
   142  		}
   143  	}
   144  	items = append(items, scnResults[index:]...)
   145  	return
   146  }
   147  
   148  func aggregateDataTableScnStats(results map[string][]*m.ProtoTableDrivenScenario, specResult *result.SpecResult) {
   149  	for _, dResult := range results {
   150  		for _, res := range dResult {
   151  			isTableIndicesExcluded := false
   152  			if res.Scenario.ExecutionStatus == m.ExecutionStatus_FAILED {
   153  				specResult.ScenarioFailedCount++
   154  			} else if res.Scenario.ExecutionStatus == m.ExecutionStatus_SKIPPED &&
   155  				!strings.Contains(res.Scenario.SkipErrors[0], "--table-rows") {
   156  				specResult.ScenarioSkippedCount++
   157  				specResult.Skipped = true
   158  			} else if res.Scenario.ExecutionStatus == m.ExecutionStatus_SKIPPED &&
   159  				strings.Contains(res.Scenario.SkipErrors[0], "--table-rows") {
   160  				isTableIndicesExcluded = true
   161  			}
   162  			if !isTableIndicesExcluded {
   163  				specResult.ScenarioCount++
   164  			}
   165  		}
   166  	}
   167  }
   168  
   169  func modifySpecStats(scn *m.ProtoScenario, specRes *result.SpecResult) {
   170  	switch scn.ExecutionStatus {
   171  	case m.ExecutionStatus_SKIPPED:
   172  		specRes.ScenarioSkippedCount++
   173  	case m.ExecutionStatus_FAILED:
   174  		specRes.ScenarioFailedCount++
   175  	}
   176  	specRes.ScenarioCount++
   177  }