Identity v3 Projects Create (#165)

* Identity v3 Projects Create

* Removing unused createErr function
diff --git a/acceptance/openstack/identity/v3/identity.go b/acceptance/openstack/identity/v3/identity.go
index 2969bc9..5bed8a4 100644
--- a/acceptance/openstack/identity/v3/identity.go
+++ b/acceptance/openstack/identity/v3/identity.go
@@ -3,12 +3,41 @@
 import (
 	"testing"
 
+	"github.com/gophercloud/gophercloud"
+	"github.com/gophercloud/gophercloud/acceptance/tools"
 	"github.com/gophercloud/gophercloud/openstack/identity/v3/endpoints"
 	"github.com/gophercloud/gophercloud/openstack/identity/v3/projects"
 	"github.com/gophercloud/gophercloud/openstack/identity/v3/services"
 	"github.com/gophercloud/gophercloud/openstack/identity/v3/tokens"
 )
 
+// CreateProject will create a project with a random name.
+// It takes an optional createOpts parameter since creating a project
+// has so many options. An error will be returned if the project was
+// unable to be created.
+func CreateProject(t *testing.T, client *gophercloud.ServiceClient, c *projects.CreateOpts) (*projects.Project, error) {
+	name := tools.RandomString("ACPTTEST", 8)
+	t.Logf("Attempting to create project: %s", name)
+
+	var createOpts projects.CreateOpts
+	if c != nil {
+		createOpts = *c
+	} else {
+		createOpts = projects.CreateOpts{}
+	}
+
+	createOpts.Name = name
+
+	project, err := projects.Create(client, createOpts).Extract()
+	if err != nil {
+		return project, err
+	}
+
+	t.Logf("Successfully created project %s with ID %s", name, project.ID)
+
+	return project, nil
+}
+
 // PrintEndpoint will print an endpoint and all of its attributes.
 func PrintEndpoint(t *testing.T, endpoint *endpoints.Endpoint) {
 	t.Logf("ID: %s", endpoint.ID)
diff --git a/acceptance/openstack/identity/v3/projects_test.go b/acceptance/openstack/identity/v3/projects_test.go
index ab982b2..4b2e539 100644
--- a/acceptance/openstack/identity/v3/projects_test.go
+++ b/acceptance/openstack/identity/v3/projects_test.go
@@ -59,3 +59,72 @@
 
 	PrintProject(t, p)
 }
+
+func TestProjectsCRUD(t *testing.T) {
+	client, err := clients.NewIdentityV3Client()
+	if err != nil {
+		t.Fatalf("Unable to obtain an identity client: %v")
+	}
+
+	project, err := CreateProject(t, client, nil)
+	if err != nil {
+		t.Fatalf("Unable to create project: %v", err)
+	}
+
+	PrintProject(t, project)
+}
+
+func TestProjectsDomain(t *testing.T) {
+	client, err := clients.NewIdentityV3Client()
+	if err != nil {
+		t.Fatalf("Unable to obtain an identity client: %v")
+	}
+
+	var iTrue = true
+	createOpts := projects.CreateOpts{
+		IsDomain: &iTrue,
+	}
+
+	projectDomain, err := CreateProject(t, client, &createOpts)
+	if err != nil {
+		t.Fatalf("Unable to create project: %v", err)
+	}
+
+	PrintProject(t, projectDomain)
+
+	createOpts = projects.CreateOpts{
+		DomainID: projectDomain.ID,
+	}
+
+	project, err := CreateProject(t, client, &createOpts)
+	if err != nil {
+		t.Fatalf("Unable to create project: %v", err)
+	}
+
+	PrintProject(t, project)
+}
+
+func TestProjectsNested(t *testing.T) {
+	client, err := clients.NewIdentityV3Client()
+	if err != nil {
+		t.Fatalf("Unable to obtain an identity client: %v")
+	}
+
+	projectMain, err := CreateProject(t, client, nil)
+	if err != nil {
+		t.Fatalf("Unable to create project: %v", err)
+	}
+
+	PrintProject(t, projectMain)
+
+	createOpts := projects.CreateOpts{
+		ParentID: projectMain.ID,
+	}
+
+	project, err := CreateProject(t, client, &createOpts)
+	if err != nil {
+		t.Fatalf("Unable to create project: %v", err)
+	}
+
+	PrintProject(t, project)
+}