-
Notifications
You must be signed in to change notification settings - Fork 565
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to use the testing server? #105
Comments
Hi @gravis, sorry about the delay. The testing server is intended to be used in the same place as an actual server, so you can point a Client instance to it. Something like:
|
Ok, but how do you use the wait command then? The container is stuck |
You would need to call Stop + Wait. I think we have something like this in tsuru, please hold on. |
Just confirmed: we have a gorountine that stops the container and automatically "unblocks" the WaitContainer call. |
Ok, thanks. It would be nice if you could share some code here, I'm still very confused. I'm trying to test a command (ie: entrypoint) inside a container, in pseudo code, it's something like: CreateContainer If I run a go routine to stop the container, how can I have hands on the resulting files inside the container? AFAIU, stopping the container will just emulate a timeout :( Thanks |
I see. You will need to manually stop the container anyway, don't you? I mean, if methods weren't private in the testing server, how would you write your test? Instead of using a goroutine, you could stop the container at any time, the time that you would access the testing server and mark the container as stopped, unleashing the WaitContainer call. |
Currently, I'm creating a real http server, with methods like:
Maybe being able to pass my own handlers would be enough.
What do you think? |
Hmm, this is interesting. Do you thing that making the server extensible, so you can specify the handler for an operation is enough? What about the API? Something like:
Should the path be a regular expression or the actual path? In your case, it would be:
What do you think? |
Sounds like a terrific idea. I still need a func to get the But I think we're heading in the right direction, and I really appreciate your open mind :) |
What about: http://play.golang.org/p/7dLcZ5ksuW :) |
Nice snippet, cChan should be exported, right? Also, the channel should be fed when the client calls CreateContainer, and not on NewServer. What do you think? Sounds fair? |
Sure, it was a proof of concept. I'm very glad you like it Thanks! |
Sorry for the huge delay. I'm planning to do it, but can you confirm that this flow will be enough for your use case? |
No problem at all. Yes, I think this would be really make it. If I find blocking issues, I will propose PRs anymay :) Thanks a lot |
Can you take a look at #113? Thanks! |
I've just pushed the CustomHandler method, can you take a look? :) Is it good? |
Damned, you're fast :) |
No hurry man :) I was wondering: should we add a method to remove the custom handler? |
Sorry, I still need some time to test this. I'm fighting a nasty bug with AttachContainer, hitting 100% CPU when getting container logs, and blocking all my routines :( |
No problem. Is it the testing server or the real server? Is the client or the server hitting 100% CPU? I may help debugging it, if you have a reproducer. :) |
I have opened a ticket actually: #114 |
@gravis thanks for reporting it! |
I'm wondering if it's the good approach now. I have started to replace my fake docker with testing.DockerServer, and ended up with copying/pasting the content of https://github.com/fsouza/go-dockerclient/blob/master/testing/server.go#L397, just to be able to replace the 2 last lines... There's probably something else to explore. Maybe a |
@gravis what about something like |
sounds good! Sorry for changing target like that. It's only when you have hands in the code that you realize how the API should behave... :( |
I also have some files I need to write in the container, I don't think there a method to add files in a container ? If not, I will probably need also something like: |
@gravis how would you access these files? Currently, "go-dockerclient" doesn't support copying files from the container. Wouldn't you need a |
From the container? You mean, TO the container, right? If it is TO the container, yes, it will be needed :) |
Sorry, I meant from the container, but I think I'm misunderstanding your use case. Will you insert files in the container in the testing server? What's the purpose? I mean, the test code would look like:
What does the production code do? |
Ok, to sum up. We have containers to run isolated processes. Theses commands will generate some output (container logs), and some files to be copied from the container, and sent to another API. requires_txt := "Flask==0.8\nJinja2==2.6"
mux := http.NewServeMux()
// CreateContainer stub
container_id := "5fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2"
mux.HandleFunc(fmt.Sprintf("/containers/create"), func(w http.ResponseWriter, r *http.Request) {
jsonContainer := fmt.Sprintf(`{
"Id": "%s",
"Warnings": []
}`, container_id)
fmt.Fprint(w, jsonContainer)
})
// StartContainer stub
mux.HandleFunc(fmt.Sprintf("/containers/%s/start", container_id), func(w http.ResponseWriter, r *http.Request) {})
// WaitContainer stub
mux.HandleFunc(fmt.Sprintf("/containers/%s/wait", container_id), func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, `{"StatusCode": 0}`)
})
mux.HandleFunc(fmt.Sprintf("/containers/%s/attach", container_id), func(w http.ResponseWriter, r *http.Request) {
outStream := utils.NewStdWriter(w, utils.Stdout)
fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
fmt.Fprint(outStream, requires_txt)
})
// CopyFromContainer stub
mux.HandleFunc(fmt.Sprintf("/containers/%s/copy", container_id), func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/octet-stream")
// Create a buffer to write our archive to.
buf := new(bytes.Buffer)
// Create a new tar archive.
tw := tar.NewWriter(buf)
// Add some files to the archive.
var files = []struct {
Name, Body string
}{
{"requires.txt", requires_txt},
}
for _, file := range files {
hdr := &tar.Header{
Name: file.Name,
Size: int64(len(file.Body)),
}
if err := tw.WriteHeader(hdr); err != nil {
log.Fatal(err)
}
if _, err := tw.Write([]byte(file.Body)); err != nil {
log.Fatal(err)
}
}
// Make sure to check the error on Close.
if err := tw.Close(); err != nil {
log.Fatal(err)
}
if _, err := io.Copy(w, buf); err != nil {
// return err
}
})
server := httptest.NewServer(mux) |
I understand now. In order to insert files into the container or customise the output, the container would have to exist, so you'd need to be able to call the methods Am I understanding it right? I think this is a scenario that is quite hard to test. |
You're 100% right :) |
I don't think you would be able to guarantee such order. You'd need some mechanism to "pre-register" the container, and have CreateContainer returning that container. Something like:
Then the production code will call CreateContainer, StartContainer, WaitContainer, AttachToContainer and CopyFromContainer, using the container returned by CreateContainer, that is the container previously prepared for creation. This would enable us to prepare the behaviour of a container before creating it. Also, as far as I can tell, we would not need the custom handler anymore. What do you think? |
I'm a bit lost with https://github.com/fsouza/go-dockerclient/blob/master/testing/server.go
I though I would be able to use it as a fake local server, but most of the funcs are private. Therefore, if I "wait" for a container in my tests, I don't have anything to change the running state to
false
, and exit of the for loop here:https://github.com/fsouza/go-dockerclient/blob/master/testing/server.go#L358
Maybe I'm missing something?
Thanks
The text was updated successfully, but these errors were encountered: