github.com/filecoin-project/bacalhau@v0.3.23-0.20230228154132-45c989550ace/pkg/test/devstack/utils.go (about)

     1  package devstack
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/filecoin-project/bacalhau/pkg/devstack"
    11  	"github.com/filecoin-project/bacalhau/pkg/executor"
    12  	noop_executor "github.com/filecoin-project/bacalhau/pkg/executor/noop"
    13  	executor_util "github.com/filecoin-project/bacalhau/pkg/executor/util"
    14  	"github.com/filecoin-project/bacalhau/pkg/job"
    15  	_ "github.com/filecoin-project/bacalhau/pkg/logger"
    16  	"github.com/filecoin-project/bacalhau/pkg/model"
    17  	"github.com/filecoin-project/bacalhau/pkg/node"
    18  	"github.com/filecoin-project/bacalhau/pkg/requester/publicapi"
    19  	noop_storage "github.com/filecoin-project/bacalhau/pkg/storage/noop"
    20  	"github.com/filecoin-project/bacalhau/pkg/system"
    21  	"github.com/stretchr/testify/require"
    22  )
    23  
    24  func prepareFolderWithFiles(t *testing.T, fileCount int) string { //nolint:unused
    25  	basePath := t.TempDir()
    26  	for i := 0; i < fileCount; i++ {
    27  		err := os.WriteFile(
    28  			fmt.Sprintf("%s/%d.txt", basePath, i),
    29  			[]byte(fmt.Sprintf("hello %d", i)),
    30  			os.ModePerm,
    31  		)
    32  		require.NoError(t, err)
    33  	}
    34  	return basePath
    35  }
    36  
    37  type DeterministicVerifierTestArgs struct {
    38  	NodeCount      int
    39  	ShardCount     int
    40  	BadActors      int
    41  	Confidence     int
    42  	ExpectedPassed int
    43  	ExpectedFailed int
    44  }
    45  
    46  func RunDeterministicVerifierTest( //nolint:funlen
    47  	ctx context.Context,
    48  	t *testing.T,
    49  	submitJob func(
    50  		apiClient *publicapi.RequesterAPIClient,
    51  		args DeterministicVerifierTestArgs,
    52  	) (string, error),
    53  	args DeterministicVerifierTestArgs,
    54  ) {
    55  	cm := system.NewCleanupManager()
    56  	defer cm.Cleanup(ctx)
    57  
    58  	options := devstack.DevStackOptions{
    59  		NumberOfHybridNodes:      args.NodeCount,
    60  		NumberOfBadComputeActors: args.BadActors,
    61  	}
    62  
    63  	storageProvidersFactory := devstack.NewNoopStorageProvidersFactoryWithConfig(noop_storage.StorageConfig{
    64  		ExternalHooks: noop_storage.StorageConfigExternalHooks{
    65  			Explode: func(ctx context.Context, storageSpec model.StorageSpec) ([]model.StorageSpec, error) {
    66  				var results []model.StorageSpec
    67  				for i := 0; i < args.ShardCount; i++ {
    68  					results = append(results, model.StorageSpec{
    69  						StorageSource: model.StorageSourceIPFS,
    70  						CID:           fmt.Sprintf("123%d", i),
    71  						Path:          fmt.Sprintf("/data/file%d.txt", i),
    72  					})
    73  				}
    74  				return results, nil
    75  			},
    76  		},
    77  	})
    78  
    79  	executorsFactory := node.ExecutorsFactoryFunc(func(
    80  		ctx context.Context, nodeConfig node.NodeConfig) (executor.ExecutorProvider, error) {
    81  		return executor_util.NewNoopExecutors(noop_executor.ExecutorConfig{
    82  			ExternalHooks: noop_executor.ExecutorConfigExternalHooks{
    83  				JobHandler: func(ctx context.Context, shard model.JobShard, resultsDir string) (*model.RunCommandResult, error) {
    84  					runOutput := &model.RunCommandResult{}
    85  					runOutput.STDOUT = fmt.Sprintf("hello world %d", shard.Index)
    86  					if nodeConfig.ComputeConfig.SimulatorConfig.IsBadActor {
    87  						runOutput.STDOUT = fmt.Sprintf("i am bad and deserve to fail %d", shard.Index)
    88  					}
    89  					err := os.WriteFile(fmt.Sprintf("%s/stdout", resultsDir), []byte(runOutput.STDOUT), 0600) //nolint:gomnd
    90  					if err != nil {
    91  						runOutput.ErrorMsg = err.Error()
    92  					}
    93  
    94  					// Adding explicit error for consistency in function signatures
    95  					return runOutput, err
    96  				},
    97  			},
    98  		}), nil
    99  	})
   100  
   101  	injector := node.NewStandardNodeDependencyInjector()
   102  	injector.ExecutorsFactory = executorsFactory
   103  	injector.StorageProvidersFactory = storageProvidersFactory
   104  
   105  	stack, err := devstack.NewDevStack(
   106  		ctx,
   107  		cm,
   108  		options,
   109  		node.NewComputeConfigWithDefaults(),
   110  		node.NewRequesterConfigWithDefaults(),
   111  		injector,
   112  	)
   113  	require.NoError(t, err)
   114  
   115  	// wait for other nodes to catch up
   116  	time.Sleep(time.Second * 1)
   117  	apiURI := stack.Nodes[0].APIServer.GetURI()
   118  	apiClient := publicapi.NewRequesterAPIClient(apiURI)
   119  
   120  	jobID, err := submitJob(apiClient, args)
   121  	require.NoError(t, err)
   122  
   123  	resolver := apiClient.GetJobStateResolver()
   124  
   125  	err = resolver.Wait(
   126  		ctx,
   127  		jobID,
   128  		job.WaitForTerminalStates(),
   129  	)
   130  	require.NoError(t, err)
   131  
   132  	state, err := resolver.GetJobState(ctx, jobID)
   133  	require.NoError(t, err)
   134  
   135  	verifiedCount := 0
   136  	failedCount := 0
   137  
   138  	for _, shard := range state.Shards {
   139  		for _, execution := range shard.Executions { //nolint:gocritic
   140  			require.True(t, execution.VerificationResult.Complete)
   141  			if execution.VerificationResult.Result {
   142  				verifiedCount++
   143  			} else {
   144  				failedCount++
   145  			}
   146  		}
   147  	}
   148  
   149  	require.Equal(t, args.ExpectedPassed*args.ShardCount, verifiedCount, "verified count should be correct")
   150  	require.Equal(t, args.ExpectedFailed*args.ShardCount, failedCount, "failed count should be correct")
   151  }