github.com/rjeczalik/terraform@v0.6.7-0.20160812060014-e251d5c7bd39/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 TestResourceAWSS3BucketObjectAcl_validation(t *testing.T) { 313 _, errors := validateS3BucketObjectAclType("incorrect", "acl") 314 if len(errors) == 0 { 315 t.Fatalf("Expected to trigger a validation error") 316 } 317 318 var testCases = []struct { 319 Value string 320 ErrCount int 321 }{ 322 { 323 Value: "public-read", 324 ErrCount: 0, 325 }, 326 { 327 Value: "public-read-write", 328 ErrCount: 0, 329 }, 330 } 331 332 for _, tc := range testCases { 333 _, errors := validateS3BucketObjectAclType(tc.Value, "acl") 334 if len(errors) != tc.ErrCount { 335 t.Fatalf("Expected not to trigger a validation error") 336 } 337 } 338 } 339 340 func testAccCheckAWSS3BucketObjectAcl(n string, expectedPerms []string) resource.TestCheckFunc { 341 return func(s *terraform.State) error { 342 rs, _ := s.RootModule().Resources[n] 343 s3conn := testAccProvider.Meta().(*AWSClient).s3conn 344 345 out, err := s3conn.GetObjectAcl(&s3.GetObjectAclInput{ 346 Bucket: aws.String(rs.Primary.Attributes["bucket"]), 347 Key: aws.String(rs.Primary.Attributes["key"]), 348 }) 349 350 if err != nil { 351 return fmt.Errorf("GetObjectAcl error: %v", err) 352 } 353 354 var perms []string 355 for _, v := range out.Grants { 356 perms = append(perms, *v.Permission) 357 } 358 sort.Strings(perms) 359 360 if !reflect.DeepEqual(perms, expectedPerms) { 361 return fmt.Errorf("Expected ACL permissions to be %v, got %v", expectedPerms, perms) 362 } 363 364 return nil 365 } 366 } 367 368 func testAccAWSS3BucketObjectConfigSource(randInt int, source string) string { 369 return fmt.Sprintf(` 370 resource "aws_s3_bucket" "object_bucket" { 371 bucket = "tf-object-test-bucket-%d" 372 } 373 resource "aws_s3_bucket_object" "object" { 374 bucket = "${aws_s3_bucket.object_bucket.bucket}" 375 key = "test-key" 376 source = "%s" 377 content_type = "binary/octet-stream" 378 } 379 `, randInt, source) 380 } 381 382 func testAccAWSS3BucketObjectConfig_withContentCharacteristics(randInt int, source string) string { 383 return fmt.Sprintf(` 384 resource "aws_s3_bucket" "object_bucket_2" { 385 bucket = "tf-object-test-bucket-%d" 386 } 387 388 resource "aws_s3_bucket_object" "object" { 389 bucket = "${aws_s3_bucket.object_bucket_2.bucket}" 390 key = "test-key" 391 source = "%s" 392 content_language = "en" 393 content_type = "binary/octet-stream" 394 } 395 `, randInt, source) 396 } 397 398 func testAccAWSS3BucketObjectConfigContent(randInt int) string { 399 return fmt.Sprintf(` 400 resource "aws_s3_bucket" "object_bucket" { 401 bucket = "tf-object-test-bucket-%d" 402 } 403 resource "aws_s3_bucket_object" "object" { 404 bucket = "${aws_s3_bucket.object_bucket.bucket}" 405 key = "test-key" 406 content = "some_bucket_content" 407 } 408 `, randInt) 409 } 410 411 func testAccAWSS3BucketObjectConfig_updates(randInt int, source string) string { 412 return fmt.Sprintf(` 413 resource "aws_s3_bucket" "object_bucket_3" { 414 bucket = "tf-object-test-bucket-%d" 415 } 416 417 resource "aws_s3_bucket_object" "object" { 418 bucket = "${aws_s3_bucket.object_bucket_3.bucket}" 419 key = "updateable-key" 420 source = "%s" 421 etag = "${md5(file("%s"))}" 422 } 423 `, randInt, source, source) 424 } 425 426 func testAccAWSS3BucketObjectConfig_updatesWithVersioning(randInt int, source string) string { 427 return fmt.Sprintf(` 428 resource "aws_s3_bucket" "object_bucket_3" { 429 bucket = "tf-object-test-bucket-%d" 430 versioning { 431 enabled = true 432 } 433 } 434 435 resource "aws_s3_bucket_object" "object" { 436 bucket = "${aws_s3_bucket.object_bucket_3.bucket}" 437 key = "updateable-key" 438 source = "%s" 439 etag = "${md5(file("%s"))}" 440 } 441 `, randInt, source, source) 442 } 443 444 func testAccAWSS3BucketObjectConfig_withKMSId(randInt int) string { 445 return fmt.Sprintf(` 446 resource "aws_kms_key" "kms_key_1" { 447 } 448 449 resource "aws_s3_bucket" "object_bucket_2" { 450 bucket = "tf-object-test-bucket-%d" 451 } 452 453 resource "aws_s3_bucket_object" "object" { 454 bucket = "${aws_s3_bucket.object_bucket_2.bucket}" 455 key = "test-key" 456 content = "stuff" 457 kms_key_id = "${aws_kms_key.kms_key_1.arn}" 458 } 459 `, randInt) 460 } 461 462 func testAccAWSS3BucketObjectConfig_acl(randInt int, acl string) string { 463 return fmt.Sprintf(` 464 resource "aws_s3_bucket" "object_bucket" { 465 bucket = "tf-object-test-bucket-%d" 466 } 467 resource "aws_s3_bucket_object" "object" { 468 bucket = "${aws_s3_bucket.object_bucket.bucket}" 469 key = "test-key" 470 content = "some_bucket_content" 471 acl = "%s" 472 } 473 `, randInt, acl) 474 }