Merge pull request #57 from rackspace/fix-get-server-details-test

Create server to get details of if no other available.
diff --git a/acceptance/03-get-server-details.go b/acceptance/03-get-server-details.go
index 3fda268..77fa522 100644
--- a/acceptance/03-get-server-details.go
+++ b/acceptance/03-get-server-details.go
@@ -15,20 +15,26 @@
 
 	withIdentity(func(auth gophercloud.AccessProvider) {
 		withServerApi(auth, func(servers gophercloud.CloudServersProvider) {
-			serverId := ""
+			var (
+				err error
+				serverId string
+				deleteAfterwards bool
+			)
+
+			// Figure out which server to provide server details for.
 			if *id == "" {
-				ss, err := servers.ListServers()
+				deleteAfterwards, serverId, err = locateAServer(servers)
 				if err != nil {
 					panic(err)
 				}
-				// We could just cheat and dump the server details from ss[0].
-				// But, that tests ListServers(), and not ServerById().  So, we
-				// elect not to cheat.
-				serverId = ss[0].Id
+				if deleteAfterwards {
+					defer servers.DeleteServerById(serverId)
+				}
 			} else {
 				serverId = *id
 			}
 
+			// Grab server details by ID, and provide a report.
 			s, err := servers.ServerById(serverId)
 			if err != nil {
 				panic(err)
@@ -75,3 +81,30 @@
 		})
 	})
 }
+
+// locateAServer queries the set of servers owned by the user.  If at least one
+// exists, the first found is picked, and its ID is returned.  Otherwise, a new
+// server will be created, and its ID returned.
+//
+// deleteAfter will be true if the caller should schedule a call to DeleteServerById()
+// to clean up.
+func locateAServer(servers gophercloud.CloudServersProvider) (deleteAfter bool, id string, err error) {
+	ss, err := servers.ListServers()
+	if err != nil {
+		return false, "", err	
+	}
+
+	if len(ss) > 0 {
+		// We could just cheat and dump the server details from ss[0].
+		// But, that tests ListServers(), and not ServerById().  So, we
+		// elect not to cheat.
+		return false, ss[0].Id, nil
+	}
+
+	serverId, err := createServer(servers, "", "", "", "")
+	if err != nil {
+		return false, "", err
+	}
+	err = waitForServerState(servers, serverId, "ACTIVE")
+	return true, serverId, err
+}
\ No newline at end of file
diff --git a/acceptance/libargs.go b/acceptance/libargs.go
index 5daea21..d9eae11 100644
--- a/acceptance/libargs.go
+++ b/acceptance/libargs.go
@@ -5,6 +5,7 @@
 	"os"
 	"crypto/rand"
 	"github.com/rackspace/gophercloud"
+	"time"
 )
 
 // getCredentials will verify existence of needed credential information
@@ -161,3 +162,20 @@
 
 	f(api)
 }
+
+// waitForServerState polls, every 10 seconds, for a given server to appear in the indicated state.
+// This call will block forever if it never appears in the desired state, so if a timeout is required,
+// make sure to call this function in a goroutine.
+func waitForServerState(api gophercloud.CloudServersProvider, id, state string) error {
+	for {
+		s, err := api.ServerById(id)
+		if err != nil {
+			return err
+		}
+		if s.Status == state {
+			return nil
+		}
+		time.Sleep(10 * time.Second)
+	}
+	panic("Impossible")
+}
\ No newline at end of file