1
// Copyright 2014 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
4
package v5_test // import "gopkg.in/juju/charmstore.v5-unstable/internal/v5"
11
jc "github.com/juju/testing/checkers"
12
"github.com/juju/testing/httptesting"
13
"github.com/juju/utils/debugstatus"
14
gc "gopkg.in/check.v1"
15
"gopkg.in/juju/charm.v6-unstable"
16
"gopkg.in/juju/charmrepo.v2-unstable/csclient/params"
18
"gopkg.in/juju/charmstore.v5-unstable/internal/mongodoc"
19
"gopkg.in/juju/charmstore.v5-unstable/internal/router"
22
var zeroTimeStr = time.Time{}.Format(time.RFC3339)
24
func (s *APISuite) TestStatus(c *gc.C) {
25
for _, id := range []*router.ResolvedURL{
26
newResolvedURL("cs:~charmers/precise/wordpress-2", 2),
27
newResolvedURL("cs:~charmers/precise/wordpress-3", 3),
28
newResolvedURL("cs:~foo/precise/mysql-9", 1),
29
newResolvedURL("cs:~bar/utopic/mysql-10", -1),
30
newResolvedURL("cs:~charmers/bundle/wordpress-simple-3", 3),
31
newResolvedURL("cs:~bar/bundle/wordpress-simple-4", -1),
33
if id.URL.Series == "bundle" {
34
s.addPublicBundleFromRepo(c, id.URL.Name, id, false)
36
s.addPublicCharmFromRepo(c, id.URL.Name, id)
40
s.PatchValue(&debugstatus.StartTime, now)
41
start := now.Add(-2 * time.Hour)
42
s.addLog(c, &mongodoc.Log{
43
Data: []byte(`"ingestion started"`),
44
Level: mongodoc.InfoLevel,
45
Type: mongodoc.IngestionType,
48
end := now.Add(-1 * time.Hour)
49
s.addLog(c, &mongodoc.Log{
50
Data: []byte(`"ingestion completed"`),
51
Level: mongodoc.InfoLevel,
52
Type: mongodoc.IngestionType,
55
statisticsStart := now.Add(-1*time.Hour - 30*time.Minute)
56
s.addLog(c, &mongodoc.Log{
57
Data: []byte(`"legacy statistics import started"`),
58
Level: mongodoc.InfoLevel,
59
Type: mongodoc.LegacyStatisticsType,
60
Time: statisticsStart,
62
statisticsEnd := now.Add(-30 * time.Minute)
63
s.addLog(c, &mongodoc.Log{
64
Data: []byte(`"legacy statistics import completed"`),
65
Level: mongodoc.InfoLevel,
66
Type: mongodoc.LegacyStatisticsType,
69
s.AssertDebugStatus(c, true, map[string]params.DebugStatus{
71
Name: "MongoDB is connected",
75
"mongo_collections": {
76
Name: "MongoDB collections",
77
Value: "All required collections exist",
81
Name: "Elastic search is running",
82
Value: "Elastic search is not configured",
86
Name: "Entities in charm store",
87
Value: "4 charms; 2 bundles; 4 promulgated",
91
Name: "Base entities in charm store",
96
Name: "Server started",
102
Value: "started: " + start.Format(time.RFC3339) + ", completed: " + end.Format(time.RFC3339),
105
"legacy_statistics": {
106
Name: "Legacy Statistics Load",
107
Value: "started: " + statisticsStart.Format(time.RFC3339) + ", completed: " + statisticsEnd.Format(time.RFC3339),
113
func (s *APISuite) TestStatusWithoutCorrectCollections(c *gc.C) {
114
s.store.DB.Entities().DropCollection()
115
s.AssertDebugStatus(c, false, map[string]params.DebugStatus{
116
"mongo_collections": {
117
Name: "MongoDB collections",
118
Value: "Missing collections: [" + s.store.DB.Entities().Name + "]",
124
func (s *APISuite) TestStatusWithoutIngestion(c *gc.C) {
125
s.AssertDebugStatus(c, false, map[string]params.DebugStatus{
128
Value: "started: " + zeroTimeStr + ", completed: " + zeroTimeStr,
134
func (s *APISuite) TestStatusIngestionStarted(c *gc.C) {
136
start := now.Add(-1 * time.Hour)
137
s.addLog(c, &mongodoc.Log{
138
Data: []byte(`"ingestion started"`),
139
Level: mongodoc.InfoLevel,
140
Type: mongodoc.IngestionType,
143
s.AssertDebugStatus(c, false, map[string]params.DebugStatus{
146
Value: "started: " + start.Format(time.RFC3339) + ", completed: " + zeroTimeStr,
152
func (s *APISuite) TestStatusWithoutLegacyStatistics(c *gc.C) {
153
s.AssertDebugStatus(c, false, map[string]params.DebugStatus{
154
"legacy_statistics": {
155
Name: "Legacy Statistics Load",
156
Value: "started: " + zeroTimeStr + ", completed: " + zeroTimeStr,
162
func (s *APISuite) TestStatusLegacyStatisticsStarted(c *gc.C) {
164
statisticsStart := now.Add(-1*time.Hour - 30*time.Minute)
165
s.addLog(c, &mongodoc.Log{
166
Data: []byte(`"legacy statistics import started"`),
167
Level: mongodoc.InfoLevel,
168
Type: mongodoc.LegacyStatisticsType,
169
Time: statisticsStart,
171
s.AssertDebugStatus(c, false, map[string]params.DebugStatus{
172
"legacy_statistics": {
173
Name: "Legacy Statistics Load",
174
Value: "started: " + statisticsStart.Format(time.RFC3339) + ", completed: " + zeroTimeStr,
180
func (s *APISuite) TestStatusLegacyStatisticsMultipleLogs(c *gc.C) {
182
statisticsStart := now.Add(-1*time.Hour - 30*time.Minute)
183
s.addLog(c, &mongodoc.Log{
184
Data: []byte(`"legacy statistics import started"`),
185
Level: mongodoc.InfoLevel,
186
Type: mongodoc.LegacyStatisticsType,
187
Time: statisticsStart.Add(-1 * time.Hour),
189
s.addLog(c, &mongodoc.Log{
190
Data: []byte(`"legacy statistics import started"`),
191
Level: mongodoc.InfoLevel,
192
Type: mongodoc.LegacyStatisticsType,
193
Time: statisticsStart,
195
statisticsEnd := now.Add(-30 * time.Minute)
196
s.addLog(c, &mongodoc.Log{
197
Data: []byte(`"legacy statistics import completed"`),
198
Level: mongodoc.InfoLevel,
199
Type: mongodoc.LegacyStatisticsType,
200
Time: statisticsEnd.Add(-1 * time.Hour),
202
s.addLog(c, &mongodoc.Log{
203
Data: []byte(`"legacy statistics import completed"`),
204
Level: mongodoc.InfoLevel,
205
Type: mongodoc.LegacyStatisticsType,
208
s.AssertDebugStatus(c, false, map[string]params.DebugStatus{
209
"legacy_statistics": {
210
Name: "Legacy Statistics Load",
211
Value: "started: " + statisticsStart.Format(time.RFC3339) + ", completed: " + statisticsEnd.Format(time.RFC3339),
217
func (s *APISuite) TestStatusBaseEntitiesError(c *gc.C) {
218
// Add a base entity without any corresponding entities.
219
entity := &mongodoc.BaseEntity{
220
URL: charm.MustParseURL("django"),
223
err := s.store.DB.BaseEntities().Insert(entity)
224
c.Assert(err, gc.IsNil)
226
s.AssertDebugStatus(c, false, map[string]params.DebugStatus{
228
Name: "Base entities in charm store",
235
// AssertDebugStatus asserts that the current /debug/status endpoint
236
// matches the given status, ignoring status duration.
237
// If complete is true, it fails if the results contain
238
// keys not mentioned in status.
239
func (s *APISuite) AssertDebugStatus(c *gc.C, complete bool, status map[string]params.DebugStatus) {
240
rec := httptesting.DoRequest(c, httptesting.DoRequestParams{
242
URL: storeURL("debug/status"),
244
c.Assert(rec.Code, gc.Equals, http.StatusOK, gc.Commentf("body: %s", rec.Body.Bytes()))
245
c.Assert(rec.Header().Get("Content-Type"), gc.Equals, "application/json")
246
var gotStatus map[string]params.DebugStatus
247
err := json.Unmarshal(rec.Body.Bytes(), &gotStatus)
248
c.Assert(err, gc.IsNil)
249
for key, r := range gotStatus {
250
if _, found := status[key]; !complete && !found {
251
delete(gotStatus, key)
257
c.Assert(gotStatus, jc.DeepEquals, status)
260
type statusWithElasticSearchSuite struct {
264
var _ = gc.Suite(&statusWithElasticSearchSuite{})
266
func (s *statusWithElasticSearchSuite) SetUpSuite(c *gc.C) {
268
s.commonSuite.SetUpSuite(c)
271
func (s *statusWithElasticSearchSuite) TestStatusWithElasticSearch(c *gc.C) {
272
rec := httptesting.DoRequest(c, httptesting.DoRequestParams{
274
URL: storeURL("debug/status"),
276
var results map[string]params.DebugStatus
277
err := json.Unmarshal(rec.Body.Bytes(), &results)
278
c.Assert(err, gc.IsNil)
279
c.Assert(results["elasticsearch"].Name, gc.Equals, "Elastic search is running")
280
c.Assert(results["elasticsearch"].Value, jc.Contains, "cluster_name:")