github.com/amplia-iiot/yutil@v1.0.1-0.20231229120411-5d96a4c5a136/pkg/merge/files_test.go (about)

     1  /*
     2  Copyright (c) 2021-2023 amplia-iiot
     3  
     4  Permission is hereby granted, free of charge, to any person obtaining a copy
     5  of this software and associated documentation files (the "Software"), to deal
     6  in the Software without restriction, including without limitation the rights
     7  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     8  copies of the Software, and to permit persons to whom the Software is
     9  furnished to do so, subject to the following conditions:
    10  
    11  The above copyright notice and this permission notice shall be included in all
    12  copies or substantial portions of the Software.
    13  
    14  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    15  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    16  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    17  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    18  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    19  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    20  SOFTWARE.
    21  */
    22  
    23  package merge
    24  
    25  import (
    26  	"fmt"
    27  	"os"
    28  	"path"
    29  	"runtime"
    30  	"strings"
    31  	"testing"
    32  
    33  	"github.com/amplia-iiot/yutil/internal/io"
    34  	itesting "github.com/amplia-iiot/yutil/internal/testing"
    35  )
    36  
    37  func init() {
    38  	// Go to root folder to access testdata/
    39  	_, filename, _, _ := runtime.Caller(0)
    40  	dir := path.Join(path.Dir(filename), "..", "..")
    41  	err := os.Chdir(dir)
    42  	if err != nil {
    43  		panic(err)
    44  	}
    45  	// Create tmp folder
    46  	if !io.Exists("tmp") {
    47  		err = os.Mkdir("tmp", 0700)
    48  		if err != nil {
    49  			panic(err)
    50  		}
    51  	}
    52  }
    53  
    54  func TestMergeFiles(t *testing.T) {
    55  	for _, i := range []struct {
    56  		base    string
    57  		changes string
    58  	}{
    59  		{"base", "dev"},
    60  		{"base", "prod"},
    61  	} {
    62  		merged, err := MergeFiles(fileToBeMerged(i.base), fileToBeMerged(i.changes))
    63  		if err != nil {
    64  			t.Fatal(err)
    65  		}
    66  		expectedContent := itesting.ReadFile(t, expectedFile([]string{i.base, i.changes}))
    67  		itesting.AssertEqual(t, format(t, expectedContent), merged)
    68  	}
    69  }
    70  
    71  func TestMergeAllFiles(t *testing.T) {
    72  	for _, files := range [][]string{
    73  		{"base", "dev"},
    74  		{"base", "prod"},
    75  		{"base", "dev", "docker"},
    76  		{"base", "prod", "docker"},
    77  	} {
    78  		merged, err := MergeAllFiles(filesToBeMerged(files))
    79  		if err != nil {
    80  			t.Fatal(err)
    81  		}
    82  		expectedContent := itesting.ReadFile(t, expectedFile(files))
    83  		itesting.AssertEqual(t, format(t, expectedContent), merged)
    84  	}
    85  }
    86  
    87  func TestMergeFilesInvalid(t *testing.T) {
    88  	for _, i := range []struct {
    89  		base     string
    90  		changes  string
    91  		expected string
    92  	}{
    93  		// Parsing error
    94  		{
    95  			base:     "invalid",
    96  			changes:  "dev",
    97  			expected: "cannot unmarshal",
    98  		},
    99  		{
   100  			base:     "base",
   101  			changes:  "invalid",
   102  			expected: "cannot unmarshal",
   103  		},
   104  		// Not exists
   105  		{
   106  			base:     "not-exists",
   107  			changes:  "dev",
   108  			expected: "no such file or directory",
   109  		},
   110  		{
   111  			base:     "base",
   112  			changes:  "not-exists",
   113  			expected: "no such file or directory",
   114  		},
   115  	} {
   116  		merged, err := MergeFiles(fileToBeMerged(i.base), fileToBeMerged(i.changes))
   117  		itesting.AssertError(t, i.expected, err)
   118  		if merged != "" {
   119  			t.Fatalf("Should not have merged")
   120  		}
   121  	}
   122  }
   123  
   124  func TestMergeAllFilesInvalid(t *testing.T) {
   125  	for _, i := range []struct {
   126  		files    []string
   127  		expected string
   128  	}{
   129  		// At least two
   130  		{
   131  			files:    []string{},
   132  			expected: "slice must contain at least two files",
   133  		},
   134  		{
   135  			files:    []string{"base"},
   136  			expected: "slice must contain at least two files",
   137  		},
   138  		// Parsing error
   139  		{
   140  			files:    []string{"base", "invalid"},
   141  			expected: "cannot unmarshal",
   142  		},
   143  		{
   144  			files:    []string{"invalid", "prod"},
   145  			expected: "cannot unmarshal",
   146  		},
   147  		{
   148  			files:    []string{"invalid", "prod", "docker"},
   149  			expected: "cannot unmarshal",
   150  		},
   151  		{
   152  			files:    []string{"base", "prod", "invalid"},
   153  			expected: "cannot unmarshal",
   154  		},
   155  		// Not exists
   156  		{
   157  			files:    []string{"base", "not-exists"},
   158  			expected: "no such file or directory",
   159  		},
   160  		{
   161  			files:    []string{"base", "prod", "not-exists"},
   162  			expected: "no such file or directory",
   163  		},
   164  	} {
   165  		merged, err := MergeAllFiles(filesToBeMerged(i.files))
   166  		itesting.AssertError(t, i.expected, err)
   167  		if merged != "" {
   168  			t.Fatalf("Should not have merged")
   169  		}
   170  	}
   171  }
   172  
   173  func TestMergeStdinWithFiles(t *testing.T) {
   174  	for _, i := range []struct {
   175  		stdin    string
   176  		files    []string
   177  		expected string
   178  	}{
   179  		{
   180  			stdin: "app: {env: {test: true}}",
   181  			files: []string{"base"},
   182  			expected: `app:
   183    api:
   184      url: http://example.com
   185      version: v1
   186    cluster:
   187      hosts:
   188      - http://one.example.com
   189      - http://two.example.com
   190    description: YAML utils
   191    env:
   192      test: true
   193    long-description: Common functionality for working with YAML files
   194    name: yutil
   195    version: 1.0.0
   196  `,
   197  		},
   198  		{
   199  			stdin: "app: {env: {test: true}}",
   200  			files: []string{"base", "dev"},
   201  			expected: `app:
   202    api:
   203      url: http://localhost:8080
   204      version: v1-dev
   205    cluster:
   206      hosts:
   207      - http://localhost:8081
   208      - http://localhost:8082
   209    description: YAML utils
   210    env:
   211      dev: true
   212      test: true
   213    long-description: Common functionality for working with YAML files
   214    name: yutil
   215    version: 1.0.0-alpha
   216  `,
   217  		},
   218  		{
   219  			stdin: "{app: {env: {test: true}}, extra: extra}",
   220  			files: []string{"base", "prod", "docker"},
   221  			expected: `app:
   222    api:
   223      url: http://service
   224      version: v1
   225    cluster:
   226      hosts:
   227      - http://service-1
   228      - http://service-2
   229    description: YAML utils
   230    env:
   231      docker: true
   232      prod: true
   233      test: true
   234    long-description: Common functionality for working with YAML files
   235    name: yutil
   236    version: 1.0.0
   237  extra: extra
   238  `,
   239  		},
   240  	} {
   241  		itesting.SimulateStdinContent(t, i.stdin, func() {
   242  			merged, err := MergeStdinWithFiles(filesToBeMerged(i.files))
   243  			if err != nil {
   244  				t.Fatal(err)
   245  			}
   246  			itesting.AssertEqual(t, i.expected, merged)
   247  		})
   248  	}
   249  }
   250  
   251  func TestMergeStdinWithFilesInvalid(t *testing.T) {
   252  	for _, i := range []struct {
   253  		stdin     string
   254  		stdinFile os.File
   255  		files     []string
   256  		expected  string
   257  	}{
   258  		// At least one file
   259  		{
   260  			stdin:    "app: {env: {test: true}}",
   261  			files:    []string{},
   262  			expected: "slice must contain at least one file",
   263  		},
   264  		// Parsing error
   265  		{
   266  			stdin:    ";",
   267  			files:    []string{"base"},
   268  			expected: "cannot unmarshal",
   269  		},
   270  		// Not exists
   271  		{
   272  			stdin:    "app: {env: {test: true}}",
   273  			files:    []string{"not-exists"},
   274  			expected: "no such file or directory",
   275  		},
   276  		// Stdin error
   277  		{
   278  			stdinFile: *os.Stderr,
   279  			files:     []string{"not-exists"},
   280  			expected:  "bad file descriptor",
   281  		},
   282  	} {
   283  		test := func() {
   284  			merged, err := MergeStdinWithFiles(filesToBeMerged(i.files))
   285  			itesting.AssertError(t, i.expected, err)
   286  			if merged != "" {
   287  				t.Fatalf("Should not have merged")
   288  			}
   289  		}
   290  		if i.stdin != "" {
   291  			itesting.SimulateStdinContent(t, i.stdin, test)
   292  		} else {
   293  			itesting.SimulateStdinFile(i.stdinFile, test)
   294  		}
   295  	}
   296  }
   297  
   298  func TestMergeAllFilesToFile(t *testing.T) {
   299  	for _, files := range [][]string{
   300  		{"base", "dev"},
   301  		{"base", "prod"},
   302  		{"base", "dev", "docker"},
   303  		{"base", "prod", "docker"},
   304  		// Empty values (https://github.com/amplia-iiot/yutil/issues/3)
   305  		{"issue-3-base", "issue-3-changes"},
   306  	} {
   307  		tmpPath := itesting.TempFilePath(t, "merged-*.yml")
   308  		defer os.Remove(tmpPath)
   309  		err := MergeAllFilesToFile(filesToBeMerged(files), tmpPath)
   310  		if err != nil {
   311  			t.Fatal(err)
   312  		}
   313  		expectedContent := itesting.ReadFile(t, expectedFile(files))
   314  		mergedContent := itesting.ReadFile(t, tmpPath)
   315  		itesting.AssertEqual(t, format(t, expectedContent), mergedContent)
   316  	}
   317  }
   318  
   319  func TestMergeAllFilesToFileInvalid(t *testing.T) {
   320  	for _, i := range []struct {
   321  		files    []string
   322  		expected string
   323  	}{
   324  		// At least two file
   325  		{
   326  			files:    []string{},
   327  			expected: "slice must contain at least two files",
   328  		},
   329  		{
   330  			files:    []string{"base"},
   331  			expected: "slice must contain at least two files",
   332  		},
   333  		// Parsing error
   334  		{
   335  			files:    []string{"base", "invalid"},
   336  			expected: "cannot unmarshal",
   337  		},
   338  		// Not exists
   339  		{
   340  			files:    []string{"base", "not-exists"},
   341  			expected: "no such file or directory",
   342  		},
   343  	} {
   344  		tmpPath := itesting.TempFilePath(t, "merged-*.yml")
   345  		defer os.Remove(tmpPath)
   346  		err := MergeAllFilesToFile(filesToBeMerged(i.files), tmpPath)
   347  		itesting.AssertError(t, i.expected, err)
   348  		if io.Exists(tmpPath) {
   349  			t.Fatalf("Should not have merged")
   350  		}
   351  	}
   352  }
   353  
   354  func expectedFile(files []string) string {
   355  	// fmt.Printf("expected: %v", files)
   356  	return fmt.Sprintf("testdata/merged/%s.yml", strings.Join(files, "-"))
   357  }
   358  
   359  func fileToBeMerged(file string) string {
   360  	return fmt.Sprintf("testdata/%s.yml", file)
   361  }
   362  
   363  func filesToBeMerged(files []string) []string {
   364  	completeFiles := make([]string, len(files))
   365  	for i, file := range files {
   366  		completeFiles[i] = fileToBeMerged(file)
   367  	}
   368  	return completeFiles
   369  }