<commit_before>package block

import (
	"bytes"
	"fmt"
	"net/http"
	"net/http/httptest"
	"os"
	"testing"
)

type test struct {
	method           string
	pattern          string
	handler          func(*Context, http.ResponseWriter, *http.Request) (APIResponse, error)
	request          string
	expectedStatus   int
	expectedResponse string
}

func myHostname() string {
	host, _ := os.Hostname()
	return host
}

var tests = []test{
	{
		"GET",
		"/",
		listAPIVersions,
		"",
		http.StatusOK,
		`{"versions":[{"status":"SUPPORTED","updated":"2014-06-28T12:20:21Z","links":[{"href":"http://docs.openstack.org/","type":"text/html","rel":"describedby"},{"href":"` + fmt.Sprintf("https://%s:8776/v2/", myHostname()) + `","rel":"self"}],"min_version":"","version":"","media-types":[{"base":"application/json","type":"application/vnd.openstack.volume+json;version=1"}],"id":"v2.0"}]}`,
	},
	{
		"GET",
		"/v2",
		showAPIv2Details,
		"",
		http.StatusOK,
		`{"choices":[{"status":"CURRENT","media-types":[{"base":"application/json","type":"application/vnd.openstack.volume+json;version=1"}],"id":"v2.0","links":[{"href":"https://kcaccard-mobl3.jf.intel.com:8776/v2/v2.json","rel":"self"}]}]}`,
	},
	{
		"GET",
		"/v2/validtenantid/limits",
		showAbsoluteLimits,
		"",
		http.StatusOK,
		`{"limits":{"rate":[],"absolute":{"totalSnapshotsUsed":0,"maxTotalBackups":-1,"maxTotalVolumeGigabytes":-1,"maxTotalSnapshots":-1,"maxTotalBackupGigabytes":-1,"totalBackupGigabytesUsed":0,"maxTotalVolumes":-1,"totalVolumesUsed":0,"totalBackupsUsed":0,"totalGigabytesUsed":0}}}`,
	},
	{
		"POST",
		"/v2/validtenantid/volumes",
		createVolume,
		`{"volume":{"size": 10,"availability_zone": null,"source_volid": null,"description":null,"multiattach ":false,"snapshot_id":null,"name":null,"imageRef":null,"volume_type":null,"metadata":{},"source_replica":null,"consistencygroup_id":null}}`,
		http.StatusAccepted,
		`{"volume":{"status":"creating","migration_status":null,"user_id":"validuserid","attachments":[],"links":[],"availability_zone":null,"bootable":false,"encrypted":false,"created_at":null,"description":null,"updated_at":null,"volume_type":null,"name":null,"replication_status":"disabled","consistencygroup_id":null,"source_volid":null,"snapshot_id":null,"multiattach":false,"metadata":{},"id":"validvolumeid","size":10}}`,
	},
	{
		"GET",
		"/v2/validtenantid/volumes",
		listVolumes,
		"",
		http.StatusOK,
		`{"volumes":[{"id":"validvolumeid1","links":[],"name":"vol-001"},{"id":"validvolumeid2","links":[],"name":"vol-002"},{"id":"validvolumeid3","links":[],"name":"vol-003"}]}`,
	},
	{
		"GET",
		"/v2/validtenantid/volumes/detail",
		listVolumesDetail,
		"",
		http.StatusOK,
		`{"volumes":[{"migration_status":null,"attachments":[{"server_id":"f4fda93b-06e0-4743-8117-bc8bcecd651b","attachment_id":"3b4db356-253d-4fab-bfa0-e3626c0b8405","host_name":null,"volume_id":"6edbc2f4-1507-44f8-ac0d-eed1d2608d38","device":"/dev/vdb","id":"6edbc2f4-1507-44f8-ac0d-eed1d2608d38"}],"links":[{"href":"http://172.16.31.1071:8776/v2/bab7d5c60cd041a0a36f7c4b6e1dd978/volumes/6edbc2f4-1507-44f8-ac0d-eed1d2608d38","rel":"self"},{"href":"http://23.253.248.171:8776/bab7d5c60cd041a0a36f7c4b6e1dd978/volumes/6edbc2f4-1507-44f8-ac0d-eed1d2608d38","rel":"bookmark"}],"availability_zone":"nova","os-vol-host-attr:host":"cephcluster","encrypted":false,"updated_at":null,"replication_status":"disabled","snapshot_id":null,"id":"6edbc2f4-1507-44f8-ac0d-eed1d2608d38","size":2,"user_id":"32779452fcd34ae1a53a797ac8a1e064","os-vol-tenant-attr:tenant_id":"bab7d5c60cd041a0a36f7c4b6e1dd978","os-vol-mig-status-attr:migstat":null,"metadata":{"attached_mode":"rw","readonly":false},"status":"in-use","description":null,"multiattach":true,"source_volid":null,"consistencygroup_id":null,"os-vol-mig-status-attr:name_id":null,"name":"vol-001","bootable":false,"created_at":null,"volume_type":null}]}`,
	},
	{
		"GET",
		"/v2/validtenantid/volumes/validvolumeid",
		showVolumeDetails,
		"",
		http.StatusOK,
		`{"volume":{"migration_status":null,"attachments":[],"links":[{"href":"http://localhost:8776/v2/0c2eba2c5af04d3f9e9d0d410b371fde/volumes/5aa119a8-d25b-45a7-8d1b-88e127885635","rel":"self"},{"href":"http://localhost:8776/0c2eba2c5af04d3f9e9d0d410b371fde/volumes/5aa119a8-d25b-45a7-8d1b-88e127885635","rel":"bookmark"}],"availability_zone":"nova","os-vol-host-attr:host":"ip-10-168-107-25","encrypted":false,"updated_at":null,"replication_status":"disabled","snapshot_id":null,"id":"5aa119a8-d25b-45a7-8d1b-88e127885635","size":1,"user_id":"32779452fcd34ae1a53a797ac8a1e064","os-vol-tenant-attr:tenant_id":"0c2eba2c5af04d3f9e9d0d410b371fde","os-vol-mig-status-attr:migstat":null,"metadata":{"contents":"not junk"},"status":"available","description":"Super volume.","multiattach":false,"source_volid":null,"consistencygroup_id":null,"os-vol-mig-status-attr:name_id":null,"name":"vol-002","bootable":false,"created_at":null,"volume_type":"None"}}`,
	},
	{
		"DELETE",
		"/v2/validtenantid/volumes/validvolumeid",
		deleteVolume,
		"",
		http.StatusAccepted,
		"null",
	},
	{
		"POST",
		"/v2/validtenantid/volumes/validvolumeid/action",
		volumeAction,
		`{"os-attach":{"instance_uuid":"validinstanceid","mountpoint":"/dev/vdc"}}`,
		http.StatusAccepted,
		"null",
	},
}

