blob: a293b504dc221a96531c2ab3420b6fac6c9d1ddf [file] [log] [blame] [view]
Jamie Hannaford8c072a32014-10-16 14:33:32 +02001# Contributing to gophercloud
2
3- [Getting started](#getting-started)
4- [Tests](#tests)
5- [Style guide](#basic-style-guide)
6- [5 ways to get involved](#5-ways-to-get-involved)
7
8## Setting up your git workspace
9
10As a contributor you will need to setup your workspace in a slightly different
11way than just downloading it. Here are the basic installation instructions:
12
131. Configure your `$GOPATH` and run `go get` as described in the main
14[README](/#how-to-install).
15
162. Move into the directory that houses your local repository:
17
18 ```bash
19 cd ${GOPATH}/src/github.com/rackspace/gophercloud
20 ```
21
223. Fork the `rackspace/gophercloud` repository and update your remote refs. You
23will need to rename the `origin` remote branch to `upstream`, and add your
24fork as `origin` instead:
25
26 ```bash
27 git remote rename origin upstream
28 git remote add origin git@github.com/<my_username>/gophercloud
29 ```
30
314. Checkout the latest development branch ([click here](/branches) to see all
32the branches):
33
34 ```bash
35 git checkout v0.2.0
36 ```
37
385. If you're working on something (discussed more in detail below), you will
39need to checkout a new feature branch:
40
41 ```bash
42 git checkout -b my-new-feature
43 ```
44
45Another thing to bear in mind is that you will need to add a few extra
46environment variables for acceptance tests - this is documented in our
47[acceptance tests readme](/acceptance).
48
49## Tests
50
51When working on a new or existing feature, testing will be the backbone of your
52work since it helps uncover and prevent regressions in the codebase. There are
53two types of test we use in gophercloud: unit tests and acceptance tests, which
54are both described below.
55
56### Unit tests
57
58Unit tests are the fine-grained tests that establish and ensure the behaviour
59of individual units of functionality. We usually test on an
60operation-by-operation basis (an operation typically being an API action) with
61the use of mocking to set up explicit expectations. Each operation will set up
62its HTTP response expectation, and then test how the system responds when fed
63this controlled, pre-determined input.
64
65To make life easier, we've introduced a bunch of test helpers to simplify the
66process of testing expectations with assertions:
67
68```go
69import (
70 "testing"
71
72 "github.com/rackspace/gophercloud/testhelper"
73)
74
75func TestSomething(t *testing.T) {
76 result, err := Operation()
77
78 testhelper.AssertEquals(t, "foo", result.Bar)
79 testhelper.AssertNoErr(t, err)
80}
81
82func TestSomethingElse(t *testing.T) {
83 testhelper.CheckEquals(t, "expected", "actual")
84}
85```
86
87`AssertEquals` and `AssertNoErr` will throw a fatal error if a value does not
88match an expected value or if an error has been declared, respectively. You can
89also use `CheckEquals` and `CheckNoErr` for the same purpose; the only difference
90being that `t.Errorf` is raised rather than `t.Fatalf`.
91
92Here is a truncated example of mocked HTTP responses:
93
94```go
95import (
96 "testing"
97
98 th "github.com/rackspace/gophercloud/testhelper"
99 fake "github.com/rackspace/gophercloud/testhelper/client"
100)
101
102func TestGet(t *testing.T) {
103 // Setup the HTTP request multiplexer and server
104 th.SetupHTTP()
105 defer th.TeardownHTTP()
106
107 th.Mux.HandleFunc("/networks/d32019d3-bc6e-4319-9c1d-6722fc136a22", func(w http.ResponseWriter, r *http.Request) {
108 // Test we're using the correct HTTP method
109 th.TestMethod(t, r, "GET")
110
111 // Test we're setting the auth token
112 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
113
114 // Set the appropriate headers for our mocked response
115 w.Header().Add("Content-Type", "application/json")
116 w.WriteHeader(http.StatusOK)
117
118 // Set the HTTP body
119 fmt.Fprintf(w, `
120{
121 "network": {
122 "status": "ACTIVE",
123 "name": "private-network",
124 "admin_state_up": true,
125 "tenant_id": "4fd44f30292945e481c7b8a0c8908869",
126 "shared": true,
127 "id": "d32019d3-bc6e-4319-9c1d-6722fc136a22"
128 }
129}
130 `)
131 })
132
133 // Call our API operation
134 network, err := Get(fake.ServiceClient(), "d32019d3-bc6e-4319-9c1d-6722fc136a22").Extract()
135
136 // Assert no errors and equality
137 th.AssertNoErr(t, err)
138 th.AssertEquals(t, n.Status, "ACTIVE")
139}
140```
141
142### Acceptance tests
143
144As we've already mentioned, unit tests have a very narrow and confined focus -
145they test small units of behaviour. Acceptance tests on the other hand have a
146far larger scope: they are fully functional tests that test the entire API of a
147service in one fell swoop. They don't care about unit isolation or mocking
148expectations, they instead do a full run-through and consequently test how the
149entire system _integrates_ together. When an API satisfies expectations, it
150proves by default that the requirements for a contract have been met.
151
152Please be aware that acceptance tests will hit a live API - and may incur
153service charges from your provider. Although most tests handle their own
154teardown procedures, it is always worth manually checking that resources are
155deleted after the test suite finishes.
156
157### Running tests
158
159To run all tests:
160
161```bash
162go test ./...
163```
164
165To run all tests with verbose output:
166
167```bash
168go test -v ./...
169```
170
171To run tests that match certain [build tags]():
172
173```bash
174go test -tags "foo bar" ./...
175```
176
177To run tests for a particular sub-package:
178
179```bash
180cd ./path/to/package && go test .
181```
182
183## Basic style guide
184
185We follow the standard formatting recommendations and language idioms set out
186in the [Effective Go](https://golang.org/doc/effective_go.html) guide. It's
187definitely worth reading - but the relevant sections are
188[formatting](https://golang.org/doc/effective_go.html#formatting)
189and [names](https://golang.org/doc/effective_go.html#names).
190
191## 5 ways to get involved
192
193There are five main ways you can get involved in our open-source project, and
194each is described briefly below. Once you've made up your mind and decided on
195your fix, you will need to follow the same basic steps that all submissions are
196required to adhere to:
197
1981. [fork](https://help.github.com/articles/fork-a-repo/) the `rackspace/gophercloud` repository
1992. checkout a [new branch](https://github.com/Kunena/Kunena-Forum/wiki/Create-a-new-branch-with-git-and-manage-branches)
2003. submit your branch as a [pull request](https://help.github.com/articles/creating-a-pull-request/)
201
202### 1. Providing feedback
203
204On of the easiest ways to get readily involved in our project is to let us know
205about your experiences using our SDK. Feedback like this is incredibly useful
206to us, because it allows us to refine and change features based on what our
207users want and expect of us. There are a bunch of ways to get in contact! You
208can [ping us](mailto:sdk-support@rackspace.com) via e-mail, talk to us on irc
209(#rackspace-dev on freenode), [tweet us](https://twitter.com/rackspace), or
210submit an issue on our [bug tracker](/issues). Things you might like to tell us
211are:
212
213* how easy was it to start using our SDK?
214* did it meet your expectations? If not, why not?
215* did our documentation help or hinder you?
216* what could we improve in general?
217
218### 2. Fixing bugs
219
220If you want to start fixing open bugs, we'd really appreciate that! Bug fixing
221is central to any project. The best way to get started is by heading to our
222[bug tracker](https://github.com/rackspace/gophercloud/issues) and finding open
223bugs that you think nobody is working on. It might be useful to comment on the
224thread to see the current state of the issue and if anybody has made any
225breakthroughs on it so far.
226
227### 3. Improving documentation
228
229We have three forms of documentation:
230
231* short README documents that briefly introduce a topic
232* reference documentation on [godoc.org](http://godoc.org) that is automatically
233generated from source code comments
234* user documentation on our [homepage](http://gophercloud.io) that includes
235getting started guides, installation guides and code samples
236
237If you feel that a certain section could be improved - whether it's to clarify
238ambiguity, correct a technical mistake, or to fix a grammatical error - please
239feel entitled to do so! We welcome doc pull requests with the same childlike
240enthusiasm as any other contribution!
241
242### 4. Optimizing existing features
243
244If you would like to improve or optimize an existing feature, please be aware
245that we adhere to [semantic versioning](http://semver.org) - which means that
246we cannot introduce breaking changes to the API without a major version change
247(v1.x -> v2.x). Making that leap is a big step, so we encourage contributors to
248refactor rather than rewrite. Running tests will prevent regression and avoid
249the possibility of breaking somebody's current implementation.
250
251Another tip is to keep the focus of your work as small as possible - try not to
252introduce a change that affects lots and lots of files because it introduces
253added risk and increases the cognitive load on the reviewers checking your
254work. Change-sets which are easily understood and will not negatively impact
255users are more likely to be integrated quickly.
256
257Lastly, if you're seeking to optimize a particular operation, you should try to
258demonstrate a negative performance impact - perhaps using go's inbuilt
259[benchmark capabilities](http://dave.cheney.net/2013/06/30/how-to-write-benchmarks-in-go).
260
261### 5. Working on a new feature
262
263If you've found something we've left out, definitely feel free to start work on
264introducing that feature. It's always useful to open an issue or submit a pull
265request early on to indicate your intent to a core contributor - this enables
266quick/early feedback and can help steer you in the right direction by avoiding
267known issues. It might also help you avoid losing time implementing something
268that might not ever work. One tip is to prefix your Pull Request issue title
269with [wip] - then people know it's a work in progress.
270
271You must ensure that all of your work is well tested - both in terms of unit
272and acceptance tests. Untested code will not be merged because it introduces
273too much of a risk to end-users.
274
275Happy hacking!