github.com/joshdk/godel@v0.0.0-20170529232908-862138a45aee/apps/distgo/cmd/artifacts/artifacts_test.go (about) 1 // Copyright 2016 Palantir Technologies, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package artifacts_test 16 17 import ( 18 "io/ioutil" 19 "path" 20 "path/filepath" 21 "testing" 22 "time" 23 24 "github.com/nmiyake/pkg/dirs" 25 "github.com/stretchr/testify/assert" 26 "github.com/stretchr/testify/require" 27 28 "github.com/palantir/godel/apps/distgo/cmd/artifacts" 29 "github.com/palantir/godel/apps/distgo/cmd/build" 30 "github.com/palantir/godel/apps/distgo/params" 31 "github.com/palantir/godel/apps/distgo/pkg/osarch" 32 ) 33 34 func TestBuildArtifacts(t *testing.T) { 35 tmpDir, cleanup, err := dirs.TempDir("", "") 36 defer cleanup() 37 require.NoError(t, err) 38 39 for i, currCase := range []struct { 40 specs func(projectDir string) []params.ProductBuildSpecWithDeps 41 osArchs []osarch.OSArch 42 want map[string][]string 43 }{ 44 // empty spec 45 { 46 specs: func(projectDir string) []params.ProductBuildSpecWithDeps { 47 return []params.ProductBuildSpecWithDeps{} 48 }, 49 want: map[string][]string{}, 50 }, 51 // returns paths for all OS/arch combinations if requested osArchs is empty 52 { 53 specs: func(projectDir string) []params.ProductBuildSpecWithDeps { 54 return []params.ProductBuildSpecWithDeps{ 55 createSpec(projectDir, "foo", "0.1.0", []osarch.OSArch{ 56 {OS: "darwin", Arch: "amd64"}, 57 {OS: "darwin", Arch: "386"}, 58 {OS: "linux", Arch: "amd64"}, 59 }, ¶ms.SLSDistInfo{}), 60 } 61 }, 62 want: map[string][]string{ 63 "foo": { 64 path.Join("build", "darwin-amd64", "foo"), 65 path.Join("build", "darwin-386", "foo"), 66 path.Join("build", "linux-amd64", "foo"), 67 }, 68 }, 69 }, 70 // returns only path to requested OS/arch 71 { 72 specs: func(projectDir string) []params.ProductBuildSpecWithDeps { 73 return []params.ProductBuildSpecWithDeps{ 74 createSpec(projectDir, "foo", "0.1.0", []osarch.OSArch{ 75 {OS: "darwin", Arch: "amd64"}, 76 {OS: "linux", Arch: "amd64"}, 77 }, ¶ms.SLSDistInfo{}), 78 } 79 }, 80 osArchs: []osarch.OSArch{{OS: "darwin", Arch: "amd64"}}, 81 want: map[string][]string{ 82 "foo": { 83 path.Join("build", "darwin-amd64", "foo"), 84 }, 85 }, 86 }, 87 // path to windows executable includes ".exe" 88 { 89 specs: func(projectDir string) []params.ProductBuildSpecWithDeps { 90 return []params.ProductBuildSpecWithDeps{ 91 createSpec(projectDir, "foo", "0.1.0", []osarch.OSArch{ 92 {OS: "windows", Arch: "amd64"}, 93 }, ¶ms.SLSDistInfo{}), 94 } 95 }, 96 want: map[string][]string{ 97 "foo": { 98 path.Join("build", "windows-amd64", "foo.exe"), 99 }, 100 }, 101 }, 102 // returns empty if os/arch that is not part of the spec is requested 103 { 104 specs: func(projectDir string) []params.ProductBuildSpecWithDeps { 105 return []params.ProductBuildSpecWithDeps{ 106 createSpec(projectDir, "foo", "0.1.0", []osarch.OSArch{ 107 {OS: "darwin", Arch: "amd64"}, 108 {OS: "linux", Arch: "amd64"}, 109 }, ¶ms.SLSDistInfo{}), 110 } 111 }, 112 osArchs: []osarch.OSArch{{OS: "windows", Arch: "amd64"}}, 113 want: map[string][]string{}, 114 }, 115 } { 116 currProjectDir, err := ioutil.TempDir(tmpDir, "") 117 require.NoError(t, err) 118 119 // relative path 120 got, err := artifacts.BuildArtifacts(currCase.specs(currProjectDir), artifacts.BuildArtifactsParams{ 121 OSArchs: currCase.osArchs, 122 }) 123 require.NoError(t, err, "Case %d", i) 124 assert.Equal(t, currCase.want, toMap(got), "Case %d", i) 125 126 // absolute path 127 got, err = artifacts.BuildArtifacts(currCase.specs(currProjectDir), artifacts.BuildArtifactsParams{ 128 AbsPath: true, 129 OSArchs: currCase.osArchs, 130 }) 131 require.NoError(t, err, "Case %d", i) 132 assert.Equal(t, toAbs(currCase.want, currProjectDir), toMap(got), "Case %d", i) 133 } 134 } 135 136 func TestBuildArtifactsRequiresBuild(t *testing.T) { 137 tmpDir, cleanup, err := dirs.TempDir(".", "") 138 defer cleanup() 139 require.NoError(t, err) 140 141 tmpDir, err = filepath.Abs(tmpDir) 142 require.NoError(t, err) 143 144 for i, currCase := range []struct { 145 specs func(projectDir string) params.ProductBuildSpecWithDeps 146 osArchs []osarch.OSArch 147 requiresBuild bool 148 beforeAction func(projectDir string, specs []params.ProductBuildSpec) 149 want map[string][]string 150 }{ 151 // returns paths to all artifacts if build has not happened 152 { 153 specs: func(projectDir string) params.ProductBuildSpecWithDeps { 154 return createSpec(projectDir, "foo", "0.1.0", []osarch.OSArch{ 155 {OS: "darwin", Arch: "amd64"}, 156 {OS: "darwin", Arch: "386"}, 157 {OS: "linux", Arch: "amd64"}, 158 }, ¶ms.SLSDistInfo{}) 159 }, 160 want: map[string][]string{ 161 "foo": { 162 path.Join("build", "darwin-amd64", "foo"), 163 path.Join("build", "darwin-386", "foo"), 164 path.Join("build", "linux-amd64", "foo"), 165 }, 166 }, 167 }, 168 // returns empty if all artifacts exist and are up-to-date 169 { 170 specs: func(projectDir string) params.ProductBuildSpecWithDeps { 171 return createSpec(projectDir, "foo", "0.1.0", []osarch.OSArch{ 172 {OS: "darwin", Arch: "amd64"}, 173 {OS: "darwin", Arch: "386"}, 174 {OS: "linux", Arch: "amd64"}, 175 }, ¶ms.SLSDistInfo{}) 176 }, 177 beforeAction: func(projectDir string, specs []params.ProductBuildSpec) { 178 // build products 179 err = build.Run(specs, nil, build.Context{ 180 Parallel: false, 181 }, ioutil.Discard) 182 require.NoError(t, err) 183 }, 184 want: map[string][]string{}, 185 }, 186 // returns paths to all artifacts if input source file has been modified 187 { 188 specs: func(projectDir string) params.ProductBuildSpecWithDeps { 189 return createSpec(projectDir, "foo", "0.1.0", []osarch.OSArch{ 190 {OS: "darwin", Arch: "amd64"}, 191 {OS: "darwin", Arch: "386"}, 192 {OS: "linux", Arch: "amd64"}, 193 }, ¶ms.SLSDistInfo{}) 194 }, 195 beforeAction: func(projectDir string, specs []params.ProductBuildSpec) { 196 // build products 197 err := build.Run(specs, nil, build.Context{ 198 Parallel: false, 199 }, ioutil.Discard) 200 require.NoError(t, err) 201 202 // sleep to ensure that modification time will differ 203 time.Sleep(time.Second) 204 205 // update source file 206 err = ioutil.WriteFile(path.Join(projectDir, "main.go"), []byte("package main; func main(){}"), 0644) 207 require.NoError(t, err) 208 }, 209 want: map[string][]string{ 210 "foo": { 211 path.Join("build", "darwin-amd64", "foo"), 212 path.Join("build", "darwin-386", "foo"), 213 path.Join("build", "linux-amd64", "foo"), 214 }, 215 }, 216 }, 217 // if OS/Archs are specified, results are filtered base on that 218 { 219 specs: func(projectDir string) params.ProductBuildSpecWithDeps { 220 return createSpec(projectDir, "foo", "0.1.0", []osarch.OSArch{ 221 {OS: "darwin", Arch: "amd64"}, 222 {OS: "darwin", Arch: "386"}, 223 {OS: "linux", Arch: "amd64"}, 224 }, ¶ms.SLSDistInfo{}) 225 }, 226 osArchs: []osarch.OSArch{ 227 {OS: "windows", Arch: "amd64"}, 228 }, 229 want: map[string][]string{}, 230 }, 231 } { 232 currProjectDir, err := ioutil.TempDir(tmpDir, "") 233 require.NoError(t, err) 234 235 err = ioutil.WriteFile(path.Join(currProjectDir, "main.go"), []byte("package main; func main(){}"), 0644) 236 require.NoError(t, err) 237 238 specWithDeps := currCase.specs(currProjectDir) 239 if currCase.beforeAction != nil { 240 currCase.beforeAction(currProjectDir, specWithDeps.AllSpecs()) 241 } 242 243 got, err := artifacts.BuildArtifacts([]params.ProductBuildSpecWithDeps{specWithDeps}, artifacts.BuildArtifactsParams{ 244 RequiresBuild: true, 245 OSArchs: currCase.osArchs, 246 }) 247 require.NoError(t, err, "Case %d", i) 248 assert.Equal(t, currCase.want, toMap(got), "Case %d", i) 249 } 250 } 251 252 func TestDistArtifacts(t *testing.T) { 253 tmpDir, cleanup, err := dirs.TempDir("", "") 254 defer cleanup() 255 require.NoError(t, err) 256 257 for i, currCase := range []struct { 258 specs func(projectDir string) []params.ProductBuildSpecWithDeps 259 want map[string][]string 260 }{ 261 { 262 specs: func(projectDir string) []params.ProductBuildSpecWithDeps { 263 return []params.ProductBuildSpecWithDeps{} 264 }, 265 want: map[string][]string{}, 266 }, 267 { 268 specs: func(projectDir string) []params.ProductBuildSpecWithDeps { 269 return []params.ProductBuildSpecWithDeps{ 270 createSpec(projectDir, "foo", "0.1.0", nil, ¶ms.SLSDistInfo{}), 271 } 272 }, 273 want: map[string][]string{ 274 "foo": {"foo-0.1.0.sls.tgz"}, 275 }, 276 }, 277 { 278 specs: func(projectDir string) []params.ProductBuildSpecWithDeps { 279 return []params.ProductBuildSpecWithDeps{ 280 createSpec(projectDir, "foo", "0.1.0", nil, ¶ms.SLSDistInfo{}), 281 createSpec(projectDir, "bar", "unspecified", nil, ¶ms.SLSDistInfo{}), 282 } 283 }, 284 want: map[string][]string{ 285 "foo": {"foo-0.1.0.sls.tgz"}, 286 "bar": {"bar-unspecified.sls.tgz"}, 287 }, 288 }, 289 { 290 specs: func(projectDir string) []params.ProductBuildSpecWithDeps { 291 return []params.ProductBuildSpecWithDeps{ 292 createSpecWithDists(projectDir, "foo", "0.1.0", nil, params.Dist{Info: ¶ms.SLSDistInfo{}}, params.Dist{Info: ¶ms.BinDistInfo{}}), 293 } 294 }, 295 want: map[string][]string{ 296 "foo": { 297 "foo-0.1.0.sls.tgz", 298 "foo-0.1.0.tgz", 299 }, 300 }, 301 }, 302 { 303 specs: func(projectDir string) []params.ProductBuildSpecWithDeps { 304 return []params.ProductBuildSpecWithDeps{ 305 createSpecWithDists(projectDir, "foo", "0.1.0", nil, params.Dist{Info: ¶ms.OSArchsBinDistInfo{ 306 OSArchs: []osarch.OSArch{ 307 { 308 OS: "darwin", 309 Arch: "amd64", 310 }, 311 }, 312 }}, params.Dist{Info: ¶ms.OSArchsBinDistInfo{ 313 OSArchs: []osarch.OSArch{ 314 { 315 OS: "linux", 316 Arch: "amd64", 317 }, 318 }, 319 }}), 320 } 321 }, 322 want: map[string][]string{ 323 "foo": { 324 "foo-0.1.0-darwin-amd64.tgz", 325 "foo-0.1.0-linux-amd64.tgz", 326 }, 327 }, 328 }, 329 { 330 specs: func(projectDir string) []params.ProductBuildSpecWithDeps { 331 return []params.ProductBuildSpecWithDeps{ 332 createSpec(projectDir, "foo", "0.1.0", nil, ¶ms.OSArchsBinDistInfo{ 333 OSArchs: []osarch.OSArch{ 334 { 335 OS: "darwin", 336 Arch: "amd64", 337 }, 338 { 339 OS: "linux", 340 Arch: "amd64", 341 }, 342 }, 343 }), 344 } 345 }, 346 want: map[string][]string{ 347 "foo": { 348 "foo-0.1.0-darwin-amd64.tgz", 349 "foo-0.1.0-linux-amd64.tgz", 350 }, 351 }, 352 }, 353 } { 354 currProjectDir, err := ioutil.TempDir(tmpDir, "") 355 require.NoError(t, err) 356 357 // relative path 358 got, err := artifacts.DistArtifacts(currCase.specs(currProjectDir), false) 359 require.NoError(t, err, "Case %d", i) 360 assert.Equal(t, currCase.want, toMap(got), "Case %d", i) 361 362 // absolute path 363 got, err = artifacts.DistArtifacts(currCase.specs(currProjectDir), true) 364 require.NoError(t, err, "Case %d", i) 365 assert.Equal(t, toAbs(currCase.want, currProjectDir), toMap(got), "Case %d", i) 366 } 367 } 368 369 func toAbs(input map[string][]string, baseDir string) map[string][]string { 370 absWant := make(map[string][]string, len(input)) 371 for k, v := range input { 372 absWant[k] = make([]string, len(v)) 373 for i := range v { 374 absWant[k][i] = path.Join(baseDir, v[i]) 375 } 376 } 377 return absWant 378 } 379 380 func createSpec(projectDir, productName, productVersion string, osArchs []osarch.OSArch, distInfo params.DistInfo) params.ProductBuildSpecWithDeps { 381 return createSpecWithDists(projectDir, productName, productVersion, osArchs, params.Dist{Info: distInfo}) 382 } 383 384 func createSpecWithDists(projectDir, productName, productVersion string, osArchs []osarch.OSArch, dists ...params.Dist) params.ProductBuildSpecWithDeps { 385 return params.ProductBuildSpecWithDeps{ 386 Spec: params.ProductBuildSpec{ 387 Product: params.Product{ 388 Build: params.Build{ 389 OutputDir: "build", 390 OSArchs: osArchs, 391 }, 392 Dist: dists, 393 }, 394 ProjectDir: projectDir, 395 ProductName: productName, 396 ProductVersion: productVersion, 397 }, 398 } 399 } 400 401 func toMap(input map[string]artifacts.OrderedStringSliceMap) map[string][]string { 402 output := make(map[string][]string, len(input)) 403 for product, m := range input { 404 keys := m.Keys() 405 var values []string 406 for _, k := range keys { 407 values = append(values, m.Get(k)...) 408 } 409 output[product] = values 410 } 411 return output 412 }