type testVolumeService struct{}

func (vs testVolumeService) GetAbsoluteLimits(tenant string) (AbsoluteLimits, error) {
	return AbsoluteLimits{
		MaxTotalBackups:         -1,
		MaxTotalVolumeGigabytes: -1,
		MaxTotalSnapshots:       -1,
		MaxTotalBackupGigabytes: -1,
		MaxTotalVolumes:         -1,
	}, nil
}

func (vs testVolumeService) ShowVolumeDetails(tenant string, volume string) (VolumeDetail, error) {
	volName := "vol-002"

	selfLink := Link{
		Href: "http://localhost:8776/v2/0c2eba2c5af04d3f9e9d0d410b371fde/volumes/5aa119a8-d25b-45a7-8d1b-88e127885635",
		Rel:  "self",
	}

	bookLink := Link{
		Href: "http://localhost:8776/0c2eba2c5af04d3f9e9d0d410b371fde/volumes/5aa119a8-d25b-45a7-8d1b-88e127885635",
		Rel:  "bookmark",
	}

	zone := "nova"
	description := "Super volume."
	volType := "None"

	meta := map[string]interface{}{
		"contents": "not junk",
	}

	return VolumeDetail{
		Attachments:       make([]Attachment, 0),
		Links:             []Link{selfLink, bookLink},
		ReplicationStatus: ReplicationDisabled,
		ID:                "5aa119a8-d25b-45a7-8d1b-88e127885635",
		Status:            Available,
		Name:              &volName,
		AvailabilityZone:  &zone,
		OSVolHostAttr:     "ip-10-168-107-25",
		Size:              1,
		UserID:            "32779452fcd34ae1a53a797ac8a1e064",
		OSVolTenantAttr:   "0c2eba2c5af04d3f9e9d0d410b371fde",
		MetaData:          meta,
		MultiAttach:       false,
		VolumeType:        &volType,
		Description:       &description,
	}, nil
}

