blob: 32935ec2343ed1a3d68e24e343fc580d0ff10701 [file] [log] [blame] [view]
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +02001# Contributing to gophercloud
2
3## Getting started
4
5There should be no fundamental differences of setup between contributors and
6normal end-users. The only thing to bear in mind is that you will need to add a
7few extra environment variables for acceptance tests - this is documented in
8our [acceptance tests readme](/acceptance).
9
10## Tests
11
12When working on a new or existing feature, testing will be the backbone of your
13work since it helps uncover and prevent regressions in the codebase. There are
14two types of test we use in gophercloud: unit tests and acceptance tests, which
15are both described below.
16
17### Unit tests
18
19Unit tests are the fine-grained tests that establish and ensure the behaviour
20of individual units of functionality. We usually test on an
21operation-by-operation basis (an operation typically being an API action) with
22the use of mocking to set up explicit expectations. Each operation will set up
23its HTTP response expectation, and then test how the system responds when fed
24this controlled, pre-determined input.
25
26To make life easier, we've introduced a bunch of test helpers to simplify the
27process of testing expectations with assertions:
28
29```go
30import (
31 "testing"
32
33 "github.com/rackspace/gophercloud/testhelper"
34)
35
36
37func TestSomething(t *testing.T) {
38 testhelper.AssertEquals(t, "expected", "actual")
39}
40
41func TestErrors(t *testing.T) {
42 result, err := Operation()
43
44 testhelper.AssertEquals(t, "foo", result.Bar)
45 testhelper.AssertNoErr(t, err)
46}
47```
48
49`AssertEquals` and `AssertNoErr` will throw a fatal error if a value does not
50match an expected value or if an error has been declared, respectively. You can
51also use `CheckEquals` and `CheckNoErr` for the same purpose; the only difference
52being that `t.Errorf` is raised rather than `t.Fatalf`.
53
54Here is a truncated example of mocked HTTP responses:
55
56```
57import (
58 "testing"
59
60 th "github.com/rackspace/gophercloud/testhelper"
61 fake "github.com/rackspace/gophercloud/testhelper/client"
62)
63
64func TestGet(t *testing.T) {
65 th.SetupHTTP()
66 defer th.TeardownHTTP()
67
68 th.Mux.HandleFunc("/networks/d32019d3-bc6e-4319-9c1d-6722fc136a22", func(w http.ResponseWriter, r *http.Request) {
69 // Test we're using the correct HTTP method
70 th.TestMethod(t, r, "GET")
71
72 // Test we're setting the auth token
73 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
74
75 // Set the appropriate headers for our mocked response
76 w.Header().Add("Content-Type", "application/json")
77 w.WriteHeader(http.StatusOK)
78
79 // Set the HTTP body
80 fmt.Fprintf(w, `
81{
82 "network": {
83 "status": "ACTIVE",
84 "name": "private-network",
85 "admin_state_up": true,
86 "tenant_id": "4fd44f30292945e481c7b8a0c8908869",
87 "shared": true,
88 "id": "d32019d3-bc6e-4319-9c1d-6722fc136a22"
89 }
90}
91 `)
92 })
93
94 // Call our API operation
95 network, err := Get(fake.ServiceClient(), "d32019d3-bc6e-4319-9c1d-6722fc136a22").Extract()
96
97 // Assert no errors and equality
98 th.AssertNoErr(t, err)
99 th.AssertEquals(t, n.Status, "ACTIVE")
100}
101```
102
103### Acceptance tests + build tags
104
105As we've already mentioned, unit tests have a very narrow and confined focus -
106they test small units of behaviour. Acceptance tests on the other hand have a
107far larger scope: they are fully functional tests that test the entire API of a
108service in one fell swoop. They don't care about unit independence or mocking
109expectations, they instead do a full run-through and consequently test how the
110entire system _integrates_ together. When an API satisfies expectations, it
111proves by default that the requirements for a contract have been met.
112
113### Running tests
114
115To run all tests:
116
117```bash
118go test ./...
119```
120
121To run all tests with verbose output:
122
123```bash
124go test -v ./...
125```
126
127To run tests that match certain [build tags]():
128
129```bash
130go test -tags "foo bar" ./...
131```
132
133To run tests for a particular sub-package:
134
135```bash
136cd ./path/to/package && go test .
137```
138
139## Basic style guide
140
141We follow the standard formatting recommendations and language idioms set out
142in the [Effective Go](https://golang.org/doc/effective_go.html) guide. It's
143definitely worth reading - but the relevant sections are
144[formatting](https://golang.org/doc/effective_go.html#formatting)
145and [names](https://golang.org/doc/effective_go.html#names).
146
147## 4 ways to get involved
148
149There are four main ways you can get involved in our open-source project, and
150each is described briefly below. Once you've made up your mind and decided on
151your fix, you will need to follow the same basic steps that all submissions are
152required to adhere to:
153
1541. [fork](https://help.github.com/articles/fork-a-repo/) the `rackspace/gophercloud` repository
1552. checkout a [new branch](https://github.com/Kunena/Kunena-Forum/wiki/Create-a-new-branch-with-git-and-manage-branches)
1563. ensure all your commits are [well-organized](https://help.github.com/articles/about-git-rebase/)
1574. submit your branch as a [pull request](https://help.github.com/articles/creating-a-pull-request/)
158
159### 1. Fixing bugs
160
161If you want to start fixing open bugs, we'd really appreciate that! Bug fixing
162is central to any project. The best way to get started is by heading to our
163[bug tracker](https://github.com/rackspace/gophercloud/issues) and finding open
164bugs that you think nobody is working on. It might be useful to comment on the
165thread to see the current state of the issue and if anybody has made any
166breakthroughs on it so far.
167
168### 2. Improving documentation
169
170We have three forms of documentation:
171
172* short README documents that briefly introduce a topic
173* reference documentation on [godoc.org](http://godoc.org) that automatically
174generates from source code comments
175* user documentation on our [homepage](http://gophercloud.io) that includes
176getting started guides, installation guides and code samples
177
178If you feel that a certain section could be improved - whether its to clarify
179ambiguity or a fix a grammatical mistake - please feel entitled to do so! We
180welcome doc pull requests with the same childlike enthusiasm as any other
181contribution!
182
183### 3. Optimizing existing features
184
185If you would like to improve or optimize an existing feature, please be aware
186that we adhere to semantic versioning] - which means that we cannot introduce
187breaking changes to the API without a major version change (v1.x -> v2.x).
188Making that leap is a big step, so we encourage contributors to refactor rather
189than rewrite. Running tests will prevent regression and avoid the possibility
190of breaking somebody's current implementation.
191
192### 4. Working on a new feature
193
194If you've found something we've left out, definitely feel free to start work on
195introducing that feature. It's always useful to open an issue first to indicate
196your intent to a core contributor - this enables quick feedback and can help
197steer you in the right direction by avoiding known issues. It might also help
198you avoid losing time implementing something that might not ever work.
199
200You must ensure that all of your work is well tested - both in terms of unit
201and acceptance tests. Untested code will not be merged because it introduces
202too much of a risk to end-users. Happy hacking!