github.com/avenga/couper@v1.12.2/config/configload/merge_internal_test.go (about) 1 package configload 2 3 import ( 4 "bytes" 5 "testing" 6 7 "github.com/google/go-cmp/cmp" 8 "github.com/hashicorp/hcl/v2" 9 "github.com/hashicorp/hcl/v2/gohcl" 10 "github.com/hashicorp/hcl/v2/hclsyntax" 11 "github.com/hashicorp/hcl/v2/hclwrite" 12 13 "github.com/avenga/couper/config/parser" 14 "github.com/avenga/couper/internal/test" 15 ) 16 17 func Test_mergeServers_ServerTLS(t *testing.T) { 18 tests := []struct { 19 name string 20 content []string 21 want string 22 wantErr bool 23 }{ 24 {"normal, one file", []string{`server { 25 tls { 26 server_certificate { 27 attr1 = "val1" 28 } 29 server_certificate { 30 attr1 = "val2" 31 } 32 client_certificate { 33 attr1 = "val3" 34 } 35 } 36 }`}, `server { 37 tls { 38 client_certificate { 39 attr1 = "val3" 40 } 41 server_certificate { 42 attr1 = "val1" 43 } 44 server_certificate { 45 attr1 = "val2" 46 } 47 } 48 } 49 `, false}, 50 {"two files, override", []string{`server { 51 tls { 52 server_certificate { 53 attr1 = "val1" 54 } 55 server_certificate { 56 attr1 = "val2" 57 } 58 server_certificate "named" { 59 attr1 = "val3" 60 } 61 client_certificate { 62 attr1 = "val1" 63 } 64 client_certificate { 65 attr1 = "val2" 66 } 67 client_certificate "named" { 68 attr1 = "val3" 69 } 70 } 71 }`, `server { 72 tls { 73 server_certificate { 74 attr2 = "val4" 75 } 76 server_certificate "named" { 77 attr2 = "val5" 78 } 79 client_certificate { 80 attr2 = "val6" 81 } 82 client_certificate "named" { 83 attr2 = "val7" 84 } 85 } 86 }`}, `server { 87 tls { 88 client_certificate { 89 attr2 = "val6" 90 } 91 server_certificate { 92 attr2 = "val4" 93 } 94 client_certificate "named" { 95 attr2 = "val7" 96 } 97 server_certificate "named" { 98 attr2 = "val5" 99 } 100 } 101 } 102 `, false}, 103 {"two files, merge", []string{`server { 104 tls { 105 server_certificate "example1.com" { 106 attr1 = "val1" 107 } 108 client_certificate "a" { 109 attr1 = "val2" 110 } 111 client_certificate { 112 attr1 = "val3" 113 } 114 } 115 }`, `server { 116 tls { 117 server_certificate "example2.com" { 118 attr2 = "val2" 119 } 120 server_certificate { 121 attr2 = "val3" 122 } 123 client_certificate "b" { 124 attr2 = "val6" 125 } 126 } 127 }`}, `server { 128 tls { 129 client_certificate { 130 attr1 = "val3" 131 } 132 server_certificate { 133 attr2 = "val3" 134 } 135 client_certificate "a" { 136 attr1 = "val2" 137 } 138 client_certificate "b" { 139 attr2 = "val6" 140 } 141 server_certificate "example1.com" { 142 attr1 = "val1" 143 } 144 server_certificate "example2.com" { 145 attr2 = "val2" 146 } 147 } 148 } 149 `, false}, 150 } 151 for _, tt := range tests { 152 t.Run(tt.name, func(st *testing.T) { 153 hlp := test.New(st) 154 155 parsedBodies, err := parseBodies(tt.content) 156 hlp.Must(err) 157 158 blocks, err := mergeServers(parsedBodies, nil) 159 hlp.Must(err) 160 161 result := writeBlocks(blocks) 162 163 if (err != nil) != tt.wantErr { 164 t.Errorf("bodiesToConfig() error = %v, wantErr %v", err, tt.wantErr) 165 return 166 } 167 168 if diff := cmp.Diff(result, tt.want); diff != "" { 169 t.Error(diff) 170 } 171 }) 172 } 173 } 174 175 func Test_mergeDefinitions_BackendTLS(t *testing.T) { 176 tests := []struct { 177 name string 178 content []string 179 want string 180 wantErr bool 181 }{ 182 {"normal, one file", []string{`definitions { 183 backend "one" { 184 tls { 185 server_ca_certificate_file = "same.crt" 186 } 187 } 188 }`}, `definitions { 189 backend "one" { 190 tls { 191 server_ca_certificate_file = "same.crt" 192 } 193 } 194 } 195 `, false}, 196 {"two files, replace", []string{`definitions { 197 backend "one" { 198 origin = "https://localhost" 199 tls { 200 server_ca_certificate_file = "one.crt" 201 } 202 } 203 }`, `definitions { 204 backend "one" { 205 tls { 206 server_ca_certificate_file = "two.crt" 207 } 208 } 209 }`}, `definitions { 210 backend "one" { 211 tls { 212 server_ca_certificate_file = "two.crt" 213 } 214 } 215 } 216 `, false}, 217 {"two files, append", []string{`definitions { 218 backend "one" { 219 tls { 220 server_ca_certificate_file = "one.crt" 221 } 222 } 223 }`, `definitions { 224 backend "two" { 225 tls { 226 server_ca_certificate_file = "two.crt" 227 } 228 } 229 }`}, `definitions { 230 backend "one" { 231 tls { 232 server_ca_certificate_file = "one.crt" 233 } 234 } 235 backend "two" { 236 tls { 237 server_ca_certificate_file = "two.crt" 238 } 239 } 240 } 241 `, false}, 242 } 243 for _, tt := range tests { 244 t.Run(tt.name, func(st *testing.T) { 245 hlp := test.New(st) 246 247 parsedBodies, err := parseBodies(tt.content) 248 hlp.Must(err) 249 250 block, _, err := mergeDefinitions(parsedBodies) 251 hlp.Must(err) 252 253 result := writeBlocks(hclsyntax.Blocks{block}) 254 255 if (err != nil) != tt.wantErr { 256 t.Errorf("bodiesToConfig() error = %v, wantErr %v", err, tt.wantErr) 257 return 258 } 259 260 if diff := cmp.Diff(result, tt.want); diff != "" { 261 t.Error(diff) 262 } 263 }) 264 } 265 } 266 267 func writeBlocks(blocks hclsyntax.Blocks) string { 268 f := hclwrite.NewEmptyFile() 269 root := f.Body() 270 271 appendSorted(root, blocks) 272 273 b := &bytes.Buffer{} 274 _, _ = f.WriteTo(b) 275 return b.String() 276 } 277 278 func parseBodies(bodies []string) ([]*hclsyntax.Body, error) { 279 var parsedBodies []*hclsyntax.Body 280 for _, bodyStr := range bodies { 281 body, err := parser.Load([]byte(bodyStr), "") 282 if err != nil { 283 return nil, err 284 } 285 parsedBodies = append(parsedBodies, body) 286 } 287 return parsedBodies, nil 288 } 289 290 func appendBlock(parent *hclwrite.Body, block *hclsyntax.Block) { 291 writeBlock := gohcl.EncodeAsBlock(block, block.Type) 292 writeBlock.SetLabels(block.Labels) 293 294 appendSorted(writeBlock.Body(), block.Body.Blocks) 295 296 appendAttrs(writeBlock.Body(), block.Body.Attributes) 297 298 parent.AppendBlock(writeBlock) 299 } 300 301 func appendAttrs(parent *hclwrite.Body, attributes hclsyntax.Attributes) { 302 for _, attr := range attributes { 303 v, _ := attr.Expr.Value(&hcl.EvalContext{}) 304 parent.SetAttributeValue(attr.Name, v) 305 } 306 } 307 308 func appendSorted(parent *hclwrite.Body, blocks hclsyntax.Blocks) { 309 named := namedBlocks{} 310 for _, block := range blocks { 311 if len(block.Labels) > 0 { 312 named[block.Type+"_"+block.Labels[0]] = block 313 } else { 314 appendBlock(parent, block) 315 } 316 } 317 for _, k := range getSortedMapKeys(named) { 318 appendBlock(parent, named[k]) 319 } 320 }