func (vs testVolumeService) CreateVolume(tenant string, req RequestedVolume) (Volume, error) {
	return Volume{
		Status:            Creating,
		UserID:            "validuserid",
		Attachments:       make([]Attachment, 0),
		Links:             make([]Link, 0),
		Bootable:          (req.ImageRef != nil),
		Description:       req.Description,
		VolumeType:        req.VolumeType,
		Name:              req.Name,
		ReplicationStatus: ReplicationDisabled,
		SourceVolID:       req.SourceVolID,
		SnapshotID:        req.SnapshotID,
		MultiAttach:       req.MultiAttach,
		MetaData:          req.MetaData,
		ID:                "validvolumeid",
		Size:              req.Size,
	}, nil
}

func (vs testVolumeService) DeleteVolume(tenant string, volume string) error {
	return nil
}

func (vs testVolumeService) AttachVolume(tenant string, volume string, instance string, mountpoint string) error {
	return nil
}

func (vs testVolumeService) ListVolumes(tenant string) ([]ListVolume, error) {
	return []ListVolume{
		{"validvolumeid1", make([]Link, 0), "vol-001"},
		{"validvolumeid2", make([]Link, 0), "vol-002"},
		{"validvolumeid3", make([]Link, 0), "vol-003"},
	}, nil
}

func (vs testVolumeService) ListVolumesDetail(tenant string) ([]VolumeDetail, error) {
	volName := "vol-001"

	attachment := Attachment{
		ServerUUID:     "f4fda93b-06e0-4743-8117-bc8bcecd651b",
		AttachmentUUID: "3b4db356-253d-4fab-bfa0-e3626c0b8405",
		VolumeUUID:     "6edbc2f4-1507-44f8-ac0d-eed1d2608d38",
		Device:         "/dev/vdb",
		DeviceUUID:     "6edbc2f4-1507-44f8-ac0d-eed1d2608d38",
	}

	selfLink := Link{
		Href: "http://23.253.248.171:8776/v2/bab7d5c60cd041a0a36f7c4b6e1dd978/volumes/6edbc2f4-1507-44f8-ac0d-eed1d2608d38",
		Rel:  "self",
	}

	bookLink := Link{
		Href: "http://23.253.248.171:8776/bab7d5c60cd041a0a36f7c4b6e1dd978/volumes/6edbc2f4-1507-44f8-ac0d-eed1d2608d38",
		Rel:  "bookmark",
	}

	zone := "nova"

	meta := map[string]interface{}{
		"attached_mode": "rw",
		"readonly":      false,
	}

	return []VolumeDetail{
		{
			Attachments:       []Attachment{attachment},
			Links:             []Link{selfLink, bookLink},
			ReplicationStatus: ReplicationDisabled,
			ID:                "6edbc2f4-1507-44f8-ac0d-eed1d2608d38",
			Status:            InUse,
			Name:              &volName,
			AvailabilityZone:  &zone,
			OSVolHostAttr:     "cephcluster",
			Size:              2,
			UserID:            "32779452fcd34ae1a53a797ac8a1e064",
			OSVolTenantAttr:   "bab7d5c60cd041a0a36f7c4b6e1dd978",
			MetaData:          meta,
			MultiAttach:       true,
		},
	}, nil
}

func TestAPIResponse(t *testing.T) {
	var vs testVolumeService

	// TBD: add context to test definition so it can be created per
	// endpoint with either a pass testVolumeService or a failure
	// one.
	context := &Context{8776, vs}

	for _, tt := range tests {
		req, err := http.NewRequest(tt.method, tt.pattern, bytes.NewBuffer([]byte(tt.request)))
		if err != nil {
			t.Fatal(err)
		}

		rr := httptest.NewRecorder()
		handler := APIHandler{context, tt.handler}

		handler.ServeHTTP(rr, req)

		status := rr.Code
		if status != tt.expectedStatus {
			t.Errorf("got %v, expected %v", status, tt.expectedStatus)
		}

		if rr.Body.String() != tt.expectedResponse {
			t.Errorf("%s: failed\ngot: %v\nexp: %v", tt.pattern, rr.Body.String(), tt.expectedResponse)
		}
	}
}

func TestRoutes(t *testing.T) {
	var vs testVolumeService
	config := APIConfig{8776, vs}

	r := Routes(config)
	if r == nil {
		t.Fatalf("No routes returned")
	}
}
<commit_msg>openstack: block: use myHostName for block_test<commit_after>package block

import (
	"bytes"
	"fmt"
	"net/http"
	"net/http/httptest"
	"os"
	"testing"
)

