Import upstream version 1.3.0+ds
Debian Janitor
1 year, 3 months ago
9 | 9 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
10 | 10 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
11 | 11 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
12 | golang.org/x/tools v0.0.0-20190328211700-ab21143f2384 h1:TFlARGu6Czu1z7q93HTxcP1P+/ZFC/IKythI5RzrnRg= | |
13 | 12 | golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= |
14 | 13 | gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww= |
15 | 14 | gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= |
136 | 136 | ValidationURL: "fakeURL", |
137 | 137 | } |
138 | 138 | |
139 | expected := fmt.Sprintf("CK: \"ck\"\nStatus: \"pending\"\nValidation URL: \"fakeURL\"\n") | |
140 | got := fmt.Sprintf("%s", ckValidationState) | |
139 | expected := "CK: \"ck\"\nStatus: \"pending\"\nValidation URL: \"fakeURL\"\n" | |
140 | got := fmt.Sprint(ckValidationState) | |
141 | 141 | |
142 | 142 | if got != expected { |
143 | 143 | t.Errorf("expected %q, got %q", expected, got) |
3 | 3 | |
4 | 4 | // APIError represents an error that can occurred while calling the API. |
5 | 5 | type APIError struct { |
6 | // Error class | |
7 | Class string `json:"class,omitempty"` | |
6 | 8 | // Error message. |
7 | Message string | |
9 | Message string `json:"message"` | |
10 | // Error details | |
11 | Details map[string]string `json:"details,omitempty"` | |
8 | 12 | // HTTP code. |
9 | 13 | Code int |
10 | 14 | // ID of the request |
12 | 16 | } |
13 | 17 | |
14 | 18 | func (err *APIError) Error() string { |
15 | return fmt.Sprintf("Error %d: %q", err.Code, err.Message) | |
19 | if err.Class == "" { | |
20 | return fmt.Sprintf("HTTP Error %d: %q", err.Code, err.Message) | |
21 | } | |
22 | ||
23 | return fmt.Sprintf("HTTP Error %d: %s: %q (X-OVH-Query-Id: %s)", err.Code, err.Class, err.Message, err.QueryID) | |
16 | 24 | } |
11 | 11 | Message: "Bad request", |
12 | 12 | } |
13 | 13 | |
14 | expected := `Error 400: "Bad request"` | |
14 | expected := `HTTP Error 400: "Bad request"` | |
15 | 15 | got := fmt.Sprintf("%s", err) |
16 | 16 | |
17 | 17 | if got != expected { |
18 | 18 | t.Errorf("expected %q, got %q", expected, got) |
19 | 19 | } |
20 | ||
21 | err.Class = "CartAlreadyExists" | |
22 | err.Code = http.StatusConflict | |
23 | err.Message = `the cart id "foobar" already exists` | |
24 | err.QueryID = "EU.ext-99.foobar" | |
25 | ||
26 | expected = `HTTP Error 409: CartAlreadyExists: "the cart id \"foobar\" already exists" (X-OVH-Query-Id: EU.ext-99.foobar)` | |
27 | got = fmt.Sprintf("%s", err) | |
28 | ||
29 | if got != expected { | |
30 | t.Errorf("expected %q, got %q", expected, got) | |
31 | } | |
20 | 32 | } |
10 | 10 | "io/ioutil" |
11 | 11 | "net/http" |
12 | 12 | "strconv" |
13 | "sync" | |
13 | "sync/atomic" | |
14 | 14 | "time" |
15 | 15 | ) |
16 | 16 | |
41 | 41 | |
42 | 42 | // Errors |
43 | 43 | var ( |
44 | ErrAPIDown = errors.New("go-vh: the OVH API is down, it does't respond to /time anymore") | |
44 | ErrAPIDown = errors.New("go-ovh: the OVH API is not reachable: failed to get /auth/time response") | |
45 | 45 | ) |
46 | 46 | |
47 | 47 | // Client represents a client to call the OVH API |
69 | 69 | // Ensures that the timeDelta function is only ran once |
70 | 70 | // sync.Once would consider init done, even in case of error |
71 | 71 | // hence a good old flag |
72 | timeDeltaMutex *sync.Mutex | |
73 | timeDeltaDone bool | |
74 | timeDelta time.Duration | |
75 | Timeout time.Duration | |
72 | timeDelta atomic.Value | |
73 | ||
74 | // Timeout configures the maximum duration to wait for an API requests to complete | |
75 | Timeout time.Duration | |
76 | ||
77 | // UserAgent configures the user-agent indication that will be sent in the requests to OVHcloud API | |
78 | UserAgent string | |
76 | 79 | } |
77 | 80 | |
78 | 81 | // NewClient represents a new client to call the API |
79 | 82 | func NewClient(endpoint, appKey, appSecret, consumerKey string) (*Client, error) { |
80 | 83 | client := Client{ |
81 | AppKey: appKey, | |
82 | AppSecret: appSecret, | |
83 | ConsumerKey: consumerKey, | |
84 | Client: &http.Client{}, | |
85 | timeDeltaMutex: &sync.Mutex{}, | |
86 | timeDeltaDone: false, | |
87 | Timeout: time.Duration(DefaultTimeout), | |
84 | AppKey: appKey, | |
85 | AppSecret: appSecret, | |
86 | ConsumerKey: consumerKey, | |
87 | Client: &http.Client{}, | |
88 | Timeout: time.Duration(DefaultTimeout), | |
88 | 89 | } |
89 | 90 | |
90 | 91 | // Get and check the configuration |
213 | 214 | return c.CallAPIWithContext(ctx, "DELETE", url, nil, resType, false) |
214 | 215 | } |
215 | 216 | |
216 | // timeDelta returns the time delta between the host and the remote API | |
217 | // timeDelta returns the time delta between the host and the remote API | |
217 | 218 | func (c *Client) getTimeDelta() (time.Duration, error) { |
218 | ||
219 | if !c.timeDeltaDone { | |
220 | // Ensure only one thread is updating | |
221 | c.timeDeltaMutex.Lock() | |
222 | ||
223 | // Ensure that the mutex will be released on return | |
224 | defer c.timeDeltaMutex.Unlock() | |
225 | ||
226 | // Did we wait ? Maybe no more needed | |
227 | if !c.timeDeltaDone { | |
228 | ovhTime, err := c.getTime() | |
229 | if err != nil { | |
230 | return 0, err | |
231 | } | |
232 | ||
233 | c.timeDelta = time.Since(*ovhTime) | |
234 | c.timeDeltaDone = true | |
235 | } | |
236 | } | |
237 | ||
238 | return c.timeDelta, nil | |
219 | d, ok := c.timeDelta.Load().(time.Duration) | |
220 | if ok { | |
221 | return d, nil | |
222 | } | |
223 | ||
224 | ovhTime, err := c.getTime() | |
225 | if err != nil { | |
226 | return 0, err | |
227 | } | |
228 | ||
229 | d = time.Since(*ovhTime) | |
230 | c.timeDelta.Store(d) | |
231 | ||
232 | return d, nil | |
239 | 233 | } |
240 | 234 | |
241 | 235 | // getTime t returns time from for a given api client endpoint |
317 | 311 | // Send the request with requested timeout |
318 | 312 | c.Client.Timeout = c.Timeout |
319 | 313 | |
314 | if c.UserAgent != "" { | |
315 | req.Header.Set("User-Agent", "github.com/ovh/go-ovh ("+c.UserAgent+")") | |
316 | } else { | |
317 | req.Header.Set("User-Agent", "github.com/ovh/go-ovh") | |
318 | } | |
319 | ||
320 | 320 | return req, nil |
321 | 321 | } |
322 | 322 |
10 | 10 | "reflect" |
11 | 11 | "strconv" |
12 | 12 | "strings" |
13 | "sync/atomic" | |
13 | 14 | "testing" |
14 | 15 | "time" |
15 | 16 | "unicode" |
70 | 71 | |
71 | 72 | // Create client |
72 | 73 | client, _ := NewClient(ts.URL, MockApplicationKey, MockApplicationSecret, MockConsumerKey) |
73 | client.timeDeltaDone = true | |
74 | client.timeDelta.Store(time.Duration(0)) | |
74 | 75 | |
75 | 76 | return ts, client |
76 | 77 | } |
401 | 402 | if err != nil { |
402 | 403 | t.Fatalf("Client.UnmarshalResponse should be able to decode the body") |
403 | 404 | } |
404 | if "1234567890" != fmt.Sprint(output["orderId"]) { | |
405 | if fmt.Sprint(output["orderId"]) != "1234567890" { | |
405 | 406 | t.Fatalf("Client.UnmarshalResponse should unmarshal long integer as json.Number instead of float64, stringified incorrectly") |
406 | 407 | } |
407 | 408 | |
521 | 522 | defer ts.Close() |
522 | 523 | |
523 | 524 | // Test |
524 | client.timeDeltaDone = false | |
525 | client.timeDelta = atomic.Value{} | |
525 | 526 | delta, err := client.getTimeDelta() |
526 | 527 | |
527 | 528 | if err != nil { |