github.com/minamijoyo/terraform@v0.7.8-0.20161029001309-18b3736ba44b/builtin/providers/aws/resource_aws_s3_bucket_object_test.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "reflect" 8 "sort" 9 "testing" 10 11 "github.com/hashicorp/terraform/helper/acctest" 12 "github.com/hashicorp/terraform/helper/resource" 13 "github.com/hashicorp/terraform/terraform" 14 15 "github.com/aws/aws-sdk-go/aws" 16 "github.com/aws/aws-sdk-go/service/s3" 17 ) 18 19 func TestAccAWSS3BucketObject_source(t *testing.T) { 20 tmpFile, err := ioutil.TempFile("", "tf-acc-s3-obj-source") 21 if err != nil { 22 t.Fatal(err) 23 } 24 defer os.Remove(tmpFile.Name()) 25 26 rInt := acctest.RandInt() 27 // first write some data to the tempfile just so it's not 0 bytes. 28 err = ioutil.WriteFile(tmpFile.Name(), []byte("{anything will do }"), 0644) 29 if err != nil { 30 t.Fatal(err) 31 } 32 var obj s3.GetObjectOutput 33 34 resource.Test(t, resource.TestCase{ 35 PreCheck: func() { testAccPreCheck(t) }, 36 Providers: testAccProviders, 37 CheckDestroy: testAccCheckAWSS3BucketObjectDestroy, 38 Steps: []resource.TestStep{ 39 resource.TestStep{ 40 Config: testAccAWSS3BucketObjectConfigSource(rInt, tmpFile.Name()), 41 Check: testAccCheckAWSS3BucketObjectExists("aws_s3_bucket_object.object", &obj), 42 }, 43 }, 44 }) 45 } 46 47 func TestAccAWSS3BucketObject_content(t *testing.T) { 48 rInt := acctest.RandInt() 49 var obj s3.GetObjectOutput 50 51 resource.Test(t, resource.TestCase{ 52 PreCheck: func() { testAccPreCheck(t) }, 53 Providers: testAccProviders, 54 CheckDestroy: testAccCheckAWSS3BucketObjectDestroy, 55 Steps: []resource.TestStep{ 56 resource.TestStep{ 57 PreConfig: func() {}, 58 Config: testAccAWSS3BucketObjectConfigContent(rInt), 59 Check: testAccCheckAWSS3BucketObjectExists("aws_s3_bucket_object.object", &obj), 60 }, 61 }, 62 }) 63 } 64 65 func TestAccAWSS3BucketObject_withContentCharacteristics(t *testing.T) { 66 tmpFile, err := ioutil.TempFile("", "tf-acc-s3-obj-content-characteristics") 67 if err != nil { 68 t.Fatal(err) 69 } 70 defer os.Remove(tmpFile.Name()) 71 72 rInt := acctest.RandInt() 73 // first write some data to the tempfile just so it's not 0 bytes. 74 err = ioutil.WriteFile(tmpFile.Name(), []byte("{anything will do }"), 0644) 75 if err != nil { 76 t.Fatal(err) 77 } 78 79 var obj s3.GetObjectOutput 80 81 resource.Test(t, resource.TestCase{ 82 PreCheck: func() { testAccPreCheck(t) }, 83 Providers: testAccProviders, 84 CheckDestroy: testAccCheckAWSS3BucketObjectDestroy, 85 Steps: []resource.TestStep{ 86 resource.TestStep{ 87 Config: testAccAWSS3BucketObjectConfig_withContentCharacteristics(rInt, tmpFile.Name()), 88 Check: resource.ComposeTestCheckFunc( 89 testAccCheckAWSS3BucketObjectExists("aws_s3_bucket_object.object", &obj), 90 resource.TestCheckResourceAttr( 91 "aws_s3_bucket_object.object", "content_type", "binary/octet-stream"), 92 ), 93 }, 94 }, 95 }) 96 } 97 98 func TestAccAWSS3BucketObject_updates(t *testing.T) { 99 tmpFile, err := ioutil.TempFile("", "tf-acc-s3-obj-updates") 100 if err != nil { 101 t.Fatal(err) 102 } 103 defer os.Remove(tmpFile.Name()) 104 105 rInt := acctest.RandInt() 106 err = ioutil.WriteFile(tmpFile.Name(), []byte("initial object state"), 0644) 107 if err != nil { 108 t.Fatal(err) 109 } 110 var obj s3.GetObjectOutput 111 112 resource.Test(t, resource.TestCase{ 113 PreCheck: func() { testAccPreCheck(t) }, 114 Providers: testAccProviders, 115 CheckDestroy: testAccCheckAWSS3BucketObjectDestroy, 116 Steps: []resource.TestStep{ 117 resource.TestStep{ 118 Config: testAccAWSS3BucketObjectConfig_updates(rInt, tmpFile.Name()), 119 Check: resource.ComposeTestCheckFunc( 120 testAccCheckAWSS3BucketObjectExists("aws_s3_bucket_object.object", &obj), 121 resource.TestCheckResourceAttr("aws_s3_bucket_object.object", "etag", "647d1d58e1011c743ec67d5e8af87b53"), 122 ), 123 }, 124 resource.TestStep{ 125 PreConfig: func() { 126 err = ioutil.WriteFile(tmpFile.Name(), []byte("modified object"), 0644) 127 if err != nil { 128 t.Fatal(err) 129 } 130 }, 131 Config: testAccAWSS3BucketObjectConfig_updates(rInt, tmpFile.Name()), 132 Check: resource.ComposeTestCheckFunc( 133 testAccCheckAWSS3BucketObjectExists("aws_s3_bucket_object.object", &obj), 134 resource.TestCheckResourceAttr("aws_s3_bucket_object.object", "etag", "1c7fd13df1515c2a13ad9eb068931f09"), 135 ), 136 }, 137 }, 138 }) 139 } 140 141 func TestAccAWSS3BucketObject_updatesWithVersioning(t *testing.T) { 142 tmpFile, err := ioutil.TempFile("", "tf-acc-s3-obj-updates-w-versions") 143 if err != nil { 144 t.Fatal(err) 145 } 146 defer os.Remove(tmpFile.Name()) 147 148 rInt := acctest.RandInt() 149 err = ioutil.WriteFile(tmpFile.Name(), []byte("initial versioned object state"), 0644) 150 if err != nil { 151 t.Fatal(err) 152 } 153 154 var originalObj, modifiedObj s3.GetObjectOutput 155 156 resource.Test(t, resource.TestCase{ 157 PreCheck: func() { testAccPreCheck(t) }, 158 Providers: testAccProviders, 159 CheckDestroy: testAccCheckAWSS3BucketObjectDestroy, 160 Steps: []resource.TestStep{ 161 resource.TestStep{ 162 Config: testAccAWSS3BucketObjectConfig_updatesWithVersioning(rInt, tmpFile.Name()), 163 Check: resource.ComposeTestCheckFunc( 164 testAccCheckAWSS3BucketObjectExists("aws_s3_bucket_object.object", &originalObj), 165 resource.TestCheckResourceAttr("aws_s3_bucket_object.object", "etag", "cee4407fa91906284e2a5e5e03e86b1b"), 166 ), 167 }, 168 resource.TestStep{ 169 PreConfig: func() { 170 err = ioutil.WriteFile(tmpFile.Name(), []byte("modified versioned object"), 0644) 171 if err != nil { 172 t.Fatal(err) 173 } 174 }, 175 Config: testAccAWSS3BucketObjectConfig_updatesWithVersioning(rInt, tmpFile.Name()), 176 Check: resource.ComposeTestCheckFunc( 177 testAccCheckAWSS3BucketObjectExists("aws_s3_bucket_object.object", &modifiedObj), 178 resource.TestCheckResourceAttr("aws_s3_bucket_object.object", "etag", "00b8c73b1b50e7cc932362c7225b8e29"), 179 testAccCheckAWSS3BucketObjectVersionIdDiffers(&originalObj, &modifiedObj), 180 ), 181 }, 182 }, 183 }) 184 } 185 186 func testAccCheckAWSS3BucketObjectVersionIdDiffers(first, second *s3.GetObjectOutput) resource.TestCheckFunc { 187 return func(s *terraform.State) error { 188 if first.VersionId == nil { 189 return fmt.Errorf("Expected first object to have VersionId: %s", first) 190 } 191 if second.VersionId == nil { 192 return fmt.Errorf("Expected second object to have VersionId: %s", second) 193 } 194 195 if *first.VersionId == *second.VersionId { 196 return fmt.Errorf("Expected Version IDs to differ, but they are equal (%s)", *first.VersionId) 197 } 198 199 return nil 200 } 201 } 202 203 func testAccCheckAWSS3BucketObjectDestroy(s *terraform.State) error { 204 s3conn := testAccProvider.Meta().(*AWSClient).s3conn 205 206 for _, rs := range s.RootModule().Resources { 207 if rs.Type != "aws_s3_bucket_object" { 208 continue 209 } 210 211 _, err := s3conn.HeadObject( 212 &s3.HeadObjectInput{ 213 Bucket: aws.String(rs.Primary.Attributes["bucket"]), 214 Key: aws.String(rs.Primary.Attributes["key"]), 215 IfMatch: aws.String(rs.Primary.Attributes["etag"]), 216 }) 217 if err == nil { 218 return fmt.Errorf("AWS S3 Object still exists: %s", rs.Primary.ID) 219 } 220 } 221 return nil 222 } 223 224 func testAccCheckAWSS3BucketObjectExists(n string, obj *s3.GetObjectOutput) resource.TestCheckFunc { 225 return func(s *terraform.State) error { 226 rs, ok := s.RootModule().Resources[n] 227 if !ok { 228 return fmt.Errorf("Not Found: %s", n) 229 } 230 231 if rs.Primary.ID == "" { 232 return fmt.Errorf("No S3 Bucket Object ID is set") 233 } 234 235 s3conn := testAccProvider.Meta().(*AWSClient).s3conn 236 out, err := s3conn.GetObject( 237 &s3.GetObjectInput{ 238 Bucket: aws.String(rs.Primary.Attributes["bucket"]), 239 Key: aws.String(rs.Primary.Attributes["key"]), 240 IfMatch: aws.String(rs.Primary.Attributes["etag"]), 241 }) 242 if err != nil { 243 return fmt.Errorf("S3Bucket Object error: %s", err) 244 } 245 246 *obj = *out 247 248 return nil 249 } 250 } 251 252 func TestAccAWSS3BucketObject_kms(t *testing.T) { 253 rInt := acctest.RandInt() 254 var obj s3.GetObjectOutput 255 256 resource.Test(t, resource.TestCase{ 257 PreCheck: func() { testAccPreCheck(t) }, 258 Providers: testAccProviders, 259 CheckDestroy: testAccCheckAWSS3BucketObjectDestroy, 260 Steps: []resource.TestStep{ 261 resource.TestStep{ 262 PreConfig: func() {}, 263 Config: testAccAWSS3BucketObjectConfig_withKMSId(rInt), 264 Check: testAccCheckAWSS3BucketObjectExists("aws_s3_bucket_object.object", &obj), 265 }, 266 }, 267 }) 268 } 269 270 func TestAccAWSS3BucketObject_acl(t *testing.T) { 271 rInt := acctest.RandInt() 272 var obj s3.GetObjectOutput 273 274 resource.Test(t, resource.TestCase{ 275 PreCheck: func() { testAccPreCheck(t) }, 276 Providers: testAccProviders, 277 CheckDestroy: testAccCheckAWSS3BucketObjectDestroy, 278 Steps: []resource.TestStep{ 279 resource.TestStep{ 280 Config: testAccAWSS3BucketObjectConfig_acl(rInt, "private"), 281 Check: resource.ComposeTestCheckFunc( 282 testAccCheckAWSS3BucketObjectExists( 283 "aws_s3_bucket_object.object", &obj), 284 resource.TestCheckResourceAttr( 285 "aws_s3_bucket_object.object", 286 "acl", 287 "private"), 288 testAccCheckAWSS3BucketObjectAcl( 289 "aws_s3_bucket_object.object", 290 []string{"FULL_CONTROL"}), 291 ), 292 }, 293 resource.TestStep{ 294 Config: testAccAWSS3BucketObjectConfig_acl(rInt, "public-read"), 295 Check: resource.ComposeTestCheckFunc( 296 testAccCheckAWSS3BucketObjectExists( 297 "aws_s3_bucket_object.object", 298 &obj), 299 resource.TestCheckResourceAttr( 300 "aws_s3_bucket_object.object", 301 "acl", 302 "public-read"), 303 testAccCheckAWSS3BucketObjectAcl( 304 "aws_s3_bucket_object.object", 305 []string{"FULL_CONTROL", "READ"}), 306 ), 307 }, 308 }, 309 }) 310 } 311 312 func testAccCheckAWSS3BucketObjectAcl(n string, expectedPerms []string) resource.TestCheckFunc { 313 return func(s *terraform.State) error { 314 rs, _ := s.RootModule().Resources[n] 315 s3conn := testAccProvider.Meta().(*AWSClient).s3conn 316 317 out, err := s3conn.GetObjectAcl(&s3.GetObjectAclInput{ 318 Bucket: aws.String(rs.Primary.Attributes["bucket"]), 319 Key: aws.String(rs.Primary.Attributes["key"]), 320 }) 321 322 if err != nil { 323 return fmt.Errorf("GetObjectAcl error: %v", err) 324 } 325 326 var perms []string 327 for _, v := range out.Grants { 328 perms = append(perms, *v.Permission) 329 } 330 sort.Strings(perms) 331 332 if !reflect.DeepEqual(perms, expectedPerms) { 333 return fmt.Errorf("Expected ACL permissions to be %v, got %v", expectedPerms, perms) 334 } 335 336 return nil 337 } 338 } 339 340 func TestResourceAWSS3BucketObjectAcl_validation(t *testing.T) { 341 _, errors := validateS3BucketObjectAclType("incorrect", "acl") 342 if len(errors) == 0 { 343 t.Fatalf("Expected to trigger a validation error") 344 } 345 346 var testCases = []struct { 347 Value string 348 ErrCount int 349 }{ 350 { 351 Value: "public-read", 352 ErrCount: 0, 353 }, 354 { 355 Value: "public-read-write", 356 ErrCount: 0, 357 }, 358 } 359 360 for _, tc := range testCases { 361 _, errors := validateS3BucketObjectAclType(tc.Value, "acl") 362 if len(errors) != tc.ErrCount { 363 t.Fatalf("Expected not to trigger a validation error") 364 } 365 } 366 } 367 368 func TestAccAWSS3BucketObject_storageClass(t *testing.T) { 369 rInt := acctest.RandInt() 370 var obj s3.GetObjectOutput 371 372 resource.Test(t, resource.TestCase{ 373 PreCheck: func() { testAccPreCheck(t) }, 374 Providers: testAccProviders, 375 CheckDestroy: testAccCheckAWSS3BucketObjectDestroy, 376 Steps: []resource.TestStep{ 377 resource.TestStep{ 378 PreConfig: func() {}, 379 Config: testAccAWSS3BucketObjectConfigContent(rInt), 380 Check: resource.ComposeTestCheckFunc( 381 testAccCheckAWSS3BucketObjectExists( 382 "aws_s3_bucket_object.object", 383 &obj), 384 resource.TestCheckResourceAttr( 385 "aws_s3_bucket_object.object", 386 "storage_class", 387 "STANDARD"), 388 testAccCheckAWSS3BucketObjectStorageClass( 389 "aws_s3_bucket_object.object", 390 "STANDARD"), 391 ), 392 }, 393 resource.TestStep{ 394 Config: testAccAWSS3BucketObjectConfig_storageClass(rInt, "REDUCED_REDUNDANCY"), 395 Check: resource.ComposeTestCheckFunc( 396 testAccCheckAWSS3BucketObjectExists( 397 "aws_s3_bucket_object.object", 398 &obj), 399 resource.TestCheckResourceAttr( 400 "aws_s3_bucket_object.object", 401 "storage_class", 402 "REDUCED_REDUNDANCY"), 403 testAccCheckAWSS3BucketObjectStorageClass( 404 "aws_s3_bucket_object.object", 405 "REDUCED_REDUNDANCY"), 406 ), 407 }, 408 }, 409 }) 410 } 411 412 func TestResourceAWSS3BucketObjectStorageClass_validation(t *testing.T) { 413 _, errors := validateS3BucketObjectStorageClassType("incorrect", "storage_class") 414 if len(errors) == 0 { 415 t.Fatalf("Expected to trigger a validation error") 416 } 417 418 var testCases = []struct { 419 Value string 420 ErrCount int 421 }{ 422 { 423 Value: "STANDARD", 424 ErrCount: 0, 425 }, 426 { 427 Value: "REDUCED_REDUNDANCY", 428 ErrCount: 0, 429 }, 430 } 431 432 for _, tc := range testCases { 433 _, errors := validateS3BucketObjectStorageClassType(tc.Value, "storage_class") 434 if len(errors) != tc.ErrCount { 435 t.Fatalf("Expected not to trigger a validation error") 436 } 437 } 438 } 439 440 func testAccCheckAWSS3BucketObjectStorageClass(n, expectedClass string) resource.TestCheckFunc { 441 return func(s *terraform.State) error { 442 rs, _ := s.RootModule().Resources[n] 443 s3conn := testAccProvider.Meta().(*AWSClient).s3conn 444 445 out, err := s3conn.HeadObject(&s3.HeadObjectInput{ 446 Bucket: aws.String(rs.Primary.Attributes["bucket"]), 447 Key: aws.String(rs.Primary.Attributes["key"]), 448 }) 449 450 if err != nil { 451 return fmt.Errorf("HeadObject error: %v", err) 452 } 453 454 // The "STANDARD" (which is also the default) storage 455 // class when set would not be included in the results. 456 storageClass := s3.StorageClassStandard 457 if out.StorageClass != nil { 458 storageClass = *out.StorageClass 459 } 460 461 if storageClass != expectedClass { 462 return fmt.Errorf("Expected Storage Class to be %v, got %v", 463 expectedClass, storageClass) 464 } 465 466 return nil 467 } 468 } 469 470 func testAccAWSS3BucketObjectConfigSource(randInt int, source string) string { 471 return fmt.Sprintf(` 472 resource "aws_s3_bucket" "object_bucket" { 473 bucket = "tf-object-test-bucket-%d" 474 } 475 resource "aws_s3_bucket_object" "object" { 476 bucket = "${aws_s3_bucket.object_bucket.bucket}" 477 key = "test-key" 478 source = "%s" 479 content_type = "binary/octet-stream" 480 } 481 `, randInt, source) 482 } 483 484 func testAccAWSS3BucketObjectConfig_withContentCharacteristics(randInt int, source string) string { 485 return fmt.Sprintf(` 486 resource "aws_s3_bucket" "object_bucket_2" { 487 bucket = "tf-object-test-bucket-%d" 488 } 489 490 resource "aws_s3_bucket_object" "object" { 491 bucket = "${aws_s3_bucket.object_bucket_2.bucket}" 492 key = "test-key" 493 source = "%s" 494 content_language = "en" 495 content_type = "binary/octet-stream" 496 } 497 `, randInt, source) 498 } 499 500 func testAccAWSS3BucketObjectConfigContent(randInt int) string { 501 return fmt.Sprintf(` 502 resource "aws_s3_bucket" "object_bucket" { 503 bucket = "tf-object-test-bucket-%d" 504 } 505 resource "aws_s3_bucket_object" "object" { 506 bucket = "${aws_s3_bucket.object_bucket.bucket}" 507 key = "test-key" 508 content = "some_bucket_content" 509 } 510 `, randInt) 511 } 512 513 func testAccAWSS3BucketObjectConfig_updates(randInt int, source string) string { 514 return fmt.Sprintf(` 515 resource "aws_s3_bucket" "object_bucket_3" { 516 bucket = "tf-object-test-bucket-%d" 517 } 518 519 resource "aws_s3_bucket_object" "object" { 520 bucket = "${aws_s3_bucket.object_bucket_3.bucket}" 521 key = "updateable-key" 522 source = "%s" 523 etag = "${md5(file("%s"))}" 524 } 525 `, randInt, source, source) 526 } 527 528 func testAccAWSS3BucketObjectConfig_updatesWithVersioning(randInt int, source string) string { 529 return fmt.Sprintf(` 530 resource "aws_s3_bucket" "object_bucket_3" { 531 bucket = "tf-object-test-bucket-%d" 532 versioning { 533 enabled = true 534 } 535 } 536 537 resource "aws_s3_bucket_object" "object" { 538 bucket = "${aws_s3_bucket.object_bucket_3.bucket}" 539 key = "updateable-key" 540 source = "%s" 541 etag = "${md5(file("%s"))}" 542 } 543 `, randInt, source, source) 544 } 545 546 func testAccAWSS3BucketObjectConfig_withKMSId(randInt int) string { 547 return fmt.Sprintf(` 548 resource "aws_kms_key" "kms_key_1" { 549 } 550 551 resource "aws_s3_bucket" "object_bucket_2" { 552 bucket = "tf-object-test-bucket-%d" 553 } 554 555 resource "aws_s3_bucket_object" "object" { 556 bucket = "${aws_s3_bucket.object_bucket_2.bucket}" 557 key = "test-key" 558 content = "stuff" 559 kms_key_id = "${aws_kms_key.kms_key_1.arn}" 560 } 561 `, randInt) 562 } 563 564 func testAccAWSS3BucketObjectConfig_acl(randInt int, acl string) string { 565 return fmt.Sprintf(` 566 resource "aws_s3_bucket" "object_bucket" { 567 bucket = "tf-object-test-bucket-%d" 568 } 569 resource "aws_s3_bucket_object" "object" { 570 bucket = "${aws_s3_bucket.object_bucket.bucket}" 571 key = "test-key" 572 content = "some_bucket_content" 573 acl = "%s" 574 } 575 `, randInt, acl) 576 } 577 578 func testAccAWSS3BucketObjectConfig_storageClass(randInt int, storage_class string) string { 579 return fmt.Sprintf(` 580 resource "aws_s3_bucket" "object_bucket" { 581 bucket = "tf-object-test-bucket-%d" 582 } 583 resource "aws_s3_bucket_object" "object" { 584 bucket = "${aws_s3_bucket.object_bucket.bucket}" 585 key = "test-key" 586 content = "some_bucket_content" 587 storage_class = "%s" 588 } 589 `, randInt, storage_class) 590 }