type test struct {
	method           string
	pattern          string
	handler          func(*Context, http.ResponseWriter, *http.Request) (APIResponse, error)
	request          string
	expectedStatus   int
	expectedResponse string
}

func myHostname() string {
	host, _ := os.Hostname()
	return host
}

var tests = []test{
	{
		"GET",
		"/",
		listAPIVersions,
		"",
		http.StatusOK,
		`{"versions":[{"status":"SUPPORTED","updated":"2014-06-28T12:20:21Z","links":[{"href":"http://docs.openstack.org/","type":"text/html","rel":"describedby"},{"href":"` + fmt.Sprintf("https://%s:8776/v2/", myHostname()) + `","rel":"self"}],"min_version":"","version":"","media-types":[{"base":"application/json","type":"application/vnd.openstack.volume+json;version=1"}],"id":"v2.0"}]}`,
	},
	{
		"GET",
		"/v2",
		showAPIv2Details,
		"",
		http.StatusOK,
		`{"choices":[{"status":"CURRENT","media-types":[{"base":"application/json","type":"application/vnd.openstack.volume+json;version=1"}],"id":"v2.0","links":[{"href":"` + fmt.Sprintf("https://%s:8776/v2/v2.json", myHostname()) + `","rel":"self"}]}]}`,
	},
	{
		"GET",
		"/v2/validtenantid/limits",
		showAbsoluteLimits,
		"",
		http.StatusOK,
		`{"limits":{"rate":[],"absolute":{"totalSnapshotsUsed":0,"maxTotalBackups":-1,"maxTotalVolumeGigabytes":-1,"maxTotalSnapshots":-1,"maxTotalBackupGigabytes":-1,"totalBackupGigabytesUsed":0,"maxTotalVolumes":-1,"totalVolumesUsed":0,"totalBackupsUsed":0,"totalGigabytesUsed":0}}}`,
	},
	{
		"POST",
		"/v2/validtenantid/volumes",
		createVolume,
		`{"volume":{"size": 10,"availability_zone": null,"source_volid": null,"description":null,"multiattach ":false,"snapshot_id":null,"name":null,"imageRef":null,"volume_type":null,"metadata":{},"source_replica":null,"consistencygroup_id":null}}`,
		http.StatusAccepted,
		`{"volume":{"status":"creating","migration_status":null,"user_id":"validuserid","attachments":[],"links":[],"availability_zone":null,"bootable":false,"encrypted":false,"created_at":null,"description":null,"updated_at":null,"volume_type":null,"name":null,"replication_status":"disabled","consistencygroup_id":null,"source_volid":null,"snapshot_id":null,"multiattach":false,"metadata":{},"id":"validvolumeid","size":10}}`,
	},
	{
		"GET",
		"/v2/validtenantid/volumes",
		listVolumes,
		"",
		http.StatusOK,
		`{"volumes":[{"id":"validvolumeid1","links":[],"name":"vol-001"},{"id":"validvolumeid2","links":[],"name":"vol-002"},{"id":"validvolumeid3","links":[],"name":"vol-003"}]}`,
	},
	{
		"GET",
		"/v2/validtenantid/volumes/detail",
		listVolumesDetail,
		"",
		http.StatusOK,
		`{"volumes":[{"migration_status":null,"attachments":[{"server_id":"f4fda93b-06e0-4743-8117-bc8bcecd651b","attachment_id":"3b4db356-253d-4fab-bfa0-e3626c0b8405","host_name":null,"volume_id":"6edbc2f4-1507-44f8-ac0d-eed1d2608d38","device":"/dev/vdb","id":"6edbc2f4-1507-44f8-ac0d-eed1d2608d38"}],"links":[{"href":"http://192.168.3.11:8776/v2/bab7d5c60cd041a0a36f7c4b6e1dd978/volumes/6edbc2f4-1507-44f8-ac0d-eed1d2608d38","rel":"self"},{"href":"http://2172.16.58.371:8776/bab7d5c60cd041a0a36f7c4b6e1dd978/volumes/6edbc2f4-1507-44f8-ac0d-eed1d2608d38","rel":"bookmark"}],"availability_zone":"nova","os-vol-host-attr:host":"cephcluster","encrypted":false,"updated_at":null,"replication_status":"disabled","snapshot_id":null,"id":"6edbc2f4-1507-44f8-ac0d-eed1d2608d38","size":2,"user_id":"32779452fcd34ae1a53a797ac8a1e064","os-vol-tenant-attr:tenant_id":"bab7d5c60cd041a0a36f7c4b6e1dd978","os-vol-mig-status-attr:migstat":null,"metadata":{"attached_mode":"rw","readonly":false},"status":"in-use","description":null,"multiattach":true,"source_volid":null,"consistencygroup_id":null,"os-vol-mig-status-attr:name_id":null,"name":"vol-001","bootable":false,"created_at":null,"volume_type":null}]}`,
	},
	{
		"GET",
		"/v2/validtenantid/volumes/validvolumeid",
		showVolumeDetails,
		"",
		http.StatusOK,
		`{"volume":{"migration_status":null,"attachments":[],"links":[{"href":"http://localhost:8776/v2/0c2eba2c5af04d3f9e9d0d410b371fde/volumes/5aa119a8-d25b-45a7-8d1b-88e127885635","rel":"self"},{"href":"http://localhost:8776/0c2eba2c5af04d3f9e9d0d410b371fde/volumes/5aa119a8-d25b-45a7-8d1b-88e127885635","rel":"bookmark"}],"availability_zone":"nova","os-vol-host-attr:host":"ip-10-168-107-25","encrypted":false,"updated_at":null,"replication_status":"disabled","snapshot_id":null,"id":"5aa119a8-d25b-45a7-8d1b-88e127885635","size":1,"user_id":"32779452fcd34ae1a53a797ac8a1e064","os-vol-tenant-attr:tenant_id":"0c2eba2c5af04d3f9e9d0d410b371fde","os-vol-mig-status-attr:migstat":null,"metadata":{"contents":"not junk"},"status":"available","description":"Super volume.","multiattach":false,"source_volid":null,"consistencygroup_id":null,"os-vol-mig-status-attr:name_id":null,"name":"vol-002","bootable":false,"created_at":null,"volume_type":"None"}}`,
	},
	{
		"DELETE",
		"/v2/validtenantid/volumes/validvolumeid",
		deleteVolume,
		"",
		http.StatusAccepted,
		"null",
	},
	{
		"POST",
		"/v2/validtenantid/volumes/validvolumeid/action",
		volumeAction,
		`{"os-attach":{"instance_uuid":"validinstanceid","mountpoint":"/dev/vdc"}}`,
		http.StatusAccepted,
		"null",
	},
}

