github.com/Benchkram/bob@v0.0.0-20220321080157-7c8f3876e225/test/e2e/multilevelbuild/multilevelbuild_test.go (about)

     1  package multilevelbuildtest
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"os"
     9  	"os/exec"
    10  	"path/filepath"
    11  	"time"
    12  
    13  	"github.com/Benchkram/bob/bob"
    14  	"github.com/Benchkram/bob/bob/playbook"
    15  	"github.com/Benchkram/bob/pkg/file"
    16  	"github.com/Benchkram/errz"
    17  
    18  	. "github.com/onsi/ginkgo"
    19  	. "github.com/onsi/gomega"
    20  )
    21  
    22  type binaryOutputFixture struct {
    23  	path   string
    24  	output string
    25  }
    26  
    27  type requiresRebuildFixture struct {
    28  	taskname        string
    29  	requiresRebuild bool
    30  }
    31  
    32  var _ = Describe("Test bob multilevel build", func() {
    33  	Context("in a fresh environment", func() {
    34  
    35  		It("initializes bob playground", func() {
    36  			Expect(bob.CreatePlayground(dir)).NotTo(HaveOccurred())
    37  		})
    38  
    39  		It("runs build all", func() {
    40  			ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
    41  			Expect(b.Build(ctx, bob.BuildAllTargetName)).NotTo(HaveOccurred())
    42  			cancel()
    43  		})
    44  
    45  		binaries := []binaryOutputFixture{
    46  			{
    47  				path:   filepath.Join(dir, "run"),
    48  				output: "Hello Playground v1\nByebye Playground v1\n",
    49  			},
    50  			{
    51  				path:   filepath.Join(dir, bob.SecondLevelDir, "runsecondlevel"),
    52  				output: "Hello Playground v2\nByebye Playground v2\n",
    53  			},
    54  			{
    55  				path:   filepath.Join(dir, bob.SecondLevelDir, bob.ThirdLevelDir, "runthirdlevel"),
    56  				output: "Hello Playground v3\nByebye Playground v3\n",
    57  			},
    58  		}
    59  
    60  		It("checks that the built binaries exist", func() {
    61  			for _, b := range binaries {
    62  				Expect(file.Exists(b.path)).To(BeTrue(), fmt.Sprintf("%s doesn't exist", b.path))
    63  			}
    64  		})
    65  
    66  		It("checks that the built binaries produce the expected output", func() {
    67  			for _, b := range binaries {
    68  				cmd := exec.Command("./" + b.path)
    69  				var stdout, stderr bytes.Buffer
    70  				cmd.Stdout = &stdout
    71  				cmd.Stderr = &stderr
    72  
    73  				// The binarys are waiting for a ctrl-c
    74  				// to shutdown.
    75  				go func() {
    76  					time.Sleep(500 * time.Millisecond)
    77  					err := cmd.Process.Signal(os.Interrupt)
    78  					Expect(err).NotTo(HaveOccurred())
    79  				}()
    80  
    81  				err := cmd.Run()
    82  				Expect(err).NotTo(HaveOccurred())
    83  
    84  				Expect(b.output).To(Equal(stderr.String()))
    85  			}
    86  		})
    87  
    88  		It("runs build multilinetouch", func() {
    89  			ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
    90  			Expect(b.Build(ctx, "multilinetouch")).NotTo(HaveOccurred())
    91  			cancel()
    92  		})
    93  
    94  		It("checks that the touched files really exist", func() {
    95  			files := []string{
    96  				"multilinefile1",
    97  				"multilinefile2",
    98  				"multilinefile3",
    99  				"multilinefile4",
   100  				"multilinefile5",
   101  			}
   102  
   103  			for _, f := range files {
   104  				Expect(file.Exists(f)).To(BeTrue(), fmt.Sprintf("%s doesn't exist", f))
   105  			}
   106  		})
   107  
   108  		It("checks that we do not require a rebuild of any of the levels", func() {
   109  			fixtures := []requiresRebuildFixture{
   110  				{
   111  					taskname:        bob.BuildAllTargetName,
   112  					requiresRebuild: false,
   113  				},
   114  				{
   115  					taskname:        "second-level/build2",
   116  					requiresRebuild: false,
   117  				},
   118  				{
   119  					taskname:        "second-level/third-level/build3",
   120  					requiresRebuild: false,
   121  				},
   122  			}
   123  
   124  			requiresRebuildMustMatchFixtures(b, fixtures)
   125  		})
   126  
   127  		It("changes a file of the second-level", func() {
   128  			f := filepath.Join(dir, bob.SecondLevelDir, "main2.go")
   129  			c, err := ioutil.ReadFile(f)
   130  			Expect(err).NotTo(HaveOccurred())
   131  
   132  			c = append(c, []byte("// some random comment so the file content is changed")...)
   133  
   134  			err = ioutil.WriteFile(f, c, 0644)
   135  			Expect(err).NotTo(HaveOccurred())
   136  		})
   137  
   138  		It("checks that we now require a rebuild of the second- and first-level, but not the third-level", func() {
   139  			fixtures := []requiresRebuildFixture{
   140  				{
   141  					taskname:        bob.BuildAllTargetName,
   142  					requiresRebuild: true,
   143  				},
   144  				{
   145  					taskname:        "second-level/build2",
   146  					requiresRebuild: true,
   147  				},
   148  				{
   149  					taskname:        "second-level/third-level/build3",
   150  					requiresRebuild: false,
   151  				},
   152  			}
   153  
   154  			requiresRebuildMustMatchFixtures(b, fixtures)
   155  		})
   156  
   157  		It("runs build all again", func() {
   158  			ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
   159  			Expect(b.Build(ctx, bob.BuildAllTargetName)).NotTo(HaveOccurred())
   160  			cancel()
   161  		})
   162  
   163  		It("checks that we do not require a rebuild of any of the levels", func() {
   164  			fixtures := []requiresRebuildFixture{
   165  				{
   166  					taskname:        bob.BuildAllTargetName,
   167  					requiresRebuild: false,
   168  				},
   169  				{
   170  					taskname:        "second-level/build2",
   171  					requiresRebuild: false,
   172  				},
   173  				{
   174  					taskname:        "second-level/third-level/build3",
   175  					requiresRebuild: false,
   176  				},
   177  			}
   178  
   179  			requiresRebuildMustMatchFixtures(b, fixtures)
   180  		})
   181  
   182  		It("changes a file of the third-level", func() {
   183  			f := filepath.Join(dir, bob.SecondLevelDir, bob.ThirdLevelDir, "main3.go")
   184  			c, err := ioutil.ReadFile(f)
   185  			Expect(err).NotTo(HaveOccurred())
   186  
   187  			c = append(c, []byte("// some random comment so the file content is changed")...)
   188  
   189  			err = ioutil.WriteFile(f, c, 0644)
   190  			Expect(err).NotTo(HaveOccurred())
   191  		})
   192  
   193  		It("checks that we now require a rebuild of the third-, second- and first-level", func() {
   194  			fixtures := []requiresRebuildFixture{
   195  				{
   196  					taskname:        bob.BuildAllTargetName,
   197  					requiresRebuild: true,
   198  				},
   199  				{
   200  					taskname:        "second-level/build2",
   201  					requiresRebuild: true,
   202  				},
   203  				{
   204  					taskname:        "second-level/third-level/build3",
   205  					requiresRebuild: true,
   206  				},
   207  			}
   208  
   209  			err := artifactsClean()
   210  			Expect(err).NotTo(HaveOccurred())
   211  			requiresRebuildMustMatchFixtures(b, fixtures)
   212  		})
   213  	})
   214  })
   215  
   216  func requiresRebuildMustMatchFixtures(b *bob.B, fixtures []requiresRebuildFixture) {
   217  	aggregate, err := b.Aggregate()
   218  	Expect(err).NotTo(HaveOccurred())
   219  	pb, err := aggregate.Playbook(bob.BuildAllTargetName)
   220  	Expect(err).NotTo(HaveOccurred())
   221  
   222  	err = pb.Build(context.Background())
   223  	errz.Log(err)
   224  	Expect(err).NotTo(HaveOccurred())
   225  
   226  	for _, f := range fixtures {
   227  		ts, err := pb.TaskStatus(f.taskname)
   228  		Expect(err).NotTo(HaveOccurred())
   229  		requiresRebuild := ts.State() != playbook.StateNoRebuildRequired
   230  
   231  		Expect(f.requiresRebuild).To(Equal(requiresRebuild), fmt.Sprintf("task's %q rebuild requirement differ, got: %t, want: %t", f.taskname, requiresRebuild, f.requiresRebuild))
   232  	}
   233  }