Adding acceptance test for secgroups :metal:
diff --git a/acceptance/openstack/compute/v2/secgroup_test.go b/acceptance/openstack/compute/v2/secgroup_test.go
new file mode 100644
index 0000000..7094031
--- /dev/null
+++ b/acceptance/openstack/compute/v2/secgroup_test.go
@@ -0,0 +1,174 @@
+// +build acceptance compute secgroups
+
+package v2
+
+import (
+	"testing"
+
+	"github.com/rackspace/gophercloud"
+	"github.com/rackspace/gophercloud/acceptance/tools"
+	"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups"
+	"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
+	"github.com/rackspace/gophercloud/pagination"
+	th "github.com/rackspace/gophercloud/testhelper"
+)
+
+func TestSecGroups(t *testing.T) {
+	client, err := newClient()
+	th.AssertNoErr(t, err)
+
+	serverID, needsDeletion := findServer(t, client)
+
+	groupID := createSecGroup(t, client)
+
+	listSecGroups(t, client)
+
+	newName := tools.RandomString("secgroup_", 5)
+	updateSecGroup(t, client, groupID, newName)
+
+	getSecGroup(t, client, groupID)
+
+	addRemoveRules(t, client, groupID)
+
+	addServerToSecGroup(t, client, serverID, newName)
+
+	removeServerFromSecGroup(t, client, serverID, newName)
+
+	if needsDeletion {
+		servers.Delete(client, serverID)
+	}
+
+	deleteSecGroup(t, client, groupID)
+}
+
+func createSecGroup(t *testing.T, client *gophercloud.ServiceClient) string {
+	opts := secgroups.CreateOpts{
+		Name:        tools.RandomString("secgroup_", 5),
+		Description: "something",
+	}
+
+	group, err := secgroups.Create(client, opts).Extract()
+	th.AssertNoErr(t, err)
+
+	t.Logf("Created secgroup %s %s", group.ID, group.Name)
+
+	return group.ID
+}
+
+func listSecGroups(t *testing.T, client *gophercloud.ServiceClient) {
+	err := secgroups.List(client).EachPage(func(page pagination.Page) (bool, error) {
+		secGrpList, err := secgroups.ExtractSecurityGroups(page)
+		th.AssertNoErr(t, err)
+
+		for _, sg := range secGrpList {
+			t.Logf("Listing secgroup %s: Name [%s] Desc [%s] TenantID [%s]", sg.ID,
+				sg.Name, sg.Description, sg.TenantID)
+		}
+
+		return true, nil
+	})
+
+	th.AssertNoErr(t, err)
+}
+
+func updateSecGroup(t *testing.T, client *gophercloud.ServiceClient, id, newName string) {
+	opts := secgroups.UpdateOpts{Name: newName}
+	group, err := secgroups.Update(client, id, opts).Extract()
+	th.AssertNoErr(t, err)
+
+	t.Logf("Updated %s's name to %s", group.ID, group.Name)
+}
+
+func getSecGroup(t *testing.T, client *gophercloud.ServiceClient, id string) {
+	group, err := secgroups.Get(client, id).Extract()
+	th.AssertNoErr(t, err)
+
+	t.Logf("Getting %s: %#v", id, group)
+}
+
+func addRemoveRules(t *testing.T, client *gophercloud.ServiceClient, id string) {
+	opts := secgroups.AddRuleOpts{
+		ParentGroupID: id,
+		FromPort:      22,
+		ToPort:        22,
+		IPProtocol:    "TCP",
+		CIDR:          "0.0.0.0/0",
+	}
+
+	rule, err := secgroups.AddRule(client, opts).Extract()
+	th.AssertNoErr(t, err)
+
+	t.Logf("Adding rule %s to group %s", rule.ID, id)
+
+	err = secgroups.DeleteRule(client, rule.ID).ExtractErr()
+	th.AssertNoErr(t, err)
+
+	t.Logf("Deleted rule %s from group %s", rule.ID, id)
+}
+
+func findServer(t *testing.T, client *gophercloud.ServiceClient) (string, bool) {
+	var serverID string
+	var needsDeletion bool
+
+	err := servers.List(client, nil).EachPage(func(page pagination.Page) (bool, error) {
+		sList, err := servers.ExtractServers(page)
+		th.AssertNoErr(t, err)
+
+		for _, s := range sList {
+			serverID = s.ID
+			needsDeletion = false
+
+			t.Logf("Found an existing server: ID [%s]", serverID)
+			break
+		}
+
+		return true, nil
+	})
+	th.AssertNoErr(t, err)
+
+	if serverID == "" {
+		t.Log("No server found, creating one")
+
+		choices, err := ComputeChoicesFromEnv()
+		th.AssertNoErr(t, err)
+
+		opts := &servers.CreateOpts{
+			Name:      tools.RandomString("secgroup_test_", 5),
+			ImageRef:  choices.ImageID,
+			FlavorRef: choices.FlavorID,
+		}
+
+		s, err := servers.Create(client, opts).Extract()
+		th.AssertNoErr(t, err)
+		serverID = s.ID
+
+		t.Logf("Created server %s, waiting for it to build", s.ID)
+		err = servers.WaitForStatus(client, serverID, "ACTIVE", 300)
+		th.AssertNoErr(t, err)
+
+		needsDeletion = true
+	}
+
+	return serverID, needsDeletion
+}
+
+func addServerToSecGroup(t *testing.T, client *gophercloud.ServiceClient, serverID, groupName string) {
+	err := secgroups.AddServerToGroup(client, serverID, groupName).ExtractErr()
+	th.AssertNoErr(t, err)
+
+	t.Logf("Adding group %s to server %s", groupName, serverID)
+}
+
+func removeServerFromSecGroup(t *testing.T, client *gophercloud.ServiceClient, serverID, groupName string) {
+	err := secgroups.RemoveServerFromGroup(client, serverID, groupName).ExtractErr()
+	th.AssertNoErr(t, err)
+
+	t.Logf("Removing group %s from server %s", groupName, serverID)
+}
+
+func deleteSecGroup(t *testing.T, client *gophercloud.ServiceClient, id string) {
+	err := secgroups.Delete(client, id).ExtractErr()
+	th.AssertNoErr(t, err)
+
+	t.Logf("Deleted group %s", id)
+}