type testVolumeService struct{}

func (vs testVolumeService) GetAbsoluteLimits(tenant string) (AbsoluteLimits, error) {
	return AbsoluteLimits{
		MaxTotalBackups:         -1,
		MaxTotalVolumeGigabytes: -1,
		MaxTotalSnapshots:       -1,
		MaxTotalBackupGigabytes: -1,
		MaxTotalVolumes:         -1,
	}, nil
}

func (vs testVolumeService) ShowVolumeDetails(tenant string, volume string) (VolumeDetail, error) {
	volName := "vol-002"

	selfLink := Link{
		Href: "http://localhost:8776/v2/0c2eba2c5af04d3f9e9d0d410b371fde/volumes/5aa119a8-d25b-45a7-8d1b-88e127885635",
		Rel:  "self",
	}

	bookLink := Link{
		Href: "http://localhost:8776/0c2eba2c5af04d3f9e9d0d410b371fde/volumes/5aa119a8-d25b-45a7-8d1b-88e127885635",
		Rel:  "bookmark",
	}

	zone := "nova"
	description := "Super volume."
	volType := "None"

	meta := map[string]interface{}{
		"contents": "not junk",
	}

	return VolumeDetail{
		Attachments:       make([]Attachment, 0),
		Links:             []Link{selfLink, bookLink},
		ReplicationStatus: ReplicationDisabled,
		ID:                "5aa119a8-d25b-45a7-8d1b-88e127885635",
		Status:            Available,
		Name:              &volName,
		AvailabilityZone:  &zone,
		OSVolHostAttr:     "ip-10-168-107-25",
		Size:              1,
		UserID:            "32779452fcd34ae1a53a797ac8a1e064",
		OSVolTenantAttr:   "0c2eba2c5af04d3f9e9d0d410b371fde",
		MetaData:          meta,
		MultiAttach:       false,
		VolumeType:        &volType,
		Description:       &description,
	}, nil
}

