go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/projects/nodes/pkg/dbmodel/main_test.go (about)

     1  /*
     2  
     3  Copyright (c) 2023 - Present. Will Charczuk. All rights reserved.
     4  Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository.
     5  
     6  */
     7  
     8  package dbmodel
     9  
    10  import (
    11  	"bytes"
    12  	"context"
    13  	"fmt"
    14  	"os"
    15  	"os/exec"
    16  	"path/filepath"
    17  	"testing"
    18  	"time"
    19  
    20  	"github.com/wcharczuk/go-incr"
    21  	"go.charczuk.com/sdk/apputil"
    22  	"go.charczuk.com/sdk/assert"
    23  	"go.charczuk.com/sdk/db"
    24  	"go.charczuk.com/sdk/db/dbutil"
    25  	"go.charczuk.com/sdk/logutil"
    26  	"go.charczuk.com/sdk/testutil"
    27  	"go.charczuk.com/sdk/uuid"
    28  )
    29  
    30  func TestMain(m *testing.M) {
    31  	testutil.New(m,
    32  		testutil.OptWithDefaultDB(
    33  			ifDebug(db.OptLog(logutil.New())),
    34  		),
    35  		testutil.OptBefore(
    36  			func(ctx context.Context) error {
    37  				return Migrations().Apply(ctx, testutil.DefaultDB())
    38  			},
    39  		),
    40  	).Run()
    41  }
    42  
    43  func ifDebug(opt db.Option) db.Option {
    44  	return func(s *db.Connection) error {
    45  		if os.Getenv("DEBUG") != "" {
    46  			opt(s)
    47  		}
    48  		return nil
    49  	}
    50  }
    51  
    52  const (
    53  	TestNodeV0Label = "test-var-00"
    54  	TestNodeV1Label = "test-var-01"
    55  	TestNodeM0Label = "test-expression"
    56  	TestNodeO0Label = "test-observer"
    57  )
    58  
    59  // CreateTestGraph creates a test graph.
    60  func CreateTestGraph(t *testing.T, mgr *dbutil.BaseManager, user *apputil.User) (*Graph, map[string]*Node) {
    61  	ctx := context.Background()
    62  	g := NewGraph()
    63  	g.UserID = user.ID
    64  	var err error
    65  	err = mgr.Invoke(ctx).Create(g)
    66  	assert.ItsNil(t, err)
    67  
    68  	v0 := Node{
    69  		ID:         uuid.V4(),
    70  		CreatedUTC: time.Now().UTC(),
    71  		GraphID:    g.ID,
    72  		UserID:     user.ID,
    73  		Label:      TestNodeV0Label,
    74  		NodeType:   "var",
    75  		OutputType: "string",
    76  	}
    77  
    78  	err = mgr.Invoke(ctx).Create(v0)
    79  	assert.ItsNil(t, err)
    80  
    81  	err = mgr.Invoke(ctx).Create(NodeValue{
    82  		GraphID:   g.ID,
    83  		NodeID:    v0.ID,
    84  		UserID:    user.ID,
    85  		ValueType: "string",
    86  		Value:     "hello",
    87  	})
    88  	assert.ItsNil(t, err)
    89  
    90  	v1 := Node{
    91  		ID:         uuid.V4(),
    92  		CreatedUTC: time.Now().UTC(),
    93  		GraphID:    g.ID,
    94  		UserID:     user.ID,
    95  		Label:      TestNodeV1Label,
    96  		NodeType:   "var",
    97  		OutputType: "string",
    98  	}
    99  
   100  	err = mgr.Invoke(ctx).Create(v1)
   101  	assert.ItsNil(t, err)
   102  
   103  	err = mgr.Invoke(ctx).Create(NodeValue{
   104  		GraphID:   g.ID,
   105  		NodeID:    v1.ID,
   106  		UserID:    user.ID,
   107  		ValueType: "string",
   108  		Value:     "world",
   109  	})
   110  	assert.ItsNil(t, err)
   111  
   112  	m0 := Node{
   113  		ID:         uuid.V4(),
   114  		CreatedUTC: time.Now().UTC(),
   115  		GraphID:    g.ID,
   116  		UserID:     user.ID,
   117  		Label:      TestNodeM0Label,
   118  		NodeType:   "expression",
   119  		InputType:  "string",
   120  		OutputType: "string",
   121  		Expression: `output = input(0) + " " + input(1)`,
   122  	}
   123  
   124  	err = mgr.Invoke(ctx).Create(m0)
   125  	assert.ItsNil(t, err)
   126  
   127  	o0 := Node{
   128  		ID:         uuid.V4(),
   129  		CreatedUTC: time.Now().UTC(),
   130  		GraphID:    g.ID,
   131  		UserID:     user.ID,
   132  		NodeType:   "observer",
   133  		Label:      TestNodeO0Label,
   134  		InputType:  "string",
   135  	}
   136  
   137  	err = mgr.Invoke(ctx).Create(o0)
   138  	assert.ItsNil(t, err)
   139  
   140  	err = mgr.Invoke(ctx).Create(Edge{
   141  		GraphID:  g.ID,
   142  		UserID:   user.ID,
   143  		ParentID: v0.ID,
   144  		ChildID:  m0.ID,
   145  	})
   146  	assert.ItsNil(t, err)
   147  
   148  	err = mgr.Invoke(ctx).Create(Edge{
   149  		GraphID:  g.ID,
   150  		UserID:   user.ID,
   151  		ParentID: v1.ID,
   152  		ChildID:  m0.ID,
   153  	})
   154  	assert.ItsNil(t, err)
   155  
   156  	err = mgr.Invoke(ctx).Create(Edge{
   157  		GraphID:  g.ID,
   158  		UserID:   user.ID,
   159  		ParentID: m0.ID,
   160  		ChildID:  o0.ID,
   161  	})
   162  	assert.ItsNil(t, err)
   163  
   164  	err = mgr.Invoke(ctx).Create(GraphRecomputeHeap{
   165  		GraphID: g.ID,
   166  		UserID:  user.ID,
   167  		NodeID:  v0.ID,
   168  	})
   169  	assert.ItsNil(t, err)
   170  
   171  	err = mgr.Invoke(ctx).Create(GraphRecomputeHeap{
   172  		GraphID: g.ID,
   173  		UserID:  user.ID,
   174  		NodeID:  v1.ID,
   175  	})
   176  	assert.ItsNil(t, err)
   177  
   178  	return g, map[string]*Node{
   179  		v0.Label: &v0,
   180  		v1.Label: &v1,
   181  		m0.Label: &m0,
   182  		o0.Label: &o0,
   183  	}
   184  }
   185  
   186  func homedir(filename string) string {
   187  	var rootDir string
   188  	if rootDir = os.Getenv("INCR_DEBUG_DOT_ROOT"); rootDir == "" {
   189  		rootDir = os.ExpandEnv("$HOME/Desktop")
   190  	}
   191  	return filepath.Join(rootDir, filename)
   192  }
   193  
   194  func dumpDot(g *incr.Graph, path string) error {
   195  	if os.Getenv("INCR_DEBUG_DOT") != "true" {
   196  		return nil
   197  	}
   198  
   199  	dotContents := new(bytes.Buffer)
   200  	if err := incr.Dot(dotContents, g); err != nil {
   201  		return err
   202  	}
   203  	dotOutput, err := os.Create(os.ExpandEnv(path))
   204  	if err != nil {
   205  		return err
   206  	}
   207  	defer func() { _ = dotOutput.Close() }()
   208  	dotFullPath, err := exec.LookPath("dot")
   209  	if err != nil {
   210  		return fmt.Errorf("there was an issue finding `dot` in your path; you may need to install the `graphviz` package or similar on your platform: %w", err)
   211  	}
   212  
   213  	errOut := new(bytes.Buffer)
   214  	cmd := exec.Command(dotFullPath, "-Tpng")
   215  	cmd.Stdin = dotContents
   216  	cmd.Stdout = dotOutput
   217  	cmd.Stderr = errOut
   218  	if err := cmd.Run(); err != nil {
   219  		return fmt.Errorf("%v; %w", errOut.String(), err)
   220  	}
   221  	return nil
   222  }