func (vs testVolumeService) CreateVolume(tenant string, req RequestedVolume) (Volume, error) {
	return Volume{
		Status:            Creating,
		UserID:            "validuserid",
		Attachments:       make([]Attachment, 0),
		Links:             make([]Link, 0),
		Bootable:          (req.ImageRef != nil),
		Description:       req.Description,
		VolumeType:        req.VolumeType,
		Name:              req.Name,
		ReplicationStatus: ReplicationDisabled,
		SourceVolID:       req.SourceVolID,
		SnapshotID:        req.SnapshotID,
		MultiAttach:       req.MultiAttach,
		MetaData:          req.MetaData,
		ID:                "validvolumeid",
		Size:              req.Size,
	}, nil
}

func (vs testVolumeService) DeleteVolume(tenant string, volume string) error {
	return nil
}

func (vs testVolumeService) AttachVolume(tenant string, volume string, instance string, mountpoint string) error {
	return nil
}

func (vs testVolumeService) ListVolumes(tenant string) ([]ListVolume, error) {
	return []ListVolume{
		{"validvolumeid1", make([]Link, 0), "vol-001"},
		{"validvolumeid2", make([]Link, 0), "vol-002"},
		{"validvolumeid3", make([]Link, 0), "vol-003"},
	}, nil
}

func (vs testVolumeService) ListVolumesDetail(tenant string) ([]VolumeDetail, error) {
	volName := "vol-001"

	attachment := Attachment{
		ServerUUID:     "f4fda93b-06e0-4743-8117-bc8bcecd651b",
		AttachmentUUID: "3b4db356-253d-4fab-bfa0-e3626c0b8405",
		VolumeUUID:     "6edbc2f4-1507-44f8-ac0d-eed1d2608d38",
		Device:         "/dev/vdb",
		DeviceUUID:     "6edbc2f4-1507-44f8-ac0d-eed1d2608d38",
	}

	selfLink := Link{
		Href: "http://23.253.248.171:8776/v2/bab7d5c60cd041a0a36f7c4b6e1dd978/volumes/6edbc2f4-1507-44f8-ac0d-eed1d2608d38",
		Rel:  "self",
	}

	bookLink := Link{
		Href: "http://2172.16.58.31:8776/bab7d5c60cd041a0a36f7c4b6e1dd978/volumes/6edbc2f4-1507-44f8-ac0d-eed1d2608d38",
		Rel:  "bookmark",
	}

	zone := "nova"

	meta := map[string]interface{}{
		"attached_mode": "rw",
		"readonly":      false,
	}

	return []VolumeDetail{
		{
			Attachments:       []Attachment{attachment},
			Links:             []Link{selfLink, bookLink},
			ReplicationStatus: ReplicationDisabled,
			ID:                "6edbc2f4-1507-44f8-ac0d-eed1d2608d38",
			Status:            InUse,
			Name:              &volName,
			AvailabilityZone:  &zone,
			OSVolHostAttr:     "cephcluster",
			Size:              2,
			UserID:            "32779452fcd34ae1a53a797ac8a1e064",
			OSVolTenantAttr:   "bab7d5c60cd041a0a36f7c4b6e1dd978",
			MetaData:          meta,
			MultiAttach:       true,
		},
	}, nil
}

func TestAPIResponse(t *testing.T) {
	var vs testVolumeService

	// TBD: add context to test definition so it can be created per
	// endpoint with either a pass testVolumeService or a failure
	// one.
	context := &Context{8776, vs}

	for _, tt := range tests {
		req, err := http.NewRequest(tt.method, tt.pattern, bytes.NewBuffer([]byte(tt.request)))
		if err != nil {
			t.Fatal(err)
		}

		rr := httptest.NewRecorder()
		handler := APIHandler{context, tt.handler}

		handler.ServeHTTP(rr, req)

		status := rr.Code
		if status != tt.expectedStatus {
			t.Errorf("got %v, expected %v", status, tt.expectedStatus)
		}

		if rr.Body.String() != tt.expectedResponse {
			t.Errorf("%s: failed\ngot: %v\nexp: %v", tt.pattern, rr.Body.String(), tt.expectedResponse)
		}
	}
}

func TestRoutes(t *testing.T) {
	var vs testVolumeService
	config := APIConfig{8776, vs}

	r := Routes(config)
	if r == nil {
		t.Fatalf("No routes returned")
	}
}

{'fraction_non_alphanumeric': 0.18639442522294236, 'fraction_numerical': 0.08635056771112519, 'mean_word_length': 4.99357476635514, 'pattern_counts': {'":': 314, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 8, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7528683', 'n_tokens_mistral': 9123, 'n_tokens_neox': 8014, 'n_words': 882}